voyager-ionic-core 8.7.6 → 8.7.9
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 +4 -7
- package/components/header.js +42 -4
- package/components/index2.js +74 -3
- package/components/ion-accordion.js +93 -14
- package/components/ion-input.js +6 -14
- package/components/ion-select.js +58 -10
- package/components/ion-textarea.js +5 -13
- package/components/ion-toggle.js +4 -7
- package/components/{notch-controller.js → validity.js} +14 -1
- 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 +4 -7
- package/dist/cjs/ion-input.cjs.entry.js +7 -15
- 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-select_3.cjs.entry.js +56 -10
- package/dist/cjs/ion-textarea.cjs.entry.js +6 -14
- package/dist/cjs/ion-toggle.cjs.entry.js +4 -7
- 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/{notch-controller-Bzqhjm4f.js → validity-C8QoAYT2.js} +14 -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 +4 -7
- 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/select/select.js +59 -11
- package/dist/collection/components/textarea/textarea.js +5 -13
- package/dist/collection/components/toggle/toggle.js +4 -7
- 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/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 +4 -7
- package/dist/esm/ion-input.entry.js +6 -14
- 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-select_3.entry.js +55 -9
- package/dist/esm/ion-textarea.entry.js +5 -13
- package/dist/esm/ion-toggle.entry.js +4 -7
- 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/{notch-controller-BwelN_JM.js → validity-B8oWougr.js} +14 -1
- package/dist/ionic/index.esm.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-43ed1ef5.entry.js +4 -0
- package/dist/ionic/p-4cc26913.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-8bdfc8f6.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-DUt5fQmA.js +4 -0
- package/dist/ionic/{p-9R1XyICs.js → p-DZRJwG4S.js} +1 -1
- package/dist/ionic/{p-DCv9sLH2.js → p-DieJyvMP.js} +1 -1
- package/dist/ionic/p-d0a2a1ab.entry.js +4 -0
- package/dist/ionic/p-dc2e126d.entry.js +4 -0
- package/dist/ionic/{p-de7b5fa3.entry.js → p-e16b69e1.entry.js} +1 -1
- package/dist/ionic/p-f65f9308.entry.js +4 -0
- package/dist/ionic/p-fc278823.entry.js +4 -0
- 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 +0 -1
- 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/select/select.d.ts +6 -0
- package/dist/types/components/textarea/textarea.d.ts +0 -4
- package/dist/types/components/toggle/toggle.d.ts +0 -1
- 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 +262 -73
- package/hydrate/index.mjs +262 -73
- package/package.json +3 -3
- package/dist/ionic/p-1c8a476d.entry.js +0 -4
- package/dist/ionic/p-3355a2ff.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-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
package/components/ion-select.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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';
|
|
5
|
-
import { c as createNotchController } from './
|
|
4
|
+
import { proxyCustomElement, HTMLElement, createEvent, Build, h, Host, forceUpdate } from '@stencil/core/internal/client';
|
|
5
|
+
import { c as createNotchController, a as checkInvalidState } from './validity.js';
|
|
6
6
|
import { i as isOptionSelected, d as defineCustomElement$8, c as compareOptions } from './radio.js';
|
|
7
7
|
import { d as inheritAttributes, e as renderHiddenInput, h as focusVisibleElement } from './helpers.js';
|
|
8
8
|
import { p as printIonWarning } from './index4.js';
|
|
@@ -65,6 +65,10 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
65
65
|
* is applied in both cases.
|
|
66
66
|
*/
|
|
67
67
|
this.hasFocus = false;
|
|
68
|
+
/**
|
|
69
|
+
* Track validation state for proper aria-live announcements.
|
|
70
|
+
*/
|
|
71
|
+
this.isInvalid = false;
|
|
68
72
|
/**
|
|
69
73
|
* The text to display on the cancel button.
|
|
70
74
|
*/
|
|
@@ -194,9 +198,46 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
194
198
|
*/
|
|
195
199
|
forceUpdate(this);
|
|
196
200
|
});
|
|
201
|
+
// Watch for class changes to update validation state.
|
|
202
|
+
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
203
|
+
this.validationObserver = new MutationObserver(() => {
|
|
204
|
+
const newIsInvalid = checkInvalidState(this.el);
|
|
205
|
+
if (this.isInvalid !== newIsInvalid) {
|
|
206
|
+
this.isInvalid = newIsInvalid;
|
|
207
|
+
/**
|
|
208
|
+
* Screen readers tend to announce changes
|
|
209
|
+
* to `aria-describedby` when the attribute
|
|
210
|
+
* is changed during a blur event for a
|
|
211
|
+
* native form control.
|
|
212
|
+
* However, the announcement can be spotty
|
|
213
|
+
* when using a non-native form control
|
|
214
|
+
* and `forceUpdate()`.
|
|
215
|
+
* This is due to `forceUpdate()` internally
|
|
216
|
+
* rescheduling the DOM update to a lower
|
|
217
|
+
* priority queue regardless if it's called
|
|
218
|
+
* inside a Promise or not, thus causing
|
|
219
|
+
* the screen reader to potentially miss the
|
|
220
|
+
* change.
|
|
221
|
+
* By using a State variable inside a Promise,
|
|
222
|
+
* it guarantees a re-render immediately at
|
|
223
|
+
* a higher priority.
|
|
224
|
+
*/
|
|
225
|
+
Promise.resolve().then(() => {
|
|
226
|
+
this.hintTextID = this.getHintTextID();
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
this.validationObserver.observe(el, {
|
|
231
|
+
attributes: true,
|
|
232
|
+
attributeFilter: ['class'],
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
// Always set initial state
|
|
236
|
+
this.isInvalid = checkInvalidState(this.el);
|
|
197
237
|
}
|
|
198
238
|
componentWillLoad() {
|
|
199
239
|
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
|
|
240
|
+
this.hintTextID = this.getHintTextID();
|
|
200
241
|
}
|
|
201
242
|
componentDidLoad() {
|
|
202
243
|
/**
|
|
@@ -220,6 +261,11 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
220
261
|
this.notchController.destroy();
|
|
221
262
|
this.notchController = undefined;
|
|
222
263
|
}
|
|
264
|
+
// Clean up validation observer to prevent memory leaks.
|
|
265
|
+
if (this.validationObserver) {
|
|
266
|
+
this.validationObserver.disconnect();
|
|
267
|
+
this.validationObserver = undefined;
|
|
268
|
+
}
|
|
223
269
|
}
|
|
224
270
|
/**
|
|
225
271
|
* Open the select overlay. The overlay is either an alert, action sheet, or popover,
|
|
@@ -690,11 +736,11 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
690
736
|
}
|
|
691
737
|
renderListbox() {
|
|
692
738
|
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.
|
|
739
|
+
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
740
|
}
|
|
695
741
|
getHintTextID() {
|
|
696
|
-
const {
|
|
697
|
-
if (
|
|
742
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
743
|
+
if (isInvalid && errorText) {
|
|
698
744
|
return errorTextId;
|
|
699
745
|
}
|
|
700
746
|
if (helperText) {
|
|
@@ -706,10 +752,10 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
706
752
|
* Renders the helper text or error text values
|
|
707
753
|
*/
|
|
708
754
|
renderHintText() {
|
|
709
|
-
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
755
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
710
756
|
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),
|
|
757
|
+
h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
|
|
758
|
+
h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text", role: "alert" }, isInvalid ? errorText : null),
|
|
713
759
|
];
|
|
714
760
|
}
|
|
715
761
|
/**
|
|
@@ -757,7 +803,7 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
757
803
|
* TODO(FW-5592): Remove hasStartEndSlots condition
|
|
758
804
|
*/
|
|
759
805
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || isExpanded || hasStartEndSlots));
|
|
760
|
-
return (h(Host, { key: '
|
|
806
|
+
return (h(Host, { key: '35b5e18e6f79a802ff2d46d1242e80ff755cc0b9', onClick: this.onClick, class: createColorClasses(this.color, {
|
|
761
807
|
[mode]: true,
|
|
762
808
|
'in-item': inItem,
|
|
763
809
|
'in-item-color': hostContext('ion-item.ion-color', el),
|
|
@@ -775,7 +821,7 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
775
821
|
[`select-justify-${justify}`]: justifyEnabled,
|
|
776
822
|
[`select-shape-${shape}`]: shape !== undefined,
|
|
777
823
|
[`select-label-placement-${labelPlacement}`]: true,
|
|
778
|
-
}) }, h("label", { key: '
|
|
824
|
+
}) }, 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
825
|
}
|
|
780
826
|
get el() { return this; }
|
|
781
827
|
static get watchers() { return {
|
|
@@ -813,6 +859,8 @@ const Select = /*@__PURE__*/ proxyCustomElement(class Select extends HTMLElement
|
|
|
813
859
|
"required": [4],
|
|
814
860
|
"isExpanded": [32],
|
|
815
861
|
"hasFocus": [32],
|
|
862
|
+
"isInvalid": [32],
|
|
863
|
+
"hintTextID": [32],
|
|
816
864
|
"open": [64]
|
|
817
865
|
}, undefined, {
|
|
818
866
|
"disabled": ["styleChanged"],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
4
|
import { proxyCustomElement, HTMLElement, createEvent, forceUpdate, Build, writeTask, h, Host } from '@stencil/core/internal/client';
|
|
5
|
-
import { c as createNotchController } from './
|
|
5
|
+
import { c as createNotchController, a as checkInvalidState } from './validity.js';
|
|
6
6
|
import { l as debounceEvent, i as inheritAriaAttributes, d as inheritAttributes, c as componentOnReady } from './helpers.js';
|
|
7
7
|
import { c as createSlotMutationController, g as getCounterText } from './input.utils.js';
|
|
8
8
|
import { h as hostContext, c as createColorClasses } from './theme.js';
|
|
@@ -192,14 +192,6 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
192
192
|
this.el.click();
|
|
193
193
|
}
|
|
194
194
|
}
|
|
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
195
|
connectedCallback() {
|
|
204
196
|
const { el } = this;
|
|
205
197
|
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate(this));
|
|
@@ -207,7 +199,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
207
199
|
// Watch for class changes to update validation state
|
|
208
200
|
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
209
201
|
this.validationObserver = new MutationObserver(() => {
|
|
210
|
-
const newIsInvalid = this.
|
|
202
|
+
const newIsInvalid = checkInvalidState(this.el);
|
|
211
203
|
if (this.isInvalid !== newIsInvalid) {
|
|
212
204
|
this.isInvalid = newIsInvalid;
|
|
213
205
|
// Force a re-render to update aria-describedby immediately
|
|
@@ -220,7 +212,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
220
212
|
});
|
|
221
213
|
}
|
|
222
214
|
// Always set initial state
|
|
223
|
-
this.isInvalid = this.
|
|
215
|
+
this.isInvalid = checkInvalidState(this.el);
|
|
224
216
|
this.debounceChanged();
|
|
225
217
|
if (Build.isBrowser) {
|
|
226
218
|
document.dispatchEvent(new CustomEvent('ionInputDidLoad', {
|
|
@@ -484,7 +476,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
484
476
|
* TODO(FW-5592): Remove hasStartEndSlots condition
|
|
485
477
|
*/
|
|
486
478
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
|
|
487
|
-
return (h(Host, { key: '
|
|
479
|
+
return (h(Host, { key: 'a70a62d7aae3831a50acd74f60b930925ada1326', class: createColorClasses(this.color, {
|
|
488
480
|
[mode]: true,
|
|
489
481
|
'has-value': hasValue,
|
|
490
482
|
'has-focus': hasFocus,
|
|
@@ -493,7 +485,7 @@ const Textarea = /*@__PURE__*/ proxyCustomElement(class Textarea extends HTMLEle
|
|
|
493
485
|
[`textarea-shape-${shape}`]: shape !== undefined,
|
|
494
486
|
[`textarea-label-placement-${labelPlacement}`]: true,
|
|
495
487
|
'textarea-disabled': disabled,
|
|
496
|
-
}) }, h("label", { key: '
|
|
488
|
+
}) }, 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
489
|
}
|
|
498
490
|
get el() { return this; }
|
|
499
491
|
static get watchers() { return {
|
package/components/ion-toggle.js
CHANGED
|
@@ -140,7 +140,6 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
140
140
|
const { checked, value } = this;
|
|
141
141
|
const isNowChecked = !checked;
|
|
142
142
|
this.checked = isNowChecked;
|
|
143
|
-
this.setFocus();
|
|
144
143
|
this.ionChange.emit({
|
|
145
144
|
checked: isNowChecked,
|
|
146
145
|
value,
|
|
@@ -191,9 +190,7 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
191
190
|
return this.value || '';
|
|
192
191
|
}
|
|
193
192
|
setFocus() {
|
|
194
|
-
|
|
195
|
-
this.focusEl.focus();
|
|
196
|
-
}
|
|
193
|
+
this.el.focus();
|
|
197
194
|
}
|
|
198
195
|
renderOnOffSwitchLabels(mode, checked) {
|
|
199
196
|
const icon = this.getSwitchLabelIcon(mode, checked);
|
|
@@ -243,7 +240,7 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
243
240
|
const value = this.getValue();
|
|
244
241
|
const rtl = isRTL(el) ? 'rtl' : 'ltr';
|
|
245
242
|
renderHiddenInput(true, el, name, checked ? value : '', disabled);
|
|
246
|
-
return (h(Host, { key: '
|
|
243
|
+
return (h(Host, { key: '17bbbc8d229868e5c872b2bc5a3faf579780c5e0', role: "switch", "aria-checked": `${checked}`, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === errorTextId, onClick: this.onClick, "aria-labelledby": hasLabel ? inputLabelId : null, "aria-label": inheritedAttributes['aria-label'] || null, "aria-disabled": disabled ? 'true' : null, tabindex: disabled ? undefined : 0, onKeyDown: this.onKeyDown, onFocus: this.onFocus, onBlur: this.onBlur, class: createColorClasses(color, {
|
|
247
244
|
[mode]: true,
|
|
248
245
|
'in-item': hostContext('ion-item', el),
|
|
249
246
|
'toggle-activated': activated,
|
|
@@ -253,10 +250,10 @@ const Toggle = /*@__PURE__*/ proxyCustomElement(class Toggle extends HTMLElement
|
|
|
253
250
|
[`toggle-alignment-${alignment}`]: alignment !== undefined,
|
|
254
251
|
[`toggle-label-placement-${labelPlacement}`]: true,
|
|
255
252
|
[`toggle-${rtl}`]: true,
|
|
256
|
-
}) }, h("label", { key: '
|
|
253
|
+
}) }, h("label", { key: '673625b62a2c909e95dccb642c91312967a6cd1c', class: "toggle-wrapper", htmlFor: inputId }, h("input", Object.assign({ key: '7dc3f357b4708116663970047765da9f8f845bf0', type: "checkbox", role: "switch", "aria-checked": `${checked}`, checked: checked, disabled: disabled, id: inputId, required: required }, inheritedAttributes)), h("div", { key: '8f1c6a182031e8cbc6727e5f4ac0e00ad4247447', class: {
|
|
257
254
|
'label-text-wrapper': true,
|
|
258
255
|
'label-text-wrapper-hidden': !hasLabel,
|
|
259
|
-
}, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: '
|
|
256
|
+
}, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, h("slot", { key: '8322b9d54dc7edeb4e16fefcde9f7ebca8d5c3e1' }), this.renderHintText()), h("div", { key: 'fe6984143db817a7b3020a3f57cf5418fc3dcc0e', class: "native-wrapper" }, this.renderToggleControl()))));
|
|
260
257
|
}
|
|
261
258
|
get el() { return this; }
|
|
262
259
|
static get watchers() { return {
|
|
@@ -150,4 +150,17 @@ const createNotchController = (el, getNotchSpacerEl, getLabelSlot) => {
|
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Checks if the form element is in an invalid state based on
|
|
155
|
+
* Ionic validation classes.
|
|
156
|
+
*
|
|
157
|
+
* @param el The form element to check.
|
|
158
|
+
* @returns `true` if the element is invalid, `false` otherwise.
|
|
159
|
+
*/
|
|
160
|
+
const checkInvalidState = (el) => {
|
|
161
|
+
const hasIonTouched = el.classList.contains('ion-touched');
|
|
162
|
+
const hasIonInvalid = el.classList.contains('ion-invalid');
|
|
163
|
+
return hasIonTouched && hasIonInvalid;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export { checkInvalidState as a, createNotchController as c };
|
|
@@ -120,15 +120,26 @@ const createFocusController = () => {
|
|
|
120
120
|
};
|
|
121
121
|
const LAST_FOCUS = 'ion-last-focus';
|
|
122
122
|
|
|
123
|
-
const iosTransitionAnimation = () => Promise.resolve().then(function () { return require('./ios.transition-
|
|
124
|
-
const mdTransitionAnimation = () => Promise.resolve().then(function () { return require('./md.transition-
|
|
123
|
+
const iosTransitionAnimation = () => Promise.resolve().then(function () { return require('./ios.transition-BOt_uW73.js'); });
|
|
124
|
+
const mdTransitionAnimation = () => Promise.resolve().then(function () { return require('./md.transition-Dt968VXB.js'); });
|
|
125
125
|
const focusController = createFocusController();
|
|
126
126
|
// TODO(FW-2832): types
|
|
127
|
+
/**
|
|
128
|
+
* Executes the main page transition.
|
|
129
|
+
* It also manages the lifecycle of header visibility (if any)
|
|
130
|
+
* to prevent visual flickering in iOS. The flickering only
|
|
131
|
+
* occurs for a condensed header that is placed above the content.
|
|
132
|
+
*
|
|
133
|
+
* @param opts Options for the transition.
|
|
134
|
+
* @returns A promise that resolves when the transition is complete.
|
|
135
|
+
*/
|
|
127
136
|
const transition = (opts) => {
|
|
128
137
|
return new Promise((resolve, reject) => {
|
|
129
138
|
index.writeTask(() => {
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
const transitioningInactiveHeader = getIosIonHeader(opts);
|
|
140
|
+
beforeTransition(opts, transitioningInactiveHeader);
|
|
141
|
+
runTransition(opts)
|
|
142
|
+
.then((result) => {
|
|
132
143
|
if (result.animation) {
|
|
133
144
|
result.animation.destroy();
|
|
134
145
|
}
|
|
@@ -137,15 +148,21 @@ const transition = (opts) => {
|
|
|
137
148
|
}, (error) => {
|
|
138
149
|
afterTransition(opts);
|
|
139
150
|
reject(error);
|
|
151
|
+
})
|
|
152
|
+
.finally(() => {
|
|
153
|
+
// Ensure that the header is restored to its original state.
|
|
154
|
+
setHeaderTransitionClass(transitioningInactiveHeader, false);
|
|
140
155
|
});
|
|
141
156
|
});
|
|
142
157
|
});
|
|
143
158
|
};
|
|
144
|
-
const beforeTransition = (opts) => {
|
|
159
|
+
const beforeTransition = (opts, transitioningInactiveHeader) => {
|
|
145
160
|
const enteringEl = opts.enteringEl;
|
|
146
161
|
const leavingEl = opts.leavingEl;
|
|
147
162
|
focusController.saveViewFocus(leavingEl);
|
|
148
163
|
setZIndex(enteringEl, leavingEl, opts.direction);
|
|
164
|
+
// Prevent flickering of the header by adding a class.
|
|
165
|
+
setHeaderTransitionClass(transitioningInactiveHeader, true);
|
|
149
166
|
if (opts.showGoBack) {
|
|
150
167
|
enteringEl.classList.add('can-go-back');
|
|
151
168
|
}
|
|
@@ -334,6 +351,39 @@ const setZIndex = (enteringEl, leavingEl, direction) => {
|
|
|
334
351
|
leavingEl.style.zIndex = '100';
|
|
335
352
|
}
|
|
336
353
|
};
|
|
354
|
+
/**
|
|
355
|
+
* Add a class to ensure that the header (if any)
|
|
356
|
+
* does not flicker during the transition. By adding the
|
|
357
|
+
* transitioning class, we ensure that the header has
|
|
358
|
+
* the necessary styles to prevent the following flickers:
|
|
359
|
+
* 1. When entering a page with a condensed header, the
|
|
360
|
+
* header should never be visible. However,
|
|
361
|
+
* it briefly renders the background color while
|
|
362
|
+
* the transition is occurring.
|
|
363
|
+
* 2. When leaving a page with a condensed header, the
|
|
364
|
+
* header has an opacity of 0 and the pages
|
|
365
|
+
* have a z-index which causes the entering page to
|
|
366
|
+
* briefly show it's content underneath the leaving page.
|
|
367
|
+
* 3. When entering a page or leaving a page with a fade
|
|
368
|
+
* header, the header should not have a background color.
|
|
369
|
+
* However, it briefly shows the background color while
|
|
370
|
+
* the transition is occurring.
|
|
371
|
+
*
|
|
372
|
+
* @param header The header element to modify.
|
|
373
|
+
* @param isTransitioning Whether the transition is occurring.
|
|
374
|
+
*/
|
|
375
|
+
const setHeaderTransitionClass = (header, isTransitioning) => {
|
|
376
|
+
if (!header) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const transitionClass = 'header-transitioning';
|
|
380
|
+
if (isTransitioning) {
|
|
381
|
+
header.classList.add(transitionClass);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
header.classList.remove(transitionClass);
|
|
385
|
+
}
|
|
386
|
+
};
|
|
337
387
|
const getIonPageElement = (element) => {
|
|
338
388
|
if (element.classList.contains('ion-page')) {
|
|
339
389
|
return element;
|
|
@@ -345,6 +395,27 @@ const getIonPageElement = (element) => {
|
|
|
345
395
|
// idk, return the original element so at least something animates and we don't have a null pointer
|
|
346
396
|
return element;
|
|
347
397
|
};
|
|
398
|
+
/**
|
|
399
|
+
* Retrieves the ion-header element from a page based on the
|
|
400
|
+
* direction of the transition.
|
|
401
|
+
*
|
|
402
|
+
* @param opts Options for the transition.
|
|
403
|
+
* @returns The ion-header element or null if not found or not in 'ios' mode.
|
|
404
|
+
*/
|
|
405
|
+
const getIosIonHeader = (opts) => {
|
|
406
|
+
const enteringEl = opts.enteringEl;
|
|
407
|
+
const leavingEl = opts.leavingEl;
|
|
408
|
+
const direction = opts.direction;
|
|
409
|
+
const mode = opts.mode;
|
|
410
|
+
if (mode !== 'ios') {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
const element = direction === 'back' ? leavingEl : enteringEl;
|
|
414
|
+
if (!element) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
return element.querySelector('ion-header');
|
|
418
|
+
};
|
|
348
419
|
|
|
349
420
|
exports.LIFECYCLE_DID_ENTER = LIFECYCLE_DID_ENTER;
|
|
350
421
|
exports.LIFECYCLE_DID_LEAVE = LIFECYCLE_DID_LEAVE;
|
package/dist/cjs/index.cjs.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
var animation = require('./animation-Bt3H9L1C.js');
|
|
7
|
-
var index = require('./index-
|
|
8
|
-
var ios_transition = require('./ios.transition-
|
|
9
|
-
var md_transition = require('./md.transition-
|
|
7
|
+
var index = require('./index-094mMFB-.js');
|
|
8
|
+
var ios_transition = require('./ios.transition-BOt_uW73.js');
|
|
9
|
+
var md_transition = require('./md.transition-Dt968VXB.js');
|
|
10
10
|
var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
|
|
11
11
|
var index$1 = require('./index-CAvQ7Tka.js');
|
|
12
12
|
var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
|
|
@@ -15,10 +15,57 @@ const accordionMdCss = ":host{display:block;position:relative;width:100%;backgro
|
|
|
15
15
|
const Accordion = class {
|
|
16
16
|
constructor(hostRef) {
|
|
17
17
|
index.registerInstance(this, hostRef);
|
|
18
|
-
this.
|
|
18
|
+
this.accordionGroupUpdateHandler = () => {
|
|
19
|
+
/**
|
|
20
|
+
* Determine if this update will cause an actual state change.
|
|
21
|
+
* We only want to mark as "interacted" if the state is changing.
|
|
22
|
+
*/
|
|
23
|
+
const accordionGroup = this.accordionGroupEl;
|
|
24
|
+
if (accordionGroup) {
|
|
25
|
+
const value = accordionGroup.value;
|
|
26
|
+
const accordionValue = this.value;
|
|
27
|
+
const shouldExpand = Array.isArray(value) ? value.includes(accordionValue) : value === accordionValue;
|
|
28
|
+
const isExpanded = this.state === 4 /* AccordionState.Expanded */ || this.state === 8 /* AccordionState.Expanding */;
|
|
29
|
+
const stateWillChange = shouldExpand !== isExpanded;
|
|
30
|
+
/**
|
|
31
|
+
* Only mark as interacted if:
|
|
32
|
+
* 1. This is not the first update we've received with a defined value
|
|
33
|
+
* 2. The state is actually changing (prevents redundant updates from enabling animations)
|
|
34
|
+
*/
|
|
35
|
+
if (this.hasReceivedFirstUpdate && stateWillChange) {
|
|
36
|
+
this.hasInteracted = true;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Only count this as the first update if the group value is defined.
|
|
40
|
+
* This prevents the initial undefined value from the group's componentDidLoad
|
|
41
|
+
* from being treated as the first real update.
|
|
42
|
+
*/
|
|
43
|
+
if (value !== undefined) {
|
|
44
|
+
this.hasReceivedFirstUpdate = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
this.updateState();
|
|
48
|
+
};
|
|
19
49
|
this.state = 1 /* AccordionState.Collapsed */;
|
|
20
50
|
this.isNext = false;
|
|
21
51
|
this.isPrevious = false;
|
|
52
|
+
/**
|
|
53
|
+
* Tracks whether a user-initiated interaction has occurred.
|
|
54
|
+
* Animations are disabled until the first interaction happens.
|
|
55
|
+
* This prevents the accordion from animating when it's programmatically
|
|
56
|
+
* set to an expanded or collapsed state on initial load.
|
|
57
|
+
*/
|
|
58
|
+
this.hasInteracted = false;
|
|
59
|
+
/**
|
|
60
|
+
* Tracks if this accordion has ever been expanded.
|
|
61
|
+
* Used to prevent the first expansion from animating.
|
|
62
|
+
*/
|
|
63
|
+
this.hasEverBeenExpanded = false;
|
|
64
|
+
/**
|
|
65
|
+
* Tracks if this accordion has received its first update from the group.
|
|
66
|
+
* Used to distinguish initial programmatic sets from user interactions.
|
|
67
|
+
*/
|
|
68
|
+
this.hasReceivedFirstUpdate = false;
|
|
22
69
|
/**
|
|
23
70
|
* The value of the accordion. Defaults to an autogenerated
|
|
24
71
|
* value.
|
|
@@ -123,10 +170,15 @@ const Accordion = class {
|
|
|
123
170
|
iconEl.setAttribute('aria-hidden', 'true');
|
|
124
171
|
ionItem.appendChild(iconEl);
|
|
125
172
|
};
|
|
126
|
-
this.expandAccordion = (
|
|
173
|
+
this.expandAccordion = () => {
|
|
127
174
|
const { contentEl, contentElWrapper } = this;
|
|
128
|
-
|
|
175
|
+
/**
|
|
176
|
+
* If the content elements aren't available yet, just set the state.
|
|
177
|
+
* This happens on initial render before the DOM is ready.
|
|
178
|
+
*/
|
|
179
|
+
if (contentEl === undefined || contentElWrapper === undefined) {
|
|
129
180
|
this.state = 4 /* AccordionState.Expanded */;
|
|
181
|
+
this.hasEverBeenExpanded = true;
|
|
130
182
|
return;
|
|
131
183
|
}
|
|
132
184
|
if (this.state === 4 /* AccordionState.Expanded */) {
|
|
@@ -135,6 +187,11 @@ const Accordion = class {
|
|
|
135
187
|
if (this.currentRaf !== undefined) {
|
|
136
188
|
cancelAnimationFrame(this.currentRaf);
|
|
137
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Mark that this accordion has been expanded at least once.
|
|
192
|
+
* This allows subsequent expansions to animate.
|
|
193
|
+
*/
|
|
194
|
+
this.hasEverBeenExpanded = true;
|
|
138
195
|
if (this.shouldAnimate()) {
|
|
139
196
|
helpers.raf(() => {
|
|
140
197
|
this.state = 8 /* AccordionState.Expanding */;
|
|
@@ -152,9 +209,13 @@ const Accordion = class {
|
|
|
152
209
|
this.state = 4 /* AccordionState.Expanded */;
|
|
153
210
|
}
|
|
154
211
|
};
|
|
155
|
-
this.collapseAccordion = (
|
|
212
|
+
this.collapseAccordion = () => {
|
|
156
213
|
const { contentEl } = this;
|
|
157
|
-
|
|
214
|
+
/**
|
|
215
|
+
* If the content element isn't available yet, just set the state.
|
|
216
|
+
* This happens on initial render before the DOM is ready.
|
|
217
|
+
*/
|
|
218
|
+
if (contentEl === undefined) {
|
|
158
219
|
this.state = 1 /* AccordionState.Collapsed */;
|
|
159
220
|
return;
|
|
160
221
|
}
|
|
@@ -189,6 +250,18 @@ const Accordion = class {
|
|
|
189
250
|
* of what is set in the config.
|
|
190
251
|
*/
|
|
191
252
|
this.shouldAnimate = () => {
|
|
253
|
+
/**
|
|
254
|
+
* Don't animate until after the first user interaction.
|
|
255
|
+
* This prevents animations on initial load when accordions
|
|
256
|
+
* start in an expanded or collapsed state programmatically.
|
|
257
|
+
*
|
|
258
|
+
* Additionally, don't animate the very first expansion even if
|
|
259
|
+
* hasInteracted is true. This handles edge cases like React StrictMode
|
|
260
|
+
* where effects run twice and might incorrectly mark as interacted.
|
|
261
|
+
*/
|
|
262
|
+
if (!this.hasInteracted || !this.hasEverBeenExpanded) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
192
265
|
if (typeof window === 'undefined') {
|
|
193
266
|
return false;
|
|
194
267
|
}
|
|
@@ -205,7 +278,7 @@ const Accordion = class {
|
|
|
205
278
|
}
|
|
206
279
|
return true;
|
|
207
280
|
};
|
|
208
|
-
this.updateState = async (
|
|
281
|
+
this.updateState = async () => {
|
|
209
282
|
const accordionGroup = this.accordionGroupEl;
|
|
210
283
|
const accordionValue = this.value;
|
|
211
284
|
if (!accordionGroup) {
|
|
@@ -214,11 +287,11 @@ const Accordion = class {
|
|
|
214
287
|
const value = accordionGroup.value;
|
|
215
288
|
const shouldExpand = Array.isArray(value) ? value.includes(accordionValue) : value === accordionValue;
|
|
216
289
|
if (shouldExpand) {
|
|
217
|
-
this.expandAccordion(
|
|
290
|
+
this.expandAccordion();
|
|
218
291
|
this.isNext = this.isPrevious = false;
|
|
219
292
|
}
|
|
220
293
|
else {
|
|
221
|
-
this.collapseAccordion(
|
|
294
|
+
this.collapseAccordion();
|
|
222
295
|
/**
|
|
223
296
|
* When using popout or inset,
|
|
224
297
|
* the collapsed accordion items
|
|
@@ -266,14 +339,14 @@ const Accordion = class {
|
|
|
266
339
|
var _a;
|
|
267
340
|
const accordionGroupEl = (this.accordionGroupEl = (_a = this.el) === null || _a === void 0 ? void 0 : _a.closest('ion-accordion-group'));
|
|
268
341
|
if (accordionGroupEl) {
|
|
269
|
-
this.updateState(
|
|
270
|
-
helpers.addEventListener(accordionGroupEl, 'ionValueChange', this.
|
|
342
|
+
this.updateState();
|
|
343
|
+
helpers.addEventListener(accordionGroupEl, 'ionValueChange', this.accordionGroupUpdateHandler);
|
|
271
344
|
}
|
|
272
345
|
}
|
|
273
346
|
disconnectedCallback() {
|
|
274
347
|
const accordionGroupEl = this.accordionGroupEl;
|
|
275
348
|
if (accordionGroupEl) {
|
|
276
|
-
helpers.removeEventListener(accordionGroupEl, 'ionValueChange', this.
|
|
349
|
+
helpers.removeEventListener(accordionGroupEl, 'ionValueChange', this.accordionGroupUpdateHandler);
|
|
277
350
|
}
|
|
278
351
|
}
|
|
279
352
|
componentDidLoad() {
|
|
@@ -297,6 +370,11 @@ const Accordion = class {
|
|
|
297
370
|
const { accordionGroupEl, disabled, readonly, value, state } = this;
|
|
298
371
|
if (disabled || readonly)
|
|
299
372
|
return;
|
|
373
|
+
/**
|
|
374
|
+
* Mark that the user has interacted with the accordion.
|
|
375
|
+
* This enables animations for all future state changes.
|
|
376
|
+
*/
|
|
377
|
+
this.hasInteracted = true;
|
|
300
378
|
if (accordionGroupEl) {
|
|
301
379
|
/**
|
|
302
380
|
* Because the accordion group may or may
|
|
@@ -317,7 +395,7 @@ const Accordion = class {
|
|
|
317
395
|
const headerPart = expanded ? 'header expanded' : 'header';
|
|
318
396
|
const contentPart = expanded ? 'content expanded' : 'content';
|
|
319
397
|
this.setAria(expanded);
|
|
320
|
-
return (index.h(index.Host, { key: '
|
|
398
|
+
return (index.h(index.Host, { key: '9c90bce01eff7e5774a19f69c872f3761d66cf3c', class: {
|
|
321
399
|
[mode]: true,
|
|
322
400
|
'accordion-expanding': this.state === 8 /* AccordionState.Expanding */,
|
|
323
401
|
'accordion-expanded': this.state === 4 /* AccordionState.Expanded */,
|
|
@@ -328,7 +406,7 @@ const Accordion = class {
|
|
|
328
406
|
'accordion-disabled': disabled,
|
|
329
407
|
'accordion-readonly': readonly,
|
|
330
408
|
'accordion-animated': this.shouldAnimate(),
|
|
331
|
-
} }, index.h("div", { key: '
|
|
409
|
+
} }, index.h("div", { key: 'cab40d5bcf3c93fd78e70b6d3906a541e725837d', onClick: () => this.toggleExpanded(), id: "header", part: headerPart, "aria-controls": "content", ref: (headerEl) => (this.headerEl = headerEl) }, index.h("slot", { key: '672bc7fb3f9e18076b41e20fc9eaeab7cafcf3a2', name: "header" })), index.h("div", { key: 'fd777ca5b4ab04aa4f44c339d58c8cd987c52bcb', id: "content", part: contentPart, role: "region", "aria-labelledby": "header", ref: (contentEl) => (this.contentEl = contentEl) }, index.h("div", { key: '0aad70a71e2cd2c16b2e98fa0bdd40421d95fe16', id: "content-wrapper", ref: (contentElWrapper) => (this.contentElWrapper = contentElWrapper) }, index.h("slot", { key: 'd630e10ac7c56b4dbf943b523f26759b83aead55', name: "content" })))));
|
|
332
410
|
}
|
|
333
411
|
static get delegatesFocus() { return true; }
|
|
334
412
|
get el() { return index.getElement(this); }
|