@helixui/library 3.4.0 → 3.4.1-next.126

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.
Files changed (105) hide show
  1. package/dist/components/hx-button-group/hx-button-group.d.ts +9 -0
  2. package/dist/components/hx-button-group/hx-button-group.d.ts.map +1 -1
  3. package/dist/components/hx-button-group/index.js +1 -1
  4. package/dist/components/hx-card/hx-card.d.ts +68 -0
  5. package/dist/components/hx-card/hx-card.d.ts.map +1 -1
  6. package/dist/components/hx-card/hx-card.styles.d.ts.map +1 -1
  7. package/dist/components/hx-card/index.js +1 -1
  8. package/dist/components/hx-checkbox/index.js +1 -1
  9. package/dist/components/hx-checkbox-group/index.js +1 -1
  10. package/dist/components/hx-color-picker/index.js +1 -1
  11. package/dist/components/hx-combobox/index.js +1 -1
  12. package/dist/components/hx-date-picker/index.js +1 -1
  13. package/dist/components/hx-dialog/index.js +1 -1
  14. package/dist/components/hx-drawer/index.js +1 -1
  15. package/dist/components/hx-dropdown/index.js +1 -1
  16. package/dist/components/hx-list/index.js +1 -1
  17. package/dist/components/hx-menu/index.js +1 -1
  18. package/dist/components/hx-meter/hx-meter.d.ts.map +1 -1
  19. package/dist/components/hx-meter/index.js +1 -1
  20. package/dist/components/hx-overflow-menu/index.js +1 -1
  21. package/dist/components/hx-popover/index.js +1 -1
  22. package/dist/components/hx-progress-bar/index.js +1 -1
  23. package/dist/components/hx-radio-group/index.js +1 -1
  24. package/dist/components/hx-select/index.js +1 -1
  25. package/dist/components/hx-spinner/hx-spinner.d.ts.map +1 -1
  26. package/dist/components/hx-spinner/index.js +1 -1
  27. package/dist/components/hx-split-button/index.js +1 -1
  28. package/dist/components/hx-stat/index.js +1 -1
  29. package/dist/components/hx-switch/index.js +1 -1
  30. package/dist/components/hx-table/hx-td.d.ts.map +1 -1
  31. package/dist/components/hx-table/hx-th.d.ts +9 -0
  32. package/dist/components/hx-table/hx-th.d.ts.map +1 -1
  33. package/dist/components/hx-table/index.js +1 -1
  34. package/dist/components/hx-tabs/index.js +1 -1
  35. package/dist/components/hx-time-picker/index.js +1 -1
  36. package/dist/components/hx-toggle-button/index.js +1 -1
  37. package/dist/components/hx-tree-view/index.js +1 -1
  38. package/dist/css/helix-all.css +14 -1
  39. package/dist/css/helix-core.css +14 -1
  40. package/dist/css/hx-card.css +14 -1
  41. package/dist/css/index.css +1 -1
  42. package/dist/css/manifest.json +1 -1
  43. package/dist/index.js +27 -27
  44. package/dist/shared/aria-idref-DCuEaknC.js +131 -0
  45. package/dist/shared/{aria-idref-CxvyzfQS.js.map → aria-idref-DCuEaknC.js.map} +1 -1
  46. package/dist/shared/{hx-button-group-DcHP5MBv.js → hx-button-group-4NUBpkyC.js} +22 -22
  47. package/dist/shared/{hx-button-group-DcHP5MBv.js.map → hx-button-group-4NUBpkyC.js.map} +1 -1
  48. package/dist/shared/{hx-card-qNAM2QNV.js → hx-card-CswtnYvj.js} +142 -85
  49. package/dist/shared/hx-card-CswtnYvj.js.map +1 -0
  50. package/dist/shared/{hx-checkbox-C48KYKFq.js → hx-checkbox-CYd0YV_u.js} +2 -2
  51. package/dist/shared/{hx-checkbox-C48KYKFq.js.map → hx-checkbox-CYd0YV_u.js.map} +1 -1
  52. package/dist/shared/{hx-checkbox-group-BJIAX3zU.js → hx-checkbox-group-D5piJLY8.js} +2 -2
  53. package/dist/shared/{hx-checkbox-group-BJIAX3zU.js.map → hx-checkbox-group-D5piJLY8.js.map} +1 -1
  54. package/dist/shared/{hx-color-picker-Dk4cBwYQ.js → hx-color-picker-DBwJzT5f.js} +2 -2
  55. package/dist/shared/{hx-color-picker-Dk4cBwYQ.js.map → hx-color-picker-DBwJzT5f.js.map} +1 -1
  56. package/dist/shared/{hx-combobox-BTLO9qiK.js → hx-combobox-NgJaLbs2.js} +2 -2
  57. package/dist/shared/{hx-combobox-BTLO9qiK.js.map → hx-combobox-NgJaLbs2.js.map} +1 -1
  58. package/dist/shared/{hx-date-picker-CiR7FVnR.js → hx-date-picker-B49yo4Vm.js} +2 -2
  59. package/dist/shared/{hx-date-picker-CiR7FVnR.js.map → hx-date-picker-B49yo4Vm.js.map} +1 -1
  60. package/dist/shared/{hx-dialog-AOZpHSuF.js → hx-dialog-B4weoj_1.js} +2 -2
  61. package/dist/shared/{hx-dialog-AOZpHSuF.js.map → hx-dialog-B4weoj_1.js.map} +1 -1
  62. package/dist/shared/{hx-drawer-DH6CdAN1.js → hx-drawer-D81tb4BD.js} +2 -2
  63. package/dist/shared/{hx-drawer-DH6CdAN1.js.map → hx-drawer-D81tb4BD.js.map} +1 -1
  64. package/dist/shared/{hx-dropdown-DiLd40Lm.js → hx-dropdown-D626S2ZG.js} +2 -2
  65. package/dist/shared/{hx-dropdown-DiLd40Lm.js.map → hx-dropdown-D626S2ZG.js.map} +1 -1
  66. package/dist/shared/{hx-list-De66EtAP.js → hx-list-Bp8HeLHh.js} +2 -2
  67. package/dist/shared/{hx-list-De66EtAP.js.map → hx-list-Bp8HeLHh.js.map} +1 -1
  68. package/dist/shared/{hx-menu-divider-BjiRIWKq.js → hx-menu-divider-A6Guuzi_.js} +2 -2
  69. package/dist/shared/{hx-menu-divider-BjiRIWKq.js.map → hx-menu-divider-A6Guuzi_.js.map} +1 -1
  70. package/dist/shared/{hx-meter-BJdh6nrF.js → hx-meter-BnpmF3Vx.js} +57 -36
  71. package/dist/shared/{hx-meter-BJdh6nrF.js.map → hx-meter-BnpmF3Vx.js.map} +1 -1
  72. package/dist/shared/{hx-overflow-menu-BQ4fiMYu.js → hx-overflow-menu-DFjJAziP.js} +2 -2
  73. package/dist/shared/{hx-overflow-menu-BQ4fiMYu.js.map → hx-overflow-menu-DFjJAziP.js.map} +1 -1
  74. package/dist/shared/{hx-popover-B9W8-tC0.js → hx-popover-BAlAFOH9.js} +2 -2
  75. package/dist/shared/{hx-popover-B9W8-tC0.js.map → hx-popover-BAlAFOH9.js.map} +1 -1
  76. package/dist/shared/{hx-progress-bar-C8nDMdYa.js → hx-progress-bar-CYz9U721.js} +2 -2
  77. package/dist/shared/{hx-progress-bar-C8nDMdYa.js.map → hx-progress-bar-CYz9U721.js.map} +1 -1
  78. package/dist/shared/{hx-radio-Z1lV1zTO.js → hx-radio-C7eTj5YI.js} +2 -2
  79. package/dist/shared/{hx-radio-Z1lV1zTO.js.map → hx-radio-C7eTj5YI.js.map} +1 -1
  80. package/dist/shared/{hx-select-D18CnJ0e.js → hx-select-DahFehiZ.js} +2 -2
  81. package/dist/shared/{hx-select-D18CnJ0e.js.map → hx-select-DahFehiZ.js.map} +1 -1
  82. package/dist/shared/{hx-spinner-BB0h2hKZ.js → hx-spinner-3qBp4jeN.js} +11 -11
  83. package/dist/shared/{hx-spinner-BB0h2hKZ.js.map → hx-spinner-3qBp4jeN.js.map} +1 -1
  84. package/dist/shared/{hx-split-button-BoABoEm5.js → hx-split-button-Ddle8iVx.js} +2 -2
  85. package/dist/shared/{hx-split-button-BoABoEm5.js.map → hx-split-button-Ddle8iVx.js.map} +1 -1
  86. package/dist/shared/{hx-stat-Dtf9lz-O.js → hx-stat-Gtw_SpK8.js} +2 -2
  87. package/dist/shared/{hx-stat-Dtf9lz-O.js.map → hx-stat-Gtw_SpK8.js.map} +1 -1
  88. package/dist/shared/{hx-switch-B6kr-EwE.js → hx-switch-TvKGvZJz.js} +2 -2
  89. package/dist/shared/{hx-switch-B6kr-EwE.js.map → hx-switch-TvKGvZJz.js.map} +1 -1
  90. package/dist/shared/{hx-tab-panel-BQtBXKLD.js → hx-tab-panel-Cu--8psg.js} +2 -2
  91. package/dist/shared/{hx-tab-panel-BQtBXKLD.js.map → hx-tab-panel-Cu--8psg.js.map} +1 -1
  92. package/dist/shared/{hx-td-BGkFOJEK.js → hx-td-BPsb6OaG.js} +141 -138
  93. package/dist/shared/hx-td-BPsb6OaG.js.map +1 -0
  94. package/dist/shared/{hx-time-picker-iwCD7rzW.js → hx-time-picker-Bo7FWzmf.js} +2 -2
  95. package/dist/shared/{hx-time-picker-iwCD7rzW.js.map → hx-time-picker-Bo7FWzmf.js.map} +1 -1
  96. package/dist/shared/{hx-toggle-button-BQ81EDkl.js → hx-toggle-button-DwBers3A.js} +2 -2
  97. package/dist/shared/{hx-toggle-button-BQ81EDkl.js.map → hx-toggle-button-DwBers3A.js.map} +1 -1
  98. package/dist/shared/{hx-tree-item-CHrUhuZL.js → hx-tree-item-CXyspGxI.js} +2 -2
  99. package/dist/shared/{hx-tree-item-CHrUhuZL.js.map → hx-tree-item-CXyspGxI.js.map} +1 -1
  100. package/dist/utils/aria-idref.d.ts.map +1 -1
  101. package/figma-inventory.json +2 -2
  102. package/package.json +2 -2
  103. package/dist/shared/aria-idref-CxvyzfQS.js +0 -126
  104. package/dist/shared/hx-card-qNAM2QNV.js.map +0 -1
  105. package/dist/shared/hx-td-BGkFOJEK.js.map +0 -1
