voyager-ionic-core 8.7.9 → 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/checkbox.js +63 -9
- package/components/ion-datetime.js +35 -2
- package/components/ion-input.js +2 -1
- package/components/ion-select.js +7 -6
- package/components/ion-textarea.js +2 -1
- package/components/ion-toggle.js +62 -12
- package/components/notch-controller.js +153 -0
- package/components/radio-group.js +60 -7
- package/components/validity.js +1 -150
- package/dist/cjs/ion-checkbox.cjs.entry.js +60 -8
- package/dist/cjs/ion-datetime_3.cjs.entry.js +35 -2
- package/dist/cjs/ion-input.cjs.entry.js +3 -2
- package/dist/cjs/ion-radio_2.cjs.entry.js +57 -6
- package/dist/cjs/ion-select_3.cjs.entry.js +7 -6
- package/dist/cjs/ion-textarea.cjs.entry.js +3 -2
- package/dist/cjs/ion-toggle.cjs.entry.js +58 -10
- package/dist/cjs/ionic.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{validity-C8QoAYT2.js → notch-controller-Bzqhjm4f.js} +0 -14
- package/dist/cjs/validity-BpS37YFM.js +19 -0
- package/dist/collection/components/checkbox/checkbox.js +67 -9
- package/dist/collection/components/datetime/datetime.js +35 -2
- package/dist/collection/components/radio-group/radio-group.js +64 -7
- package/dist/collection/components/select/select.js +5 -5
- package/dist/collection/components/toggle/toggle.js +62 -12
- package/dist/collection/utils/test/playwright/page/utils/set-content.js +7 -0
- package/dist/docs.json +1 -1
- package/dist/esm/ion-checkbox.entry.js +60 -8
- package/dist/esm/ion-datetime_3.entry.js +35 -2
- package/dist/esm/ion-input.entry.js +2 -1
- package/dist/esm/ion-radio_2.entry.js +57 -6
- package/dist/esm/ion-select_3.entry.js +6 -5
- package/dist/esm/ion-textarea.entry.js +2 -1
- package/dist/esm/ion-toggle.entry.js +58 -10
- package/dist/esm/ionic.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{validity-B8oWougr.js → notch-controller-BwelN_JM.js} +1 -14
- package/dist/esm/validity-DJztqcrH.js +17 -0
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-40c261a3.entry.js +4 -0
- package/dist/ionic/p-4e41ea20.entry.js +4 -0
- package/dist/ionic/p-7380261c.entry.js +4 -0
- package/dist/ionic/{p-DieJyvMP.js → p-DCv9sLH2.js} +1 -1
- package/dist/ionic/p-DJztqcrH.js +4 -0
- package/dist/ionic/p-c19f63d0.entry.js +4 -0
- package/dist/ionic/p-cb93126d.entry.js +4 -0
- package/dist/ionic/p-d1f54e28.entry.js +4 -0
- package/dist/ionic/p-d3014190.entry.js +4 -0
- package/dist/types/components/checkbox/checkbox.d.ts +9 -1
- package/dist/types/components/datetime/datetime.d.ts +10 -0
- package/dist/types/components/radio-group/radio-group.d.ts +9 -1
- package/dist/types/components/select/select.d.ts +2 -2
- package/dist/types/components/toggle/toggle.d.ts +7 -1
- package/dist/types/utils/forms/validity.d.ts +1 -1
- package/hydrate/index.js +312 -227
- package/hydrate/index.mjs +312 -227
- package/package.json +2 -2
- package/dist/ionic/p-4cc26913.entry.js +0 -4
- package/dist/ionic/p-4efea47a.entry.js +0 -4
- package/dist/ionic/p-7bcfc421.entry.js +0 -4
- package/dist/ionic/p-8bdfc8f6.entry.js +0 -4
- package/dist/ionic/p-dc2e126d.entry.js +0 -4
- package/dist/ionic/p-f65f9308.entry.js +0 -4
- package/dist/ionic/p-fc278823.entry.js +0 -4
|
@@ -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"]
|
package/components/validity.js
CHANGED
|
@@ -1,155 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
|
-
import { w as win } from './index9.js';
|
|
5
|
-
import { r as raf } from './helpers.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A utility to calculate the size of an outline notch
|
|
9
|
-
* width relative to the content passed. This is used in
|
|
10
|
-
* components such as `ion-select` with `fill="outline"`
|
|
11
|
-
* where we need to pass slotted HTML content. This is not
|
|
12
|
-
* needed when rendering plaintext content because we can
|
|
13
|
-
* render the plaintext again hidden with `opacity: 0` inside
|
|
14
|
-
* of the notch. As a result we can rely on the intrinsic size
|
|
15
|
-
* of the element to correctly compute the notch width. We
|
|
16
|
-
* cannot do this with slotted content because we cannot project
|
|
17
|
-
* it into 2 places at once.
|
|
18
|
-
*
|
|
19
|
-
* @internal
|
|
20
|
-
* @param el: The host element
|
|
21
|
-
* @param getNotchSpacerEl: A function that returns a reference to the notch spacer element inside of the component template.
|
|
22
|
-
* @param getLabelSlot: A function that returns a reference to the slotted content.
|
|
23
|
-
*/
|
|
24
|
-
const createNotchController = (el, getNotchSpacerEl, getLabelSlot) => {
|
|
25
|
-
let notchVisibilityIO;
|
|
26
|
-
const needsExplicitNotchWidth = () => {
|
|
27
|
-
const notchSpacerEl = getNotchSpacerEl();
|
|
28
|
-
if (
|
|
29
|
-
/**
|
|
30
|
-
* If the notch is not being used
|
|
31
|
-
* then we do not need to set the notch width.
|
|
32
|
-
*/
|
|
33
|
-
notchSpacerEl === undefined ||
|
|
34
|
-
/**
|
|
35
|
-
* If either the label property is being
|
|
36
|
-
* used or the label slot is not defined,
|
|
37
|
-
* then we do not need to estimate the notch width.
|
|
38
|
-
*/
|
|
39
|
-
el.label !== undefined ||
|
|
40
|
-
getLabelSlot() === null) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
return true;
|
|
44
|
-
};
|
|
45
|
-
const calculateNotchWidth = () => {
|
|
46
|
-
if (needsExplicitNotchWidth()) {
|
|
47
|
-
/**
|
|
48
|
-
* Run this the frame after
|
|
49
|
-
* the browser has re-painted the host element.
|
|
50
|
-
* Otherwise, the label element may have a width
|
|
51
|
-
* of 0 and the IntersectionObserver will be used.
|
|
52
|
-
*/
|
|
53
|
-
raf(() => {
|
|
54
|
-
setNotchWidth();
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* When using a label prop we can render
|
|
60
|
-
* the label value inside of the notch and
|
|
61
|
-
* let the browser calculate the size of the notch.
|
|
62
|
-
* However, we cannot render the label slot in multiple
|
|
63
|
-
* places so we need to manually calculate the notch dimension
|
|
64
|
-
* based on the size of the slotted content.
|
|
65
|
-
*
|
|
66
|
-
* This function should only be used to set the notch width
|
|
67
|
-
* on slotted label content. The notch width for label prop
|
|
68
|
-
* content is automatically calculated based on the
|
|
69
|
-
* intrinsic size of the label text.
|
|
70
|
-
*/
|
|
71
|
-
const setNotchWidth = () => {
|
|
72
|
-
const notchSpacerEl = getNotchSpacerEl();
|
|
73
|
-
if (notchSpacerEl === undefined) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (!needsExplicitNotchWidth()) {
|
|
77
|
-
notchSpacerEl.style.removeProperty('width');
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const width = getLabelSlot().scrollWidth;
|
|
81
|
-
if (
|
|
82
|
-
/**
|
|
83
|
-
* If the computed width of the label is 0
|
|
84
|
-
* and notchSpacerEl's offsetParent is null
|
|
85
|
-
* then that means the element is hidden.
|
|
86
|
-
* As a result, we need to wait for the element
|
|
87
|
-
* to become visible before setting the notch width.
|
|
88
|
-
*
|
|
89
|
-
* We do not check el.offsetParent because
|
|
90
|
-
* that can be null if the host element has
|
|
91
|
-
* position: fixed applied to it.
|
|
92
|
-
* notchSpacerEl does not have position: fixed.
|
|
93
|
-
*/
|
|
94
|
-
width === 0 &&
|
|
95
|
-
notchSpacerEl.offsetParent === null &&
|
|
96
|
-
win !== undefined &&
|
|
97
|
-
'IntersectionObserver' in win) {
|
|
98
|
-
/**
|
|
99
|
-
* If there is an IO already attached
|
|
100
|
-
* then that will update the notch
|
|
101
|
-
* once the element becomes visible.
|
|
102
|
-
* As a result, there is no need to create
|
|
103
|
-
* another one.
|
|
104
|
-
*/
|
|
105
|
-
if (notchVisibilityIO !== undefined) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
const io = (notchVisibilityIO = new IntersectionObserver((ev) => {
|
|
109
|
-
/**
|
|
110
|
-
* If the element is visible then we
|
|
111
|
-
* can try setting the notch width again.
|
|
112
|
-
*/
|
|
113
|
-
if (ev[0].intersectionRatio === 1) {
|
|
114
|
-
setNotchWidth();
|
|
115
|
-
io.disconnect();
|
|
116
|
-
notchVisibilityIO = undefined;
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
/**
|
|
120
|
-
* Set the root to be the host element
|
|
121
|
-
* This causes the IO callback
|
|
122
|
-
* to be fired in WebKit as soon as the element
|
|
123
|
-
* is visible. If we used the default root value
|
|
124
|
-
* then WebKit would only fire the IO callback
|
|
125
|
-
* after any animations (such as a modal transition)
|
|
126
|
-
* finished, and there would potentially be a flicker.
|
|
127
|
-
*/
|
|
128
|
-
{ threshold: 0.01, root: el }));
|
|
129
|
-
io.observe(notchSpacerEl);
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* If the element is visible then we can set the notch width.
|
|
134
|
-
* The notch is only visible when the label is scaled,
|
|
135
|
-
* which is why we multiply the width by 0.75 as this is
|
|
136
|
-
* the same amount the label element is scaled by in the host CSS.
|
|
137
|
-
* (See $form-control-label-stacked-scale in ionic.globals.scss).
|
|
138
|
-
*/
|
|
139
|
-
notchSpacerEl.style.setProperty('width', `${width * 0.75}px`);
|
|
140
|
-
};
|
|
141
|
-
const destroy = () => {
|
|
142
|
-
if (notchVisibilityIO) {
|
|
143
|
-
notchVisibilityIO.disconnect();
|
|
144
|
-
notchVisibilityIO = undefined;
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
return {
|
|
148
|
-
calculateNotchWidth,
|
|
149
|
-
destroy,
|
|
150
|
-
};
|
|
151
|
-
};
|
|
152
|
-
|
|
153
4
|
/**
|
|
154
5
|
* Checks if the form element is in an invalid state based on
|
|
155
6
|
* Ionic validation classes.
|
|
@@ -163,4 +14,4 @@ const checkInvalidState = (el) => {
|
|
|
163
14
|
return hasIonTouched && hasIonInvalid;
|
|
164
15
|
};
|
|
165
16
|
|
|
166
|
-
export { checkInvalidState as
|
|
17
|
+
export { checkInvalidState as c };
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
var index = require('./index-D6Wc6v08.js');
|
|
7
7
|
var helpers = require('./helpers-DrTqNghc.js');
|
|
8
|
+
var validity = require('./validity-BpS37YFM.js');
|
|
8
9
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
9
10
|
var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
|
|
10
11
|
|
|
@@ -61,6 +62,10 @@ const Checkbox = class {
|
|
|
61
62
|
* submitting if the value is invalid.
|
|
62
63
|
*/
|
|
63
64
|
this.required = false;
|
|
65
|
+
/**
|
|
66
|
+
* Track validation state for proper aria-live announcements.
|
|
67
|
+
*/
|
|
68
|
+
this.isInvalid = false;
|
|
64
69
|
/**
|
|
65
70
|
* Sets the checked property and emits
|
|
66
71
|
* the ionChange event. Use this to update the
|
|
@@ -107,16 +112,63 @@ const Checkbox = class {
|
|
|
107
112
|
ev.stopPropagation();
|
|
108
113
|
};
|
|
109
114
|
}
|
|
115
|
+
connectedCallback() {
|
|
116
|
+
const { el } = this;
|
|
117
|
+
// Watch for class changes to update validation state.
|
|
118
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
119
|
+
this.validationObserver = new MutationObserver(() => {
|
|
120
|
+
const newIsInvalid = validity.checkInvalidState(el);
|
|
121
|
+
if (this.isInvalid !== newIsInvalid) {
|
|
122
|
+
this.isInvalid = newIsInvalid;
|
|
123
|
+
/**
|
|
124
|
+
* Screen readers tend to announce changes
|
|
125
|
+
* to `aria-describedby` when the attribute
|
|
126
|
+
* is changed during a blur event for a
|
|
127
|
+
* native form control.
|
|
128
|
+
* However, the announcement can be spotty
|
|
129
|
+
* when using a non-native form control
|
|
130
|
+
* and `forceUpdate()`.
|
|
131
|
+
* This is due to `forceUpdate()` internally
|
|
132
|
+
* rescheduling the DOM update to a lower
|
|
133
|
+
* priority queue regardless if it's called
|
|
134
|
+
* inside a Promise or not, thus causing
|
|
135
|
+
* the screen reader to potentially miss the
|
|
136
|
+
* change.
|
|
137
|
+
* By using a State variable inside a Promise,
|
|
138
|
+
* it guarantees a re-render immediately at
|
|
139
|
+
* a higher priority.
|
|
140
|
+
*/
|
|
141
|
+
Promise.resolve().then(() => {
|
|
142
|
+
this.hintTextId = this.getHintTextId();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
this.validationObserver.observe(el, {
|
|
147
|
+
attributes: true,
|
|
148
|
+
attributeFilter: ['class'],
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// Always set initial state
|
|
152
|
+
this.isInvalid = validity.checkInvalidState(el);
|
|
153
|
+
}
|
|
110
154
|
componentWillLoad() {
|
|
111
155
|
this.inheritedAttributes = Object.assign({}, helpers.inheritAriaAttributes(this.el));
|
|
156
|
+
this.hintTextId = this.getHintTextId();
|
|
157
|
+
}
|
|
158
|
+
disconnectedCallback() {
|
|
159
|
+
// Clean up validation observer to prevent memory leaks.
|
|
160
|
+
if (this.validationObserver) {
|
|
161
|
+
this.validationObserver.disconnect();
|
|
162
|
+
this.validationObserver = undefined;
|
|
163
|
+
}
|
|
112
164
|
}
|
|
113
165
|
/** @internal */
|
|
114
166
|
async setFocus() {
|
|
115
167
|
this.el.focus();
|
|
116
168
|
}
|
|
117
|
-
|
|
118
|
-
const {
|
|
119
|
-
if (
|
|
169
|
+
getHintTextId() {
|
|
170
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
171
|
+
if (isInvalid && errorText) {
|
|
120
172
|
return errorTextId;
|
|
121
173
|
}
|
|
122
174
|
if (helperText) {
|
|
@@ -129,7 +181,7 @@ const Checkbox = class {
|
|
|
129
181
|
* This element should only be rendered if hint text is set.
|
|
130
182
|
*/
|
|
131
183
|
renderHintText() {
|
|
132
|
-
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
184
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
133
185
|
/**
|
|
134
186
|
* undefined and empty string values should
|
|
135
187
|
* be treated as not having helper/error text.
|
|
@@ -138,7 +190,7 @@ const Checkbox = class {
|
|
|
138
190
|
if (!hasHintText) {
|
|
139
191
|
return;
|
|
140
192
|
}
|
|
141
|
-
return (index.h("div", { class: "checkbox-bottom" }, index.h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text" }, helperText), index.h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text" }, errorText)));
|
|
193
|
+
return (index.h("div", { class: "checkbox-bottom" }, index.h("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null), index.h("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text", role: "alert" }, isInvalid ? errorText : null)));
|
|
142
194
|
}
|
|
143
195
|
render() {
|
|
144
196
|
const { color, checked, disabled, el, getSVGPath, indeterminate, inheritedAttributes, inputId, justify, labelPlacement, name, value, alignment, required, } = this;
|
|
@@ -148,7 +200,7 @@ const Checkbox = class {
|
|
|
148
200
|
helpers.renderHiddenInput(true, el, name, checked ? value : '', disabled);
|
|
149
201
|
// The host element must have a checkbox role to ensure proper VoiceOver
|
|
150
202
|
// support in Safari for accessibility.
|
|
151
|
-
return (index.h(index.Host, { key: '
|
|
203
|
+
return (index.h(index.Host, { key: 'ae0fbd4b21accbac132e6b85c513512ad9179394', role: "checkbox", "aria-checked": indeterminate ? 'mixed' : `${checked}`, "aria-describedby": this.hintTextId, "aria-invalid": this.isInvalid ? 'true' : undefined, "aria-labelledby": hasLabelContent ? this.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, onClick: this.onClick, class: theme.createColorClasses(color, {
|
|
152
204
|
[mode]: true,
|
|
153
205
|
'in-item': theme.hostContext('ion-item', el),
|
|
154
206
|
'checkbox-checked': checked,
|
|
@@ -158,10 +210,10 @@ const Checkbox = class {
|
|
|
158
210
|
[`checkbox-justify-${justify}`]: justify !== undefined,
|
|
159
211
|
[`checkbox-alignment-${alignment}`]: alignment !== undefined,
|
|
160
212
|
[`checkbox-label-placement-${labelPlacement}`]: true,
|
|
161
|
-
}) }, index.h("label", { key: '
|
|
213
|
+
}) }, index.h("label", { key: '7a3d7f3c27dde514f2dbf2e34f4629fad33ec3bf', class: "checkbox-wrapper", htmlFor: inputId }, index.h("input", Object.assign({ key: '4130d77ddf034271fecccda14e101a5a809921b6', type: "checkbox", checked: checked ? true : undefined, disabled: disabled, id: inputId, onChange: this.toggleChecked, required: required }, inheritedAttributes)), index.h("div", { key: '5daa74f4e62b0947e37764762524001ee42609d9', class: {
|
|
162
214
|
'label-text-wrapper': true,
|
|
163
215
|
'label-text-wrapper-hidden': !hasLabelContent,
|
|
164
|
-
}, part: "label", id: this.inputLabelId, onClick: this.onDivLabelClick }, index.h("slot", { key: '
|
|
216
|
+
}, part: "label", id: this.inputLabelId, onClick: this.onDivLabelClick }, index.h("slot", { key: '23ff66138f8c3a2f56f39113fc842d54b2f7952a' }), this.renderHintText()), index.h("div", { key: 'ab914d9623c19fc46821d5e62db92f1192ebbe7e', class: "native-wrapper" }, index.h("svg", { key: '66e3f4f5dcaa9756fb0e9452299954f9ed3dcb7b', class: "checkbox-icon", viewBox: "0 0 24 24", part: "container", "aria-hidden": "true" }, path)))));
|
|
165
217
|
}
|
|
166
218
|
getSVGPath(mode, indeterminate) {
|
|
167
219
|
let path = indeterminate ? (index.h("path", { d: "M6 12L18 12", part: "mark" })) : (index.h("path", { d: "M5.9,12.5l3.8,3.8l8.8-8.8", part: "mark" }));
|
|
@@ -786,6 +786,28 @@ const Datetime = class {
|
|
|
786
786
|
destroyKeyboardMO();
|
|
787
787
|
}
|
|
788
788
|
};
|
|
789
|
+
/**
|
|
790
|
+
* TODO(FW-6931): Remove this fallback upon solving the root cause
|
|
791
|
+
* Fallback to ensure the datetime becomes ready even if
|
|
792
|
+
* IntersectionObserver never reports it as intersecting.
|
|
793
|
+
*
|
|
794
|
+
* This is primarily used in environments where the observer
|
|
795
|
+
* might not fire as expected, such as when running under
|
|
796
|
+
* synthetic tests that stub IntersectionObserver.
|
|
797
|
+
*/
|
|
798
|
+
this.ensureReadyIfVisible = () => {
|
|
799
|
+
if (this.el.classList.contains('datetime-ready')) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
const rect = this.el.getBoundingClientRect();
|
|
803
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
this.initializeListeners();
|
|
807
|
+
index.writeTask(() => {
|
|
808
|
+
this.el.classList.add('datetime-ready');
|
|
809
|
+
});
|
|
810
|
+
};
|
|
789
811
|
this.processValue = (value) => {
|
|
790
812
|
const hasValue = value !== null && value !== undefined && value !== '' && (!Array.isArray(value) || value.length > 0);
|
|
791
813
|
const valueToProcess = hasValue ? data.parseDate(value) : this.defaultParts;
|
|
@@ -1103,6 +1125,17 @@ const Datetime = class {
|
|
|
1103
1125
|
* triggering the `hiddenIO` observer below.
|
|
1104
1126
|
*/
|
|
1105
1127
|
helpers.raf(() => visibleIO === null || visibleIO === void 0 ? void 0 : visibleIO.observe(intersectionTrackerRef));
|
|
1128
|
+
/**
|
|
1129
|
+
* TODO(FW-6931): Remove this fallback upon solving the root cause
|
|
1130
|
+
* Fallback: If IntersectionObserver never reports that the
|
|
1131
|
+
* datetime is visible but the host clearly has layout, ensure
|
|
1132
|
+
* we still initialize listeners and mark the component as ready.
|
|
1133
|
+
*
|
|
1134
|
+
* We schedule this after everything has had a chance to run.
|
|
1135
|
+
*/
|
|
1136
|
+
setTimeout(() => {
|
|
1137
|
+
this.ensureReadyIfVisible();
|
|
1138
|
+
}, 100);
|
|
1106
1139
|
/**
|
|
1107
1140
|
* We need to clean up listeners when the datetime is hidden
|
|
1108
1141
|
* in a popover/modal so that we can properly scroll containers
|
|
@@ -1858,7 +1891,7 @@ const Datetime = class {
|
|
|
1858
1891
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1859
1892
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1860
1893
|
helpers.renderHiddenInput(true, el, name, data.formatValue(value), disabled);
|
|
1861
|
-
return (index.h(index.Host, { key: '
|
|
1894
|
+
return (index.h(index.Host, { key: 'efdbc0922670a841bc667ceac392cdc1dedffd01', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, theme.createColorClasses(color, {
|
|
1862
1895
|
[mode]: true,
|
|
1863
1896
|
['datetime-readonly']: readonly,
|
|
1864
1897
|
['datetime-disabled']: disabled,
|
|
@@ -1868,7 +1901,7 @@ const Datetime = class {
|
|
|
1868
1901
|
[`datetime-size-${size}`]: true,
|
|
1869
1902
|
[`datetime-prefer-wheel`]: hasWheelVariant,
|
|
1870
1903
|
[`datetime-grid`]: isGridStyle,
|
|
1871
|
-
})) }, index.h("div", { key: '
|
|
1904
|
+
})) }, index.h("div", { key: '3f8bb75fcb0baff55182ef3aa1b535eacc58d81f', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
|
|
1872
1905
|
}
|
|
1873
1906
|
get el() { return index.getElement(this); }
|
|
1874
1907
|
static get watchers() { return {
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
var index = require('./index-D6Wc6v08.js');
|
|
7
|
-
var
|
|
7
|
+
var notchController = require('./notch-controller-Bzqhjm4f.js');
|
|
8
|
+
var validity = require('./validity-BpS37YFM.js');
|
|
8
9
|
var helpers = require('./helpers-DrTqNghc.js');
|
|
9
10
|
var input_utils = require('./input.utils-B_QROI2g.js');
|
|
10
11
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
@@ -235,7 +236,7 @@ const Input = class {
|
|
|
235
236
|
connectedCallback() {
|
|
236
237
|
const { el } = this;
|
|
237
238
|
this.slotMutationController = input_utils.createSlotMutationController(el, ['label', 'start', 'end'], () => index.forceUpdate(this));
|
|
238
|
-
this.notchController =
|
|
239
|
+
this.notchController = notchController.createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
|
|
239
240
|
// Watch for class changes to update validation state
|
|
240
241
|
if (typeof MutationObserver !== 'undefined') {
|
|
241
242
|
this.validationObserver = new MutationObserver(() => {
|
|
@@ -8,6 +8,7 @@ var helpers = require('./helpers-DrTqNghc.js');
|
|
|
8
8
|
var compareWithUtils = require('./compare-with-utils-DSicavqM.js');
|
|
9
9
|
var theme = require('./theme-CeDs6Hcv.js');
|
|
10
10
|
var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
|
|
11
|
+
var validity = require('./validity-BpS37YFM.js');
|
|
11
12
|
|
|
12
13
|
const radioIosCss = ":host{--inner-border-radius:50%;display:inline-block;position:relative;max-width:100%;min-height:inherit;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.radio-disabled){pointer-events:none}.radio-icon{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;contain:layout size style}.radio-icon,.radio-inner{-webkit-box-sizing:border-box;box-sizing:border-box}input{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:0;clip:rect(0 0 0 0);opacity:0;overflow:hidden;-webkit-appearance:none;-moz-appearance:none}:host(:focus){outline:none}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0;width:100%;height:100%}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}.radio-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;min-height:inherit;cursor:inherit}.label-text-wrapper{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host(.in-item) .label-text-wrapper{margin-top:10px;margin-bottom:10px}:host(.in-item.radio-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.radio-label-placement-stacked) .native-wrapper{margin-bottom:10px}.label-text-wrapper-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}:host(.radio-justify-space-between) .radio-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.radio-justify-start) .radio-wrapper{-ms-flex-pack:start;justify-content:start}:host(.radio-justify-end) .radio-wrapper{-ms-flex-pack:end;justify-content:end}:host(.radio-alignment-start) .radio-wrapper{-ms-flex-align:start;align-items:start}:host(.radio-alignment-center) .radio-wrapper{-ms-flex-align:center;align-items:center}:host(.radio-justify-space-between),:host(.radio-justify-start),:host(.radio-justify-end),:host(.radio-alignment-start),:host(.radio-alignment-center){display:block}:host(.radio-label-placement-start) .radio-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.radio-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.radio-label-placement-end) .radio-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.radio-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.radio-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.radio-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px}:host(.radio-label-placement-stacked) .radio-wrapper{-ms-flex-direction:column;flex-direction:column}:host(.radio-label-placement-stacked) .label-text-wrapper{-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host(.radio-label-placement-stacked.radio-alignment-start) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]):host(.radio-label-placement-stacked.radio-alignment-start) .label-text-wrapper,:host-context([dir=rtl]).radio-label-placement-stacked.radio-alignment-start .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.radio-label-placement-stacked.radio-alignment-start:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.radio-label-placement-stacked.radio-alignment-center) .label-text-wrapper{-webkit-transform-origin:center top;transform-origin:center top}:host-context([dir=rtl]):host(.radio-label-placement-stacked.radio-alignment-center) .label-text-wrapper,:host-context([dir=rtl]).radio-label-placement-stacked.radio-alignment-center .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}@supports selector(:dir(rtl)){:host(.radio-label-placement-stacked.radio-alignment-center:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}}:host{--color-checked:var(--ion-color-primary, #0054e9)}:host(.ion-color.radio-checked) .radio-inner{border-color:var(--ion-color-base)}.item-radio.item-ios ion-label{-webkit-margin-start:0;margin-inline-start:0}.radio-inner{width:33%;height:50%}:host(.radio-checked) .radio-inner{-webkit-transform:rotate(45deg);transform:rotate(45deg);border-width:0.125rem;border-top-width:0;border-left-width:0;border-style:solid;border-color:var(--color-checked)}:host(.radio-disabled){opacity:0.3}:host(.ion-focused) .radio-icon::after{border-radius:var(--inner-border-radius);top:-8px;display:block;position:absolute;width:36px;height:36px;background:var(--ion-color-primary-tint, #1a65eb);content:\"\";opacity:0.2}:host(.ion-focused) .radio-icon::after{inset-inline-start:-9px}.native-wrapper .radio-icon{width:0.9375rem;height:1.5rem}";
|
|
13
14
|
|
|
@@ -177,6 +178,10 @@ const RadioGroup = class {
|
|
|
177
178
|
this.helperTextId = `${this.inputId}-helper-text`;
|
|
178
179
|
this.errorTextId = `${this.inputId}-error-text`;
|
|
179
180
|
this.labelId = `${this.inputId}-lbl`;
|
|
181
|
+
/**
|
|
182
|
+
* Track validation state for proper aria-live announcements.
|
|
183
|
+
*/
|
|
184
|
+
this.isInvalid = false;
|
|
180
185
|
/**
|
|
181
186
|
* If `true`, the radios can be deselected.
|
|
182
187
|
*/
|
|
@@ -258,6 +263,52 @@ const RadioGroup = class {
|
|
|
258
263
|
this.labelId = label.id = this.name + '-lbl';
|
|
259
264
|
}
|
|
260
265
|
}
|
|
266
|
+
// Watch for class changes to update validation state.
|
|
267
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
268
|
+
this.validationObserver = new MutationObserver(() => {
|
|
269
|
+
const newIsInvalid = validity.checkInvalidState(this.el);
|
|
270
|
+
if (this.isInvalid !== newIsInvalid) {
|
|
271
|
+
this.isInvalid = newIsInvalid;
|
|
272
|
+
/**
|
|
273
|
+
* Screen readers tend to announce changes
|
|
274
|
+
* to `aria-describedby` when the attribute
|
|
275
|
+
* is changed during a blur event for a
|
|
276
|
+
* native form control.
|
|
277
|
+
* However, the announcement can be spotty
|
|
278
|
+
* when using a non-native form control
|
|
279
|
+
* and `forceUpdate()`.
|
|
280
|
+
* This is due to `forceUpdate()` internally
|
|
281
|
+
* rescheduling the DOM update to a lower
|
|
282
|
+
* priority queue regardless if it's called
|
|
283
|
+
* inside a Promise or not, thus causing
|
|
284
|
+
* the screen reader to potentially miss the
|
|
285
|
+
* change.
|
|
286
|
+
* By using a State variable inside a Promise,
|
|
287
|
+
* it guarantees a re-render immediately at
|
|
288
|
+
* a higher priority.
|
|
289
|
+
*/
|
|
290
|
+
Promise.resolve().then(() => {
|
|
291
|
+
this.hintTextId = this.getHintTextId();
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
this.validationObserver.observe(this.el, {
|
|
296
|
+
attributes: true,
|
|
297
|
+
attributeFilter: ['class'],
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
// Always set initial state
|
|
301
|
+
this.isInvalid = validity.checkInvalidState(this.el);
|
|
302
|
+
}
|
|
303
|
+
componentWillLoad() {
|
|
304
|
+
this.hintTextId = this.getHintTextId();
|
|
305
|
+
}
|
|
306
|
+
disconnectedCallback() {
|
|
307
|
+
// Clean up validation observer to prevent memory leaks.
|
|
308
|
+
if (this.validationObserver) {
|
|
309
|
+
this.validationObserver.disconnect();
|
|
310
|
+
this.validationObserver = undefined;
|
|
311
|
+
}
|
|
261
312
|
}
|
|
262
313
|
getRadios() {
|
|
263
314
|
return Array.from(this.el.querySelectorAll('ion-radio'));
|
|
@@ -333,16 +384,16 @@ const RadioGroup = class {
|
|
|
333
384
|
* Renders the helper text or error text values
|
|
334
385
|
*/
|
|
335
386
|
renderHintText() {
|
|
336
|
-
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
387
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
337
388
|
const hasHintText = !!helperText || !!errorText;
|
|
338
389
|
if (!hasHintText) {
|
|
339
390
|
return;
|
|
340
391
|
}
|
|
341
|
-
return (index.h("div", { class: "radio-group-top" }, index.h("div", { id: helperTextId, class: "helper-text" }, helperText), index.h("div", { id: errorTextId, class: "error-text" }, errorText)));
|
|
392
|
+
return (index.h("div", { class: "radio-group-top" }, index.h("div", { id: helperTextId, class: "helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null), index.h("div", { id: errorTextId, class: "error-text", role: "alert" }, isInvalid ? errorText : null)));
|
|
342
393
|
}
|
|
343
|
-
|
|
344
|
-
const {
|
|
345
|
-
if (
|
|
394
|
+
getHintTextId() {
|
|
395
|
+
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
396
|
+
if (isInvalid && errorText) {
|
|
346
397
|
return errorTextId;
|
|
347
398
|
}
|
|
348
399
|
if (helperText) {
|
|
@@ -354,7 +405,7 @@ const RadioGroup = class {
|
|
|
354
405
|
const { label, labelId, el, name, value } = this;
|
|
355
406
|
const mode = ionicGlobal.getIonMode(this);
|
|
356
407
|
helpers.renderHiddenInput(true, el, name, value, false);
|
|
357
|
-
return (index.h(index.Host, { key: '
|
|
408
|
+
return (index.h(index.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(), index.h("div", { key: '85045b45a0100a45f3b9a35d1c5a25ec63d525c4', class: "radio-group-wrapper" }, index.h("slot", { key: '53dacb87ce62398e78771fb2efaf839ab922d946' }))));
|
|
358
409
|
}
|
|
359
410
|
get el() { return index.getElement(this); }
|
|
360
411
|
static get watchers() { return {
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
var index = require('./index-D6Wc6v08.js');
|
|
7
|
-
var
|
|
7
|
+
var notchController = require('./notch-controller-Bzqhjm4f.js');
|
|
8
8
|
var compareWithUtils = require('./compare-with-utils-DSicavqM.js');
|
|
9
|
+
var validity = require('./validity-BpS37YFM.js');
|
|
9
10
|
var helpers = require('./helpers-DrTqNghc.js');
|
|
10
11
|
var overlays = require('./overlays-DxIZwUXI.js');
|
|
11
12
|
var dir = require('./dir-Cn0z1rJH.js');
|
|
@@ -165,7 +166,7 @@ const Select = class {
|
|
|
165
166
|
}
|
|
166
167
|
async connectedCallback() {
|
|
167
168
|
const { el } = this;
|
|
168
|
-
this.notchController =
|
|
169
|
+
this.notchController = notchController.createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
|
|
169
170
|
this.updateOverlayOptions();
|
|
170
171
|
this.emitStyle();
|
|
171
172
|
this.mutationO = watchOptions.watchForOptions(this.el, 'ion-select-option', async () => {
|
|
@@ -203,7 +204,7 @@ const Select = class {
|
|
|
203
204
|
* a higher priority.
|
|
204
205
|
*/
|
|
205
206
|
Promise.resolve().then(() => {
|
|
206
|
-
this.
|
|
207
|
+
this.hintTextId = this.getHintTextId();
|
|
207
208
|
});
|
|
208
209
|
}
|
|
209
210
|
});
|
|
@@ -217,7 +218,7 @@ const Select = class {
|
|
|
217
218
|
}
|
|
218
219
|
componentWillLoad() {
|
|
219
220
|
this.inheritedAttributes = helpers.inheritAttributes(this.el, ['aria-label']);
|
|
220
|
-
this.
|
|
221
|
+
this.hintTextId = this.getHintTextId();
|
|
221
222
|
}
|
|
222
223
|
componentDidLoad() {
|
|
223
224
|
/**
|
|
@@ -716,9 +717,9 @@ const Select = class {
|
|
|
716
717
|
}
|
|
717
718
|
renderListbox() {
|
|
718
719
|
const { disabled, inputId, isExpanded, required } = this;
|
|
719
|
-
return (index.h("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, "aria-describedby": this.
|
|
720
|
+
return (index.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) }));
|
|
720
721
|
}
|
|
721
|
-
|
|
722
|
+
getHintTextId() {
|
|
722
723
|
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
|
|
723
724
|
if (isInvalid && errorText) {
|
|
724
725
|
return errorTextId;
|