voyager-ionic-core 8.7.6 → 8.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/button.js +3 -7
- package/components/checkbox.js +64 -13
- package/components/header.js +42 -4
- package/components/index2.js +74 -3
- package/components/ion-accordion.js +93 -14
- package/components/ion-datetime.js +35 -2
- package/components/ion-input.js +6 -13
- package/components/ion-select.js +59 -10
- package/components/ion-textarea.js +5 -12
- package/components/ion-toggle.js +63 -16
- package/components/radio-group.js +60 -7
- package/components/validity.js +17 -0
- package/dist/cjs/{index-CD5Rjp23.js → index-094mMFB-.js} +76 -5
- package/dist/cjs/index.cjs.js +3 -3
- package/dist/cjs/ion-accordion_2.cjs.entry.js +91 -13
- package/dist/cjs/ion-app_8.cjs.entry.js +43 -5
- package/dist/cjs/ion-button_2.cjs.entry.js +3 -7
- package/dist/cjs/ion-checkbox.cjs.entry.js +61 -12
- package/dist/cjs/ion-datetime_3.cjs.entry.js +35 -2
- package/dist/cjs/ion-input.cjs.entry.js +6 -13
- package/dist/cjs/ion-modal.cjs.entry.js +1 -1
- package/dist/cjs/ion-nav_2.cjs.entry.js +1 -1
- package/dist/cjs/ion-popover.cjs.entry.js +1 -1
- package/dist/cjs/ion-radio_2.cjs.entry.js +57 -6
- package/dist/cjs/ion-select_3.cjs.entry.js +56 -9
- package/dist/cjs/ion-textarea.cjs.entry.js +5 -12
- package/dist/cjs/ion-toggle.cjs.entry.js +59 -14
- package/dist/cjs/ionic.cjs.js +1 -1
- package/dist/cjs/{ios.transition-j9CclgEW.js → ios.transition-BOt_uW73.js} +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{md.transition-CwFyRSfv.js → md.transition-Dt968VXB.js} +1 -1
- package/dist/cjs/validity-BpS37YFM.js +19 -0
- package/dist/collection/components/accordion/accordion.js +93 -14
- package/dist/collection/components/button/button.js +3 -7
- package/dist/collection/components/checkbox/checkbox.js +68 -13
- package/dist/collection/components/datetime/datetime.js +35 -2
- package/dist/collection/components/header/header.ios.css +27 -1
- package/dist/collection/components/header/header.js +5 -4
- package/dist/collection/components/header/header.utils.js +37 -0
- package/dist/collection/components/input/input.js +6 -14
- package/dist/collection/components/radio-group/radio-group.js +64 -7
- package/dist/collection/components/select/select.js +60 -12
- package/dist/collection/components/textarea/textarea.js +5 -13
- package/dist/collection/components/toggle/toggle.js +63 -16
- package/dist/collection/utils/forms/index.js +1 -0
- package/dist/collection/utils/forms/validity.js +15 -0
- package/dist/collection/utils/test/playwright/page/utils/set-content.js +7 -0
- package/dist/collection/utils/test/playwright/page/utils/spy-on-event.js +32 -0
- package/dist/collection/utils/transition/index.js +74 -3
- package/dist/docs.json +1 -1
- package/dist/esm/{index-D6G2seR8.js → index-r2D9DEro.js} +76 -5
- package/dist/esm/index.js +3 -3
- package/dist/esm/ion-accordion_2.entry.js +91 -13
- package/dist/esm/ion-app_8.entry.js +43 -5
- package/dist/esm/ion-button_2.entry.js +3 -7
- package/dist/esm/ion-checkbox.entry.js +61 -12
- package/dist/esm/ion-datetime_3.entry.js +35 -2
- package/dist/esm/ion-input.entry.js +6 -13
- package/dist/esm/ion-modal.entry.js +1 -1
- package/dist/esm/ion-nav_2.entry.js +1 -1
- package/dist/esm/ion-popover.entry.js +1 -1
- package/dist/esm/ion-radio_2.entry.js +57 -6
- package/dist/esm/ion-select_3.entry.js +56 -9
- package/dist/esm/ion-textarea.entry.js +5 -12
- package/dist/esm/ion-toggle.entry.js +59 -14
- package/dist/esm/ionic.js +1 -1
- package/dist/esm/{ios.transition-Bpq9ixwv.js → ios.transition-BDzw0_Hm.js} +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{md.transition-zOA0oanq.js → md.transition-BzDYi3qq.js} +1 -1
- package/dist/esm/validity-DJztqcrH.js +17 -0
- package/dist/ionic/index.esm.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-40c261a3.entry.js +4 -0
- package/dist/ionic/p-43ed1ef5.entry.js +4 -0
- package/dist/ionic/p-4e41ea20.entry.js +4 -0
- package/dist/ionic/{p-323421af.entry.js → p-5a39a99a.entry.js} +1 -1
- package/dist/ionic/p-5fb517e4.entry.js +4 -0
- package/dist/ionic/p-7380261c.entry.js +4 -0
- package/dist/ionic/{p-9a36e2e7.entry.js → p-95bddd49.entry.js} +1 -1
- package/dist/ionic/{p-DPhQmGJN.js → p-C7hRNDhM.js} +1 -1
- package/dist/ionic/p-DJztqcrH.js +4 -0
- package/dist/ionic/p-DUt5fQmA.js +4 -0
- package/dist/ionic/{p-9R1XyICs.js → p-DZRJwG4S.js} +1 -1
- package/dist/ionic/p-c19f63d0.entry.js +4 -0
- package/dist/ionic/p-cb93126d.entry.js +4 -0
- package/dist/ionic/p-d0a2a1ab.entry.js +4 -0
- package/dist/ionic/p-d1f54e28.entry.js +4 -0
- package/dist/ionic/p-d3014190.entry.js +4 -0
- package/dist/ionic/{p-de7b5fa3.entry.js → p-e16b69e1.entry.js} +1 -1
- package/dist/ionic/svg/checkbox-outline.svg +1 -0
- package/dist/ionic/svg/checkbox-sharp.svg +1 -0
- package/dist/ionic/svg/checkbox.svg +1 -0
- package/dist/ionic/svg/checkmark-circle-outline.svg +1 -0
- package/dist/ionic/svg/checkmark-circle-sharp.svg +1 -0
- package/dist/ionic/svg/checkmark-circle.svg +1 -0
- package/dist/ionic/svg/checkmark-done-circle-outline.svg +1 -0
- package/dist/ionic/svg/checkmark-done-circle-sharp.svg +1 -0
- package/dist/ionic/svg/checkmark-done-circle.svg +1 -0
- package/dist/ionic/svg/checkmark-done-outline.svg +1 -0
- package/dist/ionic/svg/checkmark-done-sharp.svg +1 -0
- package/dist/ionic/svg/checkmark-done.svg +1 -0
- package/dist/ionic/svg/checkmark-outline.svg +1 -0
- package/dist/ionic/svg/checkmark-sharp.svg +1 -0
- package/dist/ionic/svg/checkmark.svg +1 -0
- package/dist/ionic/svg/chevron-back-circle-outline.svg +1 -0
- package/dist/ionic/svg/chevron-back-circle-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-back-circle.svg +1 -0
- package/dist/ionic/svg/chevron-back-outline.svg +1 -0
- package/dist/ionic/svg/chevron-back-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-back.svg +1 -0
- package/dist/ionic/svg/chevron-collapse-outline.svg +1 -0
- package/dist/ionic/svg/chevron-collapse-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-collapse.svg +1 -0
- package/dist/ionic/svg/chevron-down-circle-outline.svg +1 -0
- package/dist/ionic/svg/chevron-down-circle-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-down-circle.svg +1 -0
- package/dist/ionic/svg/chevron-down-outline.svg +1 -0
- package/dist/ionic/svg/chevron-down-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-down.svg +1 -0
- package/dist/ionic/svg/chevron-expand-outline.svg +1 -0
- package/dist/ionic/svg/chevron-expand-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-expand.svg +1 -0
- package/dist/ionic/svg/chevron-forward-circle-outline.svg +1 -0
- package/dist/ionic/svg/chevron-forward-circle-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-forward-circle.svg +1 -0
- package/dist/ionic/svg/chevron-forward-outline.svg +1 -0
- package/dist/ionic/svg/chevron-forward-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-forward.svg +1 -0
- package/dist/ionic/svg/chevron-up-circle-outline.svg +1 -0
- package/dist/ionic/svg/chevron-up-circle-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-up-circle.svg +1 -0
- package/dist/ionic/svg/chevron-up-outline.svg +1 -0
- package/dist/ionic/svg/chevron-up-sharp.svg +1 -0
- package/dist/ionic/svg/chevron-up.svg +1 -0
- package/dist/ionic/svg/clipboard-outline.svg +1 -0
- package/dist/ionic/svg/clipboard-sharp.svg +1 -0
- package/dist/ionic/svg/clipboard.svg +1 -0
- package/dist/ionic/svg/close-circle-outline.svg +1 -0
- package/dist/ionic/svg/close-circle-sharp.svg +1 -0
- package/dist/ionic/svg/close-circle.svg +1 -0
- package/dist/ionic/svg/close-outline.svg +1 -0
- package/dist/ionic/svg/close-sharp.svg +1 -0
- package/dist/ionic/svg/close.svg +1 -0
- package/dist/ionic/svg/cloud-circle-outline.svg +1 -0
- package/dist/ionic/svg/cloud-circle-sharp.svg +1 -0
- package/dist/ionic/svg/cloud-circle.svg +1 -0
- package/dist/ionic/svg/cloud-done-outline.svg +1 -0
- package/dist/ionic/svg/cloud-done-sharp.svg +1 -0
- package/dist/ionic/svg/cloud-done.svg +1 -0
- package/dist/ionic/svg/cloud-download-outline.svg +1 -0
- package/dist/ionic/svg/cloud-download-sharp.svg +1 -0
- package/dist/ionic/svg/cloud-download.svg +1 -0
- package/dist/ionic/svg/cloud-offline-outline.svg +1 -0
- package/dist/ionic/svg/cloud-offline-sharp.svg +1 -0
- package/dist/ionic/svg/cloud-offline.svg +1 -0
- package/dist/ionic/svg/cloud-outline.svg +1 -0
- package/dist/ionic/svg/cloud-sharp.svg +1 -0
- package/dist/ionic/svg/cloud-upload-outline.svg +1 -0
- package/dist/ionic/svg/cloud-upload-sharp.svg +1 -0
- package/dist/ionic/svg/cloud-upload.svg +1 -0
- package/dist/ionic/svg/cloud.svg +1 -0
- package/dist/ionic/svg/cloudy-night-outline.svg +1 -0
- package/dist/ionic/svg/cloudy-night-sharp.svg +1 -0
- package/dist/ionic/svg/cloudy-night.svg +1 -0
- package/dist/ionic/svg/cloudy-outline.svg +1 -0
- package/dist/ionic/svg/cloudy-sharp.svg +1 -0
- package/dist/ionic/svg/cloudy.svg +1 -0
- package/dist/ionic/svg/code-download-outline.svg +1 -0
- package/dist/ionic/svg/code-download-sharp.svg +1 -0
- package/dist/ionic/svg/code-download.svg +1 -0
- package/dist/ionic/svg/code-outline.svg +1 -0
- package/dist/ionic/svg/code-sharp.svg +1 -0
- package/dist/ionic/svg/code-slash-outline.svg +1 -0
- package/dist/ionic/svg/code-slash-sharp.svg +1 -0
- package/dist/ionic/svg/code-slash.svg +1 -0
- package/dist/ionic/svg/code-working-outline.svg +1 -0
- package/dist/ionic/svg/code-working-sharp.svg +1 -0
- package/dist/ionic/svg/code-working.svg +1 -0
- package/dist/ionic/svg/code.svg +1 -0
- package/dist/ionic/svg/cog-outline.svg +1 -0
- package/dist/ionic/svg/cog-sharp.svg +1 -0
- package/dist/ionic/svg/cog.svg +1 -0
- package/dist/ionic/svg/color-fill-outline.svg +1 -0
- package/dist/ionic/svg/color-fill-sharp.svg +1 -0
- package/dist/ionic/svg/color-fill.svg +1 -0
- package/dist/ionic/svg/color-filter-outline.svg +1 -0
- package/dist/ionic/svg/color-filter-sharp.svg +1 -0
- package/dist/ionic/svg/color-filter.svg +1 -0
- package/dist/ionic/svg/color-palette-outline.svg +1 -0
- package/dist/ionic/svg/color-palette-sharp.svg +1 -0
- package/dist/ionic/svg/color-palette.svg +1 -0
- package/dist/ionic/svg/color-wand-outline.svg +1 -0
- package/dist/ionic/svg/color-wand-sharp.svg +1 -0
- package/dist/ionic/svg/color-wand.svg +1 -0
- package/dist/ionic/svg/compass-outline.svg +1 -0
- package/dist/ionic/svg/compass-sharp.svg +1 -0
- package/dist/ionic/svg/compass.svg +1 -0
- package/dist/ionic/svg/construct-outline.svg +1 -0
- package/dist/ionic/svg/construct-sharp.svg +1 -0
- package/dist/ionic/svg/construct.svg +1 -0
- package/dist/ionic/svg/contract-outline.svg +1 -0
- package/dist/ionic/svg/contract-sharp.svg +1 -0
- package/dist/ionic/svg/contract.svg +1 -0
- package/dist/ionic/svg/contrast-outline.svg +1 -0
- package/dist/ionic/svg/contrast-sharp.svg +1 -0
- package/dist/ionic/svg/contrast.svg +1 -0
- package/dist/ionic/svg/copy-outline.svg +1 -0
- package/dist/ionic/svg/copy-sharp.svg +1 -0
- package/dist/ionic/svg/copy.svg +1 -0
- package/dist/ionic/svg/create-outline.svg +1 -0
- package/dist/ionic/svg/create-sharp.svg +1 -0
- package/dist/ionic/svg/create.svg +1 -0
- package/dist/ionic/svg/crop-outline.svg +1 -0
- package/dist/ionic/svg/crop-sharp.svg +1 -0
- package/dist/ionic/svg/crop.svg +1 -0
- package/dist/ionic/svg/cube-outline.svg +1 -0
- package/dist/ionic/svg/cube-sharp.svg +1 -0
- package/dist/ionic/svg/cube.svg +1 -0
- package/dist/ionic/svg/cut-outline.svg +1 -0
- package/dist/ionic/svg/cut-sharp.svg +1 -0
- package/dist/ionic/svg/cut.svg +1 -0
- package/dist/ionic/svg/desktop-outline.svg +1 -0
- package/dist/ionic/svg/desktop-sharp.svg +1 -0
- package/dist/ionic/svg/desktop.svg +1 -0
- package/dist/ionic/svg/diamond-outline.svg +1 -0
- package/dist/ionic/svg/diamond-sharp.svg +1 -0
- package/dist/ionic/svg/diamond.svg +1 -0
- package/dist/ionic/svg/dice-outline.svg +1 -0
- package/dist/ionic/svg/dice-sharp.svg +1 -0
- package/dist/ionic/svg/dice.svg +1 -0
- package/dist/ionic/svg/disc-outline.svg +1 -0
- package/dist/ionic/svg/disc-sharp.svg +1 -0
- package/dist/ionic/svg/disc.svg +1 -0
- package/dist/ionic/svg/document-attach-outline.svg +1 -0
- package/dist/ionic/svg/document-attach-sharp.svg +1 -0
- package/dist/ionic/svg/document-attach.svg +1 -0
- package/dist/ionic/svg/document-lock-outline.svg +1 -0
- package/dist/ionic/svg/document-lock-sharp.svg +1 -0
- package/dist/ionic/svg/document-lock.svg +1 -0
- package/dist/ionic/svg/document-outline.svg +1 -0
- package/dist/types/components/accordion/accordion.d.ts +18 -1
- package/dist/types/components/checkbox/checkbox.d.ts +9 -2
- package/dist/types/components/datetime/datetime.d.ts +10 -0
- package/dist/types/components/header/header.utils.d.ts +10 -0
- package/dist/types/components/input/input.d.ts +0 -4
- package/dist/types/components/radio-group/radio-group.d.ts +9 -1
- package/dist/types/components/select/select.d.ts +7 -1
- package/dist/types/components/textarea/textarea.d.ts +0 -4
- package/dist/types/components/toggle/toggle.d.ts +7 -2
- package/dist/types/utils/forms/index.d.ts +1 -0
- package/dist/types/utils/forms/validity.d.ts +10 -0
- package/dist/types/utils/transition/index.d.ts +9 -0
- package/hydrate/index.js +687 -413
- package/hydrate/index.mjs +687 -413
- package/package.json +4 -4
- package/dist/ionic/p-1c8a476d.entry.js +0 -4
- package/dist/ionic/p-3355a2ff.entry.js +0 -4
- package/dist/ionic/p-4efea47a.entry.js +0 -4
- package/dist/ionic/p-62e50f80.entry.js +0 -4
- package/dist/ionic/p-785026d7.entry.js +0 -4
- package/dist/ionic/p-78c74a3e.entry.js +0 -4
- package/dist/ionic/p-7bcfc421.entry.js +0 -4
- package/dist/ionic/p-83fc84e7.entry.js +0 -4
- package/dist/ionic/p-913a7c1e.entry.js +0 -4
- package/dist/ionic/p-CMhMiYSX.js +0 -4
- package/dist/ionic/p-c17c0a01.entry.js +0 -4
|
@@ -790,6 +790,28 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
|
|
|
790
790
|
destroyKeyboardMO();
|
|
791
791
|
}
|
|
792
792
|
};
|
|
793
|
+
/**
|
|
794
|
+
* TODO(FW-6931): Remove this fallback upon solving the root cause
|
|
795
|
+
* Fallback to ensure the datetime becomes ready even if
|
|
796
|
+
* IntersectionObserver never reports it as intersecting.
|
|
797
|
+
*
|
|
798
|
+
* This is primarily used in environments where the observer
|
|
799
|
+
* might not fire as expected, such as when running under
|
|
800
|
+
* synthetic tests that stub IntersectionObserver.
|
|
801
|
+
*/
|
|
802
|
+
this.ensureReadyIfVisible = () => {
|
|
803
|
+
if (this.el.classList.contains('datetime-ready')) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
const rect = this.el.getBoundingClientRect();
|
|
807
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
this.initializeListeners();
|
|
811
|
+
writeTask(() => {
|
|
812
|
+
this.el.classList.add('datetime-ready');
|
|
813
|
+
});
|
|
814
|
+
};
|
|
793
815
|
this.processValue = (value) => {
|
|
794
816
|
const hasValue = value !== null && value !== undefined && value !== '' && (!Array.isArray(value) || value.length > 0);
|
|
795
817
|
const valueToProcess = hasValue ? parseDate(value) : this.defaultParts;
|
|
@@ -1107,6 +1129,17 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
|
|
|
1107
1129
|
* triggering the `hiddenIO` observer below.
|
|
1108
1130
|
*/
|
|
1109
1131
|
raf(() => visibleIO === null || visibleIO === void 0 ? void 0 : visibleIO.observe(intersectionTrackerRef));
|
|
1132
|
+
/**
|
|
1133
|
+
* TODO(FW-6931): Remove this fallback upon solving the root cause
|
|
1134
|
+
* Fallback: If IntersectionObserver never reports that the
|
|
1135
|
+
* datetime is visible but the host clearly has layout, ensure
|
|
1136
|
+
* we still initialize listeners and mark the component as ready.
|
|
1137
|
+
*
|
|
1138
|
+
* We schedule this after everything has had a chance to run.
|
|
1139
|
+
*/
|
|
1140
|
+
setTimeout(() => {
|
|
1141
|
+
this.ensureReadyIfVisible();
|
|
1142
|
+
}, 100);
|
|
1110
1143
|
/**
|
|
1111
1144
|
* We need to clean up listeners when the datetime is hidden
|
|
1112
1145
|
* in a popover/modal so that we can properly scroll containers
|
|
@@ -1862,7 +1895,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
|
|
|
1862
1895
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1863
1896
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1864
1897
|
renderHiddenInput(true, el, name, formatValue(value), disabled);
|
|
1865
|
-
return (h(Host, { key: '
|
|
1898
|
+
return (h(Host, { key: 'efdbc0922670a841bc667ceac392cdc1dedffd01', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
|
|
1866
1899
|
[mode]: true,
|
|
1867
1900
|
['datetime-readonly']: readonly,
|
|
1868
1901
|
['datetime-disabled']: disabled,
|
|
@@ -1872,7 +1905,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
|
|
|
1872
1905
|
[`datetime-size-${size}`]: true,
|
|
1873
1906
|
[`datetime-prefer-wheel`]: hasWheelVariant,
|
|
1874
1907
|
[`datetime-grid`]: isGridStyle,
|
|
1875
|
-
})) }, h("div", { key: '
|
|
1908
|
+
})) }, h("div", { key: '3f8bb75fcb0baff55182ef3aa1b535eacc58d81f', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
|
|
1876
1909
|
}
|
|
1877
1910
|
get el() { return this; }
|
|
1878
1911
|
static get watchers() { return {
|
package/components/ion-input.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { proxyCustomElement, HTMLElement, createEvent, forceUpdate, Build, h, Host } from '@stencil/core/internal/client';
|
|
5
5
|
import { c as createNotchController } from './notch-controller.js';
|
|
6
|
+
import { c as checkInvalidState } from './validity.js';
|
|
6
7
|
import { l as debounceEvent, i as inheritAriaAttributes, d as inheritAttributes, c as componentOnReady } from './helpers.js';
|
|
7
8
|
import { c as createSlotMutationController, g as getCounterText } from './input.utils.js';
|
|
8
9
|
import { h as hostContext, c as createColorClasses } from './theme.js';
|
|
@@ -233,14 +234,6 @@ const Input = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
|
|
|
233
234
|
componentWillLoad() {
|
|
234
235
|
this.inheritedAttributes = Object.assign(Object.assign({}, inheritAriaAttributes(this.el)), inheritAttributes(this.el, ['tabindex', 'title', 'data-form-type', 'dir']));
|
|
235
236
|
}
|
|
236
|
-
/**
|
|
237
|
-
* Checks if the input is in an invalid state based on Ionic validation classes
|
|
238
|
-
*/
|
|
239
|
-
checkInvalidState() {
|
|
240
|
-
const hasIonTouched = this.el.classList.contains('ion-touched');
|
|
241
|
-
const hasIonInvalid = this.el.classList.contains('ion-invalid');
|
|
242
|
-
return hasIonTouched && hasIonInvalid;
|
|
243
|
-
}
|
|
244
237
|
connectedCallback() {
|
|
245
238
|
const { el } = this;
|
|
246
239
|
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate(this));
|
|
@@ -248,7 +241,7 @@ const Input = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
|
|
|
248
241
|
// Watch for class changes to update validation state
|
|
249
242
|
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
250
243
|
this.validationObserver = new MutationObserver(() => {
|
|
251
|
-
const newIsInvalid =
|
|
244
|
+
const newIsInvalid = checkInvalidState(el);
|
|
252
245
|
if (this.isInvalid !== newIsInvalid) {
|
|
253
246
|
this.isInvalid = newIsInvalid;
|
|
254
247
|
// Force a re-render to update aria-describedby immediately
|
|
@@ -261,7 +254,7 @@ const Input = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
|
|
|
261
254
|
});
|
|
262
255
|
}
|
|
263
256
|
// Always set initial state
|
|
264
|
-
this.isInvalid =
|
|
257
|
+
this.isInvalid = checkInvalidState(el);
|
|
265
258
|
this.debounceChanged();
|
|
266
259
|
if (Build.isBrowser) {
|
|
267
260
|
document.dispatchEvent(new CustomEvent('ionInputDidLoad', {
|
|
@@ -525,7 +518,7 @@ const Input = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
|
|
|
525
518
|
* TODO(FW-5592): Remove hasStartEndSlots condition
|
|
526
519
|
*/
|
|
527
520
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
|
|
528
|
-
return (h(Host, { key: '
|
|
521
|
+
return (h(Host, { key: '97b5308021064d9e7434ef2d3d96f27045c1b0c4', class: createColorClasses(this.color, {
|
|
529
522
|
[mode]: true,
|
|
530
523
|
'has-value': hasValue,
|
|
531
524
|
'has-focus': hasFocus,
|
|
@@ -536,14 +529,14 @@ const Input = /*@__PURE__*/ proxyCustomElement(class Input extends HTMLElement {
|
|
|
536
529
|
'in-item': inItem,
|
|
537
530
|
'in-item-color': hostContext('ion-item.ion-color', this.el),
|
|
538
531
|
'input-disabled': disabled,
|
|
539
|
-
}) }, h("label", { key: '
|
|
532
|
+
}) }, h("label", { key: '353f68726ce180299bd9adc81e5ff7d26a48f54f', class: "input-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), h("div", { key: '2034b4bad04fc157f3298a1805819216b6f439d0', class: "native-wrapper", onClick: this.onLabelClick }, h("slot", { key: '96bb5e30176b2bd76dfb75bfbf6c1c3d4403f4bb', name: "start" }), h("input", Object.assign({ key: '1a1d75b0e414a95c89d5a760757c33548d234aca', class: "native-input", ref: (input) => (this.nativeInput = input), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, min: this.min, max: this.max, minLength: this.minlength, maxLength: this.maxlength, multiple: this.multiple, name: this.name, pattern: this.pattern, placeholder: this.placeholder || '', readOnly: readonly, required: this.required, spellcheck: this.spellcheck, step: this.step, type: this.type, value: value, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown, onCompositionstart: this.onCompositionStart, onCompositionend: this.onCompositionEnd, "aria-describedby": this.getHintTextID(), "aria-invalid": this.isInvalid ? 'true' : undefined }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (h("button", { key: '95f3df17b7691d9a2e7dcd4a51f16a94aa3ca36f', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
|
|
540
533
|
/**
|
|
541
534
|
* This prevents mobile browsers from
|
|
542
535
|
* blurring the input when the clear
|
|
543
536
|
* button is activated.
|
|
544
537
|
*/
|
|
545
538
|
ev.preventDefault();
|
|
546
|
-
}, onClick: this.clearTextInput }, h("ion-icon", { key: '
|
|
539
|
+
}, onClick: this.clearTextInput }, h("ion-icon", { key: '16b0af75eed50c8115fb5597f73b5fbf71c2530e', "aria-hidden": "true", icon: clearIconData }))), h("slot", { key: 'c48da0f8ddb3764ac43efa705bb4a6bb2d9cc2fd', name: "end" })), shouldRenderHighlight && h("div", { key: 'f15238481fc20de56ca7ecb6e350b3c024cc755e', class: "input-highlight" })), this.renderBottomContent()));
|
|
547
540
|
}
|
|
548
541
|
get el() { return this; }
|
|
549
542
|
static get watchers() { return {
|
package/components/ion-select.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
|
-
import { proxyCustomElement, HTMLElement, createEvent, h, Host, forceUpdate } from '@stencil/core/internal/client';
|
|
4
|
+
import { proxyCustomElement, HTMLElement, createEvent, Build, h, Host, forceUpdate } from '@stencil/core/internal/client';
|
|
5
5
|
import { c as createNotchController } from './notch-controller.js';
|
|
6
6
|
import { i as isOptionSelected, d as defineCustomElement$8, c as compareOptions } from './radio.js';
|
|
7
|
+
import { c as checkInvalidState } from './validity.js';
|
|
7
8
|
import { d as inheritAttributes, e as renderHiddenInput, h as focusVisibleElement } from './helpers.js';
|
|
8
9
|
import { p as printIonWarning } from './index4.js';
|
|
9
10
|
import { c as popoverController, b as actionSheetController, a as alertController, m as modalController } from './overlays.js';
|
|
@@ -65,6 +66,10 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
65
66
|
* is applied in both cases.
|
|
66
67
|
*/
|
|
67
68
|
this.hasFocus = false;
|
|
69
|
+
/**
|
|
70
|
+
* Track validation state for proper aria-live announcements.
|
|
71
|
+
*/
|
|
72
|
+
this.isInvalid = false;
|
|
68
73
|
/**
|
|
69
74
|
* The text to display on the cancel button.
|
|
70
75
|
*/
|
|
@@ -194,9 +199,46 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
194
199
|
*/
|
|
195
200
|
forceUpdate(this);
|
|
196
201
|
});
|
|
202
|
+
// Watch for class changes to update validation state.
|
|
203
|
+
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
204
|
+
this.validationObserver = new MutationObserver(() => {
|
|
205
|
+
const newIsInvalid = checkInvalidState(this.el);
|
|
206
|
+
if (this.isInvalid !== newIsInvalid) {
|
|
207
|
+
this.isInvalid = newIsInvalid;
|
|
208
|
+
/**
|
|
209
|
+
* Screen readers tend to announce changes
|
|
210
|
+
* to `aria-describedby` when the attribute
|
|
211
|
+
* is changed during a blur event for a
|
|
212
|
+
* native form control.
|
|
213
|
+
* However, the announcement can be spotty
|
|
214
|
+
* when using a non-native form control
|
|
215
|
+
* and `forceUpdate()`.
|
|
216
|
+
* This is due to `forceUpdate()` internally
|
|
217
|
+
* rescheduling the DOM update to a lower
|
|
218
|
+
* priority queue regardless if it's called
|
|
219
|
+
* inside a Promise or not, thus causing
|
|
220
|
+
* the screen reader to potentially miss the
|
|
221
|
+
* change.
|
|
222
|
+
* By using a State variable inside a Promise,
|
|
223
|
+
* it guarantees a re-render immediately at
|
|
224
|
+
* a higher priority.
|
|
225
|
+
*/
|
|
226
|
+
Promise.resolve().then(() => {
|
|
227
|
+
this.hintTextId = this.getHintTextId();
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
this.validationObserver.observe(el, {
|
|
232
|
+
attributes: true,
|
|
233
|
+
attributeFilter: ['class'],
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
// Always set initial state
|
|
237
|
+
this.isInvalid = checkInvalidState(this.el);
|
|
197
238
|
}
|
|
198
239
|
componentWillLoad() {
|
|
199
240
|
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
|
|
241
|
+
this.hintTextId = this.getHintTextId();
|
|
200
242
|
}
|
|
201
243
|
componentDidLoad() {
|
|
202
244
|
/**
|
|
@@ -220,6 +262,11 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
220
262
|
this.notchController.destroy();
|
|
221
263
|
this.notchController = undefined;
|
|
222
264
|
}
|
|
265
|
+
// Clean up validation observer to prevent memory leaks.
|
|
266
|
+
if (this.validationObserver) {
|
|
267
|
+
this.validationObserver.disconnect();
|
|
268
|
+
this.validationObserver = undefined;
|
|
269
|
+
}
|
|
223
270
|
}
|
|
224
271
|
/**
|
|
225
272
|
* Open the select overlay. The overlay is either an alert, action sheet, or popover,
|
|
@@ -690,11 +737,11 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
690
737
|
}
|
|
691
738
|
renderListbox() {
|
|
692
739
|
const { disabled, inputId, isExpanded, required } = this;
|
|
693
|
-
return (h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, "aria-describedby": this.
|
|
740
|
+
return (h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, "aria-describedby": this.hintTextId, "aria-invalid": this.isInvalid ? 'true' : undefined, "aria-required": `${required}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
|
|
694
741
|
}
|
|
695
|
-
|
|
696
|
-
const {
|
|
697
|
-
if (
|
|
742
|
+
getHintTextId() {
|
|
743
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
744
|
+
if (isInvalid && errorText) {
|
|
698
745
|
return errorTextId;
|
|
699
746
|
}
|
|
700
747
|
if (helperText) {
|
|
@@ -706,10 +753,10 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
706
753
|
* Renders the helper text or error text values
|
|
707
754
|
*/
|
|
708
755
|
renderHintText() {
|
|
709
|
-
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
756
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
710
757
|
return [
|
|
711
|
-
h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text" }, helperText),
|
|
712
|
-
h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text" }, errorText),
|
|
758
|
+
h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
|
|
759
|
+
h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text", role: "alert" }, isInvalid ? errorText : null),
|
|
713
760
|
];
|
|
714
761
|
}
|
|
715
762
|
/**
|
|
@@ -757,7 +804,7 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
757
804
|
* TODO(FW-5592): Remove hasStartEndSlots condition
|
|
758
805
|
*/
|
|
759
806
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || isExpanded || hasStartEndSlots));
|
|
760
|
-
return (h(Host, { key: '
|
|
807
|
+
return (h(Host, { key: '35b5e18e6f79a802ff2d46d1242e80ff755cc0b9', onClick: this.onClick, class: createColorClasses(this.color, {
|
|
761
808
|
[mode]: true,
|
|
762
809
|
'in-item': inItem,
|
|
763
810
|
'in-item-color': hostContext('ion-item.ion-color', el),
|
|
@@ -775,7 +822,7 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
775
822
|
[`select-justify-${justify}`]: justifyEnabled,
|
|
776
823
|
[`select-shape-${shape}`]: shape !== undefined,
|
|
777
824
|
[`select-label-placement-${labelPlacement}`]: true,
|
|
778
|
-
}) }, h("label", { key: '
|
|
825
|
+
}) }, h("label", { key: '6005b34a0c50bc4d7653a4276bc232ecd02e083c', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick }, this.renderLabelContainer(), h("div", { key: 'c7e07aa81ae856c057f16275dd058f37c5670a47', class: "select-wrapper-inner" }, h("slot", { key: '7fc2deefe0424404caacdbbd9e08ed43ba55d28a', name: "start" }), h("div", { key: '157d74ee717b1bc30b5f1c233a09b0c8456aa68e', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()), h("slot", { key: 'ea66db304528b82bf9317730b6dce3db2612f235', name: "end" }), !hasFloatingOrStackedLabel && this.renderSelectIcon()), hasFloatingOrStackedLabel && this.renderSelectIcon(), shouldRenderHighlight && h("div", { key: '786eb1530b7476f0615d4e7c0bf4e7e4dc66509c', class: "select-highlight" })), this.renderBottomContent()));
|
|
779
826
|
}
|
|
780
827
|
get el() { return this; }
|
|
781
828
|
static get watchers() { return {
|
|
@@ -813,6 +860,8 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
813
860
|
"required": [4],
|
|
814
861
|
"isExpanded": [32],
|
|
815
862
|
"hasFocus": [32],
|
|
863
|
+
"isInvalid": [32],
|
|
864
|
+
"hintTextId": [32],
|
|
816
865
|
"open": [64]
|
|
817
866
|
}, undefined, {
|
|
818
867
|
"disabled": ["styleChanged"],
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { proxyCustomElement, HTMLElement, createEvent, forceUpdate, Build, writeTask, h, Host } from '@stencil/core/internal/client';
|
|
5
5
|
import { c as createNotchController } from './notch-controller.js';
|
|
6
|
+
import { c as checkInvalidState } from './validity.js';
|
|
6
7
|
import { l as debounceEvent, i as inheritAriaAttributes, d as inheritAttributes, c as componentOnReady } from './helpers.js';
|
|
7
8
|
import { c as createSlotMutationController, g as getCounterText } from './input.utils.js';
|
|
8
9
|
import { h as hostContext, c as createColorClasses } from './theme.js';
|
|
@@ -192,14 +193,6 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
192
193
|
this.el.click();
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Checks if the textarea is in an invalid state based on Ionic validation classes
|
|
197
|
-
*/
|
|
198
|
-
checkValidationState() {
|
|
199
|
-
const hasIonTouched = this.el.classList.contains('ion-touched');
|
|
200
|
-
const hasIonInvalid = this.el.classList.contains('ion-invalid');
|
|
201
|
-
return hasIonTouched && hasIonInvalid;
|
|
202
|
-
}
|
|
203
196
|
connectedCallback() {
|
|
204
197
|
const { el } = this;
|
|
205
198
|
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate(this));
|
|
@@ -207,7 +200,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
207
200
|
// Watch for class changes to update validation state
|
|
208
201
|
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
209
202
|
this.validationObserver = new MutationObserver(() => {
|
|
210
|
-
const newIsInvalid = this.
|
|
203
|
+
const newIsInvalid = checkInvalidState(this.el);
|
|
211
204
|
if (this.isInvalid !== newIsInvalid) {
|
|
212
205
|
this.isInvalid = newIsInvalid;
|
|
213
206
|
// Force a re-render to update aria-describedby immediately
|
|
@@ -220,7 +213,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
220
213
|
});
|
|
221
214
|
}
|
|
222
215
|
// Always set initial state
|
|
223
|
-
this.isInvalid = this.
|
|
216
|
+
this.isInvalid = checkInvalidState(this.el);
|
|
224
217
|
this.debounceChanged();
|
|
225
218
|
if (Build.isBrowser) {
|
|
226
219
|
document.dispatchEvent(new CustomEvent('ionInputDidLoad', {
|
|
@@ -484,7 +477,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
484
477
|
* TODO(FW-5592): Remove hasStartEndSlots condition
|
|
485
478
|
*/
|
|
486
479
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
|
|
487
|
-
return (h(Host, { key: '
|
|
480
|
+
return (h(Host, { key: 'a70a62d7aae3831a50acd74f60b930925ada1326', class: createColorClasses(this.color, {
|
|
488
481
|
[mode]: true,
|
|
489
482
|
'has-value': hasValue,
|
|
490
483
|
'has-focus': hasFocus,
|
|
@@ -493,7 +486,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
493
486
|
[`textarea-shape-${shape}`]: shape !== undefined,
|
|
494
487
|
[`textarea-label-placement-${labelPlacement}`]: true,
|
|
495
488
|
'textarea-disabled': disabled,
|
|
496
|
-
}) }, h("label", { key: '
|
|
489
|
+
}) }, h("label", { key: '8a2dd59a60f7469df84018eb0ede3a9ec3862703', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), h("div", { key: '1bfc368236e3da7a225a45118c27fbfc1fe5fa46', class: "textarea-wrapper-inner" }, h("div", { key: '215cbb2635ff52e31a8973376989b85e7245d40f', class: "start-slot-wrapper" }, h("slot", { key: '9f6b461cdee9d629deb695d2bea054ece2f32305', name: "start" })), h("div", { key: 'c1af35a2d5bc452bebe0b22a26d15ff52b4e9fc8', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ key: '69a69b3cf0932baafbe37e6e846f1a571608d3f2', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown, "aria-describedby": this.getHintTextID(), "aria-invalid": this.isInvalid ? 'true' : undefined }, this.inheritedAttributes), value)), h("div", { key: 'c053ea8b865d0e29763aed2e4939cc9c9e374c15', class: "end-slot-wrapper" }, h("slot", { key: '930aa641833b0df54b9ea10368fc2f46d5f491f6', name: "end" }))), shouldRenderHighlight && h("div", { key: '8d12597d15f5f429d80e8272ea99e64ed924e482', class: "textarea-highlight" })), this.renderBottomContent()));
|
|
497
490
|
}
|
|
498
491
|
get el() { return this; }
|
|
499
492
|
static get watchers() { return {
|
package/components/ion-toggle.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
|
-
import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
|
|
4
|
+
import { proxyCustomElement, HTMLElement, createEvent, Build, h, Host } from '@stencil/core/internal/client';
|
|
5
5
|
import { i as inheritAriaAttributes, e as renderHiddenInput } from './helpers.js';
|
|
6
|
+
import { c as checkInvalidState } from './validity.js';
|
|
6
7
|
import { d as hapticSelection } from './haptic.js';
|
|
7
8
|
import { a as isPlatform, b as getIonMode } from './ionic-global.js';
|
|
8
9
|
import { i as isRTL } from './dir.js';
|
|
@@ -33,6 +34,10 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
33
34
|
this.inheritedAttributes = {};
|
|
34
35
|
this.didLoad = false;
|
|
35
36
|
this.activated = false;
|
|
37
|
+
/**
|
|
38
|
+
* Track validation state for proper aria-live announcements.
|
|
39
|
+
*/
|
|
40
|
+
this.isInvalid = false;
|
|
36
41
|
/**
|
|
37
42
|
* The name of the control, which is submitted with the form data.
|
|
38
43
|
*/
|
|
@@ -140,22 +145,58 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
140
145
|
const { checked, value } = this;
|
|
141
146
|
const isNowChecked = !checked;
|
|
142
147
|
this.checked = isNowChecked;
|
|
143
|
-
this.setFocus();
|
|
144
148
|
this.ionChange.emit({
|
|
145
149
|
checked: isNowChecked,
|
|
146
150
|
value,
|
|
147
151
|
});
|
|
148
152
|
}
|
|
149
153
|
async connectedCallback() {
|
|
154
|
+
const { didLoad, el } = this;
|
|
150
155
|
/**
|
|
151
156
|
* If we have not yet rendered
|
|
152
157
|
* ion-toggle, then toggleTrack is not defined.
|
|
153
158
|
* But if we are moving ion-toggle via appendChild,
|
|
154
159
|
* then toggleTrack will be defined.
|
|
155
160
|
*/
|
|
156
|
-
if (
|
|
161
|
+
if (didLoad) {
|
|
157
162
|
this.setupGesture();
|
|
158
163
|
}
|
|
164
|
+
// Watch for class changes to update validation state.
|
|
165
|
+
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
166
|
+
this.validationObserver = new MutationObserver(() => {
|
|
167
|
+
const newIsInvalid = checkInvalidState(el);
|
|
168
|
+
if (this.isInvalid !== newIsInvalid) {
|
|
169
|
+
this.isInvalid = newIsInvalid;
|
|
170
|
+
/**
|
|
171
|
+
* Screen readers tend to announce changes
|
|
172
|
+
* to `aria-describedby` when the attribute
|
|
173
|
+
* is changed during a blur event for a
|
|
174
|
+
* native form control.
|
|
175
|
+
* However, the announcement can be spotty
|
|
176
|
+
* when using a non-native form control
|
|
177
|
+
* and `forceUpdate()`.
|
|
178
|
+
* This is due to `forceUpdate()` internally
|
|
179
|
+
* rescheduling the DOM update to a lower
|
|
180
|
+
* priority queue regardless if it's called
|
|
181
|
+
* inside a Promise or not, thus causing
|
|
182
|
+
* the screen reader to potentially miss the
|
|
183
|
+
* change.
|
|
184
|
+
* By using a State variable inside a Promise,
|
|
185
|
+
* it guarantees a re-render immediately at
|
|
186
|
+
* a higher priority.
|
|
187
|
+
*/
|
|
188
|
+
Promise.resolve().then(() => {
|
|
189
|
+
this.hintTextId = this.getHintTextId();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
this.validationObserver.observe(el, {
|
|
194
|
+
attributes: true,
|
|
195
|
+
attributeFilter: ['class'],
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
// Always set initial state
|
|
199
|
+
this.isInvalid = checkInvalidState(el);
|
|
159
200
|
}
|
|
160
201
|
componentDidLoad() {
|
|
161
202
|
this.setupGesture();
|
|
@@ -166,9 +207,15 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
166
207
|
this.gesture.destroy();
|
|
167
208
|
this.gesture = undefined;
|
|
168
209
|
}
|
|
210
|
+
// Clean up validation observer to prevent memory leaks.
|
|
211
|
+
if (this.validationObserver) {
|
|
212
|
+
this.validationObserver.disconnect();
|
|
213
|
+
this.validationObserver = undefined;
|
|
214
|
+
}
|
|
169
215
|
}
|
|
170
216
|
componentWillLoad() {
|
|
171
217
|
this.inheritedAttributes = Object.assign({}, inheritAriaAttributes(this.el));
|
|
218
|
+
this.hintTextId = this.getHintTextId();
|
|
172
219
|
}
|
|
173
220
|
onStart() {
|
|
174
221
|
this.activated = true;
|
|
@@ -191,9 +238,7 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
191
238
|
return this.value || '';
|
|
192
239
|
}
|
|
193
240
|
setFocus() {
|
|
194
|
-
|
|
195
|
-
this.focusEl.focus();
|
|
196
|
-
}
|
|
241
|
+
this.el.focus();
|
|
197
242
|
}
|
|
198
243
|
renderOnOffSwitchLabels(mode, checked) {
|
|
199
244
|
const icon = this.getSwitchLabelIcon(mode, checked);
|
|
@@ -211,9 +256,9 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
211
256
|
get hasLabel() {
|
|
212
257
|
return this.el.textContent !== '';
|
|
213
258
|
}
|
|
214
|
-
|
|
215
|
-
const {
|
|
216
|
-
if (
|
|
259
|
+
getHintTextId() {
|
|
260
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
261
|
+
if (isInvalid && errorText) {
|
|
217
262
|
return errorTextId;
|
|
218
263
|
}
|
|
219
264
|
if (helperText) {
|
|
@@ -226,7 +271,7 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
226
271
|
* This element should only be rendered if hint text is set.
|
|
227
272
|
*/
|
|
228
273
|
renderHintText() {
|
|
229
|
-
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
274
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
230
275
|
/**
|
|
231
276
|
* undefined and empty string values should
|
|
232
277
|
* be treated as not having helper/error text.
|
|
@@ -235,15 +280,15 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
235
280
|
if (!hasHintText) {
|
|
236
281
|
return;
|
|
237
282
|
}
|
|
238
|
-
return (h("div", { class: "toggle-bottom" }, h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text" }, helperText), h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text" }, errorText)));
|
|
283
|
+
return (h("div", { class: "toggle-bottom" }, h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null), h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text", role: "alert" }, isInvalid ? errorText : null)));
|
|
239
284
|
}
|
|
240
285
|
render() {
|
|
241
|
-
const { activated, alignment, checked, color, disabled, el,
|
|
286
|
+
const { activated, alignment, checked, color, disabled, el, hasLabel, inheritedAttributes, inputId, inputLabelId, justify, labelPlacement, name, required, } = this;
|
|
242
287
|
const mode = getIonMode(this);
|
|
243
288
|
const value = this.getValue();
|
|
244
289
|
const rtl = isRTL(el) ? 'rtl' : 'ltr';
|
|
245
290
|
renderHiddenInput(true, el, name, checked ? value : '', disabled);
|
|
246
|
-
return (h(Host, { key: '
|
|
291
|
+
return (h(Host, { key: 'f569148edd89ee041a4719ffc4733c16b05229bd', role: "switch", "aria-checked": `${checked}`, "aria-describedby": this.hintTextId, "aria-invalid": this.isInvalid ? 'true' : undefined, onClick: this.onClick, "aria-labelledby": hasLabel ? inputLabelId : null, "aria-label": inheritedAttributes['aria-label'] || null, "aria-disabled": disabled ? 'true' : null, "aria-required": required ? 'true' : undefined, tabindex: disabled ? undefined : 0, onKeyDown: this.onKeyDown, onFocus: this.onFocus, onBlur: this.onBlur, class: createColorClasses(color, {
|
|
247
292
|
[mode]: true,
|
|
248
293
|
'in-item': hostContext('ion-item', el),
|
|
249
294
|
'toggle-activated': activated,
|
|
@@ -253,10 +298,10 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
253
298
|
[`toggle-alignment-${alignment}`]: alignment !== undefined,
|
|
254
299
|
[`toggle-label-placement-${labelPlacement}`]: true,
|
|
255
300
|
[`toggle-${rtl}`]: true,
|
|
256
|
-
}) }, h("label", { key: '
|
|
301
|
+
}) }, h("label", { key: '3027f2ac4be6de422a14486d847fbee77f615db1', class: "toggle-wrapper", htmlFor: inputId }, h("input", Object.assign({ key: '4b0304c9e879e432b80184b4e5de37d55c11b436', type: "checkbox", role: "switch", "aria-checked": `${checked}`, checked: checked, disabled: disabled, id: inputId, required: required }, inheritedAttributes)), h("div", { key: '8ef265ec942e7f01ff31cbb202ed146c6bf94e02', class: {
|
|
257
302
|
'label-text-wrapper': true,
|
|
258
303
|
'label-text-wrapper-hidden': !hasLabel,
|
|
259
|
-
}, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: '
|
|
304
|
+
}, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: '7b162b7dd27199cca2a4c995276a18b9f8e44aaf' }), this.renderHintText()), h("div", { key: 'd13c34bd42fca01cc73ddb4ea7e471b33a282a3e', class: "native-wrapper" }, this.renderToggleControl()))));
|
|
260
305
|
}
|
|
261
306
|
get el() { return this; }
|
|
262
307
|
static get watchers() { return {
|
|
@@ -279,7 +324,9 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
279
324
|
"justify": [1],
|
|
280
325
|
"alignment": [1],
|
|
281
326
|
"required": [4],
|
|
282
|
-
"activated": [32]
|
|
327
|
+
"activated": [32],
|
|
328
|
+
"isInvalid": [32],
|
|
329
|
+
"hintTextId": [32]
|
|
283
330
|
}, undefined, {
|
|
284
331
|
"disabled": ["disabledChanged"]
|
|
285
332
|
}]);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
|
-
import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
|
|
4
|
+
import { proxyCustomElement, HTMLElement, createEvent, Build, h, Host } from '@stencil/core/internal/client';
|
|
5
5
|
import { e as renderHiddenInput } from './helpers.js';
|
|
6
|
+
import { c as checkInvalidState } from './validity.js';
|
|
6
7
|
import { b as getIonMode } from './ionic-global.js';
|
|
7
8
|
|
|
8
9
|
const radioGroupIosCss = "ion-radio-group{vertical-align:top}.radio-group-wrapper{display:inline}.radio-group-top{line-height:1.5}.radio-group-top .error-text{display:none;color:var(--ion-color-danger, #c5000f)}.radio-group-top .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid .radio-group-top .error-text{display:block}.ion-touched.ion-invalid .radio-group-top .helper-text{display:none}ion-list .radio-group-top{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}";
|
|
@@ -21,6 +22,10 @@ const RadioGroup = /*@__PURE__*/ proxyCustomElement(class RadioGroup extends HTM
|
|
|
21
22
|
this.helperTextId = `${this.inputId}-helper-text`;
|
|
22
23
|
this.errorTextId = `${this.inputId}-error-text`;
|
|
23
24
|
this.labelId = `${this.inputId}-lbl`;
|
|
25
|
+
/**
|
|
26
|
+
* Track validation state for proper aria-live announcements.
|
|
27
|
+
*/
|
|
28
|
+
this.isInvalid = false;
|
|
24
29
|
/**
|
|
25
30
|
* If `true`, the radios can be deselected.
|
|
26
31
|
*/
|
|
@@ -102,6 +107,52 @@ const RadioGroup = /*@__PURE__*/ proxyCustomElement(class RadioGroup extends HTM
|
|
|
102
107
|
this.labelId = label.id = this.name + '-lbl';
|
|
103
108
|
}
|
|
104
109
|
}
|
|
110
|
+
// Watch for class changes to update validation state.
|
|
111
|
+
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
112
|
+
this.validationObserver = new MutationObserver(() => {
|
|
113
|
+
const newIsInvalid = checkInvalidState(this.el);
|
|
114
|
+
if (this.isInvalid !== newIsInvalid) {
|
|
115
|
+
this.isInvalid = newIsInvalid;
|
|
116
|
+
/**
|
|
117
|
+
* Screen readers tend to announce changes
|
|
118
|
+
* to `aria-describedby` when the attribute
|
|
119
|
+
* is changed during a blur event for a
|
|
120
|
+
* native form control.
|
|
121
|
+
* However, the announcement can be spotty
|
|
122
|
+
* when using a non-native form control
|
|
123
|
+
* and `forceUpdate()`.
|
|
124
|
+
* This is due to `forceUpdate()` internally
|
|
125
|
+
* rescheduling the DOM update to a lower
|
|
126
|
+
* priority queue regardless if it's called
|
|
127
|
+
* inside a Promise or not, thus causing
|
|
128
|
+
* the screen reader to potentially miss the
|
|
129
|
+
* change.
|
|
130
|
+
* By using a State variable inside a Promise,
|
|
131
|
+
* it guarantees a re-render immediately at
|
|
132
|
+
* a higher priority.
|
|
133
|
+
*/
|
|
134
|
+
Promise.resolve().then(() => {
|
|
135
|
+
this.hintTextId = this.getHintTextId();
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
this.validationObserver.observe(this.el, {
|
|
140
|
+
attributes: true,
|
|
141
|
+
attributeFilter: ['class'],
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
// Always set initial state
|
|
145
|
+
this.isInvalid = checkInvalidState(this.el);
|
|
146
|
+
}
|
|
147
|
+
componentWillLoad() {
|
|
148
|
+
this.hintTextId = this.getHintTextId();
|
|
149
|
+
}
|
|
150
|
+
disconnectedCallback() {
|
|
151
|
+
// Clean up validation observer to prevent memory leaks.
|
|
152
|
+
if (this.validationObserver) {
|
|
153
|
+
this.validationObserver.disconnect();
|
|
154
|
+
this.validationObserver = undefined;
|
|
155
|
+
}
|
|
105
156
|
}
|
|
106
157
|
getRadios() {
|
|
107
158
|
return Array.from(this.el.querySelectorAll('ion-radio'));
|
|
@@ -177,16 +228,16 @@ const RadioGroup = /*@__PURE__*/ proxyCustomElement(class RadioGroup extends HTM
|
|
|
177
228
|
* Renders the helper text or error text values
|
|
178
229
|
*/
|
|
179
230
|
renderHintText() {
|
|
180
|
-
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
231
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
181
232
|
const hasHintText = !!helperText || !!errorText;
|
|
182
233
|
if (!hasHintText) {
|
|
183
234
|
return;
|
|
184
235
|
}
|
|
185
|
-
return (h("div", { class: "radio-group-top" }, h("div", { id: helperTextId, class: "helper-text" }, helperText), h("div", { id: errorTextId, class: "error-text" }, errorText)));
|
|
236
|
+
return (h("div", { class: "radio-group-top" }, h("div", { id: helperTextId, class: "helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null), h("div", { id: errorTextId, class: "error-text", role: "alert" }, isInvalid ? errorText : null)));
|
|
186
237
|
}
|
|
187
|
-
|
|
188
|
-
const {
|
|
189
|
-
if (
|
|
238
|
+
getHintTextId() {
|
|
239
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
240
|
+
if (isInvalid && errorText) {
|
|
190
241
|
return errorTextId;
|
|
191
242
|
}
|
|
192
243
|
if (helperText) {
|
|
@@ -198,7 +249,7 @@ const RadioGroup = /*@__PURE__*/ proxyCustomElement(class RadioGroup extends HTM
|
|
|
198
249
|
const { label, labelId, el, name, value } = this;
|
|
199
250
|
const mode = getIonMode(this);
|
|
200
251
|
renderHiddenInput(true, el, name, value, false);
|
|
201
|
-
return (h(Host, { key: '
|
|
252
|
+
return (h(Host, { key: 'db593b3ed511e9395e3c7bfd91b787328692cd6d', role: "radiogroup", "aria-labelledby": label ? labelId : null, "aria-describedby": this.hintTextId, "aria-invalid": this.isInvalid ? 'true' : undefined, onClick: this.onClick, class: mode }, this.renderHintText(), h("div", { key: '85045b45a0100a45f3b9a35d1c5a25ec63d525c4', class: "radio-group-wrapper" }, h("slot", { key: '53dacb87ce62398e78771fb2efaf839ab922d946' }))));
|
|
202
253
|
}
|
|
203
254
|
get el() { return this; }
|
|
204
255
|
static get watchers() { return {
|
|
@@ -215,6 +266,8 @@ const RadioGroup = /*@__PURE__*/ proxyCustomElement(class RadioGroup extends HTM
|
|
|
215
266
|
"value": [1032],
|
|
216
267
|
"helperText": [1, "helper-text"],
|
|
217
268
|
"errorText": [1, "error-text"],
|
|
269
|
+
"isInvalid": [32],
|
|
270
|
+
"hintTextId": [32],
|
|
218
271
|
"setFocus": [64]
|
|
219
272
|
}, [[4, "keydown", "onKeydown"]], {
|
|
220
273
|
"value": ["valueChanged"]
|