@@ -1,10 +1,12 @@
1
- import { css as v, nothing as n, html as g } from "lit";
2
- import { property as h, state as s, customElement as x } from "lit/decorators.js";
3
- import { classMap as f } from "lit/directives/class-map.js";
4
- import { a as m } from "./forced-colors-CTEDFRGa.js";
5
- import { H as p } from "./helix-element-BNEYeiys.js";
6
- import { c as _ } from "./id-counter-DuX8vsui.js";
7
- const b = v`
1
+ import { css as _, nothing as h, html as u } from "lit";
2
+ import { property as v, state as c, customElement as y } from "lit/decorators.js";
3
+ import { classMap as w } from "lit/directives/class-map.js";
4
+ import { a as C } from "./forced-colors-CTEDFRGa.js";
5
+ import { s as A, i as I, r as S } from "./aria-idref-DCuEaknC.js";
6
+ import { f as k } from "./aria-flatten-DY6v2vah.js";
7
+ import { H as m } from "./helix-element-BNEYeiys.js";
8
+ import { c as H } from "./id-counter-DuX8vsui.js";
9
+ const L = _`
8
10
  :host {
9
11
  display: block;
10
12
  color: var(--hx-card-color, inherit);
@@ -88,7 +90,8 @@ const b = v`
88
90
  transform: translateY(var(--hx-transform-lift-md, -2px));
89
91
  }
90
92
 
91
- .card--interactive:focus-visible {
93
+ .card--interactive:focus-visible,
94
+ :host(:focus-visible) .card--interactive {
92
95
  outline: var(--hx-focus-ring-width, 2px) solid
93
96
  var(--hx-card-focus-ring-color, var(--hx-focus-ring-color, #0f7078));
94
97
  outline-offset: var(--hx-focus-ring-offset, 2px);
@@ -187,81 +190,134 @@ const b = v`
187
190
  .card__actions {
188
191
  border-top-color: CanvasText;
189
192
  }
193
+
194
+ /*
195
+ * Force a system-color focus ring on the interactive card under
196
+ * Windows High Contrast Mode — the token-driven outline above
197
+ * collapses to system colors but the explicit Highlight color is
198
+ * stricter for AT contrast and reaches the host on the modern
199
+ * host-canonical path (the host is the focused surface).
200
+ */
201
+ .card--interactive:focus-visible,
202
+ :host(:focus-visible) .card--interactive {
203
+ outline-color: Highlight;
204
+ }
190
205
  }
