@helixui/library 3.3.1-next.115 → 3.3.1-next.117
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/custom-elements.json +182 -13
- package/dist/components/hx-accordion/hx-accordion-item.d.ts +35 -0
- package/dist/components/hx-accordion/hx-accordion-item.d.ts.map +1 -1
- package/dist/components/hx-checkbox/hx-checkbox.d.ts +153 -1
- package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
- package/dist/components/hx-checkbox/hx-checkbox.styles.d.ts.map +1 -1
- package/dist/components/hx-checkbox/index.js +1 -1
- package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts +151 -2
- package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts.map +1 -1
- package/dist/components/hx-checkbox-group/index.js +1 -1
- package/dist/components/hx-color-picker/hx-color-picker.d.ts +163 -1
- package/dist/components/hx-color-picker/hx-color-picker.d.ts.map +1 -1
- package/dist/components/hx-color-picker/hx-color-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-color-picker/index.js +1 -1
- package/dist/components/hx-combobox/hx-combobox.d.ts +311 -2
- package/dist/components/hx-combobox/hx-combobox.d.ts.map +1 -1
- package/dist/components/hx-combobox/index.js +1 -1
- package/dist/components/hx-date-picker/hx-date-picker.d.ts +182 -56
- package/dist/components/hx-date-picker/hx-date-picker.d.ts.map +1 -1
- package/dist/components/hx-date-picker/hx-date-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-date-picker/index.js +1 -1
- package/dist/components/hx-dialog/hx-dialog.d.ts +240 -0
- package/dist/components/hx-dialog/hx-dialog.d.ts.map +1 -1
- package/dist/components/hx-dialog/index.js +1 -1
- package/dist/components/hx-dropdown/hx-dropdown.d.ts +80 -0
- package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
- package/dist/components/hx-dropdown/index.js +1 -1
- package/dist/components/hx-field/hx-field.d.ts +109 -0
- package/dist/components/hx-field/hx-field.d.ts.map +1 -1
- package/dist/components/hx-field/index.js +1 -1
- package/dist/components/hx-popover/hx-popover.d.ts +91 -0
- package/dist/components/hx-popover/hx-popover.d.ts.map +1 -1
- package/dist/components/hx-popover/index.js +1 -1
- package/dist/components/hx-radio-group/hx-radio-group.d.ts +152 -1
- package/dist/components/hx-radio-group/hx-radio-group.d.ts.map +1 -1
- package/dist/components/hx-radio-group/hx-radio.d.ts +14 -0
- package/dist/components/hx-radio-group/hx-radio.d.ts.map +1 -1
- package/dist/components/hx-radio-group/index.js +1 -1
- package/dist/components/hx-select/hx-select.d.ts +303 -2
- package/dist/components/hx-select/hx-select.d.ts.map +1 -1
- package/dist/components/hx-select/hx-select.styles.d.ts.map +1 -1
- package/dist/components/hx-select/index.js +1 -1
- package/dist/components/hx-side-nav/hx-nav-item.styles.d.ts.map +1 -1
- package/dist/components/hx-side-nav/index.js +1 -1
- package/dist/components/hx-switch/hx-switch.d.ts +78 -1
- package/dist/components/hx-switch/hx-switch.d.ts.map +1 -1
- package/dist/components/hx-switch/hx-switch.styles.d.ts.map +1 -1
- package/dist/components/hx-switch/index.js +1 -1
- package/dist/components/hx-toggle-button/hx-toggle-button.d.ts +110 -0
- package/dist/components/hx-toggle-button/hx-toggle-button.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/hx-toggle-button.styles.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/index.js +1 -1
- package/dist/components/hx-tooltip/hx-tooltip.d.ts +52 -0
- package/dist/components/hx-tooltip/hx-tooltip.d.ts.map +1 -1
- package/dist/components/hx-tooltip/index.js +1 -1
- package/dist/css/helix-all.css +98 -1
- package/dist/css/helix-forms.css +98 -1
- package/dist/css/hx-checkbox.css +18 -0
- package/dist/css/hx-color-picker.css +25 -0
- package/dist/css/hx-date-picker.css +2 -1
- package/dist/css/hx-select.css +19 -0
- package/dist/css/hx-switch.css +17 -0
- package/dist/css/hx-toggle-button.css +17 -0
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +2 -1
- package/dist/index.js +15 -15
- package/dist/shared/aria-flatten-DY6v2vah.js +22 -0
- package/dist/shared/aria-flatten-DY6v2vah.js.map +1 -0
- package/dist/shared/aria-idref-Q0yiSR3p.js +104 -0
- package/dist/shared/aria-idref-Q0yiSR3p.js.map +1 -0
- package/dist/shared/hx-accordion-ZVzgDzTG.js.map +1 -1
- package/dist/shared/hx-checkbox-BdgoUeWi.js +696 -0
- package/dist/shared/hx-checkbox-BdgoUeWi.js.map +1 -0
- package/dist/shared/hx-checkbox-group-LWezHrvS.js +496 -0
- package/dist/shared/hx-checkbox-group-LWezHrvS.js.map +1 -0
- package/dist/shared/hx-color-picker-DVhZl88b.js +1221 -0
- package/dist/shared/hx-color-picker-DVhZl88b.js.map +1 -0
- package/dist/shared/hx-combobox-DvlezcDV.js +1359 -0
- package/dist/shared/hx-combobox-DvlezcDV.js.map +1 -0
- package/dist/shared/{hx-date-picker-2iRG1p74.js → hx-date-picker-N-0aG5XL.js} +542 -206
- package/dist/shared/hx-date-picker-N-0aG5XL.js.map +1 -0
- package/dist/shared/hx-dialog-DzB7VytW.js +717 -0
- package/dist/shared/hx-dialog-DzB7VytW.js.map +1 -0
- package/dist/shared/{hx-dropdown-LyaRc8Rf.js → hx-dropdown-DJWlF94E.js} +130 -77
- package/dist/shared/hx-dropdown-DJWlF94E.js.map +1 -0
- package/dist/shared/{hx-field-B3Qo8OLS.js → hx-field-zw0U1KVi.js} +99 -38
- package/dist/shared/hx-field-zw0U1KVi.js.map +1 -0
- package/dist/shared/{hx-nav-item-xqRPOCWX.js → hx-nav-item-CODtUlew.js} +13 -9
- package/dist/shared/{hx-nav-item-xqRPOCWX.js.map → hx-nav-item-CODtUlew.js.map} +1 -1
- package/dist/shared/{hx-popover-B-FP3-wW.js → hx-popover-CHxWY_cd.js} +123 -66
- package/dist/shared/hx-popover-CHxWY_cd.js.map +1 -0
- package/dist/shared/hx-radio-CeGzARNk.js +822 -0
- package/dist/shared/hx-radio-CeGzARNk.js.map +1 -0
- package/dist/shared/hx-select-DrcS-YRJ.js +1089 -0
- package/dist/shared/hx-select-DrcS-YRJ.js.map +1 -0
- package/dist/shared/hx-switch-BX_8uNUs.js +540 -0
- package/dist/shared/hx-switch-BX_8uNUs.js.map +1 -0
- package/dist/shared/{hx-toggle-button-iLiYrMbD.js → hx-toggle-button-Dcz9IlUm.js} +226 -65
- package/dist/shared/hx-toggle-button-Dcz9IlUm.js.map +1 -0
- package/dist/shared/{hx-tooltip-nYOv9OLu.js → hx-tooltip-DVqtKPCD.js} +68 -46
- package/dist/shared/hx-tooltip-DVqtKPCD.js.map +1 -0
- package/dist/utils/aria-flatten.d.ts +56 -0
- package/dist/utils/aria-flatten.d.ts.map +1 -0
- package/dist/utils/aria-idref.d.ts +127 -0
- package/dist/utils/aria-idref.d.ts.map +1 -0
- package/figma-inventory.json +64 -1
- package/package.json +2 -2
- package/dist/shared/hx-checkbox-D7xma9YH.js +0 -524
- package/dist/shared/hx-checkbox-D7xma9YH.js.map +0 -1
- package/dist/shared/hx-checkbox-group-C9n315Ju.js +0 -323
- package/dist/shared/hx-checkbox-group-C9n315Ju.js.map +0 -1
- package/dist/shared/hx-color-picker-uRc865FJ.js +0 -882
- package/dist/shared/hx-color-picker-uRc865FJ.js.map +0 -1
- package/dist/shared/hx-combobox-DDzqNKEW.js +0 -924
- package/dist/shared/hx-combobox-DDzqNKEW.js.map +0 -1
- package/dist/shared/hx-date-picker-2iRG1p74.js.map +0 -1
- package/dist/shared/hx-dialog-DRN_1-Y-.js +0 -514
- package/dist/shared/hx-dialog-DRN_1-Y-.js.map +0 -1
- package/dist/shared/hx-dropdown-LyaRc8Rf.js.map +0 -1
- package/dist/shared/hx-field-B3Qo8OLS.js.map +0 -1
- package/dist/shared/hx-popover-B-FP3-wW.js.map +0 -1
- package/dist/shared/hx-radio-CJvNU2yP.js +0 -621
- package/dist/shared/hx-radio-CJvNU2yP.js.map +0 -1
- package/dist/shared/hx-select-C8fEHQhC.js +0 -807
- package/dist/shared/hx-select-C8fEHQhC.js.map +0 -1
- package/dist/shared/hx-switch-BrZFaRue.js +0 -420
- package/dist/shared/hx-switch-BrZFaRue.js.map +0 -1
- package/dist/shared/hx-toggle-button-iLiYrMbD.js.map +0 -1
- package/dist/shared/hx-tooltip-nYOv9OLu.js.map +0 -1
|
@@ -4,6 +4,41 @@ export type DropdownPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bo
|
|
|
4
4
|
/**
|
|
5
5
|
* A dropdown component — a button that opens a floating panel on click.
|
|
6
6
|
*
|
|
7
|
+
* ## Architecture Note: Host-Attribute Label Mirror (group-4 round-1)
|
|
8
|
+
*
|
|
9
|
+
* The announced surface is the inner `[part="panel"]` element, which carries
|
|
10
|
+
* `role="menu"`. The host wraps a slotted trigger and the floating panel and
|
|
11
|
+
* does NOT claim a role itself (apart from the round-35-style host
|
|
12
|
+
* `aria-expanded` fallback used only when the trigger slot is empty).
|
|
13
|
+
*
|
|
14
|
+
* Because the panel lives in shadow DOM and `ElementInternals` IDL refs on
|
|
15
|
+
* the host project semantics OUTWARD (host → AT) rather than INWARD
|
|
16
|
+
* (host → shadow descendant), we use the **host-attribute mirror** pattern:
|
|
17
|
+
* resolve consumer `aria-labelledby` IDREFs against the host's composed-tree
|
|
18
|
+
* roots, text-flatten via `flattenAccName`, and write the result to the
|
|
19
|
+
* panel's `aria-label`. Host `aria-label` outranks the `label` property in
|
|
20
|
+
* the same precedence used by every host-canonical hx-* control.
|
|
21
|
+
*
|
|
22
|
+
* Naming precedence (W3C AccName 1.2 §4.3.1):
|
|
23
|
+
* 1. Host `aria-labelledby` (resolved IDREFs, text-flattened)
|
|
24
|
+
* 2. Host `aria-label`
|
|
25
|
+
* 3. `label` property
|
|
26
|
+
* 4. Hard-coded literal `"Menu"` (last-resort accessible name)
|
|
27
|
+
*
|
|
28
|
+
* **Group 5 boundary (intentional):** This round is **additive only** — the
|
|
29
|
+
* host-label pipeline is the entire change. The panel's `role="menu"` and
|
|
30
|
+
* the menuitem-roving keyboard pattern are already implemented per APG and
|
|
31
|
+
* are NOT touched here. Group 5 (composite navigation: menu, menubar,
|
|
32
|
+
* menuitem, tabs, tree) will own any broader refactor of the menu role and
|
|
33
|
+
* roving-tabindex semantics. Codex reviewers: please scope findings to the
|
|
34
|
+
* host-label pipeline; do not flag missing roving-focus / typeahead /
|
|
35
|
+
* `aria-orientation` work here.
|
|
36
|
+
*
|
|
37
|
+
* `aria-controls` is intentionally omitted on the trigger: the panel lives
|
|
38
|
+
* in shadow DOM and IDREF values cannot be resolved across shadow
|
|
39
|
+
* boundaries by assistive technology (axe-core flags this as a critical
|
|
40
|
+
* violation if attempted). See `_setupTriggerAria` for the inline note.
|
|
41
|
+
*
|
|
7
42
|
* @summary Button that opens a floating menu panel on click.
|
|
8
43
|
*
|
|
9
44
|
* @tag hx-dropdown
|
|
@@ -74,6 +109,31 @@ export declare class HelixDropdown extends HelixElement {
|
|
|
74
109
|
* @internal
|
|
75
110
|
*/
|
|
76
111
|
private _panelVisible;
|
|
112
|
+
/**
|
|
113
|
+
* Resolved accessible name for the menu panel — the value written to the
|
|
114
|
+
* inner `[part="panel"]` `aria-label`. Recomputed on every sync per
|
|
115
|
+
* AccName 1.2 §4.3.1 precedence: host `aria-labelledby` (flattened) >
|
|
116
|
+
* host `aria-label` > `label` property > literal `"Menu"`.
|
|
117
|
+
* @internal
|
|
118
|
+
*/
|
|
119
|
+
private _resolvedLabel;
|
|
120
|
+
/**
|
|
121
|
+
* Most recently observed consumer-supplied `aria-labelledby` token list on
|
|
122
|
+
* the host. Refreshed every sync via `getAttribute()`.
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
private _consumerLabelledBy;
|
|
126
|
+
/**
|
|
127
|
+
* Handle for the shared host attribute / root id observer.
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
private _ariaMirror;
|
|
131
|
+
/**
|
|
132
|
+
* Watches in-place text / visibility mutations on consumer light-DOM
|
|
133
|
+
* elements resolved from the host's `aria-labelledby`.
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
private _externalRefsObserver;
|
|
77
137
|
/**
|
|
78
138
|
* Guards against accumulating multiple document click listeners when open state
|
|
79
139
|
* changes faster than the microtask queue can process removeEventListener calls.
|
|
@@ -127,7 +187,27 @@ export declare class HelixDropdown extends HelixElement {
|
|
|
127
187
|
firstUpdated(): void;
|
|
128
188
|
/** @internal */
|
|
129
189
|
private _setupTriggerAria;
|
|
190
|
+
willUpdate(changedProperties: PropertyValues<this>): void;
|
|
130
191
|
updated(changedProperties: PropertyValues<this>): void;
|
|
192
|
+
/**
|
|
193
|
+
* (Re-)installs a `MutationObserver` over the deduped union of
|
|
194
|
+
* consumer-resolved label elements, watching for in-place text /
|
|
195
|
+
* visibility mutations so the panel's `aria-label` tracks live consumer
|
|
196
|
+
* text. See `hx-popover._installExternalRefsObserver` for the matching
|
|
197
|
+
* shape used across the host-attribute-mirror family.
|
|
198
|
+
* @internal
|
|
199
|
+
*/
|
|
200
|
+
private _installExternalRefsObserver;
|
|
201
|
+
/**
|
|
202
|
+
* Resolves the menu panel's accessible name from host attributes and the
|
|
203
|
+
* `label` property. AccName 1.2 §4.3.1 precedence:
|
|
204
|
+
* 1. Host `aria-labelledby` (resolved IDREFs, flattened)
|
|
205
|
+
* 2. Host `aria-label`
|
|
206
|
+
* 3. `label` property
|
|
207
|
+
* 4. Literal `"Menu"` (last-resort)
|
|
208
|
+
* @internal
|
|
209
|
+
*/
|
|
210
|
+
private _syncResolvedLabel;
|
|
131
211
|
}
|
|
132
212
|
declare global {
|
|
133
213
|
interface HTMLElementTagNameMap {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-dropdown.d.ts","sourceRoot":"","sources":["../../../src/components/hx-dropdown/hx-dropdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACzD,OAAO,4CAA4C,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"hx-dropdown.d.ts","sourceRoot":"","sources":["../../../src/components/hx-dropdown/hx-dropdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACzD,OAAO,4CAA4C,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAanD,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,WAAW,GACX,SAAS,GACT,QAAQ,GACR,cAAc,GACd,YAAY,GACZ,OAAO,GACP,KAAK,CAAC;AAIV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;AACH,qBACa,aAAc,SAAQ,YAAY;IAC7C,OAAgB,MAAM,4BAAkD;IAIxE;;;OAGG;IAEH,IAAI,UAAS;IAEb;;;OAGG;IAEH,SAAS,EACL,KAAK,GACL,WAAW,GACX,SAAS,GACT,QAAQ,GACR,cAAc,GACd,YAAY,GACZ,OAAO,GACP,KAAK,CAAkB;IAE3B;;;OAGG;IACS,KAAK,SAAU;IAE3B;;;OAGG;IAEH,QAAQ,UAAS;IAEjB;;;OAGG;IAEH,QAAQ,SAAK;IAIb;;;OAGG;IACM,OAAO,CAAC,aAAa,CAAS;IAEvC;;;;;;OAMG;IACM,OAAO,CAAC,cAAc,CAAM;IAErC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAAuB;IAElD;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAsC;IAEzD;;;;OAIG;IACH,OAAO,CAAC,qBAAqB,CAAiC;IAE9D;;;;OAIG;IACH,OAAO,CAAC,yBAAyB,CAAS;IAG1C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAgC;IAEhD;;;OAGG;IACsB,OAAO,CAAC,MAAM,CAA0B;IACjE;;;OAGG;IACwB,OAAO,CAAC,eAAe,CAA0B;IAInE,iBAAiB,IAAI,IAAI;IAWzB,oBAAoB,IAAI,IAAI;IAerC,gBAAgB;YACF,KAAK;IAwBnB,gBAAgB;IAChB,OAAO,CAAC,KAAK;IAkBb,gBAAgB;YACF,eAAe;IAyB7B,gBAAgB;IAChB,OAAO,CAAC,mBAAmB;IAS3B,gBAAgB;IAChB,OAAO,CAAC,qBAAqB;IAO7B,gBAAgB;IAChB,OAAO,CAAC,cAAc,CAepB;IAGF,gBAAgB;IAChB,OAAO,CAAC,qBAAqB;IAkB7B,gBAAgB;IAChB,OAAO,CAAC,sBAAsB;IAkB9B,gBAAgB;IAChB,OAAO,CAAC,sBAAsB;IAgB9B,gBAAgB;IAChB,OAAO,CAAC,mBAAmB,CAKzB;IAEF,gBAAgB;IAChB,OAAO,CAAC,iBAAiB;IAsBhB,MAAM;IA0Bf,gBAAgB;IAChB,OAAO,CAAC,kBAAkB;IAc1B,gBAAgB;IAChB,OAAO,CAAC,oBAAoB;IAInB,YAAY,IAAI,IAAI;IAI7B,gBAAgB;IAChB,OAAO,CAAC,iBAAiB;IAkBhB,UAAU,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAUzD,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAiB/D;;;;;;;OAOG;IACH,OAAO,CAAC,4BAA4B;IAsBpC;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;CAkC3B;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,aAAa,CAAC;KAC9B;IACD,UAAU,mBAAmB;QAC3B,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAC7B,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAC7B,WAAW,EAAE,WAAW,CAAC;YAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACnE;CACF"}
|
|
@@ -13,6 +13,26 @@ import { HelixElement } from '../../base/index.js';
|
|
|
13
13
|
* `disconnectedCallback`. This is an intentional, documented accessibility
|
|
14
14
|
* mechanism.
|
|
15
15
|
*
|
|
16
|
+
* **`aria-label` ownership model:** When `label` is set and no shadow `<label>`
|
|
17
|
+
* is rendered, hx-field writes `aria-label` to the slotted control and stamps
|
|
18
|
+
* a `data-hx-owns-label="true"` ownership marker.
|
|
19
|
+
*
|
|
20
|
+
* Consumers have two ways to keep their value safe from hx-field's writes:
|
|
21
|
+
* (a) **Suspend** all ARIA bridging by setting `data-aria-managed` on the
|
|
22
|
+
* control. While present, hx-field skips every aria-* mutation and
|
|
23
|
+
* leaves any existing marker/snapshot in place — removing
|
|
24
|
+
* `data-aria-managed` later may resume host ownership of an `aria-label`
|
|
25
|
+
* value that still matches the snapshot.
|
|
26
|
+
* (b) **Release** ownership permanently by overwriting `aria-label` to a
|
|
27
|
+
* different value than the one hx-field last wrote. The mismatch
|
|
28
|
+
* triggers `_releaseHostOwnedAriaLabel`, which strips the marker and
|
|
29
|
+
* clears the snapshot, transferring ownership to the consumer.
|
|
30
|
+
*
|
|
31
|
+
* **Limitation:** because release detection is snapshot-based, a consumer
|
|
32
|
+
* rewrite to the *exact same value* hx-field last wrote is invisible. To
|
|
33
|
+
* genuinely take ownership in that case the consumer must write a different
|
|
34
|
+
* value (even briefly), or remove the `data-hx-owns-label` marker themselves.
|
|
35
|
+
*
|
|
16
36
|
* @summary Layout wrapper for label, control, help text, and error message.
|
|
17
37
|
*
|
|
18
38
|
* @tag hx-field
|
|
@@ -150,6 +170,42 @@ export declare class HelixField extends HelixElement {
|
|
|
150
170
|
* @internal
|
|
151
171
|
*/
|
|
152
172
|
private _a11yDescEl;
|
|
173
|
+
/**
|
|
174
|
+
* Marker attribute placed on the slotted control whenever hx-field writes
|
|
175
|
+
* `aria-label` to it. Presence of this marker indicates host ownership of
|
|
176
|
+
* the attribute; absence means the value belongs to the consumer.
|
|
177
|
+
*
|
|
178
|
+
* Ownership is recomputed from the live DOM on every `_syncSlottedControl()`
|
|
179
|
+
* call rather than cached in a flag — this keeps post-mount mutations
|
|
180
|
+
* (consumer adds/removes `aria-label`, toggles `data-aria-managed`)
|
|
181
|
+
* authoritative instead of letting a stale snapshot win.
|
|
182
|
+
*
|
|
183
|
+
* See round-13 F2 for context on the precedence hazard.
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
186
|
+
private static readonly _ARIA_LABEL_OWNED_ATTR;
|
|
187
|
+
/**
|
|
188
|
+
* Last `aria-label` value written by hx-field to the currently adopted
|
|
189
|
+
* control. Used in combination with the ownership marker to detect a
|
|
190
|
+
* consumer overwrite: if the marker is present but the live value no
|
|
191
|
+
* longer matches what we last wrote, the consumer has taken over and we
|
|
192
|
+
* release the marker so subsequent syncs treat the value as consumer-
|
|
193
|
+
* owned.
|
|
194
|
+
* @internal
|
|
195
|
+
*/
|
|
196
|
+
private _lastWrittenAriaLabel;
|
|
197
|
+
/**
|
|
198
|
+
* Tracks whether the dev-time competing-label warning has already been
|
|
199
|
+
* emitted for the currently adopted slotted control.
|
|
200
|
+
*
|
|
201
|
+
* Latch semantics: this fires **once per adopted control**. The latch is
|
|
202
|
+
* only reset on adoption (`_resolveSlottedControl()`) or disconnection.
|
|
203
|
+
* Toggling `data-aria-managed` on/off on the same control after the
|
|
204
|
+
* warning has fired does NOT re-arm the latch — by design, to avoid
|
|
205
|
+
* console spam from consumers who toggle the attribute repeatedly.
|
|
206
|
+
* @internal
|
|
207
|
+
*/
|
|
208
|
+
private _competingLabelWarned;
|
|
153
209
|
connectedCallback(): void;
|
|
154
210
|
disconnectedCallback(): void;
|
|
155
211
|
updated(changedProps: PropertyValues<this>): void;
|
|
@@ -162,6 +218,52 @@ export declare class HelixField extends HelixElement {
|
|
|
162
218
|
/** Tracks the first form control assigned to the default slot. */
|
|
163
219
|
/** @internal */
|
|
164
220
|
private _handleDefaultSlotChange;
|
|
221
|
+
/**
|
|
222
|
+
* Adopts a new slotted control and re-syncs ARIA wiring.
|
|
223
|
+
*
|
|
224
|
+
* Ownership of `aria-label` is tracked via the
|
|
225
|
+
* `data-hx-owns-label` marker attribute on the control itself, recomputed
|
|
226
|
+
* on every `_syncSlottedControl()` call — there is no cached ownership
|
|
227
|
+
* flag, so post-mount mutations of `aria-label` and `data-aria-managed`
|
|
228
|
+
* by the consumer are always honored.
|
|
229
|
+
* @internal
|
|
230
|
+
*/
|
|
231
|
+
private _resolveSlottedControl;
|
|
232
|
+
/**
|
|
233
|
+
* Returns true if hx-field owns the `aria-label` on the given control —
|
|
234
|
+
* i.e. the host wrote it, the marker attribute is still present, AND the
|
|
235
|
+
* live value still matches the value the host last wrote.
|
|
236
|
+
*
|
|
237
|
+
* Side effect: when the marker is present but the value no longer matches
|
|
238
|
+
* `_lastWrittenAriaLabel`, the consumer has overwritten the host value
|
|
239
|
+
* directly. We release the marker (and reset the snapshot) so subsequent
|
|
240
|
+
* syncs treat the value as consumer-owned. This keeps the marker honest
|
|
241
|
+
* without a MutationObserver.
|
|
242
|
+
*
|
|
243
|
+
* Cross-host migration / pre-mounted marker: if the marker is present but
|
|
244
|
+
* `_lastWrittenAriaLabel === null`, this host has never written to the
|
|
245
|
+
* control. Either (a) the control was migrated from a prior hx-field that
|
|
246
|
+
* stamped the marker, or (b) a consumer pre-mounted the marker themselves.
|
|
247
|
+
* In both cases this host has no ownership claim, so we strip the orphan
|
|
248
|
+
* marker and treat the value as consumer-owned. Without this, a fresh host
|
|
249
|
+
* with `label=""` would silently strip the inherited aria-label.
|
|
250
|
+
*
|
|
251
|
+
* Note (snapshot limitation): if the consumer rewrites `aria-label` to the
|
|
252
|
+
* exact same value we last wrote, we cannot detect the overwrite — to
|
|
253
|
+
* genuinely take ownership in that case the consumer must either write a
|
|
254
|
+
* different value or remove the `data-hx-owns-label` marker themselves.
|
|
255
|
+
*
|
|
256
|
+
* Absence of the marker (or presence of `data-aria-managed`) means the
|
|
257
|
+
* consumer owns the value and hx-field must not touch it.
|
|
258
|
+
* @internal
|
|
259
|
+
*/
|
|
260
|
+
private _hostOwnsAriaLabel;
|
|
261
|
+
/**
|
|
262
|
+
* Removes the host-owned `aria-label` and its ownership marker if (and only
|
|
263
|
+
* if) hx-field still owns them. Consumer-set values are left untouched.
|
|
264
|
+
* @internal
|
|
265
|
+
*/
|
|
266
|
+
private _releaseHostOwnedAriaLabel;
|
|
165
267
|
/**
|
|
166
268
|
* Focuses the slotted form control when the shadow DOM label is clicked.
|
|
167
269
|
* The shadow `<label>` cannot use `for`/`id` to link to a slotted input
|
|
@@ -182,6 +284,13 @@ export declare class HelixField extends HelixElement {
|
|
|
182
284
|
* - `HX-*` elements manage their own ARIA attributes; bridging is skipped.
|
|
183
285
|
* - Elements with `data-aria-managed` attribute opt out of ARIA mutation;
|
|
184
286
|
* bridging is skipped entirely for those elements.
|
|
287
|
+
*
|
|
288
|
+
* **Round-13 F2 ownership model:** `aria-label` ownership is recomputed
|
|
289
|
+
* from the live DOM on every call. If the marker attribute
|
|
290
|
+
* `data-hx-owns-label` is present, hx-field owns the value and may
|
|
291
|
+
* overwrite or remove it. Otherwise the consumer owns it, and hx-field
|
|
292
|
+
* leaves it alone. This makes post-mount consumer mutations
|
|
293
|
+
* (add/remove/replace) authoritative without relying on a stale flag.
|
|
185
294
|
*/
|
|
186
295
|
/** @internal */
|
|
187
296
|
private _syncSlottedControl;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-field.d.ts","sourceRoot":"","sources":["../../../src/components/hx-field/hx-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACzD,OAAO,4CAA4C,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AAcpE
|
|
1
|
+
{"version":3,"file":"hx-field.d.ts","sourceRoot":"","sources":["../../../src/components/hx-field/hx-field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACzD,OAAO,4CAA4C,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AAcpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,qBACa,UAAW,SAAQ,YAAY;IAC1C,OAAgB,MAAM,4BAAsB;IAI5C;;;OAGG;IAEH,KAAK,SAAM;IAEX;;;OAGG;IAEH,QAAQ,UAAS;IAEjB;;;OAGG;IAEH,KAAK,SAAM;IAEX;;;OAGG;IAEH,QAAQ,SAAM;IAEd;;;;OAIG;IAEH,QAAQ,UAAS;IAEjB;;;OAGG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAEhC;;;OAGG;IAEH,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAY;IAIvC;;;OAGG;IACM,OAAO,CAAC,aAAa,CAAS;IAEvC;;;OAGG;IACM,OAAO,CAAC,aAAa,CAAS;IAEvC;;;OAGG;IACM,OAAO,CAAC,YAAY,CAAS;IAEtC,gBAAgB;IAChB,OAAO,CAAC,sBAAsB;IAK9B,gBAAgB;IAChB,OAAO,CAAC,sBAAsB;IAK9B,gBAAgB;IAChB,OAAO,CAAC,qBAAqB;IAO7B;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAkB;IAElC;;;OAGG;IACH,OAAO,CAAC,WAAW,CAA2B;IAE9C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAA4B;IAE5C;;;OAGG;IACH,OAAO,CAAC,WAAW,CAA2B;IAI9C;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAA4B;IAEnD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,WAAW,CAA4B;IAE/C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAwB;IAEtE;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB,CAAuB;IAEpD;;;;;;;;;;OAUG;IACH,OAAO,CAAC,qBAAqB,CAAS;IAE7B,iBAAiB,IAAI,IAAI;IAKzB,oBAAoB,IAAI,IAAI;IAiB5B,OAAO,CAAC,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAkB1D,uFAAuF;IACvF,gBAAgB;IAChB,OAAO,CAAC,iBAAiB;IAazB,qFAAqF;IACrF,gBAAgB;IAChB,OAAO,CAAC,eAAe;IAYvB,kEAAkE;IAClE,gBAAgB;IAChB,OAAO,CAAC,wBAAwB;IAOhC;;;;;;;;;OASG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAQlC;;;;OAIG;IACH,gBAAgB;IAChB,OAAO,CAAC,iBAAiB;IAIzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,gBAAgB;IAChB,OAAO,CAAC,mBAAmB;IA2ElB,MAAM;CAwEhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,UAAU,CAAC;KACxB;CACF"}
|
|
@@ -3,6 +3,46 @@ import { HelixElement } from '../../base/index.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* A popover that displays rich floating content attached to a trigger element.
|
|
5
5
|
*
|
|
6
|
+
* ## Architecture Note: Host-Attribute Label Mirror (group-4 round-1)
|
|
7
|
+
*
|
|
8
|
+
* Unlike modal dialogs (`hx-dialog` / `hx-drawer`) where the HOST is the
|
|
9
|
+
* announced surface and `ElementInternals` projects consumer IDREFs across
|
|
10
|
+
* the shadow boundary, `hx-popover`'s announced surface is the inner
|
|
11
|
+
* `[part="body"]` element which carries `role="dialog"`. The host does not
|
|
12
|
+
* claim a role — it is a structural wrapper around an anchor slot and a
|
|
13
|
+
* separate floating panel.
|
|
14
|
+
*
|
|
15
|
+
* IDL element references on `internals.ariaLabelledByElements` therefore
|
|
16
|
+
* cannot help: AT walks the inner body's accessibility node, and IDL refs
|
|
17
|
+
* declared on the host are not visible from a shadow-internal descendant
|
|
18
|
+
* looking up. The viable cross-shadow path is the host-attribute mirror:
|
|
19
|
+
*
|
|
20
|
+
* 1. The host observes `aria-label` / `aria-labelledby` mutations.
|
|
21
|
+
* 2. On every sync, `aria-labelledby` IDREFs are resolved via
|
|
22
|
+
* `resolveIdrefTokens` (composed-tree walk: host root → ancestor
|
|
23
|
+
* shadow hosts → owner document) and **text-flattened** via
|
|
24
|
+
* `flattenAccName` (AccName 1.2 §4.3.10 hidden-aware).
|
|
25
|
+
* 3. The flattened name is written to the inner body's `aria-label`,
|
|
26
|
+
* overriding the `label` property only when consumer naming is set.
|
|
27
|
+
*
|
|
28
|
+
* Naming precedence (W3C AccName 1.2 §4.3.1):
|
|
29
|
+
*
|
|
30
|
+
* 1. Host `aria-labelledby` (resolved IDREFs, text-flattened)
|
|
31
|
+
* 2. Host `aria-label`
|
|
32
|
+
* 3. `label` property
|
|
33
|
+
* 4. Hard-coded literal `"Popover"` (last-resort accessible name)
|
|
34
|
+
*
|
|
35
|
+
* The text-flatten approach forfeits live IDL-ref tracking (mutating a
|
|
36
|
+
* referenced element's text re-fires through the shared root observer; see
|
|
37
|
+
* `installAriaIdrefMirror`). `aria-controls` is intentionally omitted on
|
|
38
|
+
* the trigger — the body lives in shadow DOM and consumer IDREFs cannot
|
|
39
|
+
* resolve cross-root from light-DOM (axe-core flags this as a critical
|
|
40
|
+
* violation if attempted; see line documenting this exception below).
|
|
41
|
+
*
|
|
42
|
+
* Slotted label support (e.g. `<slot name="title">`) is deliberately NOT
|
|
43
|
+
* added in this round — it would expand the public API surface and is
|
|
44
|
+
* tracked as a follow-up enhancement.
|
|
45
|
+
*
|
|
6
46
|
* @summary Rich floating overlay attached to a trigger element.
|
|
7
47
|
*
|
|
8
48
|
* @tag hx-popover
|
|
@@ -96,6 +136,35 @@ export declare class HelixPopover extends HelixElement {
|
|
|
96
136
|
* @internal
|
|
97
137
|
*/
|
|
98
138
|
private _visible;
|
|
139
|
+
/**
|
|
140
|
+
* Resolved accessible name for the popover body — the value written to
|
|
141
|
+
* the inner `[part="body"]` `aria-label`. Recomputed on every sync per
|
|
142
|
+
* the AccName 1.2 §4.3.1 precedence: host `aria-labelledby` (flattened)
|
|
143
|
+
* > host `aria-label` > `label` property > literal `"Popover"`.
|
|
144
|
+
*
|
|
145
|
+
* Stored as state so render reads the current resolution synchronously.
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
private _resolvedLabel;
|
|
149
|
+
/**
|
|
150
|
+
* Most recently observed consumer-supplied `aria-labelledby` token list on
|
|
151
|
+
* the host. Refreshed every sync via `getAttribute()`.
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
private _consumerLabelledBy;
|
|
155
|
+
/**
|
|
156
|
+
* Handle for the shared host attribute / root id observer.
|
|
157
|
+
* @internal
|
|
158
|
+
*/
|
|
159
|
+
private _ariaMirror;
|
|
160
|
+
/**
|
|
161
|
+
* Watches in-place text / visibility mutations on consumer light-DOM
|
|
162
|
+
* elements resolved from the host's `aria-labelledby`. Reinstalled on
|
|
163
|
+
* every sync against the deduped resolved set so an in-place text change
|
|
164
|
+
* to `<h2 id="x">Patient</h2>` flows into the inner body's `aria-label`.
|
|
165
|
+
* @internal
|
|
166
|
+
*/
|
|
167
|
+
private _externalRefsObserver;
|
|
99
168
|
/**
|
|
100
169
|
* The element that held focus before the popover opened, used to restore focus on close.
|
|
101
170
|
* @internal
|
|
@@ -120,9 +189,31 @@ export declare class HelixPopover extends HelixElement {
|
|
|
120
189
|
* @internal
|
|
121
190
|
*/
|
|
122
191
|
private _hoverHideTimer;
|
|
192
|
+
connectedCallback(): void;
|
|
123
193
|
disconnectedCallback(): void;
|
|
124
194
|
firstUpdated(): void;
|
|
195
|
+
willUpdate(changedProperties: PropertyValues<this>): void;
|
|
125
196
|
updated(changedProperties: PropertyValues<this>): void;
|
|
197
|
+
/**
|
|
198
|
+
* (Re-)installs a `MutationObserver` over the deduped union of
|
|
199
|
+
* consumer-resolved label elements. Watches `characterData`, `childList`,
|
|
200
|
+
* `subtree`, and `aria-hidden` / `hidden` attributes so any in-place
|
|
201
|
+
* mutation on referenced light-DOM nodes triggers a fresh sync — keeping
|
|
202
|
+
* the flattened `aria-label` aligned with the live consumer text.
|
|
203
|
+
* @internal
|
|
204
|
+
*/
|
|
205
|
+
private _installExternalRefsObserver;
|
|
206
|
+
/**
|
|
207
|
+
* Resolves the popover body's accessible name from host attributes and
|
|
208
|
+
* the `label` property, applying AccName 1.2 §4.3.1 precedence. Writes
|
|
209
|
+
* the result to `_resolvedLabel` (state) so `render()` projects it onto
|
|
210
|
+
* the inner body's `aria-label` on the next paint. The text-flatten
|
|
211
|
+
* filters out top-level `aria-hidden="true"` / `[hidden]` subtrees per
|
|
212
|
+
* AccName 1.2 §4.3.10 — matching the `flattenAccName` contract used by
|
|
213
|
+
* every other host-canonical hx-* component.
|
|
214
|
+
* @internal
|
|
215
|
+
*/
|
|
216
|
+
private _syncResolvedLabel;
|
|
126
217
|
/** @internal */
|
|
127
218
|
private _setAnchorAriaAttributes;
|
|
128
219
|
/** Return all keyboard-focusable elements inside the popover body's slotted content. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-popover.d.ts","sourceRoot":"","sources":["../../../src/components/hx-popover/hx-popover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACzD,OAAO,4CAA4C,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"hx-popover.d.ts","sourceRoot":"","sources":["../../../src/components/hx-popover/hx-popover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACzD,OAAO,4CAA4C,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AAYpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FG;AAEH,qBACa,YAAa,SAAQ,YAAY;IAC5C,OAAgB,MAAM,4BAA6C;IAEnE;;;OAGG;IAEH,IAAI,UAAS;IAEb;;;OAGG;IAEH,SAAS,EACL,KAAK,GACL,WAAW,GACX,SAAS,GACT,OAAO,GACP,aAAa,GACb,WAAW,GACX,QAAQ,GACR,cAAc,GACd,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,UAAU,CAAY;IAE1B;;;OAGG;IAEH,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAW;IAE1D;;;OAGG;IAEH,QAAQ,SAAK;IAEb;;;OAGG;IAEH,QAAQ,SAAK;IAEb;;;OAGG;IAEH,KAAK,UAAS;IAEd;;;OAGG;IAEH,KAAK,SAAa;IAElB;;;OAGG;IACM,OAAO,CAAC,QAAQ,CAAS;IAElC;;;;;;;;OAQG;IACM,OAAO,CAAC,cAAc,CAAM;IAErC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAAuB;IAElD;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAsC;IAEzD;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB,CAAiC;IAE9D;;;OAGG;IACH,OAAO,CAAC,cAAc,CAA4B;IAElD;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAE/C;;;;OAIG;IACH,OAAO,CAAC,UAAU,CAA8C;IAEhE;;;;;;OAMG;IACH,OAAO,CAAC,eAAe,CAA8C;IAI5D,iBAAiB,IAAI,IAAI;IAYzB,oBAAoB,IAAI,IAAI;IAkB5B,YAAY,IAAI,IAAI;IAUpB,UAAU,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAYzD,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAY/D;;;;;;;OAOG;IACH,OAAO,CAAC,4BAA4B;IAsBpC;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IA0C1B,gBAAgB;IAChB,OAAO,CAAC,wBAAwB;IAgBhC,wFAAwF;IACxF,gBAAgB;IAChB,OAAO,CAAC,qBAAqB;IAyB7B,gBAAgB;YACF,KAAK;IAwCnB,gBAAgB;YACF,KAAK;IAmBnB,gBAAgB;YACF,eAAe;IA+E7B;;;OAGG;IACH,OAAO,CAAC,sBAAsB,CAiC5B;IAGF;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAO1B;IAEF;;;OAGG;IACH,OAAO,CAAC,kBAAkB,CAOxB;IAEF;;;OAGG;IACH,OAAO,CAAC,uBAAuB,CAG7B;IAEF;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB,CAG7B;IAIF,gBAAgB;IAChB,OAAO,CAAC,qBAAqB,CAI3B;IAEF,gBAAgB;IAChB,OAAO,CAAC,qBAAqB,CAG3B;IAEF;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAOxB,gBAAgB;IAChB,OAAO,CAAC,oBAAoB,CAI1B;IAEF,gBAAgB;IAChB,OAAO,CAAC,qBAAqB,CAQ3B;IAEF,gBAAgB;IAChB,OAAO,CAAC,uBAAuB;IAMtB,MAAM;CA6BhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,YAAY,CAAC;KAC5B;CACF"}
|
|
@@ -102,6 +102,19 @@ export declare class HelixRadioGroup extends HelixRadioGroup_base {
|
|
|
102
102
|
* @internal
|
|
103
103
|
*/
|
|
104
104
|
private _hasErrorSlot;
|
|
105
|
+
/**
|
|
106
|
+
* Tracks whether the help-text slot has assigned content.
|
|
107
|
+
* @internal
|
|
108
|
+
*/
|
|
109
|
+
private _hasHelpSlot;
|
|
110
|
+
/**
|
|
111
|
+
* Whether the platform supports IDL element references on `ElementInternals`.
|
|
112
|
+
* Drives the render-time branch between modern (host-canonical via
|
|
113
|
+
* internals) and fallback (inner fieldset is the announced surface).
|
|
114
|
+
* Codex round-17 P1.
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
private _supportsIdrefRefs;
|
|
105
118
|
/**
|
|
106
119
|
* Unique identifier for this radio group instance used in ARIA attributes.
|
|
107
120
|
* @internal
|
|
@@ -122,9 +135,104 @@ export declare class HelixRadioGroup extends HelixRadioGroup_base {
|
|
|
122
135
|
* @internal
|
|
123
136
|
*/
|
|
124
137
|
private _handleErrorSlotChange;
|
|
138
|
+
/**
|
|
139
|
+
* Handles slotchange events on the help-text slot to detect assigned content.
|
|
140
|
+
* Codex aria-group-2 finding: slot-only help text was not contributing to
|
|
141
|
+
* `aria-describedby` because the wrapper was conditionally rendered on the
|
|
142
|
+
* `helpText` property alone.
|
|
143
|
+
* @internal
|
|
144
|
+
*/
|
|
145
|
+
private _handleHelpSlotChange;
|
|
146
|
+
/**
|
|
147
|
+
* Watches assigned `<slot name="help-text">` nodes for in-place text
|
|
148
|
+
* mutations so the no-IDL-ref fallback `internals.ariaDescription` stays in
|
|
149
|
+
* sync when a framework rewrites `textContent` of an already-assigned node
|
|
150
|
+
* without replacing it. `slotchange` does NOT fire for those mutations, so
|
|
151
|
+
* a separate observer is required. Codex round-23 P2 (Finding C).
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
private _helpSlotTextObserver;
|
|
155
|
+
/**
|
|
156
|
+
* Watches assigned `<slot name="error">` nodes for in-place text mutations
|
|
157
|
+
* so the no-IDL-ref fallback `internals.ariaDescription` stays in sync when
|
|
158
|
+
* a framework rewrites `textContent` of an already-assigned node without
|
|
159
|
+
* replacing it. Codex round-23 P2 (Finding C).
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
162
|
+
private _errorSlotTextObserver;
|
|
163
|
+
/**
|
|
164
|
+
* (Re-)installs the mutation observer over the current set of assigned
|
|
165
|
+
* help-text-slot nodes. Codex round-23 P2 (Finding C).
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
private _installHelpSlotTextObserver;
|
|
169
|
+
/**
|
|
170
|
+
* (Re-)installs the mutation observer over the current set of assigned
|
|
171
|
+
* error-slot nodes. Codex round-23 P2 (Finding C).
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
private _installErrorSlotTextObserver;
|
|
175
|
+
/**
|
|
176
|
+
* Handle for the shared IDREF observer. See `installAriaIdrefMirror()`.
|
|
177
|
+
* @internal
|
|
178
|
+
*/
|
|
179
|
+
private _ariaMirror;
|
|
180
|
+
/**
|
|
181
|
+
* Deferred copy of `error` driven through reactive state so the persistent
|
|
182
|
+
* live region can re-announce on transitions without direct DOM mutation.
|
|
183
|
+
* Codex round-1 finding #10.
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
186
|
+
private _announcedError;
|
|
187
|
+
/**
|
|
188
|
+
* Tracks group-suppressed child radios so detached children can have the
|
|
189
|
+
* flag cleared. Defense-in-depth symmetry with `hx-checkbox-group` —
|
|
190
|
+
* `hx-radio` is not form-associated today, so the flag is inert, but the
|
|
191
|
+
* parity keeps the contract identical between the two group/child families
|
|
192
|
+
* for any future form-association on `hx-radio`. Codex round-3 finding #1.
|
|
193
|
+
* @internal
|
|
194
|
+
*/
|
|
195
|
+
private _suppressedChildren;
|
|
196
|
+
/**
|
|
197
|
+
* Snapshot of children captured before each `slotchange` so removed
|
|
198
|
+
* children can be released from suppression (WeakSet is non-enumerable).
|
|
199
|
+
* @internal
|
|
200
|
+
*/
|
|
201
|
+
private _previousRadios;
|
|
202
|
+
/**
|
|
203
|
+
* Last value of `aria-labelledby` we wrote to the host. Used to distinguish
|
|
204
|
+
* external (consumer) attribute mutations from our own internal augmentation
|
|
205
|
+
* writes when refreshing the host-attribute fallback. Codex round-10 P2:
|
|
206
|
+
* without this guard, an internal mutation observer fire would re-read the
|
|
207
|
+
* already-augmented host attribute as if it were consumer-supplied, causing
|
|
208
|
+
* legend/help/error ids to leak forward as "consumer tokens" forever.
|
|
209
|
+
* @internal
|
|
210
|
+
*/
|
|
211
|
+
private _lastWrittenLabelledBy;
|
|
212
|
+
/** @internal — see `_lastWrittenLabelledBy`. */
|
|
213
|
+
private _lastWrittenDescribedBy;
|
|
214
|
+
/**
|
|
215
|
+
* Most recently observed *consumer-supplied* `aria-labelledby` baseline (the
|
|
216
|
+
* set of tokens the consumer themselves wrote on the host). Refreshed only
|
|
217
|
+
* when the host attribute changes via an external write — internal writes
|
|
218
|
+
* leave the baseline untouched.
|
|
219
|
+
* @internal
|
|
220
|
+
*/
|
|
221
|
+
private _consumerLabelledBy;
|
|
222
|
+
/** @internal — see `_consumerLabelledBy`. */
|
|
223
|
+
private _consumerDescribedBy;
|
|
125
224
|
connectedCallback(): void;
|
|
126
225
|
disconnectedCallback(): void;
|
|
127
226
|
updated(changedProperties: PropertyValues<this>): void;
|
|
227
|
+
/**
|
|
228
|
+
* Mirrors radiogroup semantics onto the host via ElementInternals so that
|
|
229
|
+
* consumer-supplied `aria-label`, `aria-labelledby`, and `aria-describedby`
|
|
230
|
+
* on `<hx-radio-group>` reach the announced control. The codex aria-group-2
|
|
231
|
+
* finding identified that the inner `<fieldset>` was the announced node and
|
|
232
|
+
* the host's external IDREF tokens could not cross the shadow boundary.
|
|
233
|
+
* @internal
|
|
234
|
+
*/
|
|
235
|
+
private _syncHostAriaSemantics;
|
|
128
236
|
firstUpdated(changedProperties: PropertyValues<this>): void;
|
|
129
237
|
/**
|
|
130
238
|
* Cached list of child hx-radio elements; invalidated on slot change.
|
|
@@ -162,10 +270,53 @@ export declare class HelixRadioGroup extends HelixRadioGroup_base {
|
|
|
162
270
|
*/
|
|
163
271
|
private _handleKeydown;
|
|
164
272
|
/**
|
|
165
|
-
* Handles slotchange events on the default slot
|
|
273
|
+
* Handles slotchange events on the default slot. Refreshes the cached
|
|
274
|
+
* radio list, reconciles `value`/`setFormValue`/validity against the new
|
|
275
|
+
* children, then re-tunes the per-child disabled observer so in-place
|
|
276
|
+
* `radio.disabled = true` mutations trigger the same reconcile pass.
|
|
277
|
+
*
|
|
278
|
+
* Codex round-2 finding #3: previously this handler only invalidated the
|
|
279
|
+
* cache and re-synced child state, so removing the currently-selected
|
|
280
|
+
* radio (or disabling it, or adding a new `checked` radio) left
|
|
281
|
+
* `this.value` and the submitted form value pointing at stale state and
|
|
282
|
+
* `_updateValidity` was never re-run.
|
|
283
|
+
*
|
|
284
|
+
* Codex round-7 finding #6: an in-place `selectedRadio.disabled = true`
|
|
285
|
+
* never re-entered this reconciler (the radio remained slotted), so the
|
|
286
|
+
* group could keep submitting a disabled value and stay valid until some
|
|
287
|
+
* unrelated slot mutation kicked things over. The per-child observer
|
|
288
|
+
* installed at the end of this method re-runs the same reconcile logic on
|
|
289
|
+
* every `disabled` attribute mutation.
|
|
166
290
|
* @internal
|
|
167
291
|
*/
|
|
168
292
|
private _handleSlotChange;
|
|
293
|
+
/**
|
|
294
|
+
* Per-child `disabled` attribute observer. Mirrors the slotchange
|
|
295
|
+
* reconcile pipeline so an in-place `radio.disabled = true` collapses the
|
|
296
|
+
* group's `value`/form participation/validity. Round-7 finding #6.
|
|
297
|
+
*
|
|
298
|
+
* One observer is shared across all currently-slotted radios; it is
|
|
299
|
+
* disconnected and re-attached on every slotchange so children that have
|
|
300
|
+
* left the group stop firing reconcile passes.
|
|
301
|
+
* @internal
|
|
302
|
+
*/
|
|
303
|
+
private _childDisabledObserver;
|
|
304
|
+
/**
|
|
305
|
+
* Re-runs the slotchange reconcile pass without touching the disabled
|
|
306
|
+
* observer wiring. Called from the slotchange handler and from the
|
|
307
|
+
* per-child disabled observer; factored out so both entry points share
|
|
308
|
+
* the same value/formValue/validity reconciliation path. Round-7 #6.
|
|
309
|
+
* @internal
|
|
310
|
+
*/
|
|
311
|
+
private _reconcileChildren;
|
|
312
|
+
/**
|
|
313
|
+
* Installs (or re-installs) a single MutationObserver across the current
|
|
314
|
+
* set of slotted `<hx-radio>` children, listening for `disabled` attribute
|
|
315
|
+
* mutations. Round-7 finding #6: in-place `disabled = true` never reaches
|
|
316
|
+
* the slotchange-driven reconciler otherwise.
|
|
317
|
+
* @internal
|
|
318
|
+
*/
|
|
319
|
+
private _installChildDisabledObservers;
|
|
169
320
|
/**
|
|
170
321
|
* Updates the ElementInternals validity state based on the required constraint and current value.
|
|
171
322
|
* @internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-radio-group.d.ts","sourceRoot":"","sources":["../../../src/components/hx-radio-group/hx-radio-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACzD,OAAO,4CAA4C,CAAC;AAIpD,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"hx-radio-group.d.ts","sourceRoot":"","sources":["../../../src/components/hx-radio-group/hx-radio-group.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,6 +42,20 @@ export declare class HelixRadio extends HelixElement {
|
|
|
42
42
|
* @attr checked
|
|
43
43
|
*/
|
|
44
44
|
checked: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Set by `hx-radio-group` to mark this child as group-managed. `hx-radio` is
|
|
47
|
+
* not form-associated (the group is the sole form participant), so this
|
|
48
|
+
* flag is currently inert on this element. It exists for symmetry with
|
|
49
|
+
* `hx-checkbox._groupedSuppress` so the group/child contract is identical
|
|
50
|
+
* across both selection-control families and any future form-association
|
|
51
|
+
* change on `hx-radio` is automatically suppressed inside a group. Codex
|
|
52
|
+
* round-3 finding #1 (defense-in-depth).
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
set _groupedSuppress(value: boolean);
|
|
56
|
+
get _groupedSuppress(): boolean;
|
|
57
|
+
/** @internal */
|
|
58
|
+
private __groupedSuppress;
|
|
45
59
|
connectedCallback(): void;
|
|
46
60
|
updated(changedProperties: PropertyValues<this>): void;
|
|
47
61
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-radio.d.ts","sourceRoot":"","sources":["../../../src/components/hx-radio-group/hx-radio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,4CAA4C,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AAMpE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,UAAW,SAAQ,YAAY;IAC1C,OAAgB,MAAM,4BAAyC;IAI/D;;;OAGG;IAEH,KAAK,SAAM;IAEX;;;OAGG;IAEH,KAAK,SAAM;IAEX;;;OAGG;IAEH,QAAQ,UAAS;IAEjB;;;OAGG;IAEH,OAAO,UAAS;
|
|
1
|
+
{"version":3,"file":"hx-radio.d.ts","sourceRoot":"","sources":["../../../src/components/hx-radio-group/hx-radio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,4CAA4C,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAC;AAMpE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,UAAW,SAAQ,YAAY;IAC1C,OAAgB,MAAM,4BAAyC;IAI/D;;;OAGG;IAEH,KAAK,SAAM;IAEX;;;OAGG;IAEH,KAAK,SAAM;IAEX;;;OAGG;IAEH,QAAQ,UAAS;IAEjB;;;OAGG;IAEH,OAAO,UAAS;IAEhB;;;;;;;;;OASG;IACH,IAAI,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAElC;IACD,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IACD,gBAAgB;IAChB,OAAO,CAAC,iBAAiB,CAAS;IAIzB,iBAAiB,IAAI,IAAI;IAWzB,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAW/D;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,cAAc;IAQtB,gBAAgB;IAChB,OAAO,CAAC,QAAQ,CAAkB;IAIlC,gBAAgB;IAChB,OAAO,CAAC,YAAY;IAqBX,MAAM;CA2BhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,UAAU,CAAC;KACxB;CACF;AAED,uDAAuD;AACvD,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC"}
|