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>
@@ -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
|
||||
|
||||
|
||||
8
core/src/components.d.ts
vendored
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
@import "./picker-column-option";
|
||||
@@ -0,0 +1,5 @@
|
||||
@import "./picker-column-option.scss";
|
||||
|
||||
:host(.option-active) button {
|
||||
color: current-color(base);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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'
|
||||
]);
|
||||
|
||||
|
||||
|
||||