mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Compare commits
7 Commits
5580-test
...
5580-backu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73b0e70931 | ||
|
|
8263f82c69 | ||
|
|
d24ec713f8 | ||
|
|
dd790d40d1 | ||
|
|
4517a7c8de | ||
|
|
aaa1f8d605 | ||
|
|
9865eb0bab |
4
core/src/components.d.ts
vendored
4
core/src/components.d.ts
vendored
@@ -4047,7 +4047,7 @@ declare global {
|
||||
new (): HTMLIonPickerElement;
|
||||
};
|
||||
interface HTMLIonPickerColumnElementEventMap {
|
||||
"ionChange": PickerColumnItem;
|
||||
"ionChange": string | number;
|
||||
}
|
||||
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;
|
||||
@@ -6627,7 +6627,7 @@ declare namespace LocalJSX {
|
||||
/**
|
||||
* Emitted when the value has changed.
|
||||
*/
|
||||
"onIonChange"?: (event: IonPickerColumnCustomEvent<PickerColumnItem>) => void;
|
||||
"onIonChange"?: (event: IonPickerColumnCustomEvent<string | number>) => void;
|
||||
/**
|
||||
* The selected option in the picker.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { inheritAttributes } from '@utils/helpers';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-picker-column-option',
|
||||
styleUrl: 'picker-column-option.scss',
|
||||
shadow: true,
|
||||
})
|
||||
export class PickerColumnOption implements ComponentInterface {
|
||||
@@ -22,7 +23,7 @@ export class PickerColumnOption implements ComponentInterface {
|
||||
/**
|
||||
* If `true`, the user cannot interact with the picker column option.
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
@Prop({ reflect: true }) disabled = false;
|
||||
|
||||
/**
|
||||
* The text value of the option.
|
||||
@@ -53,7 +54,11 @@ export class PickerColumnOption implements ComponentInterface {
|
||||
const { value, disabled, ariaLabel } = this;
|
||||
|
||||
return (
|
||||
<Host>
|
||||
<Host
|
||||
class={{
|
||||
'option-disabled': !!disabled,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
tabindex="-1"
|
||||
aria-label={ariaLabel}
|
||||
|
||||
@@ -33,50 +33,19 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host .picker-item {
|
||||
@include padding(0);
|
||||
@include margin(0);
|
||||
|
||||
::slotted(ion-picker-column-option) {
|
||||
display: block;
|
||||
|
||||
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;
|
||||
|
||||
scroll-snap-align: center;
|
||||
}
|
||||
|
||||
:host .picker-item-empty,
|
||||
:host .picker-item[disabled] {
|
||||
.picker-item-empty {
|
||||
cursor: default;
|
||||
|
||||
scroll-snap-align: none;
|
||||
}
|
||||
|
||||
:host .picker-item-empty,
|
||||
:host(:not([disabled])) .picker-item[disabled] {
|
||||
:host(:not([disabled])) ::slotted(ion-picker-column-option.option-disabled) {
|
||||
scroll-snap-align: none;
|
||||
}
|
||||
|
||||
@@ -84,11 +53,7 @@
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
:host .picker-item[disabled] {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
:host(.picker-column-active) .picker-item.picker-item-active {
|
||||
::slotted(ion-picker-column-option.picker-item-active) {
|
||||
color: current-color(base);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
/**
|
||||
* Emitted when the value has changed.
|
||||
*/
|
||||
@Event() ionChange!: EventEmitter<PickerColumnItem>;
|
||||
@Event() ionChange!: EventEmitter<string | number>;
|
||||
|
||||
@Watch('value')
|
||||
valueChange() {
|
||||
@@ -130,20 +130,23 @@ export class PickerColumn implements ComponentInterface {
|
||||
}
|
||||
|
||||
componentDidRender() {
|
||||
const { activeItem, items, isColumnVisible, value } = this;
|
||||
const { activeItem, isColumnVisible, value } = this;
|
||||
|
||||
if (isColumnVisible) {
|
||||
if (activeItem) {
|
||||
this.scrollActiveItemIntoView();
|
||||
} else if (items[0]?.value !== value) {
|
||||
/**
|
||||
* If the picker column does not have an active item and the current value
|
||||
* does not match the first item in the picker column, that means
|
||||
* the value is out of bounds. In this case, we assign the value to the
|
||||
* first item to match the scroll position of the column.
|
||||
*
|
||||
*/
|
||||
this.setValue(items[0].value);
|
||||
} else {
|
||||
const firstItem = this.el.querySelector('ion-picker-column-option');
|
||||
if (firstItem !== null && firstItem.value !== value) {
|
||||
/**
|
||||
* If the picker column does not have an active item and the current value
|
||||
* does not match the first item in the picker column, that means
|
||||
* the value is out of bounds. In this case, we assign the value to the
|
||||
* first item to match the scroll position of the column.
|
||||
*
|
||||
*/
|
||||
this.setValue(firstItem.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,12 +170,8 @@ export class PickerColumn implements ComponentInterface {
|
||||
*/
|
||||
@Method()
|
||||
async setValue(value?: string | number) {
|
||||
const { items } = this;
|
||||
this.value = value;
|
||||
const findItem = items.find((item) => item.value === value && item.disabled !== true);
|
||||
if (findItem) {
|
||||
this.ionChange.emit(findItem);
|
||||
}
|
||||
this.ionChange.emit(value);
|
||||
}
|
||||
|
||||
private centerPickerItemInView = (target: HTMLElement, smooth = true, canExitInputMode = true) => {
|
||||
@@ -202,10 +201,8 @@ export class PickerColumn implements ComponentInterface {
|
||||
private setPickerItemActiveState = (item: Element, isActive: boolean) => {
|
||||
if (isActive) {
|
||||
item.classList.add(PICKER_ITEM_ACTIVE_CLASS);
|
||||
item.part.add(PICKER_ITEM_ACTIVE_PART);
|
||||
} else {
|
||||
item.classList.remove(PICKER_ITEM_ACTIVE_CLASS);
|
||||
item.part.remove(PICKER_ITEM_ACTIVE_PART);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -270,7 +267,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
const { el } = this;
|
||||
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
let activeEl: HTMLElement | null = this.activeItem;
|
||||
let activeEl: HTMLElement | undefined = this.activeItem;
|
||||
|
||||
const scrollCallback = () => {
|
||||
raf(() => {
|
||||
@@ -294,7 +291,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
|
||||
const activeElement = el.shadowRoot!.elementFromPoint(centerX, centerY) as HTMLButtonElement | null;
|
||||
|
||||
if (activeEl !== null) {
|
||||
if (activeEl !== undefined) {
|
||||
this.setPickerItemActiveState(activeEl, false);
|
||||
}
|
||||
|
||||
@@ -352,22 +349,8 @@ export class PickerColumn implements ComponentInterface {
|
||||
*/
|
||||
this.canExitInputMode = true;
|
||||
|
||||
const dataIndex = activeElement.getAttribute('data-index');
|
||||
|
||||
/**
|
||||
* If no value it is
|
||||
* possible we hit one of the
|
||||
* empty padding columns.
|
||||
*/
|
||||
if (dataIndex === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = parseInt(dataIndex, 10);
|
||||
const selectedItem = this.items[index];
|
||||
|
||||
if (selectedItem.value !== this.value) {
|
||||
this.setValue(selectedItem.value);
|
||||
if (activeElement.value !== this.value) {
|
||||
this.setValue(activeElement.value);
|
||||
}
|
||||
}, 250);
|
||||
});
|
||||
@@ -412,27 +395,29 @@ export class PickerColumn implements ComponentInterface {
|
||||
};
|
||||
|
||||
get activeItem() {
|
||||
// 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
|
||||
const selector = `.picker-item[data-value="${this.value}"]${this.disabled ? '' : ':not([disabled])'}`;
|
||||
const { value } = this;
|
||||
const options = Array.from(
|
||||
this.el.querySelectorAll('ion-picker-column-option') as NodeListOf<HTMLIonPickerColumnOptionElement>
|
||||
);
|
||||
return options.find((option: HTMLIonPickerColumnOptionElement) => {
|
||||
/**
|
||||
* 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 getElementRoot(this.el).querySelector(selector) as HTMLElement | null;
|
||||
return option.value === value;
|
||||
}) as HTMLElement | undefined;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { items, color, disabled: pickerDisabled, isActive, numericInput } = this;
|
||||
const { color, disabled: pickerDisabled, isActive, numericInput } = this;
|
||||
const mode = getIonMode(this);
|
||||
|
||||
/**
|
||||
* exportparts is needed so ion-datetime can expose the parts
|
||||
* from two layers of shadow nesting. If this causes problems,
|
||||
* the attribute can be moved to datetime.tsx and set on every
|
||||
* instance of ion-picker-column there instead.
|
||||
*/
|
||||
|
||||
return (
|
||||
<Host
|
||||
exportparts={`${PICKER_ITEM_PART}, ${PICKER_ITEM_ACTIVE_PART}`}
|
||||
disabled={pickerDisabled}
|
||||
tabindex={pickerDisabled ? null : 0}
|
||||
class={createColorClasses(color, {
|
||||
@@ -450,37 +435,7 @@ export class PickerColumn implements ComponentInterface {
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
{items.map((item, index) => {
|
||||
const isItemDisabled = pickerDisabled || item.disabled || false;
|
||||
|
||||
{
|
||||
/*
|
||||
Users should be able to tab
|
||||
between multiple columns. As a result,
|
||||
we set tabindex here so that tabbing switches
|
||||
between columns instead of buttons. Users
|
||||
can still use arrow keys on the keyboard to
|
||||
navigate the column up and down.
|
||||
*/
|
||||
}
|
||||
return (
|
||||
<button
|
||||
tabindex="-1"
|
||||
class={{
|
||||
'picker-item': true,
|
||||
}}
|
||||
data-value={item.value}
|
||||
data-index={index}
|
||||
onClick={(ev: Event) => {
|
||||
this.centerPickerItemInView(ev.target as HTMLElement, true);
|
||||
}}
|
||||
disabled={isItemDisabled}
|
||||
part={PICKER_ITEM_PART}
|
||||
>
|
||||
{item.text}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<slot></slot>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
@@ -496,5 +451,3 @@ export class PickerColumn implements ComponentInterface {
|
||||
}
|
||||
|
||||
const PICKER_ITEM_ACTIVE_CLASS = 'picker-item-active';
|
||||
const PICKER_ITEM_PART = 'wheel-item';
|
||||
const PICKER_ITEM_ACTIVE_PART = 'active';
|
||||
|
||||
@@ -47,23 +47,37 @@
|
||||
<div class="grid-item">
|
||||
<h2>Default</h2>
|
||||
<ion-picker>
|
||||
<ion-picker-column id="default"></ion-picker-column>
|
||||
<ion-picker-column id="default">
|
||||
<ion-picker-column-option value="0">0</ion-picker-column-option>
|
||||
<ion-picker-column-option value="1">1</ion-picker-column-option>
|
||||
<ion-picker-column-option value="2">2</ion-picker-column-option>
|
||||
<ion-picker-column-option value="3">3</ion-picker-column-option>
|
||||
<ion-picker-column-option value="4">4</ion-picker-column-option>
|
||||
<ion-picker-column-option value="5">5</ion-picker-column-option>
|
||||
<ion-picker-column-option value="6">6</ion-picker-column-option>
|
||||
<ion-picker-column-option value="7">7</ion-picker-column-option>
|
||||
<ion-picker-column-option value="8">8</ion-picker-column-option>
|
||||
<ion-picker-column-option value="9">9</ion-picker-column-option>
|
||||
<ion-picker-column-option value="10">10</ion-picker-column-option>
|
||||
<ion-picker-column-option value="11">11</ion-picker-column-option>
|
||||
<ion-picker-column-option value="12">12</ion-picker-column-option>
|
||||
<ion-picker-column-option value="13">13</ion-picker-column-option>
|
||||
<ion-picker-column-option value="14">14</ion-picker-column-option>
|
||||
<ion-picker-column-option value="15">15</ion-picker-column-option>
|
||||
<ion-picker-column-option value="16">16</ion-picker-column-option>
|
||||
<ion-picker-column-option value="17">17</ion-picker-column-option>
|
||||
<ion-picker-column-option value="18">18</ion-picker-column-option>
|
||||
<ion-picker-column-option value="19">19</ion-picker-column-option>
|
||||
<ion-picker-column-option value="20">20</ion-picker-column-option>
|
||||
<ion-picker-column-option value="21">21</ion-picker-column-option>
|
||||
<ion-picker-column-option value="22">22</ion-picker-column-option>
|
||||
<ion-picker-column-option value="23">23</ion-picker-column-option>
|
||||
<ion-picker-column-option value="24">24</ion-picker-column-option>
|
||||
</ion-picker-column>
|
||||
</ion-picker>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
<script>
|
||||
const defaultPickerColumn = document.getElementById('default');
|
||||
|
||||
const items = Array(24)
|
||||
.fill()
|
||||
.map((_, i) => ({
|
||||
text: `${i}`,
|
||||
value: i,
|
||||
}));
|
||||
|
||||
defaultPickerColumn.items = items;
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user