191
206
  `;
192
- var u = Object.defineProperty, y = Object.getOwnPropertyDescriptor, o = (a, r, d, i) => {
193
- for (var t = i > 1 ? void 0 : i ? y(r, d) : r, c = a.length - 1, l; c >= 0; c--)
194
- (l = a[c]) && (t = (i ? l(r, d, t) : l(t)) || t);
195
- return i && t && u(r, d, t), t;
207
+ var $ = Object.defineProperty, E = Object.getOwnPropertyDescriptor, d = (e, a, t, o) => {
208
+ for (var r = o > 1 ? void 0 : o ? E(a, t) : a, n = e.length - 1, i; n >= 0; n--)
209
+ (i = e[n]) && (r = (o ? i(a, t, r) : i(r)) || r);
210
+ return o && r && $(a, t, r), r;
196
211
  };
197
- const w = _("hx-card");
198
- let e = class extends p {
212
+ const R = H("hx-card");
213
+ let s = class extends m {
199
214
  constructor() {
200
- super(...arguments), this.variant = "default", this.elevation = "flat", this.href = void 0, this.label = void 0, this._hasImage = !1, this._hasHeading = !1, this._hasFooter = !1, this._hasActions = !1, this._headingText = "", this._cardId = w(), this._headingId = `${this._cardId}-heading`;
215
+ super(...arguments), this.variant = "default", this.elevation = "flat", this.href = void 0, this.label = void 0, this._hasImage = !1, this._hasHeading = !1, this._hasFooter = !1, this._hasActions = !1, this._headingText = "", this._cardId = R(), this._headingId = `${this._cardId}-heading`, this._supportsIdrefRefs = !0, this._ariaMirror = null, this._resolvedAccessibleName = "";
201
216
  }
202
217
  /** @internal */
203
- _onImageSlotChange(a) {
204
- const r = a.target;
205
- this._hasImage = r.assignedNodes({ flatten: !0 }).length > 0;
218
+ _onImageSlotChange(e) {
219
+ const a = e.target;
220
+ this._hasImage = a.assignedNodes({ flatten: !0 }).length > 0;
206
221
  }
207
222
  /** @internal */
208
- _onHeadingSlotChange(a) {
209
- const d = a.target.assignedNodes({ flatten: !0 });
210
- this._hasHeading = d.length > 0, this._headingText = d.map((i) => {
211
- var t;
212
- return ((t = i.textContent) == null ? void 0 : t.trim()) ?? "";
213
- }).join(" ").trim();
223
+ _onHeadingSlotChange(e) {
224
+ const t = e.target.assignedNodes({ flatten: !0 });
225
+ this._hasHeading = t.length > 0, this._headingText = t.map((o) => {
226
+ var r;
227
+ return ((r = o.textContent) == null ? void 0 : r.trim()) ?? "";
228
+ }).join(" ").trim(), this._syncHostAriaSemantics();
214
229
  }
215
230
  /** @internal */
216
- _onFooterSlotChange(a) {
217
- const r = a.target;
218
- this._hasFooter = r.assignedNodes({ flatten: !0 }).length > 0;
231
+ _onFooterSlotChange(e) {
232
+ const a = e.target;
233
+ this._hasFooter = a.assignedNodes({ flatten: !0 }).length > 0;
219
234
  }
220
235
  /** @internal */
221
- _onActionsSlotChange(a) {
222
- const r = a.target;
223
- this._hasActions = r.assignedNodes({ flatten: !0 }).length > 0, this._hasActions && this.href;
224
- }
225
- updated(a) {
226
- super.updated(a), (a.has("href") || a.has("label")) && this.href && !this.label && this._headingText;
236
+ _onActionsSlotChange(e) {
237
+ const a = e.target;
238
+ this._hasActions = a.assignedNodes({ flatten: !0 }).length > 0, this._hasActions && this.href;
239
+ }
240
+ // ─── Lifecycle ───
241
+ connectedCallback() {
242
+ super.connectedCallback();
243
+ const e = this.constructor;
244
+ this._supportsIdrefRefs = e.__testSupportsIdrefRefsOverride !== null ? e.__testSupportsIdrefRefsOverride : A(this._internals), this._syncHostAriaSemantics(), this.addEventListener("click", this._handleClick), this.addEventListener("keydown", this._handleKeyDown), this._ariaMirror = I(this, () => {
245
+ this._syncHostAriaSemantics();
246
+ });
247
+ }
248
+ disconnectedCallback() {
249
+ var e;
250
+ super.disconnectedCallback(), this.removeEventListener("click", this._handleClick), this.removeEventListener("keydown", this._handleKeyDown), (e = this._ariaMirror) == null || e.disconnect(), this._ariaMirror = null;
251
+ }
252
+ updated(e) {
253
+ super.updated(e), (e.has("href") || e.has("label")) && this.href && !this.label && this._headingText, (e.has("href") || e.has("label")) && this._syncHostAriaSemantics();
254
+ }
255
+ /**
256
+ * Mirror card semantics onto the host via ElementInternals so
257
+ * consumer-supplied `aria-label` / `aria-labelledby` reaches the
258
+ * announced surface and the role honours the link / region / generic
259
+ * mapping.
260
+ *
261
+ * Suppression rule: on the legacy fallback path the inner
262
+ * `[part="card"]` element already exposes role + aria-label via the
263
+ * template. Writing the same fields on the host's ElementInternals
264
+ * would surface TWO announced controls for one logical card, so all
265
+ * host writes are cleared on the fallback path; the inner element is
266
+ * the canonical announced surface and `_resolvedAccessibleName` is
267
+ * mirrored onto it via the render branch.
268
+ * @internal
269
+ */
270
+ _syncHostAriaSemantics() {
271
+ var f;
272
+ const e = this._internals, a = !!this.href, t = ((f = this.getAttribute("aria-label")) == null ? void 0 : f.trim()) || "", o = this.getAttribute("aria-labelledby"), r = S(this, o), n = r.length > 0;
273
+ let i = "";
274
+ n ? i = r.map((l) => k(l)).filter(Boolean).join(" ") || t || this.label || this._headingText || "" : t ? i = t : this.label ? i = this.label : this._headingText && (i = this._headingText);
275
+ const p = n || !!t || !!this.label;
276
+ if (!this._supportsIdrefRefs)
277
+ e.role = null, e.ariaLabel = null;
278
+ else {
279
+ a ? e.role = "link" : p ? e.role = "region" : e.role = null;
280
+ const l = e;
281
+ l.ariaLabelledByElements = n ? r : null, n ? e.ariaLabel = null : t ? e.ariaLabel = t : this.label ? e.ariaLabel = this.label : i && (a || p) ? e.ariaLabel = i : e.ariaLabel = null;
282
+ }
283
+ this._supportsIdrefRefs && a ? this.tabIndex = 0 : this.hasAttribute("tabindex") && this.removeAttribute("tabindex"), this._resolvedAccessibleName !== i && (this._resolvedAccessibleName = i, this._supportsIdrefRefs || this.requestUpdate());
227
284
  }
228
285
  // ─── Event Handling ───
229
286
  /** @internal */
230
- _dispatchCardClick(a) {
287
+ _dispatchCardClick(e) {
231
288
  this.href && this.dispatchEvent(
232
289
  new CustomEvent("hx-click", {
233
290
  bubbles: !0,
234
291
  composed: !0,
235
- detail: { href: this.href, originalEvent: a }
292
+ detail: { href: this.href, originalEvent: e }
236
293
  })
237
294
  );
238
295
  }
239
296
  /** @internal */
240
- _handleClick(a) {
241
- this._dispatchCardClick(a);
297
+ _handleClick(e) {
298
+ this._dispatchCardClick(e);
242
299
  }
243
300
  /** @internal */
244
- _handleKeyDown(a) {
245
- this.href && a.key === "Enter" && (a.preventDefault(), this._dispatchCardClick(a));
301
+ _handleKeyDown(e) {
302
+ this.href && e.key === "Enter" && (e.preventDefault(), this._dispatchCardClick(e));
246
303
  }
247
304
  // ─── Render ───
248
305
  render() {
249
- const a = !!this.href, r = {
306
+ var g, x;
307
+ const e = !!this.href, a = !this._supportsIdrefRefs, t = this._resolvedAccessibleName, o = ((g = this.getAttribute("aria-label")) == null ? void 0 : g.trim()) || "", r = ((x = this.getAttribute("aria-labelledby")) == null ? void 0 : x.trim()) || "", n = !!o || !!r || !!this.label, i = {
250
308
  card: !0,
251
309
  [`card--${this.variant}`]: !0,
252
310
  [`card--${this.elevation}`]: !0,
253
- "card--interactive": a
254
- };
255
- return g`
311
+ "card--interactive": e
312
+ }, p = a ? e ? "link" : n ? "region" : h : h, f = a && e ? "0" : h, l = a && t ? t : h, b = a && this._hasHeading && !t ? this._headingId : h;
313
+ return u`
256
314
  <div
257
315
  part="card"
258
- class=${f(r)}
259
- role=${a ? "link" : n}
260
- tabindex=${a ? "0" : n}
261
- aria-label=${a && this.label ? this.label : n}
262
- aria-labelledby=${this._hasHeading && !this.label ? this._headingId : n}
263
- @click=${this._handleClick}
264
- @keydown=${this._handleKeyDown}
316
+ class=${w(i)}
317
+ role=${p}
318
+ tabindex=${f}
319
+ aria-label=${l}
320
+ aria-labelledby=${b}
265
321
  >
266
322
  <div class="card__image" part="image" ?hidden=${!this._hasImage}>
267
323
  <slot name="image" @slotchange=${this._onImageSlotChange}></slot>
@@ -291,42 +347,43 @@ let e = class extends p {
291
347
  `;
