Compare commits
64 Commits
ionic-modu
...
ld/5580-cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4f3c67403 | ||
|
|
5190ab3e9e | ||
|
|
1e3effcda3 | ||
|
|
2552147983 | ||
|
|
f88b74dcda | ||
|
|
ca1b51938d | ||
|
|
fdfc5fc332 | ||
|
|
b5dbc101ea | ||
|
|
59bd18a7ff | ||
|
|
91d0e267b2 | ||
|
|
cf9fe315a3 | ||
|
|
fe3070bac2 | ||
|
|
d36d645865 | ||
|
|
cf3d028d69 | ||
|
|
f9d01b9041 | ||
|
|
0ef015b5be | ||
|
|
33a21d3675 | ||
|
|
a98e85d632 | ||
|
|
e4797f73f4 | ||
|
|
d48c41db5b | ||
|
|
e8d5599aad | ||
|
|
c1d5401556 | ||
|
|
90e2d2cf2c | ||
|
|
a52413113f | ||
|
|
6d2f998d6e | ||
|
|
6ddc15f3ed | ||
|
|
514b3b6885 | ||
|
|
3da0590a09 | ||
|
|
4b564ee9b2 | ||
|
|
3b67bd3e0c | ||
|
|
cfcbcd92bd | ||
|
|
95628755aa | ||
|
|
59113bb4cd | ||
|
|
cab56466a2 | ||
|
|
656ac5bb01 | ||
|
|
dc93b8ab15 | ||
|
|
892a269d18 | ||
|
|
506f42bec4 | ||
|
|
ed8cfa06fe | ||
|
|
edb7bade3d | ||
|
|
84c3c52347 | ||
|
|
8693fd6cf3 | ||
|
|
5a9a7d1adb | ||
|
|
313285d2b8 | ||
|
|
7473d64a4e | ||
|
|
948c8d85a5 | ||
|
|
58a89b329e | ||
|
|
fc36cc50ca | ||
|
|
e933833763 | ||
|
|
34ec94ffda | ||
|
|
8d5a043a64 | ||
|
|
3470c64e51 | ||
|
|
2c773ed0e6 | ||
|
|
b1fc67227c | ||
|
|
75ee951ce8 | ||
|
|
2f3f9dc9ca | ||
|
|
b68c93d55d | ||
|
|
eace6425a2 | ||
|
|
1aeb19403b | ||
|
|
9d0834b201 | ||
|
|
7b21bd40a6 | ||
|
|
0b469646b2 | ||
|
|
5e47412e1f | ||
|
|
cc45e2220b |
6
.github/CODEOWNERS
vendored
@@ -11,6 +11,8 @@
|
||||
# In each subsection folders are ordered first by depth, then alphabetically.
|
||||
# This should make it easy to add new rules without breaking existing ones.
|
||||
|
||||
* @ionic-team/framework
|
||||
|
||||
# Frameworks
|
||||
|
||||
## Angular
|
||||
@@ -51,8 +53,8 @@
|
||||
/core/src/components/nav/ @sean-perkins
|
||||
/core/src/components/nav-link/ @sean-perkins
|
||||
|
||||
/core/src/components/picker-internal/ @liamdebeasi
|
||||
/core/src/components/picker-column-internal/ @liamdebeasi
|
||||
/core/src/components/picker/ @liamdebeasi
|
||||
/core/src/components/picker-column/ @liamdebeasi
|
||||
|
||||
/core/src/components/radio/ @amandaejohnston
|
||||
/core/src/components/radio-group/ @amandaejohnston
|
||||
|
||||
15
.github/labeler.yml
vendored
@@ -6,16 +6,17 @@
|
||||
# https://github.com/actions/labeler
|
||||
|
||||
'package: core':
|
||||
- core/**/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['core/**/*']
|
||||
|
||||
'package: angular':
|
||||
- packages/angular/**/*
|
||||
- packages/angular-*/**/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/angular/**/*', 'packages/angular-*/**/*']
|
||||
|
||||
'package: react':
|
||||
- packages/react/**/*
|
||||
- packages/react-*/**/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/react/**/*', 'packages/react-*/**/*']
|
||||
|
||||
'package: vue':
|
||||
- packages/vue/**/*
|
||||
- packages/vue-*/**/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['packages/vue/**/*', 'packages/vue-*/**/*']
|
||||
|
||||
2
.github/workflows/label.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@main
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
sync-labels: true
|
||||
|
||||
@@ -17,6 +17,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
|
||||
- [Components](#version-8x-components)
|
||||
- [Content](#version-8x-content)
|
||||
- [Datetime](#version-8x-datetime)
|
||||
- [Picker](#version-8x-picker)
|
||||
|
||||
<h2 id="version-8x-browser-platform-support">Browser and Platform Support</h2>
|
||||
|
||||
@@ -59,4 +60,9 @@ This section details the desktop browser, JavaScript framework, and mobile platf
|
||||
|
||||
+ background: red;
|
||||
}
|
||||
```
|
||||
```
|
||||
<h2 id="version-8x-picker">Picker</h2>
|
||||
|
||||
- `ion-picker` and `ion-picker-column` have been renamed to `ion-picker-legacy` and `ion-picker-legacy-column`, respectively. This change was made to accommodate the new inline picker component while allowing developers to continue to use the legacy picker during this migration period.
|
||||
- Only the component names have been changed. Usages such as `ion-picker` or `IonPicker` should be changed to `ion-picker-legacy` and `IonPickerLegacy`, respectively.
|
||||
- Non-component usages such as `pickerController` or `useIonPicker` remain unchanged. The new picker displays inline with your page content and does not have equivalents for these non-component usages.
|
||||
12
CHANGELOG.md
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.5.7](https://github.com/ionic-team/ionic-framework/compare/v7.5.6...v7.5.7) (2023-11-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** date inputs render correctly in mobile safari ([#28495](https://github.com/ionic-team/ionic-framework/issues/28495)) ([b833f0e](https://github.com/ionic-team/ionic-framework/commit/b833f0e826ddd261230e2e29b70e2dc884d8cb04)), closes [#28494](https://github.com/ionic-team/ionic-framework/issues/28494)
|
||||
* **datetime:** allow disabling datetime with prefer-wheel ([#28511](https://github.com/ionic-team/ionic-framework/issues/28511)) ([01130e1](https://github.com/ionic-team/ionic-framework/commit/01130e12e1d73bbf558da9d4dffd7122822ff39c))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.5.6](https://github.com/ionic-team/ionic-framework/compare/v7.5.5...v7.5.6) (2023-11-21)
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.5.7](https://github.com/ionic-team/ionic-framework/compare/v7.5.6...v7.5.7) (2023-11-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** date inputs render correctly in mobile safari ([#28495](https://github.com/ionic-team/ionic-framework/issues/28495)) ([b833f0e](https://github.com/ionic-team/ionic-framework/commit/b833f0e826ddd261230e2e29b70e2dc884d8cb04)), closes [#28494](https://github.com/ionic-team/ionic-framework/issues/28494)
|
||||
* **datetime:** allow disabling datetime with prefer-wheel ([#28511](https://github.com/ionic-team/ionic-framework/issues/28511)) ([01130e1](https://github.com/ionic-team/ionic-framework/commit/01130e12e1d73bbf558da9d4dffd7122822ff39c))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.5.6](https://github.com/ionic-team/ionic-framework/compare/v7.5.5...v7.5.6) (2023-11-21)
|
||||
|
||||
|
||||
|
||||
98
core/api.txt
@@ -906,47 +906,65 @@ ion-note,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "second
|
||||
ion-note,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-note,css-prop,--color
|
||||
|
||||
ion-picker,scoped
|
||||
ion-picker,prop,animated,boolean,true,false,false
|
||||
ion-picker,prop,backdropDismiss,boolean,true,false,false
|
||||
ion-picker,prop,buttons,PickerButton[],[],false,false
|
||||
ion-picker,prop,columns,PickerColumn[],[],false,false
|
||||
ion-picker,prop,cssClass,string | string[] | undefined,undefined,false,false
|
||||
ion-picker,prop,duration,number,0,false,false
|
||||
ion-picker,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-picker,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false
|
||||
ion-picker,prop,isOpen,boolean,false,false,false
|
||||
ion-picker,prop,keyboardClose,boolean,true,false,false
|
||||
ion-picker,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-picker,shadow
|
||||
ion-picker,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-picker,prop,showBackdrop,boolean,true,false,false
|
||||
ion-picker,prop,trigger,string | undefined,undefined,false,false
|
||||
ion-picker,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
|
||||
ion-picker,method,getColumn,getColumn(name: string) => Promise<PickerColumn | undefined>
|
||||
ion-picker,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
|
||||
ion-picker,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
|
||||
ion-picker,method,present,present() => Promise<void>
|
||||
ion-picker,event,didDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker,event,didPresent,void,true
|
||||
ion-picker,event,ionPickerDidDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker,event,ionPickerDidPresent,void,true
|
||||
ion-picker,event,ionPickerWillDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker,event,ionPickerWillPresent,void,true
|
||||
ion-picker,event,willDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker,event,willPresent,void,true
|
||||
ion-picker,css-prop,--backdrop-opacity
|
||||
ion-picker,css-prop,--background
|
||||
ion-picker,css-prop,--background-rgb
|
||||
ion-picker,css-prop,--border-color
|
||||
ion-picker,css-prop,--border-radius
|
||||
ion-picker,css-prop,--border-style
|
||||
ion-picker,css-prop,--border-width
|
||||
ion-picker,css-prop,--height
|
||||
ion-picker,css-prop,--max-height
|
||||
ion-picker,css-prop,--max-width
|
||||
ion-picker,css-prop,--min-height
|
||||
ion-picker,css-prop,--min-width
|
||||
ion-picker,css-prop,--width
|
||||
ion-picker,event,ionInputModeChange,PickerChangeEventDetail,true
|
||||
|
||||
ion-picker-column,shadow
|
||||
ion-picker-column,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,'primary',false,true
|
||||
ion-picker-column,prop,disabled,boolean,false,false,false
|
||||
ion-picker-column,prop,items,PickerColumnItem[],[],false,false
|
||||
ion-picker-column,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-picker-column,prop,value,number | string | undefined,undefined,false,false
|
||||
ion-picker-column,method,setFocus,setFocus() => Promise<void>
|
||||
ion-picker-column,event,ionChange,PickerColumnChangeEventDetail,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
|
||||
|
||||
ion-picker-legacy,scoped
|
||||
ion-picker-legacy,prop,animated,boolean,true,false,false
|
||||
ion-picker-legacy,prop,backdropDismiss,boolean,true,false,false
|
||||
ion-picker-legacy,prop,buttons,PickerButton[],[],false,false
|
||||
ion-picker-legacy,prop,columns,PickerColumn[],[],false,false
|
||||
ion-picker-legacy,prop,cssClass,string | string[] | undefined,undefined,false,false
|
||||
ion-picker-legacy,prop,duration,number,0,false,false
|
||||
ion-picker-legacy,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-picker-legacy,prop,htmlAttributes,undefined | { [key: string]: any; },undefined,false,false
|
||||
ion-picker-legacy,prop,isOpen,boolean,false,false,false
|
||||
ion-picker-legacy,prop,keyboardClose,boolean,true,false,false
|
||||
ion-picker-legacy,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
|
||||
ion-picker-legacy,prop,mode,"ios" | "md",undefined,false,false
|
||||
ion-picker-legacy,prop,showBackdrop,boolean,true,false,false
|
||||
ion-picker-legacy,prop,trigger,string | undefined,undefined,false,false
|
||||
ion-picker-legacy,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
|
||||
ion-picker-legacy,method,getColumn,getColumn(name: string) => Promise<PickerColumn | undefined>
|
||||
ion-picker-legacy,method,onDidDismiss,onDidDismiss<T = any>() => Promise<OverlayEventDetail<T>>
|
||||
ion-picker-legacy,method,onWillDismiss,onWillDismiss<T = any>() => Promise<OverlayEventDetail<T>>
|
||||
ion-picker-legacy,method,present,present() => Promise<void>
|
||||
ion-picker-legacy,event,didDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker-legacy,event,didPresent,void,true
|
||||
ion-picker-legacy,event,ionPickerDidDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker-legacy,event,ionPickerDidPresent,void,true
|
||||
ion-picker-legacy,event,ionPickerWillDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker-legacy,event,ionPickerWillPresent,void,true
|
||||
ion-picker-legacy,event,willDismiss,OverlayEventDetail<any>,true
|
||||
ion-picker-legacy,event,willPresent,void,true
|
||||
ion-picker-legacy,css-prop,--backdrop-opacity
|
||||
ion-picker-legacy,css-prop,--background
|
||||
ion-picker-legacy,css-prop,--background-rgb
|
||||
ion-picker-legacy,css-prop,--border-color
|
||||
ion-picker-legacy,css-prop,--border-radius
|
||||
ion-picker-legacy,css-prop,--border-style
|
||||
ion-picker-legacy,css-prop,--border-width
|
||||
ion-picker-legacy,css-prop,--height
|
||||
ion-picker-legacy,css-prop,--max-height
|
||||
ion-picker-legacy,css-prop,--max-width
|
||||
ion-picker-legacy,css-prop,--min-height
|
||||
ion-picker-legacy,css-prop,--min-width
|
||||
ion-picker-legacy,css-prop,--width
|
||||
|
||||
ion-popover,shadow
|
||||
ion-popover,prop,alignment,"center" | "end" | "start" | undefined,undefined,false,false
|
||||
|
||||
18
core/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.5.6",
|
||||
"version": "7.5.7",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "7.5.6",
|
||||
"version": "7.5.7",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.7.2",
|
||||
"@stencil/core": "^4.8.1",
|
||||
"ionicons": "^7.2.1",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
@@ -1825,9 +1825,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.7.2.tgz",
|
||||
"integrity": "sha512-sPPDYrXiTbfeUF5CCyfqysXK/yfTHC4xYR1+nHzGkS2vhRSBOLp0oPuB+xkJLKA+K2ZqDJUxpOnDxy1CLWwBXA==",
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.8.1.tgz",
|
||||
"integrity": "sha512-KG1H10j24rlyxIqOI4CG8/h9T7ObTv7giW2H3u1qXV4KKrLykDOpMcLzpqNXqL2Fki3s1QvHyl/oaRvi5waWVw==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
@@ -12184,9 +12184,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.7.2.tgz",
|
||||
"integrity": "sha512-sPPDYrXiTbfeUF5CCyfqysXK/yfTHC4xYR1+nHzGkS2vhRSBOLp0oPuB+xkJLKA+K2ZqDJUxpOnDxy1CLWwBXA=="
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.8.1.tgz",
|
||||
"integrity": "sha512-KG1H10j24rlyxIqOI4CG8/h9T7ObTv7giW2H3u1qXV4KKrLykDOpMcLzpqNXqL2Fki3s1QvHyl/oaRvi5waWVw=="
|
||||
},
|
||||
"@stencil/react-output-target": {
|
||||
"version": "0.5.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.5.6",
|
||||
"version": "7.5.7",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -31,7 +31,7 @@
|
||||
"loader/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.7.2",
|
||||
"@stencil/core": "^4.8.1",
|
||||
"ionicons": "^7.2.1",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
|
||||
151
core/scripts/testing/themes/dark.css
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Dark Colors
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
:root {
|
||||
--ion-color-primary: #428cff;
|
||||
--ion-color-primary-rgb: 66, 140, 255;
|
||||
--ion-color-primary-contrast: #ffffff;
|
||||
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-primary-shade: #3a7be0;
|
||||
--ion-color-primary-tint: #5598ff;
|
||||
|
||||
--ion-color-secondary: #50c8ff;
|
||||
--ion-color-secondary-rgb: 80, 200, 255;
|
||||
--ion-color-secondary-contrast: #ffffff;
|
||||
--ion-color-secondary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-secondary-shade: #46b0e0;
|
||||
--ion-color-secondary-tint: #62ceff;
|
||||
|
||||
--ion-color-tertiary: #6a64ff;
|
||||
--ion-color-tertiary-rgb: 106, 100, 255;
|
||||
--ion-color-tertiary-contrast: #ffffff;
|
||||
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-tertiary-shade: #5d58e0;
|
||||
--ion-color-tertiary-tint: #7974ff;
|
||||
|
||||
--ion-color-success: #2fdf75;
|
||||
--ion-color-success-rgb: 47, 223, 117;
|
||||
--ion-color-success-contrast: #000000;
|
||||
--ion-color-success-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-success-shade: #29c467;
|
||||
--ion-color-success-tint: #44e283;
|
||||
|
||||
--ion-color-warning: #ffd534;
|
||||
--ion-color-warning-rgb: 255, 213, 52;
|
||||
--ion-color-warning-contrast: #000000;
|
||||
--ion-color-warning-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-warning-shade: #e0bb2e;
|
||||
--ion-color-warning-tint: #ffd948;
|
||||
|
||||
--ion-color-danger: #ff4961;
|
||||
--ion-color-danger-rgb: 255, 73, 97;
|
||||
--ion-color-danger-contrast: #ffffff;
|
||||
--ion-color-danger-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-danger-shade: #e04055;
|
||||
--ion-color-danger-tint: #ff5b71;
|
||||
|
||||
--ion-color-dark: #f4f5f8;
|
||||
--ion-color-dark-rgb: 244, 245, 248;
|
||||
--ion-color-dark-contrast: #000000;
|
||||
--ion-color-dark-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-dark-shade: #d7d8da;
|
||||
--ion-color-dark-tint: #f5f6f9;
|
||||
|
||||
--ion-color-medium: #989aa2;
|
||||
--ion-color-medium-rgb: 152, 154, 162;
|
||||
--ion-color-medium-contrast: #000000;
|
||||
--ion-color-medium-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-medium-shade: #86888f;
|
||||
--ion-color-medium-tint: #a2a4ab;
|
||||
|
||||
--ion-color-light: #222428;
|
||||
--ion-color-light-rgb: 34, 36, 40;
|
||||
--ion-color-light-contrast: #ffffff;
|
||||
--ion-color-light-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-light-shade: #1e2023;
|
||||
--ion-color-light-tint: #383a3e;
|
||||
}
|
||||
|
||||
/*
|
||||
* iOS Dark Theme
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
.ios body {
|
||||
--ion-background-color: #000000;
|
||||
--ion-background-color-rgb: 0, 0, 0;
|
||||
|
||||
--ion-text-color: #ffffff;
|
||||
--ion-text-color-rgb: 255, 255, 255;
|
||||
|
||||
--ion-color-step-50: #0d0d0d;
|
||||
--ion-color-step-100: #1a1a1a;
|
||||
--ion-color-step-150: #262626;
|
||||
--ion-color-step-200: #333333;
|
||||
--ion-color-step-250: #404040;
|
||||
--ion-color-step-300: #4d4d4d;
|
||||
--ion-color-step-350: #595959;
|
||||
--ion-color-step-400: #666666;
|
||||
--ion-color-step-450: #737373;
|
||||
--ion-color-step-500: #808080;
|
||||
--ion-color-step-550: #8c8c8c;
|
||||
--ion-color-step-600: #999999;
|
||||
--ion-color-step-650: #a6a6a6;
|
||||
--ion-color-step-700: #b3b3b3;
|
||||
--ion-color-step-750: #bfbfbf;
|
||||
--ion-color-step-800: #cccccc;
|
||||
--ion-color-step-850: #d9d9d9;
|
||||
--ion-color-step-900: #e6e6e6;
|
||||
--ion-color-step-950: #f2f2f2;
|
||||
|
||||
--ion-toolbar-background: #0d0d0d;
|
||||
|
||||
--ion-item-background: #000000;
|
||||
|
||||
--ion-card-background: #1c1c1d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Material Design Dark Theme
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
.md body {
|
||||
--ion-background-color: #121212;
|
||||
--ion-background-color-rgb: 18, 18, 18;
|
||||
|
||||
--ion-text-color: #ffffff;
|
||||
--ion-text-color-rgb: 255, 255, 255;
|
||||
|
||||
--ion-border-color: #222222;
|
||||
|
||||
--ion-color-step-50: #1e1e1e;
|
||||
--ion-color-step-100: #2a2a2a;
|
||||
--ion-color-step-150: #363636;
|
||||
--ion-color-step-200: #414141;
|
||||
--ion-color-step-250: #4d4d4d;
|
||||
--ion-color-step-300: #595959;
|
||||
--ion-color-step-350: #656565;
|
||||
--ion-color-step-400: #717171;
|
||||
--ion-color-step-450: #7d7d7d;
|
||||
--ion-color-step-500: #898989;
|
||||
--ion-color-step-550: #949494;
|
||||
--ion-color-step-600: #a0a0a0;
|
||||
--ion-color-step-650: #acacac;
|
||||
--ion-color-step-700: #b8b8b8;
|
||||
--ion-color-step-750: #c4c4c4;
|
||||
--ion-color-step-800: #d0d0d0;
|
||||
--ion-color-step-850: #dbdbdb;
|
||||
--ion-color-step-900: #e7e7e7;
|
||||
--ion-color-step-950: #f3f3f3;
|
||||
|
||||
--ion-item-background: #1e1e1e;
|
||||
|
||||
--ion-toolbar-background: #1f1f1f;
|
||||
|
||||
--ion-tab-bar-background: #1f1f1f;
|
||||
|
||||
--ion-card-background: #1e1e1e;
|
||||
}
|
||||
323
core/src/components.d.ts
vendored
@@ -23,9 +23,9 @@ import { MenuChangeEventDetail, Side } from "./components/menu/menu-interface";
|
||||
import { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./components/modal/modal-interface";
|
||||
import { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface";
|
||||
import { ViewController } from "./components/nav/view-controller";
|
||||
import { PickerButton, PickerColumn } from "./components/picker/picker-interface";
|
||||
import { PickerColumnItem } from "./components/picker-column-internal/picker-column-internal-interfaces";
|
||||
import { PickerInternalChangeEventDetail } from "./components/picker-internal/picker-internal-interfaces";
|
||||
import { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
|
||||
import { PickerColumnChangeEventDetail, PickerColumnItem, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
|
||||
import { PickerButton, PickerColumn } from "./components/picker-legacy/picker-interface";
|
||||
import { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
|
||||
import { RadioGroupChangeEventDetail } from "./components/radio-group/radio-group-interface";
|
||||
import { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
|
||||
@@ -59,9 +59,9 @@ export { MenuChangeEventDetail, Side } from "./components/menu/menu-interface";
|
||||
export { ModalBreakpointChangeEventDetail, ModalHandleBehavior } from "./components/modal/modal-interface";
|
||||
export { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, SwipeGestureHandler, TransitionDoneFn, TransitionInstruction } from "./components/nav/nav-interface";
|
||||
export { ViewController } from "./components/nav/view-controller";
|
||||
export { PickerButton, PickerColumn } from "./components/picker/picker-interface";
|
||||
export { PickerColumnItem } from "./components/picker-column-internal/picker-column-internal-interfaces";
|
||||
export { PickerInternalChangeEventDetail } from "./components/picker-internal/picker-internal-interfaces";
|
||||
export { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
|
||||
export { PickerColumnChangeEventDetail, PickerColumnItem, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
|
||||
export { PickerButton, PickerColumn } from "./components/picker-legacy/picker-interface";
|
||||
export { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
|
||||
export { RadioGroupChangeEventDetail } from "./components/radio-group/radio-group-interface";
|
||||
export { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
|
||||
@@ -1162,7 +1162,7 @@ export namespace Components {
|
||||
*/
|
||||
"autocorrect": 'on' | 'off';
|
||||
/**
|
||||
* This Boolean attribute lets you specify that a form control should have input focus when the page loads.
|
||||
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element. This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
"autofocus": boolean;
|
||||
/**
|
||||
@@ -1274,7 +1274,7 @@ export namespace Components {
|
||||
*/
|
||||
"required": boolean;
|
||||
/**
|
||||
* Sets focus on the native `input` in `ion-input`. Use this method instead of the global `input.focus()`. Developers who wish to focus an input when a page enters should call `setFocus()` in the `ionViewDidEnter()` lifecycle method. Developers who wish to focus an input when an overlay is presented should call `setFocus` after `didPresent` has resolved.
|
||||
* Sets focus on the native `input` in `ion-input`. Use this method instead of the global `input.focus()`. Developers who wish to focus an input when a page enters should call `setFocus()` in the `ionViewDidEnter()` lifecycle method. Developers who wish to focus an input when an overlay is presented should call `setFocus` after `didPresent` has resolved. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
"setFocus": () => Promise<void>;
|
||||
/**
|
||||
@@ -1949,6 +1949,62 @@ export namespace Components {
|
||||
"mode"?: "ios" | "md";
|
||||
}
|
||||
interface IonPicker {
|
||||
"exitInputMode": () => Promise<void>;
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
}
|
||||
interface IonPickerColumn {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
"disabled": boolean;
|
||||
/**
|
||||
* A list of options to be displayed in the picker
|
||||
*/
|
||||
"items": PickerColumnItem[];
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* If `true`, tapping the picker will reveal a number input keyboard that lets the user type in values for each picker column. This is useful when working with time pickers.
|
||||
*/
|
||||
"numericInput": boolean;
|
||||
"scrollActiveItemIntoView": () => Promise<void>;
|
||||
/**
|
||||
* Sets focus on the scrollable container within the picker column. Use this method instead of the global `pickerColumn.focus()`.
|
||||
*/
|
||||
"setFocus": () => Promise<void>;
|
||||
/**
|
||||
* Sets the value prop and fires the ionChange event. This is used when we need to fire ionChange from user-generated events that cannot be caught with normal input/change event listeners.
|
||||
*/
|
||||
"setValue": (value: PickerColumnValue) => Promise<void>;
|
||||
/**
|
||||
* The selected option in the picker.
|
||||
*/
|
||||
"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.
|
||||
*/
|
||||
"disabled": boolean;
|
||||
/**
|
||||
* The text value of the option.
|
||||
*/
|
||||
"value"?: any | null;
|
||||
}
|
||||
interface IonPickerLegacy {
|
||||
/**
|
||||
* If `true`, the picker will animate.
|
||||
*/
|
||||
@@ -2032,50 +2088,12 @@ export namespace Components {
|
||||
*/
|
||||
"trigger": string | undefined;
|
||||
}
|
||||
interface IonPickerColumn {
|
||||
interface IonPickerLegacyColumn {
|
||||
/**
|
||||
* Picker column data
|
||||
*/
|
||||
"col": PickerColumn;
|
||||
}
|
||||
interface IonPickerColumnInternal {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
"disabled": boolean;
|
||||
/**
|
||||
* A list of options to be displayed in the picker
|
||||
*/
|
||||
"items": PickerColumnItem[];
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* If `true`, tapping the picker will reveal a number input keyboard that lets the user type in values for each picker column. This is useful when working with time pickers.
|
||||
*/
|
||||
"numericInput": boolean;
|
||||
"scrollActiveItemIntoView": () => Promise<void>;
|
||||
/**
|
||||
* Sets the value prop and fires the ionChange event. This is used when we need to fire ionChange from user-generated events that cannot be caught with normal input/change event listeners.
|
||||
*/
|
||||
"setValue": (value?: string | number) => Promise<void>;
|
||||
/**
|
||||
* The selected option in the picker.
|
||||
*/
|
||||
"value"?: string | number;
|
||||
}
|
||||
interface IonPickerInternal {
|
||||
"exitInputMode": () => Promise<void>;
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
}
|
||||
interface IonPopover {
|
||||
/**
|
||||
* Describes how to align the popover content with the `reference` point. Defaults to `"center"` for `ios` mode, and `"start"` for `md` mode.
|
||||
@@ -2601,7 +2619,7 @@ export namespace Components {
|
||||
*/
|
||||
"searchIcon"?: string;
|
||||
/**
|
||||
* Sets focus on the native `input` in `ion-searchbar`. Use this method instead of the global `input.focus()`. Developers who wish to focus an input when a page enters should call `setFocus()` in the `ionViewDidEnter()` lifecycle method. Developers who wish to focus an input when an overlay is presented should call `setFocus` after `didPresent` has resolved.
|
||||
* Sets focus on the native `input` in `ion-searchbar`. Use this method instead of the global `input.focus()`. Developers who wish to focus an input when a page enters should call `setFocus()` in the `ionViewDidEnter()` lifecycle method. Developers who wish to focus an input when an overlay is presented should call `setFocus` after `didPresent` has resolved. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
"setFocus": () => Promise<void>;
|
||||
/**
|
||||
@@ -2950,7 +2968,7 @@ export namespace Components {
|
||||
*/
|
||||
"autocapitalize": string;
|
||||
/**
|
||||
* This Boolean attribute lets you specify that a form control should have input focus when the page loads.
|
||||
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element. This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
"autofocus": boolean;
|
||||
/**
|
||||
@@ -3050,7 +3068,7 @@ export namespace Components {
|
||||
*/
|
||||
"rows"?: number;
|
||||
/**
|
||||
* Sets focus on the native `textarea` in `ion-textarea`. Use this method instead of the global `textarea.focus()`.
|
||||
* Sets focus on the native `textarea` in `ion-textarea`. Use this method instead of the global `textarea.focus()`. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
"setFocus": () => Promise<void>;
|
||||
/**
|
||||
@@ -3330,13 +3348,13 @@ export interface IonPickerColumnCustomEvent<T> extends CustomEvent<T> {
|
||||
detail: T;
|
||||
target: HTMLIonPickerColumnElement;
|
||||
}
|
||||
export interface IonPickerColumnInternalCustomEvent<T> extends CustomEvent<T> {
|
||||
export interface IonPickerLegacyCustomEvent<T> extends CustomEvent<T> {
|
||||
detail: T;
|
||||
target: HTMLIonPickerColumnInternalElement;
|
||||
target: HTMLIonPickerLegacyElement;
|
||||
}
|
||||
export interface IonPickerInternalCustomEvent<T> extends CustomEvent<T> {
|
||||
export interface IonPickerLegacyColumnCustomEvent<T> extends CustomEvent<T> {
|
||||
detail: T;
|
||||
target: HTMLIonPickerInternalElement;
|
||||
target: HTMLIonPickerLegacyColumnElement;
|
||||
}
|
||||
export interface IonPopoverCustomEvent<T> extends CustomEvent<T> {
|
||||
detail: T;
|
||||
@@ -4020,14 +4038,7 @@ declare global {
|
||||
new (): HTMLIonNoteElement;
|
||||
};
|
||||
interface HTMLIonPickerElementEventMap {
|
||||
"ionPickerDidPresent": void;
|
||||
"ionPickerWillPresent": void;
|
||||
"ionPickerWillDismiss": OverlayEventDetail;
|
||||
"ionPickerDidDismiss": OverlayEventDetail;
|
||||
"didPresent": void;
|
||||
"willPresent": void;
|
||||
"willDismiss": OverlayEventDetail;
|
||||
"didDismiss": OverlayEventDetail;
|
||||
"ionInputModeChange": PickerChangeEventDetail;
|
||||
}
|
||||
interface HTMLIonPickerElement extends Components.IonPicker, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonPickerElementEventMap>(type: K, listener: (this: HTMLIonPickerElement, ev: IonPickerCustomEvent<HTMLIonPickerElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
@@ -4044,7 +4055,7 @@ declare global {
|
||||
new (): HTMLIonPickerElement;
|
||||
};
|
||||
interface HTMLIonPickerColumnElementEventMap {
|
||||
"ionPickerColChange": PickerColumn;
|
||||
"ionChange": PickerColumnChangeEventDetail;
|
||||
}
|
||||
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;
|
||||
@@ -4060,39 +4071,52 @@ declare global {
|
||||
prototype: HTMLIonPickerColumnElement;
|
||||
new (): HTMLIonPickerColumnElement;
|
||||
};
|
||||
interface HTMLIonPickerColumnInternalElementEventMap {
|
||||
"ionChange": PickerColumnItem;
|
||||
interface HTMLIonPickerColumnOptionElement extends Components.IonPickerColumnOption, HTMLStencilElement {
|
||||
}
|
||||
interface HTMLIonPickerColumnInternalElement extends Components.IonPickerColumnInternal, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonPickerColumnInternalElementEventMap>(type: K, listener: (this: HTMLIonPickerColumnInternalElement, ev: IonPickerColumnInternalCustomEvent<HTMLIonPickerColumnInternalElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof HTMLIonPickerColumnInternalElementEventMap>(type: K, listener: (this: HTMLIonPickerColumnInternalElement, ev: IonPickerColumnInternalCustomEvent<HTMLIonPickerColumnInternalElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
var HTMLIonPickerColumnInternalElement: {
|
||||
prototype: HTMLIonPickerColumnInternalElement;
|
||||
new (): HTMLIonPickerColumnInternalElement;
|
||||
var HTMLIonPickerColumnOptionElement: {
|
||||
prototype: HTMLIonPickerColumnOptionElement;
|
||||
new (): HTMLIonPickerColumnOptionElement;
|
||||
};
|
||||
interface HTMLIonPickerInternalElementEventMap {
|
||||
"ionInputModeChange": PickerInternalChangeEventDetail;
|
||||
interface HTMLIonPickerLegacyElementEventMap {
|
||||
"ionPickerDidPresent": void;
|
||||
"ionPickerWillPresent": void;
|
||||
"ionPickerWillDismiss": OverlayEventDetail;
|
||||
"ionPickerDidDismiss": OverlayEventDetail;
|
||||
"didPresent": void;
|
||||
"willPresent": void;
|
||||
"willDismiss": OverlayEventDetail;
|
||||
"didDismiss": OverlayEventDetail;
|
||||
}
|
||||
interface HTMLIonPickerInternalElement extends Components.IonPickerInternal, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonPickerInternalElementEventMap>(type: K, listener: (this: HTMLIonPickerInternalElement, ev: IonPickerInternalCustomEvent<HTMLIonPickerInternalElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
interface HTMLIonPickerLegacyElement extends Components.IonPickerLegacy, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonPickerLegacyElementEventMap>(type: K, listener: (this: HTMLIonPickerLegacyElement, ev: IonPickerLegacyCustomEvent<HTMLIonPickerLegacyElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof HTMLIonPickerInternalElementEventMap>(type: K, listener: (this: HTMLIonPickerInternalElement, ev: IonPickerInternalCustomEvent<HTMLIonPickerInternalElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener<K extends keyof HTMLIonPickerLegacyElementEventMap>(type: K, listener: (this: HTMLIonPickerLegacyElement, ev: IonPickerLegacyCustomEvent<HTMLIonPickerLegacyElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
var HTMLIonPickerInternalElement: {
|
||||
prototype: HTMLIonPickerInternalElement;
|
||||
new (): HTMLIonPickerInternalElement;
|
||||
var HTMLIonPickerLegacyElement: {
|
||||
prototype: HTMLIonPickerLegacyElement;
|
||||
new (): HTMLIonPickerLegacyElement;
|
||||
};
|
||||
interface HTMLIonPickerLegacyColumnElementEventMap {
|
||||
"ionPickerColChange": PickerColumn;
|
||||
}
|
||||
interface HTMLIonPickerLegacyColumnElement extends Components.IonPickerLegacyColumn, HTMLStencilElement {
|
||||
addEventListener<K extends keyof HTMLIonPickerLegacyColumnElementEventMap>(type: K, listener: (this: HTMLIonPickerLegacyColumnElement, ev: IonPickerLegacyColumnCustomEvent<HTMLIonPickerLegacyColumnElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof HTMLIonPickerLegacyColumnElementEventMap>(type: K, listener: (this: HTMLIonPickerLegacyColumnElement, ev: IonPickerLegacyColumnCustomEvent<HTMLIonPickerLegacyColumnElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
var HTMLIonPickerLegacyColumnElement: {
|
||||
prototype: HTMLIonPickerLegacyColumnElement;
|
||||
new (): HTMLIonPickerLegacyColumnElement;
|
||||
};
|
||||
interface HTMLIonPopoverElementEventMap {
|
||||
"ionPopoverDidPresent": void;
|
||||
@@ -4647,8 +4671,9 @@ declare global {
|
||||
"ion-note": HTMLIonNoteElement;
|
||||
"ion-picker": HTMLIonPickerElement;
|
||||
"ion-picker-column": HTMLIonPickerColumnElement;
|
||||
"ion-picker-column-internal": HTMLIonPickerColumnInternalElement;
|
||||
"ion-picker-internal": HTMLIonPickerInternalElement;
|
||||
"ion-picker-column-option": HTMLIonPickerColumnOptionElement;
|
||||
"ion-picker-legacy": HTMLIonPickerLegacyElement;
|
||||
"ion-picker-legacy-column": HTMLIonPickerLegacyColumnElement;
|
||||
"ion-popover": HTMLIonPopoverElement;
|
||||
"ion-progress-bar": HTMLIonProgressBarElement;
|
||||
"ion-radio": HTMLIonRadioElement;
|
||||
@@ -5854,7 +5879,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"autocorrect"?: 'on' | 'off';
|
||||
/**
|
||||
* This Boolean attribute lets you specify that a form control should have input focus when the page loads.
|
||||
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element. This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
"autofocus"?: boolean;
|
||||
/**
|
||||
@@ -6580,6 +6605,57 @@ declare namespace LocalJSX {
|
||||
"mode"?: "ios" | "md";
|
||||
}
|
||||
interface IonPicker {
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
"onIonInputModeChange"?: (event: IonPickerCustomEvent<PickerChangeEventDetail>) => void;
|
||||
}
|
||||
interface IonPickerColumn {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* A list of options to be displayed in the picker
|
||||
*/
|
||||
"items"?: PickerColumnItem[];
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* If `true`, tapping the picker will reveal a number input keyboard that lets the user type in values for each picker column. This is useful when working with time pickers.
|
||||
*/
|
||||
"numericInput"?: boolean;
|
||||
/**
|
||||
* Emitted when the value has changed.
|
||||
*/
|
||||
"onIonChange"?: (event: IonPickerColumnCustomEvent<PickerColumnChangeEventDetail>) => void;
|
||||
/**
|
||||
* The selected option in the picker.
|
||||
*/
|
||||
"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.
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* The text value of the option.
|
||||
*/
|
||||
"value"?: any | null;
|
||||
}
|
||||
interface IonPickerLegacy {
|
||||
/**
|
||||
* If `true`, the picker will animate.
|
||||
*/
|
||||
@@ -6633,35 +6709,35 @@ declare namespace LocalJSX {
|
||||
/**
|
||||
* Emitted after the picker has dismissed. Shorthand for ionPickerDidDismiss.
|
||||
*/
|
||||
"onDidDismiss"?: (event: IonPickerCustomEvent<OverlayEventDetail>) => void;
|
||||
"onDidDismiss"?: (event: IonPickerLegacyCustomEvent<OverlayEventDetail>) => void;
|
||||
/**
|
||||
* Emitted after the picker has presented. Shorthand for ionPickerWillDismiss.
|
||||
*/
|
||||
"onDidPresent"?: (event: IonPickerCustomEvent<void>) => void;
|
||||
"onDidPresent"?: (event: IonPickerLegacyCustomEvent<void>) => void;
|
||||
/**
|
||||
* Emitted after the picker has dismissed.
|
||||
*/
|
||||
"onIonPickerDidDismiss"?: (event: IonPickerCustomEvent<OverlayEventDetail>) => void;
|
||||
"onIonPickerDidDismiss"?: (event: IonPickerLegacyCustomEvent<OverlayEventDetail>) => void;
|
||||
/**
|
||||
* Emitted after the picker has presented.
|
||||
*/
|
||||
"onIonPickerDidPresent"?: (event: IonPickerCustomEvent<void>) => void;
|
||||
"onIonPickerDidPresent"?: (event: IonPickerLegacyCustomEvent<void>) => void;
|
||||
/**
|
||||
* Emitted before the picker has dismissed.
|
||||
*/
|
||||
"onIonPickerWillDismiss"?: (event: IonPickerCustomEvent<OverlayEventDetail>) => void;
|
||||
"onIonPickerWillDismiss"?: (event: IonPickerLegacyCustomEvent<OverlayEventDetail>) => void;
|
||||
/**
|
||||
* Emitted before the picker has presented.
|
||||
*/
|
||||
"onIonPickerWillPresent"?: (event: IonPickerCustomEvent<void>) => void;
|
||||
"onIonPickerWillPresent"?: (event: IonPickerLegacyCustomEvent<void>) => void;
|
||||
/**
|
||||
* Emitted before the picker has dismissed. Shorthand for ionPickerWillDismiss.
|
||||
*/
|
||||
"onWillDismiss"?: (event: IonPickerCustomEvent<OverlayEventDetail>) => void;
|
||||
"onWillDismiss"?: (event: IonPickerLegacyCustomEvent<OverlayEventDetail>) => void;
|
||||
/**
|
||||
* Emitted before the picker has presented. Shorthand for ionPickerWillPresent.
|
||||
*/
|
||||
"onWillPresent"?: (event: IonPickerCustomEvent<void>) => void;
|
||||
"onWillPresent"?: (event: IonPickerLegacyCustomEvent<void>) => void;
|
||||
"overlayIndex": number;
|
||||
/**
|
||||
* If `true`, a backdrop will be displayed behind the picker.
|
||||
@@ -6672,7 +6748,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"trigger"?: string | undefined;
|
||||
}
|
||||
interface IonPickerColumn {
|
||||
interface IonPickerLegacyColumn {
|
||||
/**
|
||||
* Picker column data
|
||||
*/
|
||||
@@ -6680,44 +6756,7 @@ declare namespace LocalJSX {
|
||||
/**
|
||||
* Emitted when the selected value has changed
|
||||
*/
|
||||
"onIonPickerColChange"?: (event: IonPickerColumnCustomEvent<PickerColumn>) => void;
|
||||
}
|
||||
interface IonPickerColumnInternal {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
"disabled"?: boolean;
|
||||
/**
|
||||
* A list of options to be displayed in the picker
|
||||
*/
|
||||
"items"?: PickerColumnItem[];
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
/**
|
||||
* If `true`, tapping the picker will reveal a number input keyboard that lets the user type in values for each picker column. This is useful when working with time pickers.
|
||||
*/
|
||||
"numericInput"?: boolean;
|
||||
/**
|
||||
* Emitted when the value has changed.
|
||||
*/
|
||||
"onIonChange"?: (event: IonPickerColumnInternalCustomEvent<PickerColumnItem>) => void;
|
||||
/**
|
||||
* The selected option in the picker.
|
||||
*/
|
||||
"value"?: string | number;
|
||||
}
|
||||
interface IonPickerInternal {
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
*/
|
||||
"mode"?: "ios" | "md";
|
||||
"onIonInputModeChange"?: (event: IonPickerInternalCustomEvent<PickerInternalChangeEventDetail>) => void;
|
||||
"onIonPickerColChange"?: (event: IonPickerLegacyColumnCustomEvent<PickerColumn>) => void;
|
||||
}
|
||||
interface IonPopover {
|
||||
/**
|
||||
@@ -7699,7 +7738,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"autocapitalize"?: string;
|
||||
/**
|
||||
* This Boolean attribute lets you specify that a form control should have input focus when the page loads.
|
||||
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element. This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
"autofocus"?: boolean;
|
||||
/**
|
||||
@@ -8086,8 +8125,9 @@ declare namespace LocalJSX {
|
||||
"ion-note": IonNote;
|
||||
"ion-picker": IonPicker;
|
||||
"ion-picker-column": IonPickerColumn;
|
||||
"ion-picker-column-internal": IonPickerColumnInternal;
|
||||
"ion-picker-internal": IonPickerInternal;
|
||||
"ion-picker-column-option": IonPickerColumnOption;
|
||||
"ion-picker-legacy": IonPickerLegacy;
|
||||
"ion-picker-legacy-column": IonPickerLegacyColumn;
|
||||
"ion-popover": IonPopover;
|
||||
"ion-progress-bar": IonProgressBar;
|
||||
"ion-radio": IonRadio;
|
||||
@@ -8183,8 +8223,9 @@ declare module "@stencil/core" {
|
||||
"ion-note": LocalJSX.IonNote & JSXBase.HTMLAttributes<HTMLIonNoteElement>;
|
||||
"ion-picker": LocalJSX.IonPicker & JSXBase.HTMLAttributes<HTMLIonPickerElement>;
|
||||
"ion-picker-column": LocalJSX.IonPickerColumn & JSXBase.HTMLAttributes<HTMLIonPickerColumnElement>;
|
||||
"ion-picker-column-internal": LocalJSX.IonPickerColumnInternal & JSXBase.HTMLAttributes<HTMLIonPickerColumnInternalElement>;
|
||||
"ion-picker-internal": LocalJSX.IonPickerInternal & JSXBase.HTMLAttributes<HTMLIonPickerInternalElement>;
|
||||
"ion-picker-column-option": LocalJSX.IonPickerColumnOption & JSXBase.HTMLAttributes<HTMLIonPickerColumnOptionElement>;
|
||||
"ion-picker-legacy": LocalJSX.IonPickerLegacy & JSXBase.HTMLAttributes<HTMLIonPickerLegacyElement>;
|
||||
"ion-picker-legacy-column": LocalJSX.IonPickerLegacyColumn & JSXBase.HTMLAttributes<HTMLIonPickerLegacyColumnElement>;
|
||||
"ion-popover": LocalJSX.IonPopover & JSXBase.HTMLAttributes<HTMLIonPopoverElement>;
|
||||
"ion-progress-bar": LocalJSX.IonProgressBar & JSXBase.HTMLAttributes<HTMLIonProgressBarElement>;
|
||||
"ion-radio": LocalJSX.IonRadio & JSXBase.HTMLAttributes<HTMLIonRadioElement>;
|
||||
|
||||
@@ -337,6 +337,17 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
|
||||
if (this.isOpen === true) {
|
||||
raf(() => this.present());
|
||||
}
|
||||
|
||||
/**
|
||||
* When binding values in frameworks such as Angular
|
||||
* it is possible for the value to be set after the Web Component
|
||||
* initializes but before the value watcher is set up in Stencil.
|
||||
* As a result, the watcher callback may not be fired.
|
||||
* We work around this by manually calling the watcher
|
||||
* callback when the component has loaded and the watcher
|
||||
* is configured.
|
||||
*/
|
||||
this.triggerChanged();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -376,6 +376,17 @@ export class Alert implements ComponentInterface, OverlayInterface {
|
||||
if (this.isOpen === true) {
|
||||
raf(() => this.present());
|
||||
}
|
||||
|
||||
/**
|
||||
* When binding values in frameworks such as Angular
|
||||
* it is possible for the value to be set after the Web Component
|
||||
* initializes but before the value watcher is set up in Stencil.
|
||||
* As a result, the watcher callback may not be fired.
|
||||
* We work around this by manually calling the watcher
|
||||
* callback when the component has loaded and the watcher
|
||||
* is configured.
|
||||
*/
|
||||
this.triggerChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
}
|
||||
|
||||
async function showPicker() {
|
||||
const picker = Object.assign(document.createElement('ion-picker'), {
|
||||
const picker = Object.assign(document.createElement('ion-picker-legacy'), {
|
||||
columns: [
|
||||
{
|
||||
name: 'Picker',
|
||||
|
||||
@@ -25,19 +25,6 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* When using the wheel picker to switch
|
||||
* between months, sometimes the allowed
|
||||
* dates may be filtered. As a result, it
|
||||
* is possible to get a layout shift as
|
||||
* the picker column will shrink to fit the
|
||||
* widest item in the column. Setting a minimum
|
||||
* width avoids this layout shifting.
|
||||
*/
|
||||
ion-picker-column-internal {
|
||||
min-width: 26px;
|
||||
}
|
||||
|
||||
:host(.datetime-size-fixed) {
|
||||
width: auto;
|
||||
height: auto;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { caretDownSharp, caretUpSharp, chevronBack, chevronDown, chevronForward
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import type { Color, Mode, StyleEventDetail } from '../../interface';
|
||||
import type { PickerColumnItem } from '../picker-column-internal/picker-column-internal-interfaces';
|
||||
import type { PickerColumnItem } from '../picker-column/picker-column-interfaces';
|
||||
|
||||
import type {
|
||||
DatetimePresentation,
|
||||
@@ -1527,7 +1527,7 @@ export class Datetime implements ComponentInterface {
|
||||
forcePresentation === 'time-date'
|
||||
? [this.renderTimePickerColumns(forcePresentation), this.renderDatePickerColumns(forcePresentation)]
|
||||
: [this.renderDatePickerColumns(forcePresentation), this.renderTimePickerColumns(forcePresentation)];
|
||||
return <ion-picker-internal>{renderArray}</ion-picker-internal>;
|
||||
return <ion-picker>{renderArray}</ion-picker>;
|
||||
}
|
||||
|
||||
private renderDatePickerColumns(forcePresentation: string) {
|
||||
@@ -1613,11 +1613,10 @@ export class Datetime implements ComponentInterface {
|
||||
: `${defaultParts.year}-${defaultParts.month}-${defaultParts.day}`;
|
||||
|
||||
return (
|
||||
<ion-picker-column-internal
|
||||
<ion-picker-column
|
||||
class="date-column"
|
||||
color={this.color}
|
||||
disabled={disabled}
|
||||
items={items}
|
||||
value={todayString}
|
||||
onIonChange={(ev: CustomEvent) => {
|
||||
// TODO(FW-1823) Remove this when iOS 14 support is dropped.
|
||||
@@ -1647,7 +1646,18 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
></ion-picker-column-internal>
|
||||
>
|
||||
{items.map((item) => (
|
||||
<ion-picker-column-option
|
||||
part={item.value === todayString ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART}
|
||||
key={item.value}
|
||||
disabled={item.disabled}
|
||||
value={item.value}
|
||||
>
|
||||
{item.text}
|
||||
</ion-picker-column-option>
|
||||
))}
|
||||
</ion-picker-column>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1731,14 +1741,14 @@ export class Datetime implements ComponentInterface {
|
||||
const { disabled, workingParts } = this;
|
||||
|
||||
const activePart = this.getActivePartsWithFallback();
|
||||
const pickerColumnValue = (workingParts.day !== null ? workingParts.day : this.defaultParts.day) ?? undefined;
|
||||
|
||||
return (
|
||||
<ion-picker-column-internal
|
||||
<ion-picker-column
|
||||
class="day-column"
|
||||
color={this.color}
|
||||
disabled={disabled}
|
||||
items={days}
|
||||
value={(workingParts.day !== null ? workingParts.day : this.defaultParts.day) ?? undefined}
|
||||
value={pickerColumnValue}
|
||||
onIonChange={(ev: CustomEvent) => {
|
||||
// TODO(FW-1823) Remove this when iOS 14 support is dropped.
|
||||
// Due to a Safari 14 issue we need to destroy
|
||||
@@ -1764,7 +1774,18 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
></ion-picker-column-internal>
|
||||
>
|
||||
{days.map((day) => (
|
||||
<ion-picker-column-option
|
||||
part={day.value === pickerColumnValue ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART}
|
||||
key={day.value}
|
||||
disabled={day.disabled}
|
||||
value={day.value}
|
||||
>
|
||||
{day.text}
|
||||
</ion-picker-column-option>
|
||||
))}
|
||||
</ion-picker-column>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1778,11 +1799,10 @@ export class Datetime implements ComponentInterface {
|
||||
const activePart = this.getActivePartsWithFallback();
|
||||
|
||||
return (
|
||||
<ion-picker-column-internal
|
||||
<ion-picker-column
|
||||
class="month-column"
|
||||
color={this.color}
|
||||
disabled={disabled}
|
||||
items={months}
|
||||
value={workingParts.month}
|
||||
onIonChange={(ev: CustomEvent) => {
|
||||
// TODO(FW-1823) Remove this when iOS 14 support is dropped.
|
||||
@@ -1809,7 +1829,18 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
></ion-picker-column-internal>
|
||||
>
|
||||
{months.map((month) => (
|
||||
<ion-picker-column-option
|
||||
part={month.value === workingParts.month ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART}
|
||||
key={month.value}
|
||||
disabled={month.disabled}
|
||||
value={month.value}
|
||||
>
|
||||
{month.text}
|
||||
</ion-picker-column-option>
|
||||
))}
|
||||
</ion-picker-column>
|
||||
);
|
||||
}
|
||||
private renderYearPickerColumn(years: PickerColumnItem[]) {
|
||||
@@ -1822,11 +1853,10 @@ export class Datetime implements ComponentInterface {
|
||||
const activePart = this.getActivePartsWithFallback();
|
||||
|
||||
return (
|
||||
<ion-picker-column-internal
|
||||
<ion-picker-column
|
||||
class="year-column"
|
||||
color={this.color}
|
||||
disabled={disabled}
|
||||
items={years}
|
||||
value={workingParts.year}
|
||||
onIonChange={(ev: CustomEvent) => {
|
||||
// TODO(FW-1823) Remove this when iOS 14 support is dropped.
|
||||
@@ -1853,7 +1883,18 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
></ion-picker-column-internal>
|
||||
>
|
||||
{years.map((year) => (
|
||||
<ion-picker-column-option
|
||||
part={year.value === workingParts.year ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART}
|
||||
key={year.value}
|
||||
disabled={year.disabled}
|
||||
value={year.value}
|
||||
>
|
||||
{year.text}
|
||||
</ion-picker-column-option>
|
||||
))}
|
||||
</ion-picker-column>
|
||||
);
|
||||
}
|
||||
private renderTimePickerColumns(forcePresentation: string) {
|
||||
@@ -1897,11 +1938,10 @@ export class Datetime implements ComponentInterface {
|
||||
const activePart = this.getActivePartsWithFallback();
|
||||
|
||||
return (
|
||||
<ion-picker-column-internal
|
||||
<ion-picker-column
|
||||
color={this.color}
|
||||
disabled={disabled}
|
||||
value={activePart.hour}
|
||||
items={hoursData}
|
||||
numericInput
|
||||
onIonChange={(ev: CustomEvent) => {
|
||||
this.setWorkingParts({
|
||||
@@ -1916,7 +1956,18 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
></ion-picker-column-internal>
|
||||
>
|
||||
{hoursData.map((hour) => (
|
||||
<ion-picker-column-option
|
||||
part={hour.value === activePart.hour ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART}
|
||||
key={hour.value}
|
||||
disabled={hour.disabled}
|
||||
value={hour.value}
|
||||
>
|
||||
{hour.text}
|
||||
</ion-picker-column-option>
|
||||
))}
|
||||
</ion-picker-column>
|
||||
);
|
||||
}
|
||||
private renderMinutePickerColumn(minutesData: PickerColumnItem[]) {
|
||||
@@ -1926,11 +1977,10 @@ export class Datetime implements ComponentInterface {
|
||||
const activePart = this.getActivePartsWithFallback();
|
||||
|
||||
return (
|
||||
<ion-picker-column-internal
|
||||
<ion-picker-column
|
||||
color={this.color}
|
||||
disabled={disabled}
|
||||
value={activePart.minute}
|
||||
items={minutesData}
|
||||
numericInput
|
||||
onIonChange={(ev: CustomEvent) => {
|
||||
this.setWorkingParts({
|
||||
@@ -1945,7 +1995,18 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
></ion-picker-column-internal>
|
||||
>
|
||||
{minutesData.map((minute) => (
|
||||
<ion-picker-column-option
|
||||
part={minute.value === activePart.minute ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART}
|
||||
key={minute.value}
|
||||
disabled={minute.disabled}
|
||||
value={minute.value}
|
||||
>
|
||||
{minute.text}
|
||||
</ion-picker-column-option>
|
||||
))}
|
||||
</ion-picker-column>
|
||||
);
|
||||
}
|
||||
private renderDayPeriodPickerColumn(dayPeriodData: PickerColumnItem[]) {
|
||||
@@ -1958,12 +2019,11 @@ export class Datetime implements ComponentInterface {
|
||||
const isDayPeriodRTL = isLocaleDayPeriodRTL(this.locale);
|
||||
|
||||
return (
|
||||
<ion-picker-column-internal
|
||||
<ion-picker-column
|
||||
style={isDayPeriodRTL ? { order: '-1' } : {}}
|
||||
color={this.color}
|
||||
disabled={disabled}
|
||||
value={activePart.ampm}
|
||||
items={dayPeriodData}
|
||||
onIonChange={(ev: CustomEvent) => {
|
||||
const hour = calculateHourFromAMPM(workingParts, ev.detail.value);
|
||||
|
||||
@@ -1981,7 +2041,20 @@ export class Datetime implements ComponentInterface {
|
||||
|
||||
ev.stopPropagation();
|
||||
}}
|
||||
></ion-picker-column-internal>
|
||||
>
|
||||
{dayPeriodData.map((dayPeriod) => (
|
||||
<ion-picker-column-option
|
||||
part={
|
||||
dayPeriod.value === activePart.ampm ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART
|
||||
}
|
||||
key={dayPeriod.value}
|
||||
disabled={dayPeriod.disabled}
|
||||
value={dayPeriod.value}
|
||||
>
|
||||
{dayPeriod.text}
|
||||
</ion-picker-column-option>
|
||||
))}
|
||||
</ion-picker-column>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2345,7 +2418,7 @@ export class Datetime implements ComponentInterface {
|
||||
* This will correctly scroll the element position to the correct time value,
|
||||
* before the popover is fully presented.
|
||||
*/
|
||||
const cols = (ev.target! as HTMLElement).querySelectorAll('ion-picker-column-internal');
|
||||
const cols = (ev.target! as HTMLElement).querySelectorAll('ion-picker-column');
|
||||
// TODO (FW-615): Potentially remove this when intersection observers are fixed in picker column
|
||||
cols.forEach((col) => col.scrollActiveItemIntoView());
|
||||
}}
|
||||
@@ -2529,3 +2602,5 @@ export class Datetime implements ComponentInterface {
|
||||
}
|
||||
|
||||
let datetimeIds = 0;
|
||||
const WHEEL_ITEM_PART = 'wheel-item';
|
||||
const WHEEL_ITEM_ACTIVE_PART = `active`;
|
||||
|
||||
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
@@ -52,28 +52,28 @@
|
||||
}
|
||||
|
||||
/*
|
||||
The second selectors that target ion-picker(-column)-internal
|
||||
The second selectors that target ion-picker(-column)
|
||||
directly are for styling the time picker. This is currently
|
||||
undocumented usage.
|
||||
*/
|
||||
|
||||
.custom-grid-wheel,
|
||||
ion-picker-internal {
|
||||
ion-picker {
|
||||
--wheel-highlight-background: rgb(218, 216, 255);
|
||||
--wheel-fade-background-rgb: 245, 235, 247;
|
||||
}
|
||||
|
||||
ion-picker-internal {
|
||||
ion-picker {
|
||||
background-color: rgb(245, 235, 247);
|
||||
}
|
||||
|
||||
.custom-grid-wheel::part(wheel-item),
|
||||
ion-picker-column-internal::part(wheel-item) {
|
||||
ion-picker-column-option {
|
||||
color: rgb(255, 134, 154);
|
||||
}
|
||||
|
||||
.custom-grid-wheel::part(wheel-item active),
|
||||
ion-picker-column-internal::part(wheel-item active) {
|
||||
ion-picker-column-option.option-active {
|
||||
color: rgb(128, 30, 171);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
page,
|
||||
}) => {
|
||||
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
|
||||
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
|
||||
const monthColumnItems = page.locator('ion-datetime .month-column ion-picker-column-option');
|
||||
|
||||
await expect(monthYearToggle).toContainText('January 2022');
|
||||
|
||||
@@ -34,7 +34,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
test('should adjust the selected day when moving to a month with a different number of days', async ({ page }) => {
|
||||
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
|
||||
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
|
||||
const monthColumnItems = page.locator('ion-datetime .month-column ion-picker-column-option');
|
||||
const datetime = page.locator('ion-datetime');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { h } from '@stencil/core';
|
||||
import { newSpecPage } from '@stencil/core/testing';
|
||||
|
||||
import { Datetime } from '../../../datetime/datetime';
|
||||
import { PickerColumnInternal } from '../../../picker-column-internal/picker-column-internal';
|
||||
import { PickerInternal } from '../../../picker-internal/picker-internal';
|
||||
import { PickerColumn } from '../../../picker-column/picker-column';
|
||||
import { Picker } from '../../../picker/picker';
|
||||
|
||||
describe('ion-datetime disabled', () => {
|
||||
beforeEach(() => {
|
||||
@@ -19,7 +19,7 @@ describe('ion-datetime disabled', () => {
|
||||
|
||||
it('picker should be disabled in prefer wheel mode', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Datetime, PickerColumnInternal, PickerInternal],
|
||||
components: [Datetime, PickerColumn, Picker],
|
||||
template: () => (
|
||||
<ion-datetime id="inline-datetime-wheel" disabled prefer-wheel value="2022-04-21T00:00:00"></ion-datetime>
|
||||
),
|
||||
@@ -28,7 +28,7 @@ describe('ion-datetime disabled', () => {
|
||||
await page.waitForChanges();
|
||||
|
||||
const datetime = page.body.querySelector('ion-datetime')!;
|
||||
const columns = datetime.shadowRoot!.querySelectorAll('ion-picker-column-internal');
|
||||
const columns = datetime.shadowRoot!.querySelectorAll('ion-picker-column');
|
||||
|
||||
await expect(columns.length).toEqual(4);
|
||||
|
||||
|
||||
@@ -107,14 +107,13 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
test('should correctly localize year column data', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime prefer-wheel="true" locale="ar-EG" presentation="date" value="2022-01-01"></ion-datetime>
|
||||
<ion-datetime prefer-wheel="true" locale="ar-EG" presentation="date" value="2022-01-01" max="2022" min="2022"></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const datetimeYear = page.locator('ion-datetime .year-column .picker-item[data-value="2022"]');
|
||||
|
||||
const datetimeYear = page.locator('ion-datetime .year-column ion-picker-column-option').nth(0);
|
||||
await expect(datetimeYear).toHaveText('٢٠٢٢');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -109,12 +109,8 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
||||
await page.click('.time-body');
|
||||
await ionPopoverDidPresent.next();
|
||||
|
||||
const hours = page.locator(
|
||||
'ion-popover ion-picker-column-internal:nth-child(1) .picker-item:not(.picker-item-empty)'
|
||||
);
|
||||
const minutes = page.locator(
|
||||
'ion-popover ion-picker-column-internal:nth-child(2) .picker-item:not(.picker-item-empty)'
|
||||
);
|
||||
const hours = page.locator('ion-popover ion-picker-column:nth-child(1) ion-picker-column-option');
|
||||
const minutes = page.locator('ion-popover ion-picker-column:nth-child(2) ion-picker-column-option');
|
||||
|
||||
expect(await hours.count()).toBe(12);
|
||||
expect(await minutes.count()).toBe(60);
|
||||
@@ -218,9 +214,7 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
||||
config
|
||||
);
|
||||
|
||||
const hourPickerItems = page.locator(
|
||||
'ion-datetime ion-picker-column-internal:first-of-type .picker-item:not(.picker-item-empty)'
|
||||
);
|
||||
const hourPickerItems = page.locator('ion-datetime ion-picker-column:first-of-type ion-picker-column-option');
|
||||
await expect(hourPickerItems).toHaveText(['8', '9', '10', '11']);
|
||||
});
|
||||
|
||||
@@ -242,9 +236,7 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
||||
config
|
||||
);
|
||||
|
||||
const hourPickerItems = page.locator(
|
||||
'ion-datetime ion-picker-column-internal:first-of-type .picker-item:not(.picker-item-empty)'
|
||||
);
|
||||
const hourPickerItems = page.locator('ion-datetime ion-picker-column:first-of-type ion-picker-column-option');
|
||||
await expect(hourPickerItems).toHaveText(['12', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']);
|
||||
});
|
||||
|
||||
@@ -308,7 +300,7 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
||||
);
|
||||
|
||||
const datetime = page.locator('ion-datetime');
|
||||
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
|
||||
const monthColumnItems = page.locator('ion-datetime .month-column ion-picker-column-option');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
@@ -360,9 +352,7 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
||||
|
||||
await ionPopoverDidPresent.next();
|
||||
|
||||
const hours = page.locator(
|
||||
'ion-popover ion-picker-column-internal:nth-child(1) .picker-item:not(.picker-item-empty)'
|
||||
);
|
||||
const hours = page.locator('ion-popover ion-picker-column:nth-child(1) ion-picker-column-option');
|
||||
|
||||
await expect(await hours.count()).toBe(4);
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 25 KiB |
@@ -25,7 +25,7 @@
|
||||
<ion-content class="ion-padding">
|
||||
<ion-button id="open-datetime" onclick="presentPopover(defaultPopover, event)">Present Popover</ion-button>
|
||||
<ion-popover class="datetime-popover" id="default-popover">
|
||||
<ion-datetime value="2022-05-03"></ion-datetime>
|
||||
<ion-datetime value="2022-05-03T14:23:00.000Z"></ion-datetime>
|
||||
</ion-popover>
|
||||
</ion-content>
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('ion-datetime .day-column .picker-item[data-value]');
|
||||
const dayValues = page.locator('ion-datetime .day-column ion-picker-column-option');
|
||||
expect(await dayValues.count()).toEqual(27);
|
||||
});
|
||||
test('should respect the max bounds', async ({ page }) => {
|
||||
@@ -95,7 +95,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('ion-datetime .day-column .picker-item[data-value]');
|
||||
const dayValues = page.locator('ion-datetime .day-column ion-picker-column-option');
|
||||
expect(await dayValues.count()).toEqual(1);
|
||||
});
|
||||
test('should respect isDateEnabled preference', async ({ page }) => {
|
||||
@@ -118,9 +118,9 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const disabledMonths = page.locator('.month-column .picker-item[disabled]');
|
||||
const disabledYears = page.locator('.year-column .picker-item[disabled]');
|
||||
const disabledDays = page.locator('.day-column .picker-item[disabled]');
|
||||
const disabledMonths = page.locator('.month-column ion-picker-column-option.option-disabled');
|
||||
const disabledYears = page.locator('.year-column ion-picker-column-option.option-disabled');
|
||||
const disabledDays = page.locator('.day-column ion-picker-column-option.option-disabled');
|
||||
|
||||
expect(await disabledMonths.count()).toBe(0);
|
||||
expect(await disabledYears.count()).toBe(0);
|
||||
@@ -143,9 +143,9 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const monthValues = page.locator('.month-column .picker-item:not(.picker-item-empty)');
|
||||
const yearValues = page.locator('.year-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.day-column .picker-item:not(.picker-item-empty)');
|
||||
const monthValues = page.locator('.month-column ion-picker-column-option');
|
||||
const yearValues = page.locator('.year-column ion-picker-column-option');
|
||||
const dayValues = page.locator('.day-column ion-picker-column-option');
|
||||
|
||||
expect(await monthValues.count()).toBe(2);
|
||||
expect(await yearValues.count()).toBe(3);
|
||||
@@ -178,7 +178,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
const monthValues = page.locator('.month-column .picker-item:not(.picker-item-empty)');
|
||||
const monthValues = page.locator('.month-column ion-picker-column-option');
|
||||
|
||||
// Change month value
|
||||
await monthValues.nth(0).click();
|
||||
@@ -212,7 +212,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
const dayValues = page.locator('.day-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.day-column ion-picker-column-option');
|
||||
|
||||
// Change day value
|
||||
await dayValues.nth(0).click();
|
||||
@@ -233,7 +233,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
const yearValues = page.locator('.year-column .picker-item:not(.picker-item-empty)');
|
||||
const yearValues = page.locator('.year-column ion-picker-column-option');
|
||||
|
||||
/**
|
||||
* Change year value
|
||||
@@ -259,9 +259,9 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await datetime.evaluate((el: HTMLIonDatetimeElement) => (el.value = '2021-05-25T12:40:00.000Z'));
|
||||
await page.waitForChanges();
|
||||
|
||||
const selectedMonth = datetime.locator('.month-column .picker-item-active');
|
||||
const selectedDay = datetime.locator('.day-column .picker-item-active');
|
||||
const selectedYear = datetime.locator('.year-column .picker-item-active');
|
||||
const selectedMonth = datetime.locator('.month-column ion-picker-column-option.option-active');
|
||||
const selectedDay = datetime.locator('.day-column ion-picker-column-option.option-active');
|
||||
const selectedYear = datetime.locator('.year-column ion-picker-column-option.option-active');
|
||||
|
||||
await expect(selectedMonth).toHaveText(/May/);
|
||||
await expect(selectedDay).toHaveText(/25/);
|
||||
@@ -287,9 +287,8 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const monthValues = page.locator('.month-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.day-column .picker-item:not(.picker-item-empty)');
|
||||
|
||||
const monthValues = page.locator('.month-column ion-picker-column-option');
|
||||
const dayValues = page.locator('.day-column ion-picker-column-option');
|
||||
await expect(monthValues).toHaveText(['1月', '2月', '3月']);
|
||||
await expect(dayValues).toHaveText(['1日', '2日', '3日']);
|
||||
});
|
||||
@@ -308,7 +307,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const columns = page.locator('ion-picker-column-internal');
|
||||
const columns = page.locator('ion-picker-column');
|
||||
|
||||
await expect(columns.nth(0)).toHaveClass(/month-column/);
|
||||
await expect(columns.nth(1)).toHaveClass(/day-column/);
|
||||
@@ -329,7 +328,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const columns = page.locator('ion-picker-column-internal');
|
||||
const columns = page.locator('ion-picker-column');
|
||||
|
||||
await expect(columns.nth(0)).toHaveClass(/day-column/);
|
||||
await expect(columns.nth(1)).toHaveClass(/month-column/);
|
||||
@@ -348,7 +347,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('ion-datetime .date-column .picker-item[data-value]');
|
||||
const dayValues = page.locator('ion-datetime .date-column ion-picker-column-option');
|
||||
expect(await dayValues.count()).toEqual(57);
|
||||
});
|
||||
test('should respect the max bounds', async ({ page }) => {
|
||||
@@ -361,7 +360,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('ion-datetime .date-column .picker-item[data-value]');
|
||||
const dayValues = page.locator('ion-datetime .date-column ion-picker-column-option');
|
||||
expect(await dayValues.count()).toEqual(41);
|
||||
});
|
||||
test('should respect isDateEnabled preference', async ({ page }) => {
|
||||
@@ -384,7 +383,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const disabledDates = page.locator('.date-column .picker-item[disabled]');
|
||||
const disabledDates = page.locator('.date-column ion-picker-column-option.option-disabled');
|
||||
|
||||
expect(await disabledDates.count()).toBe(44);
|
||||
});
|
||||
@@ -405,7 +404,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dateValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
expect(await dateValues.count()).toBe(5);
|
||||
});
|
||||
@@ -426,8 +425,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
|
||||
const dateValues = page.locator('.date-column ion-picker-column-option');
|
||||
await expect(dateValues).toHaveText(['2月1日(火)', '2月2日(水)', '2月3日(木)']);
|
||||
});
|
||||
test('should respect min and max bounds even across years', async ({ page }) => {
|
||||
@@ -447,18 +445,19 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateColumn = page.locator('.date-column');
|
||||
const dateValues = dateColumn.locator('.picker-item:not(.picker-item-empty)');
|
||||
const dateColumnScrollEl = dateColumn.locator('.picker-opts');
|
||||
const dateValues = dateColumn.locator('ion-picker-column-option');
|
||||
|
||||
expect(await dateValues.count()).toBe(90);
|
||||
|
||||
/**
|
||||
* Select 1st item to change the dates rendered
|
||||
*/
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2022-1-1');
|
||||
await dateColumn.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await expect(dateValues.nth(0)).toHaveJSProperty('value', '2022-1-1');
|
||||
await dateColumnScrollEl.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2021-12-1');
|
||||
await expect(dateValues.nth(0)).toHaveJSProperty('value', '2021-12-1');
|
||||
});
|
||||
test('should keep sliding window if default window is within min and max constraints', async ({ page }) => {
|
||||
await page.setContent(
|
||||
@@ -476,7 +475,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
expect(await dayValues.count()).toBe(92);
|
||||
});
|
||||
@@ -496,7 +495,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
expect(await dayValues.count()).toBe(15);
|
||||
});
|
||||
@@ -514,7 +513,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
// Change day/month value
|
||||
await dayValues.nth(0).click();
|
||||
@@ -533,7 +532,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('ion-datetime .date-column .picker-item[data-value]');
|
||||
const dayValues = page.locator('ion-datetime .date-column ion-picker-column-option');
|
||||
expect(await dayValues.count()).toEqual(57);
|
||||
});
|
||||
test('should respect the max bounds', async ({ page }) => {
|
||||
@@ -546,7 +545,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('ion-datetime .date-column .picker-item[data-value]');
|
||||
const dayValues = page.locator('ion-datetime .date-column ion-picker-column-option');
|
||||
expect(await dayValues.count()).toEqual(41);
|
||||
});
|
||||
test('should respect isDateEnabled preference', async ({ page }) => {
|
||||
@@ -569,7 +568,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const disabledDates = page.locator('.date-column .picker-item[disabled]');
|
||||
const disabledDates = page.locator('.date-column ion-picker-column-option.option-disabled');
|
||||
|
||||
expect(await disabledDates.count()).toBe(44);
|
||||
});
|
||||
@@ -590,7 +589,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dateValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
expect(await dateValues.count()).toBe(5);
|
||||
});
|
||||
@@ -611,7 +610,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dateValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
await expect(dateValues).toHaveText(['2月1日(火)', '2月2日(水)', '2月3日(木)']);
|
||||
});
|
||||
@@ -632,18 +631,19 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dateColumn = page.locator('.date-column');
|
||||
const dateValues = dateColumn.locator('.picker-item:not(.picker-item-empty)');
|
||||
const dateColumnScrollEl = dateColumn.locator('.picker-opts');
|
||||
const dateValues = dateColumn.locator('ion-picker-column-option');
|
||||
|
||||
expect(await dateValues.count()).toBe(90);
|
||||
|
||||
/**
|
||||
* Select 1st item to change the dates rendered
|
||||
*/
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2022-1-1');
|
||||
await dateColumn.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await expect(dateValues.nth(0)).toHaveJSProperty('value', '2022-1-1');
|
||||
await dateColumnScrollEl.evaluate((el: HTMLElement) => (el.scrollTop = 0));
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(dateValues.nth(0)).toHaveAttribute('data-value', '2021-12-1');
|
||||
await expect(dateValues.nth(0)).toHaveJSProperty('value', '2021-12-1');
|
||||
});
|
||||
test('should keep sliding window if default window is within min and max constraints', async ({ page }) => {
|
||||
await page.setContent(
|
||||
@@ -661,7 +661,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
expect(await dayValues.count()).toBe(92);
|
||||
});
|
||||
@@ -681,7 +681,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const dayValues = page.locator('.date-column .picker-item:not(.picker-item-empty)');
|
||||
const dayValues = page.locator('.date-column ion-picker-column-option');
|
||||
|
||||
expect(await dayValues.count()).toBe(15);
|
||||
});
|
||||
|
||||
@@ -227,7 +227,7 @@ class TimePickerFixture {
|
||||
}
|
||||
|
||||
async expectTime(hour: number, minute: number, ampm: string) {
|
||||
const pickerColumns = this.timePicker.locator('ion-picker-column-internal');
|
||||
const pickerColumns = this.timePicker.locator('ion-picker-column');
|
||||
|
||||
await expect(pickerColumns.nth(0)).toHaveJSProperty('value', hour);
|
||||
await expect(pickerColumns.nth(1)).toHaveJSProperty('value', minute);
|
||||
|
||||
@@ -49,7 +49,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config, scree
|
||||
|
||||
await calendarMonthYear.click();
|
||||
await page.waitForChanges();
|
||||
await page.locator('.month-column .picker-item[data-value="3"]').click();
|
||||
await page.locator('.month-column ion-picker-column-option').nth(2).click();
|
||||
await page.waitForChanges();
|
||||
await expect(calendarMonthYear).toHaveText('March 2022');
|
||||
|
||||
@@ -78,7 +78,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config, scree
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForChanges();
|
||||
|
||||
const marchPickerItem = page.locator('.month-column .picker-item[data-value="3"]');
|
||||
const marchPickerItem = page.locator('.month-column ion-picker-column-option').nth(2);
|
||||
await expect(marchPickerItem).toBeVisible();
|
||||
});
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
config
|
||||
);
|
||||
|
||||
const items = page.locator('.month-column .picker-item:not(.picker-item-empty)');
|
||||
const items = page.locator('.month-column ion-picker-column-option');
|
||||
await expect(items).toHaveText(['May', 'June', 'October']);
|
||||
});
|
||||
test('should render correct years', async ({ page }) => {
|
||||
@@ -40,7 +40,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
config
|
||||
);
|
||||
|
||||
const items = page.locator('.year-column .picker-item:not(.picker-item-empty)');
|
||||
const items = page.locator('.year-column ion-picker-column-option');
|
||||
await expect(items).toHaveText(['2022', '2021', '2020']);
|
||||
});
|
||||
test('should render correct hours', async ({ page }) => {
|
||||
@@ -51,7 +51,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
config
|
||||
);
|
||||
|
||||
const items = page.locator('ion-picker-column-internal:first-of-type .picker-item:not(.picker-item-empty)');
|
||||
const items = page.locator('ion-picker-column:first-of-type ion-picker-column-option');
|
||||
await expect(items).toHaveText(['1', '2', '3']);
|
||||
});
|
||||
test('should render correct minutes', async ({ page }) => {
|
||||
@@ -62,7 +62,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
config
|
||||
);
|
||||
|
||||
const items = page.locator('ion-picker-column-internal:nth-of-type(2) .picker-item:not(.picker-item-empty)');
|
||||
const items = page.locator('ion-picker-column:nth-of-type(2) ion-picker-column-option');
|
||||
await expect(items).toHaveText(['01', '02', '03']);
|
||||
});
|
||||
test('should adjust default parts for allowed hour and minute values', async ({ page }) => {
|
||||
@@ -93,23 +93,25 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const minuteItems = page.locator(
|
||||
'ion-picker-column-internal:nth-of-type(2) .picker-item:not(.picker-item-empty)'
|
||||
);
|
||||
await expect(minuteItems).toHaveText(['00', '15', '30', '45']);
|
||||
await expect(minuteItems.nth(1)).toHaveClass(/picker-item-active/);
|
||||
const minuteColumn = page.locator('ion-picker-column').nth(1);
|
||||
const minuteItems = minuteColumn.locator('ion-picker-column-option');
|
||||
|
||||
const hourItems = page.locator('ion-picker-column-internal:nth-of-type(1) .picker-item:not(.picker-item-empty)');
|
||||
await expect(minuteItems).toHaveText(['00', '15', '30', '45']);
|
||||
await expect(minuteColumn).toHaveJSProperty('value', 15);
|
||||
|
||||
const hourColumn = page.locator('ion-picker-column').nth(0);
|
||||
const hourItems = hourColumn.locator('ion-picker-column-option');
|
||||
await expect(hourItems).toHaveText(['2']);
|
||||
await expect(hourItems.nth(0)).toHaveClass(/picker-item-active/);
|
||||
await expect(hourColumn).toHaveJSProperty('value', 2);
|
||||
|
||||
/**
|
||||
* Since the allowed hour is 2AM, the time period
|
||||
* should switch from PM to AM.
|
||||
*/
|
||||
const ampmItems = page.locator('ion-picker-column-internal:nth-of-type(3) .picker-item:not(.picker-item-empty)');
|
||||
const ampmColumn = page.locator('ion-picker-column').nth(2);
|
||||
const ampmItems = ampmColumn.locator('ion-picker-column-option');
|
||||
await expect(ampmItems).toHaveText(['AM', 'PM']);
|
||||
await expect(ampmItems.nth(0)).toHaveClass(/picker-item-active/);
|
||||
await expect(ampmColumn).toHaveJSProperty('value', 'am');
|
||||
});
|
||||
test('should adjust default parts month for allowed month values', async ({ page }) => {
|
||||
/**
|
||||
@@ -139,9 +141,9 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const monthItems = page.locator('.month-column .picker-item:not(.picker-item-empty)');
|
||||
const monthItems = page.locator('.month-column ion-picker-column-option');
|
||||
await expect(monthItems).toHaveText(['January']);
|
||||
await expect(monthItems.nth(0)).toHaveClass(/picker-item-active/);
|
||||
await expect(monthItems.nth(0)).toHaveClass(/option-active/);
|
||||
});
|
||||
test('today date highlight should persist even if disallowed from dayValues', async ({ page }) => {
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Mode } from '../../../interface';
|
||||
import type { PickerColumnItem } from '../../picker-column-internal/picker-column-internal-interfaces';
|
||||
import type { PickerColumnItem } from '../../picker-column/picker-column-interfaces';
|
||||
import type { DatetimeParts, DatetimeHourCycle } from '../datetime-interface';
|
||||
|
||||
import { isAfter, isBefore, isSameDay } from './comparison';
|
||||
@@ -380,7 +380,7 @@ export const getMonthColumnData = (
|
||||
* @param minParts The minimum bound on the date that can be returned
|
||||
* @param maxParts The maximum bound on the date that can be returned
|
||||
* @param dayValues The allowed date values
|
||||
* @returns Date data to be used in ion-picker-column-internal
|
||||
* @returns Date data to be used in ion-picker-column
|
||||
*/
|
||||
export const getDayColumnData = (
|
||||
locale: string,
|
||||
|
||||
@@ -95,7 +95,9 @@ export class Input implements ComponentInterface {
|
||||
@Prop() autocorrect: 'on' | 'off' = 'off';
|
||||
|
||||
/**
|
||||
* This Boolean attribute lets you specify that a form control should have input focus when the page loads.
|
||||
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element.
|
||||
*
|
||||
* This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
@Prop() autofocus = false;
|
||||
|
||||
@@ -424,6 +426,8 @@ export class Input implements ComponentInterface {
|
||||
*
|
||||
* Developers who wish to focus an input when an overlay is presented
|
||||
* should call `setFocus` after `didPresent` has resolved.
|
||||
*
|
||||
* See [managing focus](/docs/developing/managing-focus) for more information.
|
||||
*/
|
||||
@Method()
|
||||
async setFocus() {
|
||||
|
||||
@@ -225,6 +225,17 @@ export class Loading implements ComponentInterface, OverlayInterface {
|
||||
if (this.isOpen === true) {
|
||||
raf(() => this.present());
|
||||
}
|
||||
|
||||
/**
|
||||
* When binding values in frameworks such as Angular
|
||||
* it is possible for the value to be set after the Web Component
|
||||
* initializes but before the value watcher is set up in Stencil.
|
||||
* As a result, the watcher callback may not be fired.
|
||||
* We work around this by manually calling the watcher
|
||||
* callback when the component has loaded and the watcher
|
||||
* is configured.
|
||||
*/
|
||||
this.triggerChanged();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
|
||||
@@ -368,6 +368,17 @@ export class Modal implements ComponentInterface, OverlayInterface {
|
||||
raf(() => this.present());
|
||||
}
|
||||
this.breakpointsChanged(this.breakpoints);
|
||||
|
||||
/**
|
||||
* When binding values in frameworks such as Angular
|
||||
* it is possible for the value to be set after the Web Component
|
||||
* initializes but before the value watcher is set up in Stencil.
|
||||
* As a result, the watcher callback may not be fired.
|
||||
* We work around this by manually calling the watcher
|
||||
* callback when the component has loaded and the watcher
|
||||
* is configured.
|
||||
*/
|
||||
this.triggerChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export interface PickerColumnItem {
|
||||
text: string;
|
||||
value: string | number;
|
||||
disabled?: boolean;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
@import "./picker-column-internal.scss";
|
||||
@@ -1,6 +0,0 @@
|
||||
@import "./picker-column-internal.scss";
|
||||
@import "../../themes/ionic.globals.md";
|
||||
|
||||
:host .picker-item-active {
|
||||
color: current-color(base);
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
// Picker Internal
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
@include padding(0px, 16px, 0px, 16px);
|
||||
|
||||
height: 200px;
|
||||
|
||||
outline: none;
|
||||
|
||||
font-size: 22px;
|
||||
scroll-snap-type: y mandatory;
|
||||
|
||||
/**
|
||||
* Need to explicitly set overflow-x: hidden
|
||||
* for older implementations of scroll snapping.
|
||||
*/
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
|
||||
// Hide scrollbars on Firefox
|
||||
scrollbar-width: none;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide scrollbars on Chrome and Safari
|
||||
*/
|
||||
:host::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host .picker-item {
|
||||
@include padding(0);
|
||||
@include margin(0);
|
||||
|
||||
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] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
:host .picker-item-empty,
|
||||
:host(:not([disabled])) .picker-item[disabled] {
|
||||
scroll-snap-align: none;
|
||||
}
|
||||
|
||||
:host([disabled]) {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
:host .picker-item[disabled] {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
:host(.picker-column-active) .picker-item.picker-item-active {
|
||||
color: current-color(base);
|
||||
}
|
||||
|
||||
@media (any-hover: hover) {
|
||||
:host(:focus) {
|
||||
outline: none;
|
||||
|
||||
background: current-color(base, 0.2);
|
||||
}
|
||||
}
|
||||
@@ -1,501 +0,0 @@
|
||||
import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
|
||||
import { getElementRoot, raf } from '@utils/helpers';
|
||||
import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from '@utils/native/haptic';
|
||||
import { isPlatform } from '@utils/platform';
|
||||
import { createColorClasses } from '@utils/theme';
|
||||
|
||||
import { getIonMode } from '../../global/ionic-global';
|
||||
import type { Color } from '../../interface';
|
||||
import type { PickerInternalCustomEvent } from '../picker-internal/picker-internal-interfaces';
|
||||
|
||||
import type { PickerColumnItem } from './picker-column-internal-interfaces';
|
||||
|
||||
/**
|
||||
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
|
||||
* @internal
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-picker-column-internal',
|
||||
styleUrls: {
|
||||
ios: 'picker-column-internal.ios.scss',
|
||||
md: 'picker-column-internal.md.scss',
|
||||
},
|
||||
shadow: true,
|
||||
})
|
||||
export class PickerColumnInternal implements ComponentInterface {
|
||||
private destroyScrollListener?: () => void;
|
||||
private isScrolling = false;
|
||||
private scrollEndCallback?: () => void;
|
||||
private isColumnVisible = false;
|
||||
private parentEl?: HTMLIonPickerInternalElement | null;
|
||||
private canExitInputMode = true;
|
||||
|
||||
@State() isActive = false;
|
||||
|
||||
@Element() el!: HTMLIonPickerColumnInternalElement;
|
||||
|
||||
/**
|
||||
* If `true`, the user cannot interact with the picker.
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* A list of options to be displayed in the picker
|
||||
*/
|
||||
@Prop() items: PickerColumnItem[] = [];
|
||||
|
||||
/**
|
||||
* The selected option in the picker.
|
||||
*/
|
||||
@Prop({ mutable: true }) value?: string | number;
|
||||
|
||||
/**
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* If `true`, tapping the picker will
|
||||
* reveal a number input keyboard that lets
|
||||
* the user type in values for each picker
|
||||
* column. This is useful when working
|
||||
* with time pickers.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
@Prop() numericInput = false;
|
||||
|
||||
/**
|
||||
* Emitted when the value has changed.
|
||||
*/
|
||||
@Event() ionChange!: EventEmitter<PickerColumnItem>;
|
||||
|
||||
@Watch('value')
|
||||
valueChange() {
|
||||
if (this.isColumnVisible) {
|
||||
/**
|
||||
* Only scroll the active item into view when the picker column
|
||||
* is actively visible to the user.
|
||||
*/
|
||||
this.scrollActiveItemIntoView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only setup scroll listeners
|
||||
* when the picker is visible, otherwise
|
||||
* the container will have a scroll
|
||||
* height of 0px.
|
||||
*/
|
||||
componentWillLoad() {
|
||||
const visibleCallback = (entries: IntersectionObserverEntry[]) => {
|
||||
const ev = entries[0];
|
||||
|
||||
if (ev.isIntersecting) {
|
||||
const { activeItem, el } = this;
|
||||
|
||||
this.isColumnVisible = true;
|
||||
/**
|
||||
* Because this initial call to scrollActiveItemIntoView has to fire before
|
||||
* the scroll listener is set up, we need to manage the active class manually.
|
||||
*/
|
||||
const oldActive = getElementRoot(el).querySelector(`.${PICKER_ITEM_ACTIVE_CLASS}`);
|
||||
if (oldActive) {
|
||||
this.setPickerItemActiveState(oldActive, false);
|
||||
}
|
||||
this.scrollActiveItemIntoView();
|
||||
if (activeItem) {
|
||||
this.setPickerItemActiveState(activeItem, true);
|
||||
}
|
||||
|
||||
this.initializeScrollListener();
|
||||
} else {
|
||||
this.isColumnVisible = false;
|
||||
|
||||
if (this.destroyScrollListener) {
|
||||
this.destroyScrollListener();
|
||||
this.destroyScrollListener = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
new IntersectionObserver(visibleCallback, { threshold: 0.001 }).observe(this.el);
|
||||
|
||||
const parentEl = (this.parentEl = this.el.closest('ion-picker-internal') as HTMLIonPickerInternalElement | null);
|
||||
if (parentEl !== null) {
|
||||
// TODO(FW-2832): type
|
||||
parentEl.addEventListener('ionInputModeChange', (ev: any) => this.inputModeChange(ev));
|
||||
}
|
||||
}
|
||||
|
||||
componentDidRender() {
|
||||
const { activeItem, items, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@Method()
|
||||
async scrollActiveItemIntoView() {
|
||||
const activeEl = this.activeItem;
|
||||
|
||||
if (activeEl) {
|
||||
this.centerPickerItemInView(activeEl, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value prop and fires the ionChange event.
|
||||
* This is used when we need to fire ionChange from
|
||||
* user-generated events that cannot be caught with normal
|
||||
* input/change event listeners.
|
||||
* @internal
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
private centerPickerItemInView = (target: HTMLElement, smooth = true, canExitInputMode = true) => {
|
||||
const { el, isColumnVisible } = this;
|
||||
if (isColumnVisible) {
|
||||
// (Vertical offset from parent) - (three empty picker rows) + (half the height of the target to ensure the scroll triggers)
|
||||
const top = target.offsetTop - 3 * target.clientHeight + target.clientHeight / 2;
|
||||
|
||||
if (el.scrollTop !== top) {
|
||||
/**
|
||||
* Setting this flag prevents input
|
||||
* mode from exiting in the picker column's
|
||||
* scroll callback. This is useful when the user manually
|
||||
* taps an item or types on the keyboard as both
|
||||
* of these can cause a scroll to occur.
|
||||
*/
|
||||
this.canExitInputMode = canExitInputMode;
|
||||
el.scroll({
|
||||
top,
|
||||
left: 0,
|
||||
behavior: smooth ? 'smooth' : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When ionInputModeChange is emitted, each column
|
||||
* needs to check if it is the one being made available
|
||||
* for text entry.
|
||||
*/
|
||||
private inputModeChange = (ev: PickerInternalCustomEvent) => {
|
||||
if (!this.numericInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { useInputMode, inputModeColumn } = ev.detail;
|
||||
|
||||
/**
|
||||
* If inputModeColumn is undefined then this means
|
||||
* all numericInput columns are being selected.
|
||||
*/
|
||||
const isColumnActive = inputModeColumn === undefined || inputModeColumn === this.el;
|
||||
|
||||
if (!useInputMode || !isColumnActive) {
|
||||
this.setInputModeActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setInputModeActive(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Setting isActive will cause a re-render.
|
||||
* As a result, we do not want to cause the
|
||||
* re-render mid scroll as this will cause
|
||||
* the picker column to jump back to
|
||||
* whatever value was selected at the
|
||||
* start of the scroll interaction.
|
||||
*/
|
||||
private setInputModeActive = (state: boolean) => {
|
||||
if (this.isScrolling) {
|
||||
this.scrollEndCallback = () => {
|
||||
this.isActive = state;
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
this.isActive = state;
|
||||
};
|
||||
|
||||
/**
|
||||
* When the column scrolls, the component
|
||||
* needs to determine which item is centered
|
||||
* in the view and will emit an ionChange with
|
||||
* the item object.
|
||||
*/
|
||||
private initializeScrollListener = () => {
|
||||
/**
|
||||
* The haptics for the wheel picker are
|
||||
* an iOS-only feature. As a result, they should
|
||||
* be disabled on Android.
|
||||
*/
|
||||
const enableHaptics = isPlatform('ios');
|
||||
const { el } = this;
|
||||
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
let activeEl: HTMLElement | null = this.activeItem;
|
||||
|
||||
const scrollCallback = () => {
|
||||
raf(() => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = undefined;
|
||||
}
|
||||
|
||||
if (!this.isScrolling) {
|
||||
enableHaptics && hapticSelectionStart();
|
||||
this.isScrolling = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select item in the center of the column
|
||||
* which is the month/year that we want to select
|
||||
*/
|
||||
const bbox = el.getBoundingClientRect();
|
||||
const centerX = bbox.x + bbox.width / 2;
|
||||
const centerY = bbox.y + bbox.height / 2;
|
||||
|
||||
const activeElement = el.shadowRoot!.elementFromPoint(centerX, centerY) as HTMLButtonElement | null;
|
||||
|
||||
if (activeEl !== null) {
|
||||
this.setPickerItemActiveState(activeEl, false);
|
||||
}
|
||||
|
||||
if (activeElement === null || activeElement.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are selecting a new value,
|
||||
* we need to run haptics again.
|
||||
*/
|
||||
if (activeElement !== activeEl) {
|
||||
enableHaptics && hapticSelectionChanged();
|
||||
|
||||
if (this.canExitInputMode) {
|
||||
/**
|
||||
* The native iOS wheel picker
|
||||
* only dismisses the keyboard
|
||||
* once the selected item has changed
|
||||
* as a result of a swipe
|
||||
* from the user. If `canExitInputMode` is
|
||||
* `false` then this means that the
|
||||
* scroll is happening as a result of
|
||||
* the `value` property programmatically changing
|
||||
* either by an application or by the user via the keyboard.
|
||||
*/
|
||||
this.exitInputMode();
|
||||
}
|
||||
}
|
||||
|
||||
activeEl = activeElement;
|
||||
this.setPickerItemActiveState(activeElement, true);
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
this.isScrolling = false;
|
||||
enableHaptics && hapticSelectionEnd();
|
||||
|
||||
/**
|
||||
* Certain tasks (such as those that
|
||||
* cause re-renders) should only be done
|
||||
* once scrolling has finished, otherwise
|
||||
* flickering may occur.
|
||||
*/
|
||||
const { scrollEndCallback } = this;
|
||||
if (scrollEndCallback) {
|
||||
scrollEndCallback();
|
||||
this.scrollEndCallback = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this flag as the
|
||||
* next scroll interaction could
|
||||
* be a scroll from the user. In this
|
||||
* case, we should exit input mode.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}, 250);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap this in an raf so that the scroll callback
|
||||
* does not fire when component is initially shown.
|
||||
*/
|
||||
raf(() => {
|
||||
el.addEventListener('scroll', scrollCallback);
|
||||
|
||||
this.destroyScrollListener = () => {
|
||||
el.removeEventListener('scroll', scrollCallback);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells the parent picker to
|
||||
* exit text entry mode. This is only called
|
||||
* when the selected item changes during scroll, so
|
||||
* we know that the user likely wants to scroll
|
||||
* instead of type.
|
||||
*/
|
||||
private exitInputMode = () => {
|
||||
const { parentEl } = this;
|
||||
|
||||
if (parentEl == null) return;
|
||||
|
||||
parentEl.exitInputMode();
|
||||
|
||||
/**
|
||||
* setInputModeActive only takes
|
||||
* effect once scrolling stops to avoid
|
||||
* a component re-render while scrolling.
|
||||
* However, we want the visual active
|
||||
* indicator to go away immediately, so
|
||||
* we call classList.remove here.
|
||||
*/
|
||||
this.el.classList.remove('picker-column-active');
|
||||
};
|
||||
|
||||
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])'}`;
|
||||
|
||||
return getElementRoot(this.el).querySelector(selector) as HTMLElement | null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { items, 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-internal there instead.
|
||||
*/
|
||||
|
||||
return (
|
||||
<Host
|
||||
exportparts={`${PICKER_ITEM_PART}, ${PICKER_ITEM_ACTIVE_PART}`}
|
||||
disabled={pickerDisabled}
|
||||
tabindex={pickerDisabled ? null : 0}
|
||||
class={createColorClasses(color, {
|
||||
[mode]: true,
|
||||
['picker-column-active']: isActive,
|
||||
['picker-column-numeric-input']: numericInput,
|
||||
})}
|
||||
>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<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>
|
||||
);
|
||||
})}
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<div class="picker-item picker-item-empty" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const PICKER_ITEM_ACTIVE_CLASS = 'picker-item-active';
|
||||
const PICKER_ITEM_PART = 'wheel-item';
|
||||
const PICKER_ITEM_ACTIVE_PART = 'active';
|
||||
@@ -1,193 +0,0 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not vary across directions.
|
||||
*/
|
||||
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('picker-column-internal: disabled rendering'), () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker-internal>
|
||||
<ion-picker-column-internal value="b"></ion-picker-column-internal>
|
||||
</ion-picker-internal>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column-internal');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a', disabled: true },
|
||||
{ text: 'B', value: 'b' },
|
||||
{ text: 'C', value: 'c', disabled: true }
|
||||
]
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const picker = page.locator('ion-picker-internal');
|
||||
await expect(picker).toHaveScreenshot(screenshot(`picker-internal-disabled`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This behavior does not vary across modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('picker-column-internal: disabled items'), () => {
|
||||
test('all picker items should be enabled by default', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker-internal>
|
||||
<ion-picker-column-internal></ion-picker-column-internal>
|
||||
</ion-picker-internal>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column-internal');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a' },
|
||||
{ text: 'B', value: 'b' },
|
||||
{ text: 'C', value: 'c' }
|
||||
]
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const pickerItems = page.locator('ion-picker-column-internal .picker-item:not(.picker-item-empty, [disabled])');
|
||||
|
||||
expect(await pickerItems.count()).toBe(3);
|
||||
});
|
||||
test('disabled picker item should not be interactive', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker-internal>
|
||||
<ion-picker-column-internal></ion-picker-column-internal>
|
||||
</ion-picker-internal>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column-internal');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a' },
|
||||
{ text: 'B', value: 'b', disabled: true },
|
||||
{ text: 'C', value: 'c' }
|
||||
]
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const disabledItem = page.locator('ion-picker-column-internal .picker-item[disabled]');
|
||||
await expect(disabledItem).not.toBeEnabled();
|
||||
});
|
||||
test('disabled picker item should not be considered active', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker-internal>
|
||||
<ion-picker-column-internal value="b"></ion-picker-column-internal>
|
||||
</ion-picker-internal>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column-internal');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a' },
|
||||
{ text: 'B', value: 'b', disabled: true },
|
||||
{ text: 'C', value: 'c' }
|
||||
]
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const disabledItem = page.locator('ion-picker-column-internal .picker-item[data-value="b"]');
|
||||
await expect(disabledItem).not.toHaveClass(/picker-item-active/);
|
||||
});
|
||||
test('setting the value to a disabled item should not cause that item to be active', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker-internal>
|
||||
<ion-picker-column-internal></ion-picker-column-internal>
|
||||
</ion-picker-internal>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column-internal');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a' },
|
||||
{ text: 'B', value: 'b', disabled: true },
|
||||
{ text: 'C', value: 'c' }
|
||||
]
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const pickerColumn = page.locator('ion-picker-column-internal');
|
||||
await pickerColumn.evaluate((el: HTMLIonPickerColumnInternalElement) => (el.value = 'b'));
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
const disabledItem = page.locator('ion-picker-column-internal .picker-item[data-value="b"]');
|
||||
await expect(disabledItem).toBeDisabled();
|
||||
await expect(disabledItem).not.toHaveClass(/picker-item-active/);
|
||||
});
|
||||
test('defaulting the value to a disabled item should not cause that item to be active', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-picker-internal>
|
||||
<ion-picker-column-internal></ion-picker-column-internal>
|
||||
</ion-picker-internal>
|
||||
|
||||
<script>
|
||||
const column = document.querySelector('ion-picker-column-internal');
|
||||
column.items = [
|
||||
{ text: 'A', value: 'a' },
|
||||
{ text: 'B', value: 'b', disabled: true },
|
||||
{ text: 'C', value: 'c' }
|
||||
]
|
||||
column.value = 'b'
|
||||
</script>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const disabledItem = page.locator('ion-picker-column-internal .picker-item[data-value="b"]');
|
||||
await expect(disabledItem).toBeDisabled();
|
||||
await expect(disabledItem).not.toHaveClass(/picker-item-active/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This behavior does not vary across directions.
|
||||
*/
|
||||
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('picker-column-internal: disabled column rendering'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/src/components/picker-column-internal/test/disabled', config);
|
||||
});
|
||||
|
||||
test('disabled column should not have visual regressions', async ({ page }) => {
|
||||
const disabledColumn = page.locator('#column-disabled');
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(disabledColumn).toHaveScreenshot(screenshot('picker-internal-disabled-column'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This behavior does not vary across modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('picker-column-internal: disabled column'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/src/components/picker-column-internal/test/disabled', config);
|
||||
});
|
||||
|
||||
test('item in disabled column should not be interactive', async ({ page }) => {
|
||||
const secondItem = page.locator('#column-disabled .picker-item:not(.picker-item-empty)').nth(1);
|
||||
await expect(secondItem).toBeDisabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1 @@
|
||||
@import "./picker-column-option";
|
||||
@@ -0,0 +1,5 @@
|
||||
@import "./picker-column-option";
|
||||
|
||||
:host(.option-active) {
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
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 {
|
||||
/**
|
||||
* We keep track of the parent picker column
|
||||
* so we can update the value of it when
|
||||
* clicking an enable option.
|
||||
*/
|
||||
private pickerColumn: HTMLIonPickerColumnElement | null = null;
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* The aria-label of the option.
|
||||
*
|
||||
* If the value changes, then it will trigger a
|
||||
* re-render of the picker since it's a @State variable.
|
||||
* Otherwise, the `aria-label` attribute cannot be updated
|
||||
* after the component is loaded.
|
||||
*/
|
||||
@State() ariaLabel?: string | null = null;
|
||||
|
||||
/**
|
||||
* If `true`, the user cannot interact with the picker column option.
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* The text value of the option.
|
||||
*/
|
||||
@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.
|
||||
*
|
||||
* @param ariaLbl The new aria-label value.
|
||||
*/
|
||||
@Watch('aria-label')
|
||||
onAriaLabelChange(ariaLbl: string) {
|
||||
this.ariaLabel = ariaLbl;
|
||||
}
|
||||
|
||||
componentWillLoad() {
|
||||
const inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
|
||||
/**
|
||||
* The initial value of `aria-label` needs to be set for
|
||||
* the first render.
|
||||
|
||||
*/
|
||||
this.ariaLabel = inheritedAttributes['aria-label'] || null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.pickerColumn = this.el.closest('ion-picker-column');
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.pickerColumn = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The column options can load at any time
|
||||
* so the options needs to tell the
|
||||
* parent picker column when it is loaded
|
||||
* so the picker column can ensure it is
|
||||
* centered in the view.
|
||||
*
|
||||
* We intentionally run this for every
|
||||
* option. If we only ran this from
|
||||
* the selected option then if the newly
|
||||
* loaded options were not selected then
|
||||
* scrollActiveItemIntoView would not be called.
|
||||
*/
|
||||
componentDidLoad() {
|
||||
const { pickerColumn } = this;
|
||||
if (pickerColumn !== null) {
|
||||
pickerColumn.scrollActiveItemIntoView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When an option is clicked update the
|
||||
* parent picker column value. This
|
||||
* component will handle centering the option
|
||||
* in the column view.
|
||||
*/
|
||||
onClick() {
|
||||
const { pickerColumn } = this;
|
||||
if (pickerColumn !== null) {
|
||||
pickerColumn.setValue(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { color, disabled, ariaLabel } = this;
|
||||
const mode = getIonMode(this);
|
||||
|
||||
return (
|
||||
<Host
|
||||
class={createColorClasses(color, {
|
||||
[mode]: true,
|
||||
['option-disabled']: disabled,
|
||||
})}
|
||||
>
|
||||
<button tabindex="-1" aria-label={ariaLabel} disabled={disabled} onClick={() => this.onClick()}>
|
||||
<slot></slot>
|
||||
</button>
|
||||
</Host>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<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" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<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>
|
||||
@@ -0,0 +1,18 @@
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not vary across directions
|
||||
*/
|
||||
configs({ directions: ['ltr'] }).forEach(({ config, title }) => {
|
||||
test.describe(title('picker column option: a11y'), () => {
|
||||
test('should not have accessibility violations', async ({ page }) => {
|
||||
await page.goto(`/src/components/picker-column-option/test/a11y`, config);
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Picker Column Option - Basic</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" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<style>
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(250px, 1fr));
|
||||
grid-row-gap: 20px;
|
||||
grid-column-gap: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
|
||||
color: #6f7378;
|
||||
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Picker Column Option - Basic</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Default</h2>
|
||||
<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>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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 |