mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
522d279e28 | ||
|
|
ff3c491680 |
2
core/src/components.d.ts
vendored
2
core/src/components.d.ts
vendored
@@ -4067,6 +4067,7 @@ declare global {
|
||||
};
|
||||
interface HTMLIonPickerColumnElementEventMap {
|
||||
"ionChange": PickerColumnChangeEventDetail;
|
||||
"ionValueChange": void;
|
||||
}
|
||||
interface HTMLIonPickerColumnElement extends Components.IonPickerColumn, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonPickerColumnElementEventMap>(type: K, listener: (this: HTMLIonPickerColumnElement, ev: IonPickerColumnCustomEvent<HTMLIonPickerColumnElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
@@ -6648,6 +6649,7 @@ declare namespace LocalJSX {
|
||||
* Emitted when the value has changed.
|
||||
*/
|
||||
"onIonChange"?: (event: IonPickerColumnCustomEvent<PickerColumnChangeEventDetail>) => void;
|
||||
"onIonValueChange"?: (event: IonPickerColumnCustomEvent<void>) => void;
|
||||
/**
|
||||
* The selected option in the picker.
|
||||
*/
|
||||
|
||||
@@ -33,6 +33,7 @@ export class PickerColumnOption implements ComponentInterface {
|
||||
* after the component is loaded.
|
||||
*/
|
||||
@State() ariaLabel?: string | null = null;
|
||||
@State() selected = false;
|
||||
|
||||
/**
|
||||
* If `true`, the user cannot interact with the picker column option.
|
||||
@@ -72,11 +73,27 @@ export class PickerColumnOption implements ComponentInterface {
|
||||
this.ariaLabel = inheritedAttributes['aria-label'] || null;
|
||||
}
|
||||
|
||||
private columnValueChange = () => {
|
||||
const { pickerColumn } = this;
|
||||
if (pickerColumn) {
|
||||
this.selected = pickerColumn.value === this.value;
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.pickerColumn = this.el.closest('ion-picker-column');
|
||||
const pickerColumn = this.pickerColumn = this.el.closest('ion-picker-column');
|
||||
|
||||
if (pickerColumn) {
|
||||
pickerColumn.addEventListener('ionValueChange', this.columnValueChange)
|
||||
this.columnValueChange();
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.pickerColumn) {
|
||||
this. pickerColumn.removeEventListener('ionValueChange', this.columnValueChange)
|
||||
}
|
||||
|
||||
this.pickerColumn = null;
|
||||
}
|
||||
|
||||
@@ -114,7 +131,7 @@ export class PickerColumnOption implements ComponentInterface {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { color, disabled, ariaLabel } = this;
|
||||
const { color, disabled, ariaLabel, selected } = this;
|
||||
const mode = getIonMode(this);
|
||||
|
||||
return (
|
||||
@@ -124,7 +141,12 @@ export class PickerColumnOption implements ComponentInterface {
|
||||
['option-disabled']: disabled,
|
||||
})}
|
||||
>
|
||||
<button tabindex="-1" aria-label={ariaLabel} disabled={disabled} onClick={() => this.onClick()}>
|
||||
<button
|
||||
aria-label={ariaLabel}
|
||||
tabindex="-1"
|
||||
disabled={disabled}
|
||||
onClick={() => this.onClick()}
|
||||
>
|
||||
<slot></slot>
|
||||
</button>
|
||||
</Host>
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
@@ -19,6 +22,18 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.focusable {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
|
||||
background: rgba(0, 255, 0, 0.1);
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.picker-opts {
|
||||
/**
|
||||
* This padding must be set here and not on the
|
||||
|
||||
@@ -69,6 +69,8 @@ export class PickerColumn implements ComponentInterface {
|
||||
*/
|
||||
@Event() ionChange!: EventEmitter<PickerColumnChangeEventDetail>;
|
||||
|
||||
@Event() ionValueChange!: EventEmitter<void>
|
||||
|
||||
@Watch('value')
|
||||
valueChange() {
|
||||
if (this.isColumnVisible) {
|
||||
@@ -78,6 +80,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
*/
|
||||
this.scrollActiveItemIntoView(true);
|
||||
}
|
||||
this.ionValueChange.emit();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,6 +215,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
|
||||
private setPickerItemActiveState = (item: HTMLIonPickerColumnOptionElement, isActive: boolean) => {
|
||||
if (isActive) {
|
||||
this.el.shadowRoot!.querySelector('.focusable')!.setAttribute('aria-valuetext', item.innerText)
|
||||
item.classList.add(PICKER_ITEM_ACTIVE_CLASS);
|
||||
} else {
|
||||
item.classList.remove(PICKER_ITEM_ACTIVE_CLASS);
|
||||
@@ -400,6 +404,8 @@ export class PickerColumn implements ComponentInterface {
|
||||
this.canExitInputMode = true;
|
||||
|
||||
this.setValue(newActiveElement.value);
|
||||
//newActiveElement.tabIndex = 0;
|
||||
//newActiveElement.focus();
|
||||
}, 250);
|
||||
});
|
||||
};
|
||||
@@ -463,6 +469,20 @@ export class PickerColumn implements ComponentInterface {
|
||||
render() {
|
||||
const { color, disabled, isActive, numericInput } = this;
|
||||
const mode = getIonMode(this);
|
||||
const opts = Array.from(this.el.querySelectorAll<HTMLIonPickerColumnOptionElement>('ion-picker-column-option'));
|
||||
|
||||
const index = opts.findIndex((option) => {
|
||||
/**
|
||||
* If the whole picker column is disabled, the current value should appear active
|
||||
* If the current value item is specifically disabled, it should not appear active
|
||||
*/
|
||||
if (!this.disabled && option.disabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return option.value === this.value;
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<Host
|
||||
@@ -474,9 +494,90 @@ export class PickerColumn implements ComponentInterface {
|
||||
})}
|
||||
>
|
||||
<slot name="prefix"></slot>
|
||||
<div
|
||||
class="picker-opts"
|
||||
<div class="focusable"
|
||||
onKeyDown={(ev) => {
|
||||
console.log('helloooo',ev)
|
||||
|
||||
const buttons = Array.from(this.el.querySelectorAll<HTMLIonPickerColumnOptionElement>('ion-picker-column-option'));
|
||||
|
||||
let index = buttons.findIndex((option) => {
|
||||
|
||||
/**
|
||||
* If the whole picker column is disabled, the current value should appear active
|
||||
* If the current value item is specifically disabled, it should not appear active
|
||||
*/
|
||||
if (!this.disabled && option.disabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return option.value === this.value;
|
||||
});
|
||||
|
||||
if (index > -1) {
|
||||
if (ev.key === 'ArrowDown') {
|
||||
|
||||
let el = buttons[index + 1];
|
||||
while(el && el.disabled === true) {
|
||||
index += 1;
|
||||
el = buttons[index];
|
||||
}
|
||||
|
||||
console.log('FOUND',el)
|
||||
if (el) {
|
||||
this.value = el.value;
|
||||
}
|
||||
ev.preventDefault();
|
||||
|
||||
} else if (ev.key === 'ArrowUp') {
|
||||
let el = buttons[index - 1];
|
||||
while(el && el.disabled === true) {
|
||||
index -= 1;
|
||||
el = buttons[index];
|
||||
}
|
||||
|
||||
console.log('FOUND',el)
|
||||
if (el) {
|
||||
this.value = el.value;
|
||||
}
|
||||
ev.preventDefault();
|
||||
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
} else if (index - 1 > buttons.length) {
|
||||
index = buttons.length - 1;
|
||||
}
|
||||
|
||||
const buttonToFocus = buttons[index];
|
||||
if (buttonToFocus) {
|
||||
//this.value = buttonToFocus.value;
|
||||
setTimeout(() => {
|
||||
//buttonToFocus.tabIndex = 0;
|
||||
//buttonToFocus.focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
aria-label="select a month"
|
||||
aria-valuenow={index}
|
||||
aria-valuemax={opts.length - 1}
|
||||
aria-valuemin={0}
|
||||
aria-orientation="vertical"
|
||||
aria-valuetext={this.activeItem?.innerText}
|
||||
role="slider"
|
||||
tabindex={disabled ? undefined : 0}
|
||||
onInput={(ev) => {
|
||||
console.log('tEST',ev)
|
||||
}}
|
||||
|
||||
></div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="picker-opts"
|
||||
ref={(el) => {
|
||||
this.scrollEl = el;
|
||||
}}
|
||||
|
||||
@@ -16,6 +16,15 @@
|
||||
<h1>Picker - a11y</h1>
|
||||
|
||||
<ion-picker>
|
||||
<ion-picker-column color="tertiary" value="3">
|
||||
<ion-picker-column-option value="1" color="tertiary">First</ion-picker-column-option>
|
||||
<ion-picker-column-option value="2" color="tertiary">Second</ion-picker-column-option>
|
||||
<ion-picker-column-option value="3" color="tertiary">Third</ion-picker-column-option>
|
||||
<ion-picker-column-option value="4" color="tertiary">Fourth</ion-picker-column-option>
|
||||
<ion-picker-column-option value="5" color="tertiary" disabled="true">Fifth</ion-picker-column-option>
|
||||
<ion-picker-column-option value="6" color="tertiary">Sixth</ion-picker-column-option>
|
||||
<ion-picker-column-option value="7" color="tertiary">Seventh</ion-picker-column-option>
|
||||
</ion-picker-column>
|
||||
<ion-picker-column color="tertiary" value="3">
|
||||
<ion-picker-column-option value="1" color="tertiary">First</ion-picker-column-option>
|
||||
<ion-picker-column-option value="2" color="tertiary">Second</ion-picker-column-option>
|
||||
|
||||
Reference in New Issue
Block a user