feat(picker-column): add styles, disabled and active states (#28621)

Issue number: Internal

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

We'd like to introduce a new API to the picker column to allow
developers to manipulate the picker options right in the DOM. Currently
developers need to pass an object which is quite cumbersome as you need
to re-pass that object anytime you want to change a single option.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

This PR does some of the prep work to make integrating the picker column
option into picker column easier. It does the following things:

1. Copies the base button styles from picker-column over to
picker-column-option
2. Creates active and disabled states (plus styles)
3. Add tests for base styles

Note: There are duplicate styles across picker-column and
picker-column-option that will be cleaned up once picker-column-option
is integrated and shown to be functional.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

---------

Co-authored-by: ionitron <hi@ionicframework.com>
This commit is contained in:
Liam DeBeasi
2023-12-05 14:40:53 -05:00
committed by GitHub
parent 0b469646b2
commit 91d0e267b2
36 changed files with 162 additions and 18 deletions

View File

@@ -919,6 +919,7 @@ ion-picker-column,prop,value,number | string | undefined,undefined,false,false
ion-picker-column,event,ionChange,PickerColumnItem,true
ion-picker-column-option,shadow
ion-picker-column-option,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,'primary',false,true
ion-picker-column-option,prop,disabled,boolean,false,false,false
ion-picker-column-option,prop,value,any,undefined,false,false

View File

@@ -1987,6 +1987,10 @@ export namespace Components {
"value"?: string | number;
}
interface IonPickerColumnOption {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* If `true`, the user cannot interact with the picker column option.
*/
@@ -6634,6 +6638,10 @@ declare namespace LocalJSX {
"value"?: string | number;
}
interface IonPickerColumnOption {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* If `true`, the user cannot interact with the picker column option.
*/

View File

@@ -0,0 +1 @@
@import "./picker-column-option";

View File

@@ -0,0 +1,5 @@
@import "./picker-column-option.scss";
:host(.option-active) button {
color: current-color(base);
}

View File

@@ -0,0 +1,45 @@
@import "../../themes/ionic.globals";
// Picker Column
// --------------------------------------------------
button {
@include padding(0);
@include margin(0);
width: 100%;
height: 34px;
border: 0px;
outline: none;
background: transparent;
color: inherit;
font-family: $font-family-base;
font-size: inherit;
line-height: 34px;
text-align: inherit;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
overflow: hidden;
}
:host(.option-disabled) {
opacity: 0.4;
}
:host(.option-disabled) button {
cursor: default;
}

View File

@@ -1,9 +1,17 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';
import { inheritAttributes } from '@utils/helpers';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import type { Color } from '../../interface';
@Component({
tag: 'ion-picker-column-option',
styleUrls: {
ios: 'picker-column-option.ios.scss',
md: 'picker-column-option.md.scss',
},
shadow: true,
})
export class PickerColumnOption implements ComponentInterface {
@@ -29,6 +37,13 @@ export class PickerColumnOption implements ComponentInterface {
*/
@Prop() value?: any | null;
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information on colors, see [theming](/docs/theming/basics).
*/
@Prop({ reflect: true }) color?: Color = 'primary';
/**
* The aria-label of the option has changed after the
* first render and needs to be updated within the component.
@@ -50,19 +65,17 @@ export class PickerColumnOption implements ComponentInterface {
}
render() {
const { value, disabled, ariaLabel } = this;
const { color, value, disabled, ariaLabel } = this;
const mode = getIonMode(this);
return (
<Host>
<button
tabindex="-1"
aria-label={ariaLabel}
class={{
'picker-opt': true,
'picker-opt-disabled': !!disabled,
}}
disabled={disabled}
>
<Host
class={createColorClasses(color, {
[mode]: true,
['option-disabled']: disabled,
})}
>
<button tabindex="-1" aria-label={ariaLabel} disabled={disabled}>
<slot>{value}</slot>
</button>
</Host>

View File

@@ -2,7 +2,7 @@
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Picker Column Option - Basic</title>
<title>Picker Column Option - a11y</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
@@ -14,6 +14,9 @@
<main>
<ion-picker-column-option> my option </ion-picker-column-option>
<ion-picker-column-option aria-label="the best one"> other option </ion-picker-column-option>
<ion-picker-column-option color="tertiary" class="option-active">option</ion-picker-column-option>
<ion-picker-column-option disabled="true">option</ion-picker-column-option>
<ion-picker-column-option color="tertiary" class="option-active" disabled="true">option</ion-picker-column-option>
</main>
</body>
</html>

View File

@@ -46,7 +46,19 @@
<div class="grid">
<div class="grid-item">
<h2>Default</h2>
<ion-picker-column-option> my option </ion-picker-column-option>
<ion-picker-column-option>My Option</ion-picker-column-option>
</div>
<div class="grid-item">
<h2>Disabled</h2>
<ion-picker-column-option disabled="true">My Option</ion-picker-column-option>
</div>
<div class="grid-item">
<h2>Active</h2>
<ion-picker-column-option class="option-active">My Option</ion-picker-column-option>
</div>
<div class="grid-item">
<h2>Active / Disabled</h2>
<ion-picker-column-option class="option-active" disabled="true">My Option</ion-picker-column-option>
</div>
</div>
</ion-content>

View File

@@ -0,0 +1,55 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('picker-column-option: rendering'), () => {
test('picker option should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-picker-column-option value="option">My Option</ion-picker-column-option>
`,
config
);
const option = page.locator('ion-picker-column-option');
await expect(option).toHaveScreenshot(screenshot('picker-column-option'));
});
test('disabled picker option should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-picker-column-option disabled="true" value="option">My Option</ion-picker-column-option>
`,
config
);
const option = page.locator('ion-picker-column-option');
await expect(option).toHaveScreenshot(screenshot('disabled-picker-column-option'));
});
test('active picker option should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-picker-column-option class="option-active" value="option">My Option</ion-picker-column-option>
`,
config
);
const option = page.locator('ion-picker-column-option');
await expect(option).toHaveScreenshot(screenshot('active-picker-column-option'));
});
test('disabled active picker option should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-picker-column-option class="option-active" disabled="true" value="option">My Option</ion-picker-column-option>
`,
config
);
const option = page.locator('ion-picker-column-option');
await expect(option).toHaveScreenshot(screenshot('disabled-active-picker-column-option'));
});
});
});

View File

@@ -1476,14 +1476,14 @@ export declare interface IonPickerColumn extends Components.IonPickerColumn {
@ProxyCmp({
inputs: ['disabled', 'value']
inputs: ['color', 'disabled', 'value']
})
@Component({
selector: 'ion-picker-column-option',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['disabled', 'value'],
inputs: ['color', 'disabled', 'value'],
})
export class IonPickerColumnOption {
protected el: HTMLElement;

View File

@@ -1473,14 +1473,14 @@ export declare interface IonPickerColumn extends Components.IonPickerColumn {
@ProxyCmp({
defineCustomElementFn: defineIonPickerColumnOption,
inputs: ['disabled', 'value']
inputs: ['color', 'disabled', 'value']
})
@Component({
selector: 'ion-picker-column-option',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['disabled', 'value'],
inputs: ['color', 'disabled', 'value'],
standalone: true
})
export class IonPickerColumnOption {

View File

@@ -589,7 +589,8 @@ export const IonPickerColumn = /*@__PURE__*/ defineContainer<JSX.IonPickerColumn
export const IonPickerColumnOption = /*@__PURE__*/ defineContainer<JSX.IonPickerColumnOption>('ion-picker-column-option', defineIonPickerColumnOption, [
'disabled',
'value'
'value',
'color'
]);