@ionic/core 8.7.4-dev.11755809082.11a7702b → 8.7.4-dev.11756388042.1a103a79
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/ion-datetime.js +4 -3
- package/components/ion-input.js +8 -63
- package/components/ion-menu.js +5 -2
- package/components/ion-textarea.js +7 -62
- package/components/overlays.js +18 -109
- package/components/picker-column-option.js +3 -3
- package/components/picker-column.js +3 -39
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/ion-action-sheet.cjs.entry.js +1 -1
- package/dist/cjs/ion-alert.cjs.entry.js +1 -1
- package/dist/cjs/ion-datetime_3.cjs.entry.js +4 -4
- package/dist/cjs/ion-input.cjs.entry.js +8 -62
- package/dist/cjs/ion-loading.cjs.entry.js +1 -1
- package/dist/cjs/ion-menu_3.cjs.entry.js +6 -3
- package/dist/cjs/ion-modal.cjs.entry.js +1 -1
- package/dist/cjs/ion-picker-column-option.cjs.entry.js +3 -3
- package/dist/cjs/ion-picker-column.cjs.entry.js +3 -39
- package/dist/cjs/ion-popover.cjs.entry.js +1 -1
- package/dist/cjs/ion-select-modal.cjs.entry.js +1 -1
- package/dist/cjs/ion-select_3.cjs.entry.js +1 -1
- package/dist/cjs/ion-textarea.cjs.entry.js +7 -61
- package/dist/cjs/ion-toast.cjs.entry.js +1 -1
- package/dist/cjs/ionic.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{overlays-CglR7j-u.js → overlays-v_jc1Hok.js} +17 -108
- package/dist/collection/components/datetime/datetime.js +4 -3
- package/dist/collection/components/input/input.js +9 -64
- package/dist/collection/components/menu/menu.js +9 -2
- package/dist/collection/components/picker-column/picker-column.js +3 -39
- package/dist/collection/components/picker-column-option/picker-column-option.ios.css +2 -2
- package/dist/collection/components/picker-column-option/picker-column-option.js +1 -1
- package/dist/collection/components/picker-column-option/picker-column-option.md.css +2 -2
- package/dist/collection/components/textarea/textarea.js +8 -63
- package/dist/collection/utils/overlays.js +17 -109
- package/dist/docs.json +5 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/ion-action-sheet.entry.js +1 -1
- package/dist/esm/ion-alert.entry.js +1 -1
- package/dist/esm/ion-datetime_3.entry.js +4 -4
- package/dist/esm/ion-input.entry.js +8 -62
- package/dist/esm/ion-loading.entry.js +1 -1
- package/dist/esm/ion-menu_3.entry.js +6 -3
- package/dist/esm/ion-modal.entry.js +1 -1
- package/dist/esm/ion-picker-column-option.entry.js +3 -3
- package/dist/esm/ion-picker-column.entry.js +3 -39
- package/dist/esm/ion-popover.entry.js +1 -1
- package/dist/esm/ion-select-modal.entry.js +1 -1
- package/dist/esm/ion-select_3.entry.js +1 -1
- package/dist/esm/ion-textarea.entry.js +7 -61
- package/dist/esm/ion-toast.entry.js +1 -1
- package/dist/esm/ionic.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{overlays-ZX_4-t_r.js → overlays-BJaRj3Rj.js} +18 -109
- package/dist/ionic/index.esm.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/{p-f2884bc2.entry.js → p-095073c6.entry.js} +1 -1
- package/dist/ionic/p-1488b7cc.entry.js +4 -0
- package/dist/ionic/p-1ab0fc21.entry.js +4 -0
- package/dist/ionic/{p-92e8f208.entry.js → p-2060feb1.entry.js} +1 -1
- package/dist/ionic/p-22a0f820.entry.js +4 -0
- package/dist/ionic/{p-c575e7ce.entry.js → p-5a9be5a3.entry.js} +1 -1
- package/dist/ionic/{p-7bac2c5f.entry.js → p-60ff6bf6.entry.js} +1 -1
- package/dist/ionic/p-8888efe4.entry.js +4 -0
- package/dist/ionic/{p-ab33ef20.entry.js → p-89c2e0a3.entry.js} +1 -1
- package/dist/ionic/p-CoDfkBuk.js +4 -0
- package/dist/ionic/{p-91d6ccb0.entry.js → p-b17f0554.entry.js} +1 -1
- package/dist/ionic/p-b292804d.entry.js +4 -0
- package/dist/ionic/p-c5210d3e.entry.js +4 -0
- package/dist/ionic/{p-ac434970.entry.js → p-cd93c119.entry.js} +1 -1
- package/dist/ionic/p-dc8d0bb9.entry.js +4 -0
- package/dist/types/components/input/input.d.ts +0 -9
- package/dist/types/components/picker-column/picker-column.d.ts +0 -7
- package/dist/types/components/textarea/textarea.d.ts +0 -9
- package/hydrate/index.js +46 -248
- package/hydrate/index.mjs +46 -248
- package/package.json +2 -2
- package/dist/ionic/p-1d5b934a.entry.js +0 -4
- package/dist/ionic/p-1d65c601.entry.js +0 -4
- package/dist/ionic/p-29032e49.entry.js +0 -4
- package/dist/ionic/p-33017191.entry.js +0 -4
- package/dist/ionic/p-8d96a0cd.entry.js +0 -4
- package/dist/ionic/p-982fe1c4.entry.js +0 -4
- package/dist/ionic/p-CSwZyt05.js +0 -4
- package/dist/ionic/p-f456d176.entry.js +0 -4
|
@@ -5,6 +5,7 @@ import { Host, h, writeTask } from "@stencil/core";
|
|
|
5
5
|
import { startFocusVisible } from "../../utils/focus-visible";
|
|
6
6
|
import { getElementRoot, raf, renderHiddenInput } from "../../utils/helpers";
|
|
7
7
|
import { printIonError, printIonWarning } from "../../utils/logging/index";
|
|
8
|
+
import { FOCUS_TRAP_DISABLE_CLASS } from "../../utils/overlays";
|
|
8
9
|
import { isRTL } from "../../utils/rtl/index";
|
|
9
10
|
import { createColorClasses } from "../../utils/theme";
|
|
10
11
|
import { caretDownSharp, caretUpSharp, chevronBack, chevronDown, chevronForward } from "ionicons/icons";
|
|
@@ -1099,7 +1100,7 @@ export class Datetime {
|
|
|
1099
1100
|
const renderArray = forcePresentation === 'time-date'
|
|
1100
1101
|
? [this.renderTimePickerColumns(forcePresentation), this.renderDatePickerColumns(forcePresentation)]
|
|
1101
1102
|
: [this.renderDatePickerColumns(forcePresentation), this.renderTimePickerColumns(forcePresentation)];
|
|
1102
|
-
return h("ion-picker",
|
|
1103
|
+
return h("ion-picker", { class: FOCUS_TRAP_DISABLE_CLASS }, renderArray);
|
|
1103
1104
|
}
|
|
1104
1105
|
renderDatePickerColumns(forcePresentation) {
|
|
1105
1106
|
return forcePresentation === 'date-time' || forcePresentation === 'time-date'
|
|
@@ -1656,7 +1657,7 @@ export class Datetime {
|
|
|
1656
1657
|
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
|
|
1657
1658
|
const hasWheelVariant = hasDatePresentation && preferWheel;
|
|
1658
1659
|
renderHiddenInput(true, el, name, formatValue(value), disabled);
|
|
1659
|
-
return (h(Host, { key: '
|
|
1660
|
+
return (h(Host, { key: '57492534800ea059a7c2bbd9f0059cc0b75ae8d2', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
|
|
1660
1661
|
[mode]: true,
|
|
1661
1662
|
['datetime-readonly']: readonly,
|
|
1662
1663
|
['datetime-disabled']: disabled,
|
|
@@ -1666,7 +1667,7 @@ export class Datetime {
|
|
|
1666
1667
|
[`datetime-size-${size}`]: true,
|
|
1667
1668
|
[`datetime-prefer-wheel`]: hasWheelVariant,
|
|
1668
1669
|
[`datetime-grid`]: isGridStyle,
|
|
1669
|
-
})) }, h("div", { key: '
|
|
1670
|
+
})) }, h("div", { key: '97dac5e5195635ac0bc5fb472b9d09e5c3c6bbc3', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
|
|
1670
1671
|
}
|
|
1671
1672
|
static get is() { return "ion-datetime"; }
|
|
1672
1673
|
static get encapsulation() { return "shadow"; }
|
|
@@ -39,10 +39,6 @@ export class Input {
|
|
|
39
39
|
* is applied in both cases.
|
|
40
40
|
*/
|
|
41
41
|
this.hasFocus = false;
|
|
42
|
-
/**
|
|
43
|
-
* Track validation state for proper aria-live announcements
|
|
44
|
-
*/
|
|
45
|
-
this.isInvalid = false;
|
|
46
42
|
/**
|
|
47
43
|
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
|
|
48
44
|
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
|
@@ -128,19 +124,6 @@ export class Input {
|
|
|
128
124
|
}
|
|
129
125
|
this.didInputClearOnEdit = false;
|
|
130
126
|
this.ionBlur.emit(ev);
|
|
131
|
-
/**
|
|
132
|
-
* Check validation state after blur to handle framework-managed classes.
|
|
133
|
-
* Frameworks like Angular update classes asynchronously, often using
|
|
134
|
-
* requestAnimationFrame or promises. Using setTimeout ensures we check
|
|
135
|
-
* after all microtasks and animation frames have completed.
|
|
136
|
-
*/
|
|
137
|
-
setTimeout(() => {
|
|
138
|
-
const newIsInvalid = this.checkValidationState();
|
|
139
|
-
if (this.isInvalid !== newIsInvalid) {
|
|
140
|
-
this.isInvalid = newIsInvalid;
|
|
141
|
-
forceUpdate(this);
|
|
142
|
-
}
|
|
143
|
-
}, 100);
|
|
144
127
|
};
|
|
145
128
|
this.onFocus = (ev) => {
|
|
146
129
|
this.hasFocus = true;
|
|
@@ -240,42 +223,10 @@ export class Input {
|
|
|
240
223
|
componentWillLoad() {
|
|
241
224
|
this.inheritedAttributes = Object.assign(Object.assign({}, inheritAriaAttributes(this.el)), inheritAttributes(this.el, ['tabindex', 'title', 'data-form-type', 'dir']));
|
|
242
225
|
}
|
|
243
|
-
/**
|
|
244
|
-
* Checks if the input is in an invalid state based on validation classes
|
|
245
|
-
*/
|
|
246
|
-
checkValidationState() {
|
|
247
|
-
// Check for both Ionic and Angular validation classes on the element itself
|
|
248
|
-
// Angular applies ng-touched/ng-invalid directly to the host element with ngModel
|
|
249
|
-
const hasIonTouched = this.el.classList.contains('ion-touched');
|
|
250
|
-
const hasIonInvalid = this.el.classList.contains('ion-invalid');
|
|
251
|
-
const hasNgTouched = this.el.classList.contains('ng-touched');
|
|
252
|
-
const hasNgInvalid = this.el.classList.contains('ng-invalid');
|
|
253
|
-
// Return true if we have both touched and invalid states from either framework
|
|
254
|
-
const isTouched = hasIonTouched || hasNgTouched;
|
|
255
|
-
const isInvalid = hasIonInvalid || hasNgInvalid;
|
|
256
|
-
return isTouched && isInvalid;
|
|
257
|
-
}
|
|
258
226
|
connectedCallback() {
|
|
259
227
|
const { el } = this;
|
|
260
228
|
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate(this));
|
|
261
229
|
this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
|
|
262
|
-
// Watch for class changes to update validation state
|
|
263
|
-
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
264
|
-
this.validationObserver = new MutationObserver(() => {
|
|
265
|
-
const newIsInvalid = this.checkValidationState();
|
|
266
|
-
if (this.isInvalid !== newIsInvalid) {
|
|
267
|
-
this.isInvalid = newIsInvalid;
|
|
268
|
-
// Force a re-render to update aria-describedby immediately
|
|
269
|
-
forceUpdate(this);
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
this.validationObserver.observe(el, {
|
|
273
|
-
attributes: true,
|
|
274
|
-
attributeFilter: ['class'],
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
// Always set initial state
|
|
278
|
-
this.isInvalid = this.checkValidationState();
|
|
279
230
|
this.debounceChanged();
|
|
280
231
|
if (Build.isBrowser) {
|
|
281
232
|
document.dispatchEvent(new CustomEvent('ionInputDidLoad', {
|
|
@@ -312,11 +263,6 @@ export class Input {
|
|
|
312
263
|
this.notchController.destroy();
|
|
313
264
|
this.notchController = undefined;
|
|
314
265
|
}
|
|
315
|
-
// Clean up validation observer to prevent memory leaks
|
|
316
|
-
if (this.validationObserver) {
|
|
317
|
-
this.validationObserver.disconnect();
|
|
318
|
-
this.validationObserver = undefined;
|
|
319
|
-
}
|
|
320
266
|
}
|
|
321
267
|
/**
|
|
322
268
|
* Sets focus on the native `input` in `ion-input`. Use this method instead of the global
|
|
@@ -418,15 +364,15 @@ export class Input {
|
|
|
418
364
|
* Renders the helper text or error text values
|
|
419
365
|
*/
|
|
420
366
|
renderHintText() {
|
|
421
|
-
const { helperText, errorText, helperTextId, errorTextId
|
|
367
|
+
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
422
368
|
return [
|
|
423
|
-
|
|
424
|
-
|
|
369
|
+
h("div", { id: helperTextId, class: "helper-text" }, helperText),
|
|
370
|
+
h("div", { id: errorTextId, class: "error-text" }, errorText),
|
|
425
371
|
];
|
|
426
372
|
}
|
|
427
373
|
getHintTextID() {
|
|
428
|
-
const {
|
|
429
|
-
if (
|
|
374
|
+
const { el, helperText, errorText, helperTextId, errorTextId } = this;
|
|
375
|
+
if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
|
|
430
376
|
return errorTextId;
|
|
431
377
|
}
|
|
432
378
|
if (helperText) {
|
|
@@ -539,7 +485,7 @@ export class Input {
|
|
|
539
485
|
* TODO(FW-5592): Remove hasStartEndSlots condition
|
|
540
486
|
*/
|
|
541
487
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
|
|
542
|
-
return (h(Host, { key: '
|
|
488
|
+
return (h(Host, { key: '41b2526627e7d2773a80f011b123284203a71ca0', class: createColorClasses(this.color, {
|
|
543
489
|
[mode]: true,
|
|
544
490
|
'has-value': hasValue,
|
|
545
491
|
'has-focus': hasFocus,
|
|
@@ -550,14 +496,14 @@ export class Input {
|
|
|
550
496
|
'in-item': inItem,
|
|
551
497
|
'in-item-color': hostContext('ion-item.ion-color', this.el),
|
|
552
498
|
'input-disabled': disabled,
|
|
553
|
-
}) }, h("label", { key: '
|
|
499
|
+
}) }, h("label", { key: '9ab078363e32528102b441ad1791d83f86fdcbdc', class: "input-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), h("div", { key: 'e34b594980ec62e4c618e827fadf7669a39ad0d8', class: "native-wrapper", onClick: this.onLabelClick }, h("slot", { key: '12dc04ead5502e9e5736240e918bf9331bf7b5d9', name: "start" }), h("input", Object.assign({ key: 'df356eb4ced23109b2c0242f36dc043aba8782d6', 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.getHintTextID() === this.errorTextId }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (h("button", { key: 'f79f68cabcd4ea99419331174a377827db0c0741', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
|
|
554
500
|
/**
|
|
555
501
|
* This prevents mobile browsers from
|
|
556
502
|
* blurring the input when the clear
|
|
557
503
|
* button is activated.
|
|
558
504
|
*/
|
|
559
505
|
ev.preventDefault();
|
|
560
|
-
}, onClick: this.clearTextInput }, h("ion-icon", { key: '
|
|
506
|
+
}, onClick: this.clearTextInput }, h("ion-icon", { key: '237ec07ec2e10f08818a332bb596578c2c49f770', "aria-hidden": "true", icon: clearIconData }))), h("slot", { key: '1f0a3624aa3e8dc3c307a6762230ab698768a5e5', name: "end" })), shouldRenderHighlight && h("div", { key: '8a8cbb82695a722a0010b53dd0b1f1f97534a20b', class: "input-highlight" })), this.renderBottomContent()));
|
|
561
507
|
}
|
|
562
508
|
static get is() { return "ion-input"; }
|
|
563
509
|
static get encapsulation() { return "scoped"; }
|
|
@@ -1256,8 +1202,7 @@ export class Input {
|
|
|
1256
1202
|
}
|
|
1257
1203
|
static get states() {
|
|
1258
1204
|
return {
|
|
1259
|
-
"hasFocus": {}
|
|
1260
|
-
"isInvalid": {}
|
|
1205
|
+
"hasFocus": {}
|
|
1261
1206
|
};
|
|
1262
1207
|
}
|
|
1263
1208
|
static get events() {
|
|
@@ -293,6 +293,9 @@ export class Menu {
|
|
|
293
293
|
* @param role The role of the element that is closing the menu.
|
|
294
294
|
*/
|
|
295
295
|
setOpen(shouldOpen, animated = true, role) {
|
|
296
|
+
var _a;
|
|
297
|
+
// Blur the active element to prevent it from being kept focused inside an element that will be set with aria-hidden="true"
|
|
298
|
+
(_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.blur();
|
|
296
299
|
return menuController._setOpen(this, shouldOpen, animated, role);
|
|
297
300
|
}
|
|
298
301
|
trapKeyboardFocus(ev, doc) {
|
|
@@ -655,14 +658,14 @@ export class Menu {
|
|
|
655
658
|
* the ionBackButton listener in the menu controller
|
|
656
659
|
* will handle closing the menu when Escape is pressed.
|
|
657
660
|
*/
|
|
658
|
-
return (h(Host, { key: '
|
|
661
|
+
return (h(Host, { key: '70a427f3414a476414c3386efe6c8723fd37eccf', onKeyDown: shouldUseCloseWatcher() ? null : this.onKeydown, role: "navigation", "aria-label": inheritedAttributes['aria-label'] || 'menu', class: {
|
|
659
662
|
[mode]: true,
|
|
660
663
|
[`menu-type-${type}`]: true,
|
|
661
664
|
'menu-enabled': !disabled,
|
|
662
665
|
[`menu-side-${side}`]: true,
|
|
663
666
|
'menu-pane-visible': isPaneVisible,
|
|
664
667
|
'split-pane-side': hostContext('ion-split-pane', el),
|
|
665
|
-
} }, h("div", { key: '
|
|
668
|
+
} }, h("div", { key: '83af04e5a47d5a92caafaf06088a7114ae61984b', class: "menu-inner", part: "container", ref: (el) => (this.menuInnerEl = el) }, h("slot", { key: '7b35048642864bd0f30de9f6b61c949c1b601692' })), h("ion-backdrop", { key: '347af516c7970d80dd11c6d1ed61e9a040ceb5fb', ref: (el) => (this.backdropEl = el), class: "menu-backdrop", tappable: false, stopPropagation: false, part: "backdrop" })));
|
|
666
669
|
}
|
|
667
670
|
static get is() { return "ion-menu"; }
|
|
668
671
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1071,6 +1074,10 @@ export class Menu {
|
|
|
1071
1074
|
"Promise": {
|
|
1072
1075
|
"location": "global",
|
|
1073
1076
|
"id": "global::Promise"
|
|
1077
|
+
},
|
|
1078
|
+
"HTMLElement": {
|
|
1079
|
+
"location": "global",
|
|
1080
|
+
"id": "global::HTMLElement"
|
|
1074
1081
|
}
|
|
1075
1082
|
},
|
|
1076
1083
|
"return": "Promise<boolean>"
|
|
@@ -411,23 +411,6 @@ export class PickerColumn {
|
|
|
411
411
|
var _a;
|
|
412
412
|
return el ? (_a = el.getAttribute('aria-label')) !== null && _a !== void 0 ? _a : el.innerText : '';
|
|
413
413
|
};
|
|
414
|
-
/**
|
|
415
|
-
* Render an element that overlays the column. This element is for assistive
|
|
416
|
-
* tech to allow users to navigate the column up/down. This element should receive
|
|
417
|
-
* focus as it listens for synthesized keyboard events as required by the
|
|
418
|
-
* slider role: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/slider_role
|
|
419
|
-
*/
|
|
420
|
-
this.renderAssistiveFocusable = () => {
|
|
421
|
-
const { activeItem } = this;
|
|
422
|
-
const valueText = this.getOptionValueText(activeItem);
|
|
423
|
-
/**
|
|
424
|
-
* When using the picker, the valuetext provides important context that valuenow
|
|
425
|
-
* does not. Additionally, using non-zero valuemin/valuemax values can cause
|
|
426
|
-
* WebKit to incorrectly announce numeric valuetext values (such as a year
|
|
427
|
-
* like "2024") as percentages: https://bugs.webkit.org/show_bug.cgi?id=273126
|
|
428
|
-
*/
|
|
429
|
-
return (h("div", { ref: (el) => (this.assistiveFocusable = el), class: "assistive-focusable", role: "slider", tabindex: this.disabled ? undefined : 0, "aria-label": this.ariaLabel, "aria-valuemin": 0, "aria-valuemax": 0, "aria-valuenow": 0, "aria-valuetext": valueText, "aria-orientation": "vertical", onKeyDown: (ev) => this.onKeyDown(ev) }));
|
|
430
|
-
};
|
|
431
414
|
}
|
|
432
415
|
ariaLabelChanged(newValue) {
|
|
433
416
|
this.ariaLabel = newValue;
|
|
@@ -568,33 +551,14 @@ export class PickerColumn {
|
|
|
568
551
|
render() {
|
|
569
552
|
const { color, disabled, isActive, numericInput } = this;
|
|
570
553
|
const mode = getIonMode(this);
|
|
571
|
-
return (h(Host, { key: '
|
|
554
|
+
return (h(Host, { key: 'db903fd415f8a2d91994dececca481c1af8ba6a9', class: createColorClasses(color, {
|
|
572
555
|
[mode]: true,
|
|
573
556
|
['picker-column-active']: isActive,
|
|
574
557
|
['picker-column-numeric-input']: numericInput,
|
|
575
558
|
['picker-column-disabled']: disabled,
|
|
576
|
-
}) },
|
|
559
|
+
}) }, h("slot", { key: '02ce9e1dd7df91afcd50b06416552bcffb5dec98', name: "prefix" }), h("div", { key: '6dfd7d2429bec19244a6b1afb4448121963a031b', class: "picker-opts", ref: (el) => {
|
|
577
560
|
this.scrollEl = el;
|
|
578
|
-
},
|
|
579
|
-
/**
|
|
580
|
-
* When an element has an overlay scroll style and
|
|
581
|
-
* a fixed height, Firefox will focus the scrollable
|
|
582
|
-
* container if the content exceeds the container's
|
|
583
|
-
* dimensions.
|
|
584
|
-
*
|
|
585
|
-
* This causes keyboard navigation to focus to this
|
|
586
|
-
* element instead of going to the next element in
|
|
587
|
-
* the tab order.
|
|
588
|
-
*
|
|
589
|
-
* The desired behavior is for the user to be able to
|
|
590
|
-
* focus the assistive focusable element and tab to
|
|
591
|
-
* the next element in the tab order. Instead of tabbing
|
|
592
|
-
* to this element.
|
|
593
|
-
*
|
|
594
|
-
* To prevent this, we set the tabIndex to -1. This
|
|
595
|
-
* will match the behavior of the other browsers.
|
|
596
|
-
*/
|
|
597
|
-
tabIndex: -1 }, h("div", { key: '13a9ee686132af32240710730765de4c0003a9e8', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: 'dbccba4920833cfcebe9b0fc763458ec3053705a', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: '682b43f83a5ea2e46067457f3af118535e111edb', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("slot", { key: 'd27e1e1dc0504b2f4627a29912a05bb91e8e413a' }), h("div", { key: '61c948dbb9cf7469aed3018542bc0954211585ba', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: 'cf46c277fbee65e35ff44ce0d53ce12aa9cbf9db', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: 'bbc0e2d491d3f836ab849493ade2f7fa6ad9244e', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0")), h("slot", { key: 'd25cbbe14b2914fe7b878d43b4e3f4a8c8177d24', name: "suffix" })));
|
|
561
|
+
}, role: "slider", tabindex: this.disabled ? undefined : 0, "aria-label": this.ariaLabel, "aria-valuemin": 0, "aria-valuemax": 0, "aria-valuenow": 0, "aria-valuetext": this.getOptionValueText(this.activeItem), "aria-orientation": "vertical", onKeyDown: (ev) => this.onKeyDown(ev) }, h("div", { key: 'e30ce0b9cefbfe4d4441fa33acf595da31855c3f', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: '8be2bd293c12c6ba720d9b31d0d561a96f42e97d', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: '8afdcddddabbf646fbb55cb0ba4448309a2c1dd9', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("slot", { key: '6aa0dacc34d6848575ad5b122b9046982308ca43' }), h("div", { key: '92ec8a357414c1b779b11d1dd18fb87a7ee63982', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: 'b89457cb74b5907c25594ff6720ac54ca537e933', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), h("div", { key: '5bbc92e6bc24de08e39873bf08c5b668373ac0f8', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0")), h("slot", { key: 'd7bf2b519214f0f3576a4ca79844ad97827dd97f', name: "suffix" })));
|
|
598
562
|
}
|
|
599
563
|
static get is() { return "ion-picker-column"; }
|
|
600
564
|
static get encapsulation() { return "shadow"; }
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
* }
|
|
54
54
|
* }
|
|
55
55
|
*/
|
|
56
|
-
button {
|
|
56
|
+
.picker-column-option-button {
|
|
57
57
|
padding-left: 0;
|
|
58
58
|
padding-right: 0;
|
|
59
59
|
padding-top: 0;
|
|
@@ -82,6 +82,6 @@ button {
|
|
|
82
82
|
opacity: 0.4;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
:host(.option-disabled) button {
|
|
85
|
+
:host(.option-disabled) .picker-column-option-button {
|
|
86
86
|
cursor: default;
|
|
87
87
|
}
|
|
@@ -94,7 +94,7 @@ export class PickerColumnOption {
|
|
|
94
94
|
return (h(Host, { key: 'f816729941aabcb31ddfdce3ffe2e2139030d715', class: createColorClasses(color, {
|
|
95
95
|
[mode]: true,
|
|
96
96
|
['option-disabled']: disabled,
|
|
97
|
-
}) }, h("
|
|
97
|
+
}) }, h("div", { key: 'd942de84fd14d7dc06b1e5cf4f7920d1dc3c6371', class: 'picker-column-option-button', role: "button", "aria-label": ariaLabel, onClick: () => this.onClick() }, h("slot", { key: 'b0df5717b42209e649097209a01476e1a66f5c5c' }))));
|
|
98
98
|
}
|
|
99
99
|
static get is() { return "ion-picker-column-option"; }
|
|
100
100
|
static get encapsulation() { return "shadow"; }
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
* }
|
|
54
54
|
* }
|
|
55
55
|
*/
|
|
56
|
-
button {
|
|
56
|
+
.picker-column-option-button {
|
|
57
57
|
padding-left: 0;
|
|
58
58
|
padding-right: 0;
|
|
59
59
|
padding-top: 0;
|
|
@@ -82,7 +82,7 @@ button {
|
|
|
82
82
|
opacity: 0.4;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
:host(.option-disabled) button {
|
|
85
|
+
:host(.option-disabled) .picker-column-option-button {
|
|
86
86
|
cursor: default;
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -37,10 +37,6 @@ export class Textarea {
|
|
|
37
37
|
* is applied in both cases.
|
|
38
38
|
*/
|
|
39
39
|
this.hasFocus = false;
|
|
40
|
-
/**
|
|
41
|
-
* Track validation state for proper aria-live announcements
|
|
42
|
-
*/
|
|
43
|
-
this.isInvalid = false;
|
|
44
40
|
/**
|
|
45
41
|
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
|
|
46
42
|
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
|
@@ -130,19 +126,6 @@ export class Textarea {
|
|
|
130
126
|
}
|
|
131
127
|
this.didTextareaClearOnEdit = false;
|
|
132
128
|
this.ionBlur.emit(ev);
|
|
133
|
-
/**
|
|
134
|
-
* Check validation state after blur to handle framework-managed classes.
|
|
135
|
-
* Frameworks like Angular update classes asynchronously, often using
|
|
136
|
-
* requestAnimationFrame or promises. Using setTimeout ensures we check
|
|
137
|
-
* after all microtasks and animation frames have completed.
|
|
138
|
-
*/
|
|
139
|
-
setTimeout(() => {
|
|
140
|
-
const newIsInvalid = this.checkValidationState();
|
|
141
|
-
if (this.isInvalid !== newIsInvalid) {
|
|
142
|
-
this.isInvalid = newIsInvalid;
|
|
143
|
-
forceUpdate(this);
|
|
144
|
-
}
|
|
145
|
-
}, 100);
|
|
146
129
|
};
|
|
147
130
|
this.onKeyDown = (ev) => {
|
|
148
131
|
this.checkClearOnEdit(ev);
|
|
@@ -200,42 +183,10 @@ export class Textarea {
|
|
|
200
183
|
this.el.click();
|
|
201
184
|
}
|
|
202
185
|
}
|
|
203
|
-
/**
|
|
204
|
-
* Checks if the textarea is in an invalid state based on validation classes
|
|
205
|
-
*/
|
|
206
|
-
checkValidationState() {
|
|
207
|
-
// Check for both Ionic and Angular validation classes on the element itself
|
|
208
|
-
// Angular applies ng-touched/ng-invalid directly to the host element with ngModel
|
|
209
|
-
const hasIonTouched = this.el.classList.contains('ion-touched');
|
|
210
|
-
const hasIonInvalid = this.el.classList.contains('ion-invalid');
|
|
211
|
-
const hasNgTouched = this.el.classList.contains('ng-touched');
|
|
212
|
-
const hasNgInvalid = this.el.classList.contains('ng-invalid');
|
|
213
|
-
// Return true if we have both touched and invalid states from either framework
|
|
214
|
-
const isTouched = hasIonTouched || hasNgTouched;
|
|
215
|
-
const isInvalid = hasIonInvalid || hasNgInvalid;
|
|
216
|
-
return isTouched && isInvalid;
|
|
217
|
-
}
|
|
218
186
|
connectedCallback() {
|
|
219
187
|
const { el } = this;
|
|
220
188
|
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate(this));
|
|
221
189
|
this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
|
|
222
|
-
// Watch for class changes to update validation state
|
|
223
|
-
if (Build.isBrowser && typeof MutationObserver !== 'undefined') {
|
|
224
|
-
this.validationObserver = new MutationObserver(() => {
|
|
225
|
-
const newIsInvalid = this.checkValidationState();
|
|
226
|
-
if (this.isInvalid !== newIsInvalid) {
|
|
227
|
-
this.isInvalid = newIsInvalid;
|
|
228
|
-
// Force a re-render to update aria-describedby immediately
|
|
229
|
-
forceUpdate(this);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
this.validationObserver.observe(el, {
|
|
233
|
-
attributes: true,
|
|
234
|
-
attributeFilter: ['class'],
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
// Always set initial state
|
|
238
|
-
this.isInvalid = this.checkValidationState();
|
|
239
190
|
this.debounceChanged();
|
|
240
191
|
if (Build.isBrowser) {
|
|
241
192
|
document.dispatchEvent(new CustomEvent('ionInputDidLoad', {
|
|
@@ -257,11 +208,6 @@ export class Textarea {
|
|
|
257
208
|
this.notchController.destroy();
|
|
258
209
|
this.notchController = undefined;
|
|
259
210
|
}
|
|
260
|
-
// Clean up validation observer to prevent memory leaks
|
|
261
|
-
if (this.validationObserver) {
|
|
262
|
-
this.validationObserver.disconnect();
|
|
263
|
-
this.validationObserver = undefined;
|
|
264
|
-
}
|
|
265
211
|
}
|
|
266
212
|
componentWillLoad() {
|
|
267
213
|
this.inheritedAttributes = Object.assign(Object.assign({}, inheritAriaAttributes(this.el)), inheritAttributes(this.el, ['data-form-type', 'title', 'tabindex', 'dir']));
|
|
@@ -432,15 +378,15 @@ export class Textarea {
|
|
|
432
378
|
* Renders the helper text or error text values
|
|
433
379
|
*/
|
|
434
380
|
renderHintText() {
|
|
435
|
-
const { helperText, errorText, helperTextId, errorTextId
|
|
381
|
+
const { helperText, errorText, helperTextId, errorTextId } = this;
|
|
436
382
|
return [
|
|
437
|
-
|
|
438
|
-
|
|
383
|
+
h("div", { id: helperTextId, class: "helper-text" }, helperText),
|
|
384
|
+
h("div", { id: errorTextId, class: "error-text" }, errorText),
|
|
439
385
|
];
|
|
440
386
|
}
|
|
441
387
|
getHintTextID() {
|
|
442
|
-
const {
|
|
443
|
-
if (
|
|
388
|
+
const { el, helperText, errorText, helperTextId, errorTextId } = this;
|
|
389
|
+
if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
|
|
444
390
|
return errorTextId;
|
|
445
391
|
}
|
|
446
392
|
if (helperText) {
|
|
@@ -499,7 +445,7 @@ export class Textarea {
|
|
|
499
445
|
* TODO(FW-5592): Remove hasStartEndSlots condition
|
|
500
446
|
*/
|
|
501
447
|
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
|
|
502
|
-
return (h(Host, { key: '
|
|
448
|
+
return (h(Host, { key: 'd9f2ede0107987fc42c99e310cd2336bad5a5755', class: createColorClasses(this.color, {
|
|
503
449
|
[mode]: true,
|
|
504
450
|
'has-value': hasValue,
|
|
505
451
|
'has-focus': hasFocus,
|
|
@@ -508,7 +454,7 @@ export class Textarea {
|
|
|
508
454
|
[`textarea-shape-${shape}`]: shape !== undefined,
|
|
509
455
|
[`textarea-label-placement-${labelPlacement}`]: true,
|
|
510
456
|
'textarea-disabled': disabled,
|
|
511
|
-
}) }, h("label", { key: '
|
|
457
|
+
}) }, h("label", { key: '9de598b95237462bb3bccffaefe83afbb43554b8', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), h("div", { key: 'e33c426c6541d723ccc246bb404c03687726ff83', class: "textarea-wrapper-inner" }, h("div", { key: '521e11af9d54d281b0a2b1c25bcfc6f742c18296', class: "start-slot-wrapper" }, h("slot", { key: '515523f6ca3ce0e5dd08f3275c21a190fb1ca177', name: "start" })), h("div", { key: '916e01e00de8400ae00ef06bc1fb62d8be2eee08', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, h("textarea", Object.assign({ key: '810271e6532d90e27dab1fcb26546113c1ce9cb0', 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.getHintTextID() === this.errorTextId }, this.inheritedAttributes), value)), h("div", { key: '80aca9ea9546dca9d38efd291a6b0be384bb6978', class: "end-slot-wrapper" }, h("slot", { key: '407fab16c66a9f4a542369bfecc0d9afa0065977', name: "end" }))), shouldRenderHighlight && h("div", { key: 'f00523a6698fac8a1996e04303487bef01d10f25', class: "textarea-highlight" })), this.renderBottomContent()));
|
|
512
458
|
}
|
|
513
459
|
static get is() { return "ion-textarea"; }
|
|
514
460
|
static get encapsulation() { return "scoped"; }
|
|
@@ -1079,8 +1025,7 @@ export class Textarea {
|
|
|
1079
1025
|
}
|
|
1080
1026
|
static get states() {
|
|
1081
1027
|
return {
|
|
1082
|
-
"hasFocus": {}
|
|
1083
|
-
"isInvalid": {}
|
|
1028
|
+
"hasFocus": {}
|
|
1084
1029
|
};
|
|
1085
1030
|
}
|
|
1086
1031
|
static get events() {
|