292
348
  }
293
349
  };
294
- e.shadowRootOptions = {
295
- ...p.shadowRootOptions,
350
+ s.shadowRootOptions = {
351
+ ...m.shadowRootOptions,
296
352
  delegatesFocus: !0
297
353
  };
298
- e.styles = [b, m];
299
- o([
300
- h({ type: String, reflect: !0 })
301
- ], e.prototype, "variant", 2);
302
- o([
303
- h({ type: String, reflect: !0 })
304
- ], e.prototype, "elevation", 2);
305
- o([
306
- h({ type: String, attribute: "hx-href" })
307
- ], e.prototype, "href", 2);
308
- o([
309
- h({ type: String, attribute: "hx-label" })
310
- ], e.prototype, "label", 2);
311
- o([
312
- s()
313
- ], e.prototype, "_hasImage", 2);
314
- o([
315
- s()
316
- ], e.prototype, "_hasHeading", 2);
317
- o([
318
- s()
319
- ], e.prototype, "_hasFooter", 2);
320
- o([
321
- s()
322
- ], e.prototype, "_hasActions", 2);
323
- o([
324
- s()
325
- ], e.prototype, "_headingText", 2);
326
- e = o([
327
- x("hx-card")
328
- ], e);
354
+ s.styles = [L, C];
355
+ s.__testSupportsIdrefRefsOverride = null;
356
+ d([
357
+ v({ type: String, reflect: !0 })
358
+ ], s.prototype, "variant", 2);
359
+ d([
360
+ v({ type: String, reflect: !0 })
361
+ ], s.prototype, "elevation", 2);
362
+ d([
363
+ v({ type: String, attribute: "hx-href" })
364
+ ], s.prototype, "href", 2);
365
+ d([
366
+ v({ type: String, attribute: "hx-label" })
367
+ ], s.prototype, "label", 2);
368
+ d([
369
+ c()
370
+ ], s.prototype, "_hasImage", 2);
371
+ d([
372
+ c()
373
+ ], s.prototype, "_hasHeading", 2);
374
+ d([
375
+ c()
376
+ ], s.prototype, "_hasFooter", 2);
377
+ d([
378
+ c()
379
+ ], s.prototype, "_hasActions", 2);
380
+ d([
381
+ c()
382
+ ], s.prototype, "_headingText", 2);
383
+ s = d([
384
+ y("hx-card")
385
+ ], s);
329
386
  export {
330
- e as H
387
+ s as H
331
388
  };
332
- //# sourceMappingURL=hx-card-qNAM2QNV.js.map
389
+ //# sourceMappingURL=hx-card-CswtnYvj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-card-CswtnYvj.js","sources":["../../src/components/hx-card/hx-card.styles.ts","../../src/components/hx-card/hx-card.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-card styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-card-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * neutral-0 = #FFFFFF, neutral-200 = #D6DBD5, neutral-800 = #202B39,\n * neutral-600 = #4A5362, primary-500 = #429797.\n */\nexport const helixCardStyles = css`\n :host {\n display: block;\n color: var(--hx-card-color, inherit);\n background-color: var(--hx-card-bg, var(--hx-color-surface-default, #ffffff));\n }\n\n .card {\n display: flex;\n flex-direction: column;\n gap: var(--hx-card-gap, var(--hx-space-4, 1rem));\n background-color: var(--hx-card-bg, var(--hx-color-surface-default, #ffffff));\n color: var(--hx-card-color, var(--hx-color-text-strong, #202b39));\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-card-border-color, var(--hx-color-border-default, #d6dbd5));\n border-radius: var(--hx-card-border-radius, var(--hx-border-radius-lg, 0.5rem));\n overflow: hidden;\n font-family: var(--hx-card-font-family, var(--hx-font-family-sans, sans-serif));\n transition:\n box-shadow var(--hx-transition-normal, 250ms ease),\n transform var(--hx-transition-normal, 250ms ease);\n }\n\n /* ─── Elevation Variants ─── */\n\n .card--flat {\n box-shadow: none;\n }\n\n .card--raised {\n box-shadow: var(--hx-card-shadow, var(--hx-shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1)));\n }\n\n .card--floating {\n box-shadow: var(\n --hx-card-shadow-floating,\n var(--hx-shadow-xl, 0 20px 25px -5px rgb(0 0 0 / 0.1))\n );\n }\n\n /* ─── Style Variants ─── */\n\n .card--default {\n /* Default styling — uses base styles */\n }\n\n .card--featured {\n border-color: var(--hx-card-featured-border-color, var(--hx-color-primary-500, #429797));\n border-width: var(--hx-card-featured-border-width, var(--hx-border-width-medium, 2px));\n }\n\n .card--compact .card__body {\n padding: var(--hx-space-3, 0.75rem);\n }\n\n .card--compact .card__heading {\n padding-top: var(--hx-space-3, 0.75rem);\n padding-inline-end: var(--hx-space-3, 0.75rem);\n padding-inline-start: var(--hx-space-3, 0.75rem);\n }\n\n .card--compact .card__footer {\n padding-inline-end: var(--hx-space-3, 0.75rem);\n padding-bottom: var(--hx-space-3, 0.75rem);\n padding-inline-start: var(--hx-space-3, 0.75rem);\n }\n\n .card--compact .card__actions {\n padding-inline-end: var(--hx-space-3, 0.75rem);\n padding-bottom: var(--hx-space-3, 0.75rem);\n padding-inline-start: var(--hx-space-3, 0.75rem);\n }\n\n /* ─── Interactive ─── */\n\n .card--interactive {\n cursor: pointer;\n }\n\n .card--interactive:hover {\n box-shadow: var(--hx-card-shadow-hover, var(--hx-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1)));\n transform: translateY(var(--hx-transform-lift-md, -2px));\n }\n\n .card--interactive:focus-visible,\n :host(:focus-visible) .card--interactive {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-card-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .card--interactive:active {\n transform: translateY(0);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .card {\n transition: none;\n }\n\n .card--interactive:hover {\n transform: none;\n }\n\n .card--interactive:active {\n transform: none;\n }\n }\n\n /* ─── Hidden empty slot wrappers ─── */\n\n [hidden] {\n display: none !important;\n }\n\n /* ─── Sections ─── */\n\n .card__image {\n overflow: hidden;\n line-height: 0;\n }\n\n .card__image ::slotted(img) {\n width: 100%;\n aspect-ratio: var(--hx-card-image-aspect-ratio, 16 / 9);\n display: block;\n object-fit: cover;\n }\n\n .card__heading {\n padding-top: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n padding-inline-end: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n padding-bottom: 0;\n padding-inline-start: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n font-size: var(--hx-font-size-xl, 1.25rem);\n font-weight: var(--hx-font-weight-semibold, 600);\n line-height: var(--hx-line-height-tight, 1.25);\n }\n\n .card__body {\n padding: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n flex: 1;\n font-size: var(--hx-font-size-md, 1rem);\n line-height: var(--hx-line-height-normal, 1.5);\n /*\n * Body color cascades: component-tier --hx-card-body-color overrides\n * the host-tier --hx-card-color, which falls back to text-secondary.\n * Preserves the propagation contract: setting --hx-card-color on the\n * host flows into the body slot (and through to slotted light-DOM\n * descendants via flat-tree inheritance).\n */\n color: var(--hx-card-body-color, var(--hx-card-color, var(--hx-color-text-secondary, #313e4b)));\n }\n\n .card__footer {\n padding-top: 0;\n padding-inline-end: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n padding-bottom: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n padding-inline-start: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n }\n\n .card__actions {\n display: flex;\n gap: var(--hx-space-2, 0.5rem);\n padding-top: var(--hx-space-4, 1rem);\n padding-inline-end: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n padding-bottom: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n padding-inline-start: var(--hx-card-padding, var(--hx-space-6, 1.5rem));\n border-top: var(--hx-border-width-thin, 1px) solid\n var(--hx-card-border-color, var(--hx-color-border-default, #d6dbd5));\n margin-top: auto;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n /* Belt-and-suspenders: rich per-class HC overrides PLUS the forcedColorsSurface mixin. */\n\n @media (forced-colors: active) {\n .card {\n border-color: CanvasText;\n }\n\n .card__actions {\n border-top-color: CanvasText;\n }\n\n /*\n * Force a system-color focus ring on the interactive card under\n * Windows High Contrast Mode — the token-driven outline above\n * collapses to system colors but the explicit Highlight color is\n * stricter for AT contrast and reaches the host on the modern\n * host-canonical path (the host is the focused surface).\n */\n .card--interactive:focus-visible,\n :host(:focus-visible) .card--interactive {\n outline-color: Highlight;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { helixCardStyles } from './hx-card.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\n\nconst _nextCardId = createIdCounter('hx-card');\n\n/**\n * A flexible card component for displaying grouped content.\n *\n * @summary Content container with image, heading, body, footer, and action slots.\n *\n * @tag hx-card\n *\n * Group 10 host-canonical: when a card carries an accessible name (consumer\n * `aria-label` / `aria-labelledby`, the `hx-label` property, or slotted\n * heading text on the interactive variant) the announced role is written\n * to the host via `_internals.role`. The mapping is:\n * - `hx-href` set -> host role=\"link\" + tabindex=\"0\"\n * - non-interactive named -> host role=\"region\"\n * - non-interactive plain -> no host role (generic container)\n *\n * `delegatesFocus: true` is preserved so that focusable descendants\n * slotted inside the card still receive Tab focus first; the host itself\n * is only focusable when it carries `role=\"link\"`.\n *\n * On the legacy fallback path (engines without IDL element-references on\n * `ElementInternals`) the inner `[part=\"card\"]` element keeps the role +\n * tabindex + aria-label so a single announced surface remains, and the\n * host writes are suppressed to avoid a duplicate-treeitem-style\n * problem. The resolved accessible name is mirrored onto the inner\n * element via `aria-label` for parity with the modern path.\n *\n * @slot image - Optional image or media content at the top of the card.\n * @slot heading - The card heading/title content. Use a semantic heading element (h2, h3, etc.) for proper accessibility.\n * @slot - Default slot for the card body content.\n * @slot footer - Optional footer content below the body.\n * @slot actions - Optional action buttons, rendered with a top border separator. Do NOT use together with hx-href (interactive card + focusable actions is an ARIA anti-pattern).\n *\n * @fires {CustomEvent<{href: string, originalEvent: MouseEvent | KeyboardEvent}>} hx-click - Dispatched when an interactive card (with hx-href) is clicked.\n *\n * @csspart card - The outer card container element.\n * @csspart image - The image slot container.\n * @csspart heading - The heading slot container.\n * @csspart body - The body slot container.\n * @csspart footer - The footer slot container.\n * @csspart actions - The actions slot container.\n *\n * @cssprop [--hx-card-bg=var(--hx-color-neutral-0)] - Card background color.\n * @cssprop [--hx-card-color=var(--hx-color-neutral-800)] - Card text color.\n * @cssprop [--hx-card-border-color=var(--hx-color-neutral-200)] - Card border color.\n * @cssprop [--hx-card-border-radius=var(--hx-border-radius-lg)] - Card border radius.\n * @cssprop [--hx-card-padding=var(--hx-space-6)] - Internal padding for card sections.\n * @cssprop [--hx-card-gap=var(--hx-space-4)] - Gap between card sections.\n * @cssprop [--hx-card-image-aspect-ratio=16/9] - Aspect ratio for the image slot.\n * @cssprop [--hx-border-radius-lg] - CSS custom property.\n * @cssprop [--hx-border-width-medium] - Width.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-card-focus-ring-color=var(--hx-focus-ring-color)] - Color.\n * @cssprop [--hx-card-font-family=var(--hx-font-family-sans)] - Font family for card text content.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-color-neutral-600] - Color.\n * @cssprop [--hx-color-neutral-800] - Color.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-font-size-xl] - Font size.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-line-height-tight] - Line height.\n * @cssprop [--hx-shadow-lg] - Box shadow.\n * @cssprop [--hx-shadow-md] - Box shadow.\n * @cssprop [--hx-shadow-xl] - Box shadow.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-transform-lift-md] - Transform applied on hover to lift the card.\n * @cssprop [--hx-transition-normal] - Transition timing.\n */\n@customElement('hx-card')\nexport class HelixCard extends HelixElement {\n /** @internal */\n static override shadowRootOptions = {\n ...HelixElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n static override styles = [helixCardStyles, forcedColorsSurface];\n\n /**\n * Test seam (codex push-gate round-1 lift): when set to `true` or\n * `false`, overrides the platform `supportsIdrefElementReferences`\n * probe before `connectedCallback` seeds `_supportsIdrefRefs`. Mirrors\n * the hx-menu-item / hx-tree-item / hx-select seam — required so tests\n * can deterministically exercise the legacy fallback render branch.\n *\n * Production code MUST NOT touch this field. It is `static` so the\n * test stub cleanup is global and obvious.\n * @internal\n */\n static __testSupportsIdrefRefsOverride: boolean | null = null;\n\n /**\n * Visual style variant of the card.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'featured' | 'compact' = 'default';\n\n /**\n * Elevation (shadow depth) of the card.\n * @attr elevation\n */\n @property({ type: String, reflect: true })\n elevation: 'flat' | 'raised' | 'floating' = 'flat';\n\n /**\n * Optional URL. When set, the card becomes interactive (clickable)\n * and navigates to this URL on click.\n * Uses the hx-href attribute to avoid conflicting with the native HTML href attribute.\n * @attr hx-href\n */\n @property({ type: String, attribute: 'hx-href' })\n href: string | undefined = undefined;\n\n /**\n * Accessible label for interactive cards. Use this to provide a meaningful\n * description of the card's purpose rather than exposing the raw URL.\n * Only applies when hx-href is set.\n * @attr hx-label\n */\n @property({ type: String, attribute: 'hx-label' })\n label: string | undefined = undefined;\n\n // ─── Slot Detection ───\n\n /**\n * Tracks whether any content is assigned to the image slot, controlling slot container visibility.\n * @internal\n */\n @state() private _hasImage = false;\n\n /**\n * Tracks whether any content is assigned to the heading slot, controlling slot container visibility.\n * @internal\n */\n @state() private _hasHeading = false;\n\n /**\n * Tracks whether any content is assigned to the footer slot, controlling slot container visibility.\n * @internal\n */\n @state() private _hasFooter = false;\n\n /**\n * Tracks whether any content is assigned to the actions slot, controlling slot container visibility.\n * @internal\n */\n @state() private _hasActions = false;\n\n /**\n * Text content extracted from the heading slot, used as a fallback accessible\n * name for interactive cards when no explicit `hx-label` is provided.\n * @internal\n */\n @state() private _headingText = '';\n\n /**\n * Unique identifier for this card instance, used in ARIA attributes.\n * @internal\n */\n private _cardId = _nextCardId();\n /**\n * Unique identifier for the heading element, used in aria-labelledby.\n * @internal\n */\n private _headingId = `${this._cardId}-heading`;\n\n // ─── Host-canonical ARIA bookkeeping ───\n\n /** @internal */\n private _supportsIdrefRefs = true;\n\n /** @internal */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Resolved accessible name for the card — read by both\n * `_syncHostAriaSemantics()` (modern path: host `internals.ariaLabel`)\n * and the fallback `render()` branch (legacy path: inner\n * `[part=\"card\"]` `aria-label`). Empty string means \"no override\" —\n * for the interactive variant slotted heading text provides the\n * implicit name through the announced surface (host on modern; inner\n * div on fallback).\n *\n * AccName 1.2 §4.3.1 precedence: consumer host `aria-labelledby`\n * (flattened) > consumer host `aria-label` > component `hx-label`\n * property > implicit slotted heading text.\n * @internal\n */\n private _resolvedAccessibleName = '';\n\n /** @internal */\n private _onImageSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasImage = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _onHeadingSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const nodes = slot.assignedNodes({ flatten: true });\n this._hasHeading = nodes.length > 0;\n this._headingText = nodes\n .map((n) => n.textContent?.trim() ?? '')\n .join(' ')\n .trim();\n // Heading text contributes to the accessible name on the interactive\n // path; resync host semantics so consumer-supplied overrides still\n // win and the fallback render branch has a fresh `_resolvedAccessibleName`.\n this._syncHostAriaSemantics();\n }\n\n /** @internal */\n private _onFooterSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFooter = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _onActionsSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasActions = slot.assignedNodes({ flatten: true }).length > 0;\n if (this._hasActions && this.href) {\n devWarn(\n 'hx-card',\n 'Using hx-href (interactive card) together with the actions slot is an ARIA anti-pattern: ' +\n 'interactive controls cannot be nested inside role=\"link\". ' +\n 'Use either hx-href or the actions slot, not both.',\n );\n }\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Honour the static test override so synthetic environments choose\n // the path BEFORE connect runs — the fallback render branch needs\n // to be selected at first paint so the role + aria-label placement\n // matches a legacy engine for the entire lifecycle.\n const ctor = this.constructor as typeof HelixCard;\n this._supportsIdrefRefs =\n ctor.__testSupportsIdrefRefsOverride !== null\n ? ctor.__testSupportsIdrefRefsOverride\n : supportsIdrefElementReferences(this._internals);\n\n this._syncHostAriaSemantics();\n\n // Click + keydown live on the HOST so a single dispatch fires per\n // logical activation regardless of which surface is focused: on\n // the modern path the host (role=\"link\") receives focus directly;\n // on the legacy fallback path the inner element receives focus and\n // its events bubble through the composed path to the host. The\n // inner template intentionally does NOT wire the same handlers to\n // avoid a double dispatch.\n this.addEventListener('click', this._handleClick);\n this.addEventListener('keydown', this._handleKeyDown);\n\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('click', this._handleClick);\n this.removeEventListener('keydown', this._handleKeyDown);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n // WCAG 4.1.2: interactive cards (with hx-href) must have an accessible name\n if (\n (changedProperties.has('href') || changedProperties.has('label')) &&\n this.href &&\n !this.label &&\n !this._headingText\n ) {\n devWarn(\n 'hx-card',\n \"Interactive card (hx-href is set) is missing an accessible name. Set `hx-label` or provide heading slot content to describe the card's destination or purpose (WCAG 4.1.2).\",\n );\n }\n if (changedProperties.has('href') || changedProperties.has('label')) {\n this._syncHostAriaSemantics();\n }\n }\n\n /**\n * Mirror card semantics onto the host via ElementInternals so\n * consumer-supplied `aria-label` / `aria-labelledby` reaches the\n * announced surface and the role honours the link / region / generic\n * mapping.\n *\n * Suppression rule: on the legacy fallback path the inner\n * `[part=\"card\"]` element already exposes role + aria-label via the\n * template. Writing the same fields on the host's ElementInternals\n * would surface TWO announced controls for one logical card, so all\n * host writes are cleared on the fallback path; the inner element is\n * the canonical announced surface and `_resolvedAccessibleName` is\n * mirrored onto it via the render branch.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n const isInteractive = !!this.href;\n\n // Resolve the consumer's effective accessible-name overrides first\n // — these win over the hx-label property and slotted heading text\n // per AccName 1.2 §4.3.1.\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const consumerLabelledBy = this.getAttribute('aria-labelledby');\n const labelEls = resolveIdrefTokens(this, consumerLabelledBy);\n const hasEffectiveLabelledBy = labelEls.length > 0;\n\n // AccName precedence ladder for the resolved string used by the\n // fallback render branch:\n // aria-labelledby (flattened) > aria-label > hx-label > heading text\n let resolved = '';\n if (hasEffectiveLabelledBy) {\n resolved =\n labelEls\n .map((el) => flattenAccName(el))\n .filter(Boolean)\n .join(' ') ||\n hostAriaLabel ||\n this.label ||\n this._headingText ||\n '';\n } else if (hostAriaLabel) {\n resolved = hostAriaLabel;\n } else if (this.label) {\n resolved = this.label;\n } else if (this._headingText) {\n resolved = this._headingText;\n }\n\n // Whether the card has an EXPLICIT accessible-name override\n // (aria-label / aria-labelledby / hx-label). Slotted heading text\n // alone is not enough to trigger the default-mode role promotion\n // to \"region\": the user prompt scopes Option B to \"promote only\n // when a name exists\" with name-source = explicit consumer\n // override or component property, not implicit slotted content\n // (otherwise every card with a heading silently becomes a\n // landmark, which clutters AT navigation).\n const hasExplicitName = hasEffectiveLabelledBy || !!hostAriaLabel || !!this.label;\n\n if (!this._supportsIdrefRefs) {\n // Legacy fallback: keep the inner element as the canonical\n // announced surface. Clear any host writes to avoid a duplicate\n // role + label; the render branch mirrors `_resolvedAccessibleName`\n // onto the inner div.\n internals.role = null;\n internals.ariaLabel = null;\n } else {\n // Modern host-canonical path: host carries the role and label.\n if (isInteractive) {\n internals.role = 'link';\n } else if (hasExplicitName) {\n // ARIA-in-HTML: a region without an accessible name fails\n // 4.1.2, so the role is only promoted when an explicit name\n // exists. Implicit heading text does not promote.\n internals.role = 'region';\n } else {\n internals.role = null;\n }\n\n // Project consumer aria-labelledby IDREFs through the IDL\n // element-references API so cross-shadow targets resolve. The\n // implicit heading element lives inside this component's shadow\n // root, so for the heading-fallback case we still rely on\n // `internals.ariaLabel` (set below) — the heading is not in the\n // host's light DOM and IDREFs cannot reach it from outside.\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n };\n const refsInternals = internals as InternalsWithRefs;\n refsInternals.ariaLabelledByElements = hasEffectiveLabelledBy ? labelEls : null;\n\n // `internals.ariaLabel` cascade:\n // - aria-labelledby resolved -> null (element refs win, don't shadow them)\n // - host aria-label -> use it directly (consumer wins over property)\n // - hx-label property -> mirror onto host\n // - else if heading text exists and host carries a role ->\n // mirror heading text so AT announces something even when\n // ariaLabelledByElements isn't supported\n if (hasEffectiveLabelledBy) {\n internals.ariaLabel = null;\n } else if (hostAriaLabel) {\n internals.ariaLabel = hostAriaLabel;\n } else if (this.label) {\n internals.ariaLabel = this.label;\n } else if (resolved && (isInteractive || hasExplicitName)) {\n internals.ariaLabel = resolved;\n } else {\n internals.ariaLabel = null;\n }\n }\n\n // Tabindex: link cards are focusable on the host. Region/generic\n // cards stay non-focusable so the host doesn't add a stop in the\n // sequential tab order — `delegatesFocus` will still route focus to\n // a focusable descendant if one is slotted into the body. On the\n // legacy fallback path the inner element carries tabindex via the\n // template, so the host stays out of the tab order entirely.\n if (this._supportsIdrefRefs && isInteractive) {\n this.tabIndex = 0;\n } else {\n // Defer to the absence of an explicit attribute (matches the\n // pre-migration default of \"no host tabindex\") rather than -1,\n // which would block delegated focus into focusable descendants.\n if (this.hasAttribute('tabindex')) {\n this.removeAttribute('tabindex');\n }\n }\n\n if (this._resolvedAccessibleName !== resolved) {\n this._resolvedAccessibleName = resolved;\n if (!this._supportsIdrefRefs) {\n this.requestUpdate();\n }\n }\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _dispatchCardClick(originalEvent: MouseEvent | KeyboardEvent): void {\n if (!this.href) return;\n\n /**\n * Dispatched when an interactive card is clicked.\n * Includes the target href in the detail.\n * @event hx-click\n */\n this.dispatchEvent(\n new CustomEvent<{ href: string; originalEvent: MouseEvent | KeyboardEvent }>('hx-click', {\n bubbles: true,\n composed: true,\n detail: { href: this.href, originalEvent },\n }),\n );\n }\n\n /** @internal */\n private _handleClick(e: MouseEvent): void {\n this._dispatchCardClick(e);\n }\n\n /** @internal */\n private _handleKeyDown(e: KeyboardEvent): void {\n if (!this.href) return;\n\n // WCAG 2.1.1 / ARIA APG: role=\"link\" activates on Enter only.\n // Space is reserved for scrolling and must not activate links.\n if (e.key === 'Enter') {\n e.preventDefault();\n this._dispatchCardClick(e);\n }\n }\n\n // ─── Render ───\n\n override render() {\n const isInteractive = !!this.href;\n // On the legacy fallback path the inner element is the canonical\n // announced surface and must carry the role, tabindex, and resolved\n // accessible name. On the modern path the host owns those via\n // `_internals` and the inner element stays presentational.\n const useFallbackAria = !this._supportsIdrefRefs;\n const fallbackResolved = this._resolvedAccessibleName;\n // Region promotion on the fallback path mirrors the modern path:\n // only an explicit consumer override (aria-label / aria-labelledby\n // / hx-label) triggers the role. Heading text alone stays as\n // implicit body content under a generic container.\n const hostAriaLabelAttr = this.getAttribute('aria-label')?.trim() || '';\n const hostAriaLabelledByAttr = this.getAttribute('aria-labelledby')?.trim() || '';\n const fallbackHasExplicitName = !!hostAriaLabelAttr || !!hostAriaLabelledByAttr || !!this.label;\n\n const classes = {\n card: true,\n [`card--${this.variant}`]: true,\n [`card--${this.elevation}`]: true,\n 'card--interactive': isInteractive,\n };\n\n const innerRole = useFallbackAria\n ? isInteractive\n ? 'link'\n : fallbackHasExplicitName\n ? 'region'\n : nothing\n : nothing;\n const innerTabindex = useFallbackAria && isInteractive ? '0' : nothing;\n const innerAriaLabel = useFallbackAria && fallbackResolved ? fallbackResolved : nothing;\n const innerAriaLabelledBy =\n useFallbackAria && this._hasHeading && !fallbackResolved ? this._headingId : nothing;\n\n // Click + keydown are wired on the HOST in connectedCallback so the\n // event path is uniform across the modern and fallback paths and a\n // single dispatch fires per logical activation regardless of where\n // the focused surface lives. The inner template stays free of\n // @click/@keydown to avoid a double-dispatch when bubbling.\n return html`\n <div\n part=\"card\"\n class=${classMap(classes)}\n role=${innerRole}\n tabindex=${innerTabindex}\n aria-label=${innerAriaLabel}\n aria-labelledby=${innerAriaLabelledBy}\n >\n <div class=\"card__image\" part=\"image\" ?hidden=${!this._hasImage}>\n <slot name=\"image\" @slotchange=${this._onImageSlotChange}></slot>\n </div>\n\n <div\n class=\"card__heading\"\n part=\"heading\"\n id=${this._headingId}\n ?hidden=${!this._hasHeading}\n >\n <slot name=\"heading\" @slotchange=${this._onHeadingSlotChange}></slot>\n </div>\n\n <div class=\"card__body\" part=\"body\">\n <slot></slot>\n </div>\n\n <div class=\"card__footer\" part=\"footer\" ?hidden=${!this._hasFooter}>\n <slot name=\"footer\" @slotchange=${this._onFooterSlotChange}></slot>\n </div>\n\n <div class=\"card__actions\" part=\"actions\" ?hidden=${!this._hasActions}>\n <slot name=\"actions\" @slotchange=${this._onActionsSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-card': HelixCard;\n }\n}\n"],"names":["helixCardStyles","css","_nextCardId","createIdCounter","HelixCard","HelixElement","slot","nodes","n","_a","ctor","supportsIdrefElementReferences","installAriaIdrefMirror","changedProperties","internals","isInteractive","hostAriaLabel","consumerLabelledBy","labelEls","resolveIdrefTokens","hasEffectiveLabelledBy","resolved","el","flattenAccName","hasExplicitName","refsInternals","originalEvent","useFallbackAria","fallbackResolved","hostAriaLabelAttr","hostAriaLabelledByAttr","_b","fallbackHasExplicitName","classes","innerRole","nothing","innerTabindex","innerAriaLabel","innerAriaLabelledBy","html","classMap","forcedColorsSurface","__decorateClass","property","state","customElement"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { ifDefined as d } from "lit/directives/if-defined.js";
5
5
  import { live as y } from "lit/directives/live.js";
6
6
  import { F as A } from "./FormMixin-B8PXk5RQ.js";
7
7
  import { b as H } from "./forced-colors-CTEDFRGa.js";
8
- import { s as $, i as B, r as I } from "./aria-idref-CxvyzfQS.js";
8
+ import { s as $, i as B, r as I } from "./aria-idref-DCuEaknC.js";
9
9
  import { m as D } from "./aria-delegation-Doq6RRUy.js";
10
10
  import { c as R } from "./id-counter-DuX8vsui.js";
11
11
  import { H as q } from "./helix-element-BNEYeiys.js";
@@ -693,4 +693,4 @@ r = o([
693
693
  export {
694
694
  r as H
695
695
  };
696
- //# sourceMappingURL=hx-checkbox-C48KYKFq.js.map
696
+ //# sourceMappingURL=hx-checkbox-CYd0YV_u.js.map