@helixui/library 2.1.2-next.44 → 2.1.2-next.45
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 +9 -9
- package/dist/components/hx-action-bar/hx-action-bar.d.ts +24 -3
- package/dist/components/hx-action-bar/hx-action-bar.d.ts.map +1 -1
- package/dist/components/hx-action-bar/index.js +1 -1
- package/dist/components/hx-badge/hx-badge.styles.d.ts.map +1 -1
- package/dist/components/hx-badge/index.js +1 -1
- package/dist/components/hx-link/hx-link.d.ts.map +1 -1
- package/dist/components/hx-link/index.js +1 -1
- package/dist/css/helix-all.css +33 -14
- package/dist/css/helix-core.css +33 -14
- package/dist/css/hx-badge.css +33 -14
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +2 -2
- package/dist/index.js +3 -3
- package/dist/shared/{hx-action-bar-BpY1Z1UV.js → hx-action-bar-CNLYufVd.js} +39 -28
- package/dist/shared/hx-action-bar-CNLYufVd.js.map +1 -0
- package/dist/shared/{hx-badge-DDXTLoWi.js → hx-badge-RPzd-t5l.js} +44 -25
- package/dist/shared/hx-badge-RPzd-t5l.js.map +1 -0
- package/dist/shared/{hx-link-IVsXmsKx.js → hx-link-B8IwUMSc.js} +5 -4
- package/dist/shared/{hx-link-IVsXmsKx.js.map → hx-link-B8IwUMSc.js.map} +1 -1
- package/package.json +2 -2
- package/dist/shared/hx-action-bar-BpY1Z1UV.js.map +0 -1
- package/dist/shared/hx-badge-DDXTLoWi.js.map +0 -1
package/custom-elements.json
CHANGED
|
@@ -422,13 +422,13 @@
|
|
|
422
422
|
},
|
|
423
423
|
{
|
|
424
424
|
"kind": "field",
|
|
425
|
-
"name": "
|
|
425
|
+
"name": "accessibleLabel",
|
|
426
426
|
"type": {
|
|
427
427
|
"text": "string"
|
|
428
428
|
},
|
|
429
|
-
"default": "'
|
|
430
|
-
"description": "Accessible label for the toolbar.\nRequired when multiple toolbars appear on the same page.",
|
|
431
|
-
"attribute": "
|
|
429
|
+
"default": "''",
|
|
430
|
+
"description": "Accessible label for the toolbar.\nRequired when multiple toolbars appear on the same page.\n\nAccepts both `accessible-label` and the standard `aria-label` HTML attribute.\nThe `accessible-label` attribute takes precedence when both are set.\n\nPreviously this was exposed as the `ariaLabel` JS property, which shadowed\nthe native `HTMLElement.ariaLabel`. That shadowing is removed; use\n`accessibleLabel` or the HTML attributes instead.",
|
|
431
|
+
"attribute": "accessible-label"
|
|
432
432
|
}
|
|
433
433
|
],
|
|
434
434
|
"attributes": [
|
|
@@ -472,14 +472,14 @@
|
|
|
472
472
|
"attribute": "sticky"
|
|
473
473
|
},
|
|
474
474
|
{
|
|
475
|
-
"name": "
|
|
475
|
+
"name": "accessible-label",
|
|
476
476
|
"type": {
|
|
477
477
|
"text": "string"
|
|
478
478
|
},
|
|
479
|
-
"default": "'
|
|
480
|
-
"description": "Accessible label for the toolbar.\nRequired when multiple toolbars appear on the same page.",
|
|
481
|
-
"fieldName": "
|
|
482
|
-
"attribute": "
|
|
479
|
+
"default": "''",
|
|
480
|
+
"description": "Accessible label for the toolbar.\nRequired when multiple toolbars appear on the same page.\n\nAccepts both `accessible-label` and the standard `aria-label` HTML attribute.\nThe `accessible-label` attribute takes precedence when both are set.\n\nPreviously this was exposed as the `ariaLabel` JS property, which shadowed\nthe native `HTMLElement.ariaLabel`. That shadowing is removed; use\n`accessibleLabel` or the HTML attributes instead.",
|
|
481
|
+
"fieldName": "accessibleLabel",
|
|
482
|
+
"attribute": "accessible-label"
|
|
483
483
|
}
|
|
484
484
|
],
|
|
485
485
|
"superclass": {
|
|
@@ -25,8 +25,9 @@ export type ActionBarSize = 'sm' | 'md' | 'lg';
|
|
|
25
25
|
* @cssprop [--hx-action-bar-gap=var(--hx-space-2,0.5rem)] - Gap between slotted items.
|
|
26
26
|
* @cssprop [--hx-action-bar-z-index=10] - Z-index when sticky or bottom position.
|
|
27
27
|
*
|
|
28
|
-
* @attr {string}
|
|
28
|
+
* @attr {string} accessible-label - Identifies the toolbar to assistive technology.
|
|
29
29
|
* When multiple toolbars appear on the same page, each must have a unique, descriptive label.
|
|
30
|
+
* Falls back to the native `aria-label` attribute if not set.
|
|
30
31
|
*
|
|
31
32
|
* @example
|
|
32
33
|
* ```html
|
|
@@ -69,9 +70,29 @@ export declare class HelixActionBar extends LitElement {
|
|
|
69
70
|
/**
|
|
70
71
|
* Accessible label for the toolbar.
|
|
71
72
|
* Required when multiple toolbars appear on the same page.
|
|
72
|
-
*
|
|
73
|
+
*
|
|
74
|
+
* Accepts both `accessible-label` and the standard `aria-label` HTML attribute.
|
|
75
|
+
* The `accessible-label` attribute takes precedence when both are set.
|
|
76
|
+
*
|
|
77
|
+
* Previously this was exposed as the `ariaLabel` JS property, which shadowed
|
|
78
|
+
* the native `HTMLElement.ariaLabel`. That shadowing is removed; use
|
|
79
|
+
* `accessibleLabel` or the HTML attributes instead.
|
|
80
|
+
*
|
|
81
|
+
* @attr accessible-label
|
|
73
82
|
*/
|
|
74
|
-
|
|
83
|
+
accessibleLabel: string;
|
|
84
|
+
/**
|
|
85
|
+
* Observed mirror of the host's `aria-label` attribute so Lit re-renders
|
|
86
|
+
* when consumers set `aria-label` (the standard HTML pattern).
|
|
87
|
+
* @internal
|
|
88
|
+
*/
|
|
89
|
+
private _ariaLabelAttr;
|
|
90
|
+
/**
|
|
91
|
+
* Returns the effective label for the toolbar, checking accessible-label first,
|
|
92
|
+
* then the aria-label attribute, falling back to 'Actions'.
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
private get _effectiveLabel();
|
|
75
96
|
/** Cached list of focusable items — invalidated on slot change. */
|
|
76
97
|
/** @internal */
|
|
77
98
|
private _focusableCache;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-action-bar.d.ts","sourceRoot":"","sources":["../../../src/components/hx-action-bar/hx-action-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,MAAM,KAAK,CAAC;AACvC,OAAO,4CAA4C,CAAC;AAMpD,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C
|
|
1
|
+
{"version":3,"file":"hx-action-bar.d.ts","sourceRoot":"","sources":["../../../src/components/hx-action-bar/hx-action-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,MAAM,KAAK,CAAC;AACvC,OAAO,4CAA4C,CAAC;AAMpD,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBACa,cAAe,SAAQ,UAAU;IAC5C,OAAgB,MAAM,4BAA0B;IAEhD;;;OAGG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAEhC;;;OAGG;IAEH,OAAO,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAa;IAEvD;;;;;;;OAOG;IAEH,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAS;IAE9C;;;;OAIG;IACH,IACI,MAAM,IAAI,OAAO,CAEpB;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,EAUxB;IACD,gBAAgB;IAChB,OAAO,CAAC,OAAO,CAAS;IAExB;;;;;;;;;;;;OAYG;IAEH,eAAe,EAAE,MAAM,CAAM;IAE7B;;;;OAIG;IAEH,OAAO,CAAC,cAAc,CAAc;IAEpC;;;;OAIG;IACH,OAAO,KAAK,eAAe,GAE1B;IAED,mEAAmE;IACnE,gBAAgB;IAChB,OAAO,CAAC,eAAe,CAA8B;IAErD;OACG;IAEH,OAAO,CAAC,YAAY,CAAS;IAI7B,2EAA2E;IAC3E,gBAAgB;IAChB,OAAO,CAAC,cAAc,CAwBpB;IAEO,iBAAiB,IAAI,IAAI;IAyBzB,YAAY,IAAI,IAAI;IAMpB,oBAAoB,IAAI,IAAI;IAOrC,gBAAgB;IAChB,OAAO,CAAC,YAAY;IAcpB,gBAAgB;IAChB,OAAO,CAAC,kBAAkB;IAgC1B,gBAAgB;IAChB,OAAO,CAAC,mBAAmB;IAY3B,gBAAgB;IAChB,OAAO,CAAC,UAAU;IAuBlB,gBAAgB;IAChB,OAAO,CAAC,iBAAiB;IAUhB,MAAM;CA4BhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,cAAc,CAAC;KACjC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-badge.styles.d.ts","sourceRoot":"","sources":["../../../src/components/hx-badge/hx-badge.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"hx-badge.styles.d.ts","sourceRoot":"","sources":["../../../src/components/hx-badge/hx-badge.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,yBAqM5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-link.d.ts","sourceRoot":"","sources":["../../../src/components/hx-link/hx-link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AACrD,OAAO,4CAA4C,CAAC;AAMpD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBACa,SAAU,SAAQ,UAAU;IACvC,OAAgB,MAAM,4BAAqB;IAE3C;;;OAGG;IAEH,IAAI,EAAE,MAAM,GAAG,SAAS,CAAa;IAErC;;;;;OAKG;IAEH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAa;IAEvC;;;OAGG;IAEH,OAAO,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAa;IAErD;;;;;OAKG;IAEH,QAAQ,UAAS;IAEjB;;;;OAIG;IAEH,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAa;IAEzC;;;;OAIG;IAEH,GAAG,EAAE,MAAM,GAAG,SAAS,CAAa;IAIpC,gBAAgB;IAChB,OAAO,CAAC,YAAY;IAkBpB,gBAAgB;IAChB,OAAO,CAAC,WAAW;IAMnB,gBAAgB;IAChB,OAAO,CAAC,mBAAmB;IAuBlB,MAAM;
|
|
1
|
+
{"version":3,"file":"hx-link.d.ts","sourceRoot":"","sources":["../../../src/components/hx-link/hx-link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AACrD,OAAO,4CAA4C,CAAC;AAMpD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBACa,SAAU,SAAQ,UAAU;IACvC,OAAgB,MAAM,4BAAqB;IAE3C;;;OAGG;IAEH,IAAI,EAAE,MAAM,GAAG,SAAS,CAAa;IAErC;;;;;OAKG;IAEH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAa;IAEvC;;;OAGG;IAEH,OAAO,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAa;IAErD;;;;;OAKG;IAEH,QAAQ,UAAS;IAEjB;;;;OAIG;IAEH,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAa;IAEzC;;;;OAIG;IAEH,GAAG,EAAE,MAAM,GAAG,SAAS,CAAa;IAIpC,gBAAgB;IAChB,OAAO,CAAC,YAAY;IAkBpB,gBAAgB;IAChB,OAAO,CAAC,WAAW;IAMnB,gBAAgB;IAChB,OAAO,CAAC,mBAAmB;IAuBlB,MAAM;CAqChB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,SAAS,EAAE,SAAS,CAAC;KACtB;CACF"}
|
package/dist/css/helix-all.css
CHANGED
|
@@ -520,43 +520,64 @@
|
|
|
520
520
|
.badge--primary {
|
|
521
521
|
--hx-badge-bg: var(--hx-color-primary-500, #2563eb);
|
|
522
522
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
523
|
-
--hx-badge-pulse-color: var(
|
|
523
|
+
--hx-badge-pulse-color-internal: var(
|
|
524
|
+
--hx-badge-pulse-color,
|
|
525
|
+
var(--hx-color-primary-500, #2563eb)
|
|
526
|
+
);
|
|
524
527
|
}
|
|
525
528
|
|
|
526
529
|
.badge--secondary {
|
|
527
530
|
--hx-badge-bg: var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6));
|
|
528
531
|
--hx-badge-color: var(--hx-badge-secondary-color, var(--hx-color-neutral-700, #374151));
|
|
529
|
-
--hx-badge-pulse-color: var(
|
|
532
|
+
--hx-badge-pulse-color-internal: var(
|
|
533
|
+
--hx-badge-pulse-color,
|
|
534
|
+
var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6))
|
|
535
|
+
);
|
|
530
536
|
}
|
|
531
537
|
|
|
532
538
|
.badge--success {
|
|
533
539
|
--hx-badge-bg: var(--hx-color-success-700, #15803d);
|
|
534
540
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
535
|
-
--hx-badge-pulse-color: var(
|
|
541
|
+
--hx-badge-pulse-color-internal: var(
|
|
542
|
+
--hx-badge-pulse-color,
|
|
543
|
+
var(--hx-color-success-700, #15803d)
|
|
544
|
+
);
|
|
536
545
|
}
|
|
537
546
|
|
|
538
547
|
.badge--warning {
|
|
539
548
|
--hx-badge-bg: var(--hx-color-warning-500, #eab308);
|
|
540
549
|
--hx-badge-color: var(--hx-color-neutral-900, #1a1a1a);
|
|
541
|
-
--hx-badge-pulse-color: var(
|
|
550
|
+
--hx-badge-pulse-color-internal: var(
|
|
551
|
+
--hx-badge-pulse-color,
|
|
552
|
+
var(--hx-color-warning-500, #eab308)
|
|
553
|
+
);
|
|
542
554
|
}
|
|
543
555
|
|
|
544
556
|
.badge--error {
|
|
545
557
|
--hx-badge-bg: var(--hx-color-error-500, #dc2626);
|
|
546
558
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
547
|
-
--hx-badge-pulse-color: var(
|
|
559
|
+
--hx-badge-pulse-color-internal: var(
|
|
560
|
+
--hx-badge-pulse-color,
|
|
561
|
+
var(--hx-color-error-500, #dc2626)
|
|
562
|
+
);
|
|
548
563
|
}
|
|
549
564
|
|
|
550
565
|
.badge--neutral {
|
|
551
566
|
--hx-badge-bg: var(--hx-color-neutral-200, #e5e7eb);
|
|
552
567
|
--hx-badge-color: var(--hx-color-neutral-700, #374151);
|
|
553
|
-
--hx-badge-pulse-color: var(
|
|
568
|
+
--hx-badge-pulse-color-internal: var(
|
|
569
|
+
--hx-badge-pulse-color,
|
|
570
|
+
var(--hx-color-neutral-200, #e5e7eb)
|
|
571
|
+
);
|
|
554
572
|
}
|
|
555
573
|
|
|
556
574
|
.badge--info {
|
|
557
575
|
--hx-badge-bg: var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1));
|
|
558
576
|
--hx-badge-color: var(--hx-badge-info-color, var(--hx-color-neutral-0, #ffffff));
|
|
559
|
-
--hx-badge-pulse-color: var(
|
|
577
|
+
--hx-badge-pulse-color-internal: var(
|
|
578
|
+
--hx-badge-pulse-color,
|
|
579
|
+
var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1))
|
|
580
|
+
);
|
|
560
581
|
}
|
|
561
582
|
|
|
562
583
|
/* ─── Semantic Variant Label (WCAG 1.4.1) ─── */
|
|
@@ -590,13 +611,11 @@
|
|
|
590
611
|
border-radius: var(--hx-border-radius-full, 9999px);
|
|
591
612
|
}
|
|
592
613
|
|
|
593
|
-
/* Guard: hide
|
|
594
|
-
.badge--dot ::slotted(*)
|
|
595
|
-
|
|
596
|
-
}
|
|
597
|
-
|
|
614
|
+
/* Guard: hide all inner content in dot mode — the dot is purely visual */
|
|
615
|
+
.badge--dot ::slotted(*),
|
|
616
|
+
.badge--dot slot,
|
|
598
617
|
.badge--dot slot[name='prefix'] {
|
|
599
|
-
display: none;
|
|
618
|
+
display: none !important;
|
|
600
619
|
}
|
|
601
620
|
|
|
602
621
|
/* ─── Pulse Animation ─── */
|
|
@@ -605,7 +624,7 @@
|
|
|
605
624
|
0%,
|
|
606
625
|
100% {
|
|
607
626
|
opacity: 1;
|
|
608
|
-
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color, currentColor);
|
|
627
|
+
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color-internal, currentColor);
|
|
609
628
|
}
|
|
610
629
|
50% {
|
|
611
630
|
opacity: var(--hx-opacity-75, 0.75);
|
package/dist/css/helix-core.css
CHANGED
|
@@ -180,43 +180,64 @@
|
|
|
180
180
|
.badge--primary {
|
|
181
181
|
--hx-badge-bg: var(--hx-color-primary-500, #2563eb);
|
|
182
182
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
183
|
-
--hx-badge-pulse-color: var(
|
|
183
|
+
--hx-badge-pulse-color-internal: var(
|
|
184
|
+
--hx-badge-pulse-color,
|
|
185
|
+
var(--hx-color-primary-500, #2563eb)
|
|
186
|
+
);
|
|
184
187
|
}
|
|
185
188
|
|
|
186
189
|
.badge--secondary {
|
|
187
190
|
--hx-badge-bg: var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6));
|
|
188
191
|
--hx-badge-color: var(--hx-badge-secondary-color, var(--hx-color-neutral-700, #374151));
|
|
189
|
-
--hx-badge-pulse-color: var(
|
|
192
|
+
--hx-badge-pulse-color-internal: var(
|
|
193
|
+
--hx-badge-pulse-color,
|
|
194
|
+
var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6))
|
|
195
|
+
);
|
|
190
196
|
}
|
|
191
197
|
|
|
192
198
|
.badge--success {
|
|
193
199
|
--hx-badge-bg: var(--hx-color-success-700, #15803d);
|
|
194
200
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
195
|
-
--hx-badge-pulse-color: var(
|
|
201
|
+
--hx-badge-pulse-color-internal: var(
|
|
202
|
+
--hx-badge-pulse-color,
|
|
203
|
+
var(--hx-color-success-700, #15803d)
|
|
204
|
+
);
|
|
196
205
|
}
|
|
197
206
|
|
|
198
207
|
.badge--warning {
|
|
199
208
|
--hx-badge-bg: var(--hx-color-warning-500, #eab308);
|
|
200
209
|
--hx-badge-color: var(--hx-color-neutral-900, #1a1a1a);
|
|
201
|
-
--hx-badge-pulse-color: var(
|
|
210
|
+
--hx-badge-pulse-color-internal: var(
|
|
211
|
+
--hx-badge-pulse-color,
|
|
212
|
+
var(--hx-color-warning-500, #eab308)
|
|
213
|
+
);
|
|
202
214
|
}
|
|
203
215
|
|
|
204
216
|
.badge--error {
|
|
205
217
|
--hx-badge-bg: var(--hx-color-error-500, #dc2626);
|
|
206
218
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
207
|
-
--hx-badge-pulse-color: var(
|
|
219
|
+
--hx-badge-pulse-color-internal: var(
|
|
220
|
+
--hx-badge-pulse-color,
|
|
221
|
+
var(--hx-color-error-500, #dc2626)
|
|
222
|
+
);
|
|
208
223
|
}
|
|
209
224
|
|
|
210
225
|
.badge--neutral {
|
|
211
226
|
--hx-badge-bg: var(--hx-color-neutral-200, #e5e7eb);
|
|
212
227
|
--hx-badge-color: var(--hx-color-neutral-700, #374151);
|
|
213
|
-
--hx-badge-pulse-color: var(
|
|
228
|
+
--hx-badge-pulse-color-internal: var(
|
|
229
|
+
--hx-badge-pulse-color,
|
|
230
|
+
var(--hx-color-neutral-200, #e5e7eb)
|
|
231
|
+
);
|
|
214
232
|
}
|
|
215
233
|
|
|
216
234
|
.badge--info {
|
|
217
235
|
--hx-badge-bg: var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1));
|
|
218
236
|
--hx-badge-color: var(--hx-badge-info-color, var(--hx-color-neutral-0, #ffffff));
|
|
219
|
-
--hx-badge-pulse-color: var(
|
|
237
|
+
--hx-badge-pulse-color-internal: var(
|
|
238
|
+
--hx-badge-pulse-color,
|
|
239
|
+
var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1))
|
|
240
|
+
);
|
|
220
241
|
}
|
|
221
242
|
|
|
222
243
|
/* ─── Semantic Variant Label (WCAG 1.4.1) ─── */
|
|
@@ -250,13 +271,11 @@
|
|
|
250
271
|
border-radius: var(--hx-border-radius-full, 9999px);
|
|
251
272
|
}
|
|
252
273
|
|
|
253
|
-
/* Guard: hide
|
|
254
|
-
.badge--dot ::slotted(*)
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
|
|
274
|
+
/* Guard: hide all inner content in dot mode — the dot is purely visual */
|
|
275
|
+
.badge--dot ::slotted(*),
|
|
276
|
+
.badge--dot slot,
|
|
258
277
|
.badge--dot slot[name='prefix'] {
|
|
259
|
-
display: none;
|
|
278
|
+
display: none !important;
|
|
260
279
|
}
|
|
261
280
|
|
|
262
281
|
/* ─── Pulse Animation ─── */
|
|
@@ -265,7 +284,7 @@
|
|
|
265
284
|
0%,
|
|
266
285
|
100% {
|
|
267
286
|
opacity: 1;
|
|
268
|
-
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color, currentColor);
|
|
287
|
+
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color-internal, currentColor);
|
|
269
288
|
}
|
|
270
289
|
50% {
|
|
271
290
|
opacity: var(--hx-opacity-75, 0.75);
|
package/dist/css/hx-badge.css
CHANGED
|
@@ -44,43 +44,64 @@
|
|
|
44
44
|
.badge--primary {
|
|
45
45
|
--hx-badge-bg: var(--hx-color-primary-500, #2563eb);
|
|
46
46
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
47
|
-
--hx-badge-pulse-color: var(
|
|
47
|
+
--hx-badge-pulse-color-internal: var(
|
|
48
|
+
--hx-badge-pulse-color,
|
|
49
|
+
var(--hx-color-primary-500, #2563eb)
|
|
50
|
+
);
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
.badge--secondary {
|
|
51
54
|
--hx-badge-bg: var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6));
|
|
52
55
|
--hx-badge-color: var(--hx-badge-secondary-color, var(--hx-color-neutral-700, #374151));
|
|
53
|
-
--hx-badge-pulse-color: var(
|
|
56
|
+
--hx-badge-pulse-color-internal: var(
|
|
57
|
+
--hx-badge-pulse-color,
|
|
58
|
+
var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6))
|
|
59
|
+
);
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
.badge--success {
|
|
57
63
|
--hx-badge-bg: var(--hx-color-success-700, #15803d);
|
|
58
64
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
59
|
-
--hx-badge-pulse-color: var(
|
|
65
|
+
--hx-badge-pulse-color-internal: var(
|
|
66
|
+
--hx-badge-pulse-color,
|
|
67
|
+
var(--hx-color-success-700, #15803d)
|
|
68
|
+
);
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
.badge--warning {
|
|
63
72
|
--hx-badge-bg: var(--hx-color-warning-500, #eab308);
|
|
64
73
|
--hx-badge-color: var(--hx-color-neutral-900, #1a1a1a);
|
|
65
|
-
--hx-badge-pulse-color: var(
|
|
74
|
+
--hx-badge-pulse-color-internal: var(
|
|
75
|
+
--hx-badge-pulse-color,
|
|
76
|
+
var(--hx-color-warning-500, #eab308)
|
|
77
|
+
);
|
|
66
78
|
}
|
|
67
79
|
|
|
68
80
|
.badge--error {
|
|
69
81
|
--hx-badge-bg: var(--hx-color-error-500, #dc2626);
|
|
70
82
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
71
|
-
--hx-badge-pulse-color: var(
|
|
83
|
+
--hx-badge-pulse-color-internal: var(
|
|
84
|
+
--hx-badge-pulse-color,
|
|
85
|
+
var(--hx-color-error-500, #dc2626)
|
|
86
|
+
);
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
.badge--neutral {
|
|
75
90
|
--hx-badge-bg: var(--hx-color-neutral-200, #e5e7eb);
|
|
76
91
|
--hx-badge-color: var(--hx-color-neutral-700, #374151);
|
|
77
|
-
--hx-badge-pulse-color: var(
|
|
92
|
+
--hx-badge-pulse-color-internal: var(
|
|
93
|
+
--hx-badge-pulse-color,
|
|
94
|
+
var(--hx-color-neutral-200, #e5e7eb)
|
|
95
|
+
);
|
|
78
96
|
}
|
|
79
97
|
|
|
80
98
|
.badge--info {
|
|
81
99
|
--hx-badge-bg: var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1));
|
|
82
100
|
--hx-badge-color: var(--hx-badge-info-color, var(--hx-color-neutral-0, #ffffff));
|
|
83
|
-
--hx-badge-pulse-color: var(
|
|
101
|
+
--hx-badge-pulse-color-internal: var(
|
|
102
|
+
--hx-badge-pulse-color,
|
|
103
|
+
var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1))
|
|
104
|
+
);
|
|
84
105
|
}
|
|
85
106
|
|
|
86
107
|
/* ─── Semantic Variant Label (WCAG 1.4.1) ─── */
|
|
@@ -114,13 +135,11 @@
|
|
|
114
135
|
border-radius: var(--hx-border-radius-full, 9999px);
|
|
115
136
|
}
|
|
116
137
|
|
|
117
|
-
/* Guard: hide
|
|
118
|
-
.badge--dot ::slotted(*)
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
138
|
+
/* Guard: hide all inner content in dot mode — the dot is purely visual */
|
|
139
|
+
.badge--dot ::slotted(*),
|
|
140
|
+
.badge--dot slot,
|
|
122
141
|
.badge--dot slot[name='prefix'] {
|
|
123
|
-
display: none;
|
|
142
|
+
display: none !important;
|
|
124
143
|
}
|
|
125
144
|
|
|
126
145
|
/* ─── Pulse Animation ─── */
|
|
@@ -129,7 +148,7 @@
|
|
|
129
148
|
0%,
|
|
130
149
|
100% {
|
|
131
150
|
opacity: 1;
|
|
132
|
-
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color, currentColor);
|
|
151
|
+
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color-internal, currentColor);
|
|
133
152
|
}
|
|
134
153
|
50% {
|
|
135
154
|
opacity: var(--hx-opacity-75, 0.75);
|
package/dist/css/index.css
CHANGED
package/dist/css/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-04-
|
|
2
|
+
"generated": "2026-04-12T12:32:51.327Z",
|
|
3
3
|
"components": [
|
|
4
4
|
{
|
|
5
5
|
"name": "hx-accordion",
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"--hx-badge-info-color",
|
|
131
131
|
"--hx-badge-padding-x",
|
|
132
132
|
"--hx-badge-padding-y",
|
|
133
|
-
"--hx-badge-pulse-color",
|
|
133
|
+
"--hx-badge-pulse-color-internal",
|
|
134
134
|
"--hx-badge-pulse-duration",
|
|
135
135
|
"--hx-badge-pulse-easing",
|
|
136
136
|
"--hx-badge-secondary-bg",
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { e as d } from "./shared/document-token-adoption-DuYNKd4k.js";
|
|
2
2
|
import { H as u, a as T } from "./shared/hx-accordion-CpfO0YQo.js";
|
|
3
|
-
import { H as S } from "./shared/hx-action-bar-
|
|
3
|
+
import { H as S } from "./shared/hx-action-bar-CNLYufVd.js";
|
|
4
4
|
import { H as g } from "./shared/hx-alert-CHOjTBds.js";
|
|
5
5
|
import { H as v } from "./shared/hx-avatar-an-WsuLl.js";
|
|
6
|
-
import { H as y } from "./shared/hx-badge-
|
|
6
|
+
import { H as y } from "./shared/hx-badge-RPzd-t5l.js";
|
|
7
7
|
import { H as E } from "./shared/hx-banner-B-WEDiq7.js";
|
|
8
8
|
import { H as P, a as k } from "./shared/hx-breadcrumb-item-DzLyeL5Z.js";
|
|
9
9
|
import { H as A } from "./shared/hx-button-DoN8jjQT.js";
|
|
@@ -35,7 +35,7 @@ import { H as ke } from "./shared/hx-help-text-Bmb80bP4.js";
|
|
|
35
35
|
import { H as Ae } from "./shared/hx-icon-BKHs3OLu.js";
|
|
36
36
|
import { H as Le } from "./shared/hx-icon-button-CJuy9xbw.js";
|
|
37
37
|
import { H as Ne } from "./shared/hx-image-ztiXumZB.js";
|
|
38
|
-
import { H as Ge } from "./shared/hx-link-
|
|
38
|
+
import { H as Ge } from "./shared/hx-link-B8IwUMSc.js";
|
|
39
39
|
import { H as $e, a as Ve } from "./shared/hx-list-CoTDMp19.js";
|
|
40
40
|
import { H as We, a as Xe, b as Ye } from "./shared/hx-menu-divider-DRT8yHRZ.js";
|
|
41
41
|
import { H as qe } from "./shared/hx-meter-BvSJoqDp.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { css as d, LitElement as b, html as
|
|
1
|
+
import { css as d, LitElement as b, html as f } from "lit";
|
|
2
2
|
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
|
-
import { property as c, state as
|
|
4
|
-
import { d as
|
|
5
|
-
const
|
|
3
|
+
import { property as c, state as p, customElement as u } from "lit/decorators.js";
|
|
4
|
+
import { d as v } from "./dev-warn-YlwPHjtX.js";
|
|
5
|
+
const x = d`
|
|
6
6
|
:host {
|
|
7
7
|
display: block;
|
|
8
8
|
}
|
|
@@ -121,13 +121,13 @@ const v = d`
|
|
|
121
121
|
}
|
|
122
122
|
`;
|
|
123
123
|
var g = Object.defineProperty, m = Object.getOwnPropertyDescriptor, l = (t, e, i, s) => {
|
|
124
|
-
for (var a = s > 1 ? void 0 : s ? m(e, i) : e, o = t.length - 1,
|
|
125
|
-
(
|
|
124
|
+
for (var a = s > 1 ? void 0 : s ? m(e, i) : e, o = t.length - 1, n; o >= 0; o--)
|
|
125
|
+
(n = t[o]) && (a = (s ? n(e, i, a) : n(a)) || a);
|
|
126
126
|
return s && a && g(e, i, a), a;
|
|
127
127
|
};
|
|
128
|
-
let
|
|
128
|
+
let r = class extends b {
|
|
129
129
|
constructor() {
|
|
130
|
-
super(...arguments), this.size = "md", this.variant = "default", this.position = "top", this._sticky = !1, this.
|
|
130
|
+
super(...arguments), this.size = "md", this.variant = "default", this.position = "top", this._sticky = !1, this.accessibleLabel = "", this._ariaLabelAttr = "", this._focusableCache = null, this._hasOverflow = !1, this._handleKeydown = (t) => {
|
|
131
131
|
var e, i;
|
|
132
132
|
if (t.key === "ArrowRight")
|
|
133
133
|
t.preventDefault(), this._moveFocus("next");
|
|
@@ -140,7 +140,7 @@ let n = class extends b {
|
|
|
140
140
|
} else if (t.key === "End") {
|
|
141
141
|
t.preventDefault();
|
|
142
142
|
const s = this._getFocusableItems(), a = s.length - 1;
|
|
143
|
-
s.length && (s.forEach((o,
|
|
143
|
+
s.length && (s.forEach((o, n) => o.setAttribute("tabindex", n === a ? "0" : "-1")), (i = s[a]) == null || i.focus());
|
|
144
144
|
}
|
|
145
145
|
};
|
|
146
146
|
}
|
|
@@ -151,10 +151,18 @@ let n = class extends b {
|
|
|
151
151
|
const e = this._sticky;
|
|
152
152
|
this._sticky = t, this.requestUpdate("sticky", e);
|
|
153
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Returns the effective label for the toolbar, checking accessible-label first,
|
|
156
|
+
* then the aria-label attribute, falling back to 'Actions'.
|
|
157
|
+
* @internal
|
|
158
|
+
*/
|
|
159
|
+
get _effectiveLabel() {
|
|
160
|
+
return this.accessibleLabel || this._ariaLabelAttr || "Actions";
|
|
161
|
+
}
|
|
154
162
|
connectedCallback() {
|
|
155
163
|
super.connectedCallback();
|
|
156
164
|
const t = this.getAttribute("size");
|
|
157
|
-
t !== null && !this.hasAttribute("hx-size") && (this.size = t), this.hasAttribute("role") ? this.getAttribute("role") !== "none" &&
|
|
165
|
+
t !== null && !this.hasAttribute("hx-size") && (this.size = t), this.hasAttribute("role") ? this.getAttribute("role") !== "none" && v(
|
|
158
166
|
"hx-action-bar",
|
|
159
167
|
`Setting role="${this.getAttribute("role")}" on the host creates a duplicate toolbar announcement. The shadow DOM already contains role="toolbar". Set role="none" on the host to suppress it.`
|
|
160
168
|
) : this.setAttribute("role", "none"), this.addEventListener("keydown", this._handleKeydown);
|
|
@@ -185,8 +193,8 @@ let n = class extends b {
|
|
|
185
193
|
if (this._isFocusable(o))
|
|
186
194
|
e.push(o);
|
|
187
195
|
else {
|
|
188
|
-
const
|
|
189
|
-
for (const h of Array.from(
|
|
196
|
+
const n = o.querySelectorAll("*");
|
|
197
|
+
for (const h of Array.from(n))
|
|
190
198
|
this._isFocusable(h) && e.push(h);
|
|
191
199
|
}
|
|
192
200
|
}
|
|
@@ -208,8 +216,8 @@ let n = class extends b {
|
|
|
208
216
|
if (!e.length) return;
|
|
209
217
|
const i = document.activeElement, s = e.indexOf(i);
|
|
210
218
|
let a;
|
|
211
|
-
t === "next" ? a = s < e.length - 1 ? s + 1 : 0 : a = s > 0 ? s - 1 : e.length - 1, e.forEach((
|
|
212
|
-
|
|
219
|
+
t === "next" ? a = s < e.length - 1 ? s + 1 : 0 : a = s > 0 ? s - 1 : e.length - 1, e.forEach((n, h) => {
|
|
220
|
+
n.setAttribute("tabindex", h === a ? "0" : "-1");
|
|
213
221
|
}), (o = e[a]) == null || o.focus();
|
|
214
222
|
}
|
|
215
223
|
// ─── Event Handlers ───
|
|
@@ -221,11 +229,11 @@ let n = class extends b {
|
|
|
221
229
|
// ─── Render ───
|
|
222
230
|
render() {
|
|
223
231
|
const t = this.position === "sticky" || this.sticky, e = this.position === "bottom", i = t ? " base--sticky" : e ? " base--bottom" : "";
|
|
224
|
-
return
|
|
232
|
+
return f`
|
|
225
233
|
<div
|
|
226
234
|
part="base"
|
|
227
235
|
role="toolbar"
|
|
228
|
-
aria-label=${this.
|
|
236
|
+
aria-label=${this._effectiveLabel}
|
|
229
237
|
aria-orientation="horizontal"
|
|
230
238
|
class="base base--${this.size} base--${this.variant}${i}"
|
|
231
239
|
>
|
|
@@ -245,29 +253,32 @@ let n = class extends b {
|
|
|
245
253
|
`;
|
|
246
254
|
}
|
|
247
255
|
};
|
|
248
|
-
|
|
256
|
+
r.styles = [x];
|
|
249
257
|
l([
|
|
250
258
|
c({ type: String, reflect: !0, attribute: "hx-size" })
|
|
251
|
-
],
|
|
259
|
+
], r.prototype, "size", 2);
|
|
252
260
|
l([
|
|
253
261
|
c({ type: String, reflect: !0 })
|
|
254
|
-
],
|
|
262
|
+
], r.prototype, "variant", 2);
|
|
255
263
|
l([
|
|
256
264
|
c({ type: String, reflect: !0 })
|
|
257
|
-
],
|
|
265
|
+
], r.prototype, "position", 2);
|
|
258
266
|
l([
|
|
259
267
|
c({ type: Boolean, reflect: !0 })
|
|
260
|
-
],
|
|
268
|
+
], r.prototype, "sticky", 1);
|
|
269
|
+
l([
|
|
270
|
+
c({ attribute: "accessible-label" })
|
|
271
|
+
], r.prototype, "accessibleLabel", 2);
|
|
261
272
|
l([
|
|
262
273
|
c({ attribute: "aria-label" })
|
|
263
|
-
],
|
|
274
|
+
], r.prototype, "_ariaLabelAttr", 2);
|
|
264
275
|
l([
|
|
265
|
-
|
|
266
|
-
],
|
|
267
|
-
|
|
276
|
+
p()
|
|
277
|
+
], r.prototype, "_hasOverflow", 2);
|
|
278
|
+
r = l([
|
|
268
279
|
u("hx-action-bar")
|
|
269
|
-
],
|
|
280
|
+
], r);
|
|
270
281
|
export {
|
|
271
|
-
|
|
282
|
+
r as H
|
|
272
283
|
};
|
|
273
|
-
//# sourceMappingURL=hx-action-bar-
|
|
284
|
+
//# sourceMappingURL=hx-action-bar-CNLYufVd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hx-action-bar-CNLYufVd.js","sources":["../../src/components/hx-action-bar/hx-action-bar.styles.ts","../../src/components/hx-action-bar/hx-action-bar.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixActionBarStyles = css`\n :host {\n display: block;\n }\n\n /* ─── Base ─── */\n\n .base {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--hx-action-bar-gap, var(--hx-space-2, 0.5rem));\n padding: var(--hx-action-bar-padding, var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem));\n background: var(--hx-action-bar-bg, transparent);\n border: var(--hx-action-bar-border, none);\n box-sizing: border-box;\n width: 100%;\n }\n\n /* ─── Sticky (top) ─── */\n\n .base--sticky {\n position: sticky;\n top: 0;\n padding-top: max(var(--hx-action-bar-padding-block-start, 0px), env(safe-area-inset-top, 0px));\n z-index: var(--hx-action-bar-z-index, 10);\n /*\n * Consumers: when this bar is sticky, add scroll-padding-top to the scroll container\n * equal to the bar's rendered height so anchor targets are not hidden behind the bar.\n * Example: .scroll-container { scroll-padding-top: 2.5rem; }\n */\n }\n\n /* ─── Bottom sticky ─── */\n\n .base--bottom {\n position: sticky;\n bottom: 0;\n /*\n * Respect iOS home-indicator safe area on devices with notch/home bar.\n * Falls back to 0px on devices that do not support env().\n */\n padding-bottom: max(\n var(--hx-action-bar-padding-block-end, 0px),\n env(safe-area-inset-bottom, 0px)\n );\n z-index: var(--hx-action-bar-z-index, 10);\n }\n\n /* ─── Variant: outlined ─── */\n\n .base--outlined {\n background: var(--hx-action-bar-bg, var(--hx-color-neutral-0, #fff));\n border: var(\n --hx-action-bar-border,\n var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #e5e7eb)\n );\n border-radius: var(--hx-border-radius-md, 0.375rem);\n }\n\n /* ─── Variant: filled ─── */\n\n .base--filled {\n background: var(--hx-action-bar-bg, var(--hx-color-neutral-50, #f9fafb));\n border-radius: var(--hx-border-radius-md, 0.375rem);\n }\n\n /* ─── Size modifiers ─── */\n\n .base--sm {\n padding: var(--hx-action-bar-padding, var(--hx-space-1, 0.25rem) var(--hx-space-2, 0.5rem));\n gap: var(--hx-action-bar-gap, var(--hx-space-1, 0.25rem));\n min-height: var(--hx-size-8, 2rem);\n }\n\n .base--md {\n min-height: var(--hx-size-10, 2.5rem);\n }\n\n .base--lg {\n padding: var(--hx-action-bar-padding, var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem));\n gap: var(--hx-action-bar-gap, var(--hx-space-3, 0.75rem));\n min-height: var(--hx-size-12, 3rem);\n }\n\n /* ─── Sections ─── */\n\n .section {\n display: flex;\n align-items: center;\n gap: inherit;\n }\n\n /*\n * Equal flex-basis on start and end guarantees the center section is visually centered\n * within the full bar width, regardless of how wide start and end content are.\n */\n .section--start {\n flex: 1 1 0;\n justify-content: flex-start;\n }\n\n .section--center {\n flex: 0 0 auto;\n justify-content: center;\n }\n\n .section--end {\n flex: 1 1 0;\n justify-content: flex-end;\n }\n\n /* ─── Slotted content ─── */\n\n ::slotted(*) {\n flex-shrink: 0;\n }\n`;\n","import { LitElement, html } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { helixActionBarStyles } from './hx-action-bar.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// Re-export size type for external consumers.\nexport type ActionBarSize = 'sm' | 'md' | 'lg';\n\n/**\n * A horizontal toolbar container for grouping related action buttons and controls.\n * Implements the ARIA toolbar pattern with roving tabindex keyboard navigation.\n *\n * @summary Horizontal action bar for grouping related controls.\n *\n * @tag hx-action-bar\n *\n * @slot start - Left-aligned actions.\n * @slot - Center content (default slot).\n * @slot end - Right-aligned actions.\n * @slot overflow - Actions revealed when the bar is constrained for space.\n *\n * @csspart base - The root toolbar container element.\n * @csspart start - The start (left) slot wrapper.\n * @csspart center - The center (default) slot wrapper.\n * @csspart end - The end (right) slot wrapper.\n * @csspart overflow - The overflow slot wrapper (hidden when no overflow content).\n *\n * @cssprop [--hx-action-bar-bg=transparent] - Bar background color (default variant).\n * @cssprop [--hx-action-bar-border=none] - Bar border (default variant).\n * @cssprop [--hx-action-bar-padding=var(--hx-space-2,0.5rem) var(--hx-space-3,0.75rem)] - Inner padding.\n * @cssprop [--hx-action-bar-gap=var(--hx-space-2,0.5rem)] - Gap between slotted items.\n * @cssprop [--hx-action-bar-z-index=10] - Z-index when sticky or bottom position.\n *\n * @attr {string} accessible-label - Identifies the toolbar to assistive technology.\n * When multiple toolbars appear on the same page, each must have a unique, descriptive label.\n * Falls back to the native `aria-label` attribute if not set.\n *\n * @example\n * ```html\n * <hx-action-bar aria-label=\"Patient actions\">\n * <hx-button slot=\"start\">Save</hx-button>\n * <hx-button slot=\"end\" variant=\"ghost\">Cancel</hx-button>\n * </hx-action-bar>\n * ```\n */\n@customElement('hx-action-bar')\nexport class HelixActionBar extends LitElement {\n static override styles = [helixActionBarStyles];\n\n /**\n * Size of the action bar — propagated as a data attribute to slotted children.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Visual variant controlling the bar background.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'outlined' | 'filled' = 'default';\n\n /**\n * Position and sticky behavior of the action bar.\n * - `top` — normal flow (default)\n * - `sticky` — sticks to the top of the scroll container; add `scroll-padding-top` to the\n * scroll container equal to the bar height to prevent anchor targets from scrolling behind it\n * - `bottom` — sticks to the bottom of the scroll container with iOS safe-area-inset support\n * @attr position\n */\n @property({ type: String, reflect: true })\n position: 'top' | 'bottom' | 'sticky' = 'top';\n\n /**\n * @deprecated Use `position=\"sticky\"` instead.\n * When true, the bar sticks to the top of its scroll container.\n * @attr sticky\n */\n @property({ type: Boolean, reflect: true })\n get sticky(): boolean {\n return this._sticky;\n }\n set sticky(value: boolean) {\n if (value) {\n devWarn(\n 'hx-action-bar',\n 'The `sticky` property is deprecated. Use `position=\"sticky\"` instead.',\n );\n }\n const old = this._sticky;\n this._sticky = value;\n this.requestUpdate('sticky', old);\n }\n /** @internal */\n private _sticky = false;\n\n /**\n * Accessible label for the toolbar.\n * Required when multiple toolbars appear on the same page.\n *\n * Accepts both `accessible-label` and the standard `aria-label` HTML attribute.\n * The `accessible-label` attribute takes precedence when both are set.\n *\n * Previously this was exposed as the `ariaLabel` JS property, which shadowed\n * the native `HTMLElement.ariaLabel`. That shadowing is removed; use\n * `accessibleLabel` or the HTML attributes instead.\n *\n * @attr accessible-label\n */\n @property({ attribute: 'accessible-label' })\n accessibleLabel: string = '';\n\n /**\n * Observed mirror of the host's `aria-label` attribute so Lit re-renders\n * when consumers set `aria-label` (the standard HTML pattern).\n * @internal\n */\n @property({ attribute: 'aria-label' })\n private _ariaLabelAttr: string = '';\n\n /**\n * Returns the effective label for the toolbar, checking accessible-label first,\n * then the aria-label attribute, falling back to 'Actions'.\n * @internal\n */\n private get _effectiveLabel(): string {\n return this.accessibleLabel || this._ariaLabelAttr || 'Actions';\n }\n\n /** Cached list of focusable items — invalidated on slot change. */\n /** @internal */\n private _focusableCache: HTMLElement[] | null = null;\n\n /** Whether the overflow slot has assigned content. * @internal\n */\n @state()\n private _hasOverflow = false;\n\n // ─── Lifecycle ───\n\n /** Arrow function field — stable reference for add/removeEventListener. */\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n if (e.key === 'ArrowRight') {\n e.preventDefault();\n this._moveFocus('next');\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n this._moveFocus('prev');\n } else if (e.key === 'Home') {\n e.preventDefault();\n // Move directly to first item — do NOT call _moveFocus which would visit other items first.\n const items = this._getFocusableItems();\n if (items.length) {\n items.forEach((el, i) => el.setAttribute('tabindex', i === 0 ? '0' : '-1'));\n items[0]?.focus();\n }\n } else if (e.key === 'End') {\n e.preventDefault();\n const items = this._getFocusableItems();\n const last = items.length - 1;\n if (items.length) {\n items.forEach((el, i) => el.setAttribute('tabindex', i === last ? '0' : '-1'));\n items[last]?.focus();\n }\n }\n };\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-action-bar', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as ActionBarSize;\n }\n // Prevent dual aria-label announcement: the host carries the consumer's\n // aria-label attribute while the inner div[role=\"toolbar\"] receives the\n // same value. Setting role=\"none\" on the host hides it from the\n // accessibility tree so only the toolbar is announced.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'none');\n } else if (this.getAttribute('role') !== 'none') {\n devWarn(\n 'hx-action-bar',\n `Setting role=\"${this.getAttribute('role')}\" on the host creates a duplicate toolbar announcement. ` +\n 'The shadow DOM already contains role=\"toolbar\". Set role=\"none\" on the host to suppress it.',\n );\n }\n this.addEventListener('keydown', this._handleKeydown);\n }\n\n override firstUpdated(): void {\n // Slot assignments are complete by firstUpdated; initialize roving tabindex\n // immediately rather than waiting for the async slotchange event.\n this._initRovingTabindex();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n }\n\n // ─── Focusable item discovery ───\n\n /** @internal */\n private _isFocusable(el: HTMLElement): boolean {\n // Check disabled via DOM attribute (native elements) or property (custom elements)\n if (el.hasAttribute('disabled')) return false;\n const elWithDisabled = el as HTMLElement & { disabled?: boolean };\n if (elWithDisabled.disabled === true) return false;\n\n // Use the IDL tabIndex property — covers both DOM attribute and ElementInternals settings.\n // Custom elements (e.g. hx-button) that set tabIndex via ElementInternals are discoverable.\n if (el.tabIndex >= 0) return true;\n\n const tag = el.tagName.toLowerCase();\n return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea';\n }\n\n /** @internal */\n private _getFocusableItems(): HTMLElement[] {\n if (this._focusableCache) return this._focusableCache;\n\n const slots = this.shadowRoot?.querySelectorAll('slot') ?? [];\n const items: HTMLElement[] = [];\n\n for (const slot of Array.from(slots)) {\n const assigned = (slot as HTMLSlotElement).assignedElements({ flatten: true });\n for (const el of assigned) {\n if (!(el instanceof HTMLElement)) continue;\n if (this._isFocusable(el)) {\n // Element is itself focusable — include it and do NOT also recurse into its children\n // to prevent double-counting compound components (e.g. <a><button>).\n items.push(el);\n } else {\n // Element is a non-focusable wrapper (e.g. <div>, <span>) — find focusable children.\n const descendants = el.querySelectorAll<HTMLElement>('*');\n for (const d of Array.from(descendants)) {\n if (this._isFocusable(d)) {\n items.push(d);\n }\n }\n }\n }\n }\n\n this._focusableCache = items;\n return items;\n }\n\n // ─── Roving tabindex helpers ───\n\n /** @internal */\n private _initRovingTabindex(): void {\n this._focusableCache = null; // invalidate cache on slot change\n const items = this._getFocusableItems();\n if (!items.length) return;\n // Find the currently active item. If none exists (e.g. first render or active item was\n // removed), fall back to index 0. Then set ALL items explicitly so newly added items and\n // items whose tabindex changed externally are always in a correct state.\n const activeIndex = items.findIndex((el) => el.getAttribute('tabindex') === '0');\n const targetIndex = activeIndex === -1 ? 0 : activeIndex;\n items.forEach((el, i) => el.setAttribute('tabindex', i === targetIndex ? '0' : '-1'));\n }\n\n /** @internal */\n private _moveFocus(direction: 'next' | 'prev'): void {\n const items = this._getFocusableItems();\n if (!items.length) return;\n\n const focused = document.activeElement as HTMLElement | null;\n const currentIndex = items.indexOf(focused as HTMLElement);\n\n let nextIndex: number;\n if (direction === 'next') {\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n } else {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n }\n\n items.forEach((el, i) => {\n el.setAttribute('tabindex', i === nextIndex ? '0' : '-1');\n });\n\n items[nextIndex]?.focus();\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n if (slot.name === 'overflow') {\n this._hasOverflow = slot.assignedElements({ flatten: true }).length > 0;\n }\n this._initRovingTabindex();\n }\n\n // ─── Render ───\n\n override render() {\n const isSticky = this.position === 'sticky' || this.sticky;\n const isBottom = this.position === 'bottom';\n const positionClass = isSticky ? ' base--sticky' : isBottom ? ' base--bottom' : '';\n\n return html`\n <div\n part=\"base\"\n role=\"toolbar\"\n aria-label=${this._effectiveLabel}\n aria-orientation=\"horizontal\"\n class=\"base base--${this.size} base--${this.variant}${positionClass}\"\n >\n <div part=\"start\" class=\"section section--start\">\n <slot name=\"start\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n <div part=\"center\" class=\"section section--center\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n <div part=\"end\" class=\"section section--end\">\n <slot name=\"end\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n <div part=\"overflow\" class=\"section section--overflow\" ?hidden=${!this._hasOverflow}>\n <slot name=\"overflow\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-action-bar': HelixActionBar;\n }\n}\n"],"names":["helixActionBarStyles","css","HelixActionBar","LitElement","e","items","el","i","_a","last","_b","value","old","legacySize","devWarn","tag","slots","slot","assigned","descendants","d","activeIndex","targetIndex","direction","focused","currentIndex","nextIndex","isSticky","isBottom","positionClass","html","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { css as c, LitElement as g, nothing as
|
|
1
|
+
import { css as c, LitElement as g, nothing as s, html as d } from "lit";
|
|
2
2
|
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { property as i, state as p, customElement as x } from "lit/decorators.js";
|
|
4
4
|
import { classMap as u } from "lit/directives/class-map.js";
|
|
@@ -48,43 +48,64 @@ const v = c`
|
|
|
48
48
|
.badge--primary {
|
|
49
49
|
--hx-badge-bg: var(--hx-color-primary-500, #2563eb);
|
|
50
50
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
51
|
-
--hx-badge-pulse-color: var(
|
|
51
|
+
--hx-badge-pulse-color-internal: var(
|
|
52
|
+
--hx-badge-pulse-color,
|
|
53
|
+
var(--hx-color-primary-500, #2563eb)
|
|
54
|
+
);
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
.badge--secondary {
|
|
55
58
|
--hx-badge-bg: var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6));
|
|
56
59
|
--hx-badge-color: var(--hx-badge-secondary-color, var(--hx-color-neutral-700, #374151));
|
|
57
|
-
--hx-badge-pulse-color: var(
|
|
60
|
+
--hx-badge-pulse-color-internal: var(
|
|
61
|
+
--hx-badge-pulse-color,
|
|
62
|
+
var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6))
|
|
63
|
+
);
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
.badge--success {
|
|
61
67
|
--hx-badge-bg: var(--hx-color-success-700, #15803d);
|
|
62
68
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
63
|
-
--hx-badge-pulse-color: var(
|
|
69
|
+
--hx-badge-pulse-color-internal: var(
|
|
70
|
+
--hx-badge-pulse-color,
|
|
71
|
+
var(--hx-color-success-700, #15803d)
|
|
72
|
+
);
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
.badge--warning {
|
|
67
76
|
--hx-badge-bg: var(--hx-color-warning-500, #eab308);
|
|
68
77
|
--hx-badge-color: var(--hx-color-neutral-900, #1a1a1a);
|
|
69
|
-
--hx-badge-pulse-color: var(
|
|
78
|
+
--hx-badge-pulse-color-internal: var(
|
|
79
|
+
--hx-badge-pulse-color,
|
|
80
|
+
var(--hx-color-warning-500, #eab308)
|
|
81
|
+
);
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
.badge--error {
|
|
73
85
|
--hx-badge-bg: var(--hx-color-error-500, #dc2626);
|
|
74
86
|
--hx-badge-color: var(--hx-color-neutral-0, #ffffff);
|
|
75
|
-
--hx-badge-pulse-color: var(
|
|
87
|
+
--hx-badge-pulse-color-internal: var(
|
|
88
|
+
--hx-badge-pulse-color,
|
|
89
|
+
var(--hx-color-error-500, #dc2626)
|
|
90
|
+
);
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
.badge--neutral {
|
|
79
94
|
--hx-badge-bg: var(--hx-color-neutral-200, #e5e7eb);
|
|
80
95
|
--hx-badge-color: var(--hx-color-neutral-700, #374151);
|
|
81
|
-
--hx-badge-pulse-color: var(
|
|
96
|
+
--hx-badge-pulse-color-internal: var(
|
|
97
|
+
--hx-badge-pulse-color,
|
|
98
|
+
var(--hx-color-neutral-200, #e5e7eb)
|
|
99
|
+
);
|
|
82
100
|
}
|
|
83
101
|
|
|
84
102
|
.badge--info {
|
|
85
103
|
--hx-badge-bg: var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1));
|
|
86
104
|
--hx-badge-color: var(--hx-badge-info-color, var(--hx-color-neutral-0, #ffffff));
|
|
87
|
-
--hx-badge-pulse-color: var(
|
|
105
|
+
--hx-badge-pulse-color-internal: var(
|
|
106
|
+
--hx-badge-pulse-color,
|
|
107
|
+
var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1))
|
|
108
|
+
);
|
|
88
109
|
}
|
|
89
110
|
|
|
90
111
|
/* ─── Semantic Variant Label (WCAG 1.4.1) ─── */
|
|
@@ -118,13 +139,11 @@ const v = c`
|
|
|
118
139
|
border-radius: var(--hx-border-radius-full, 9999px);
|
|
119
140
|
}
|
|
120
141
|
|
|
121
|
-
/* Guard: hide
|
|
122
|
-
.badge--dot ::slotted(*)
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
142
|
+
/* Guard: hide all inner content in dot mode — the dot is purely visual */
|
|
143
|
+
.badge--dot ::slotted(*),
|
|
144
|
+
.badge--dot slot,
|
|
126
145
|
.badge--dot slot[name='prefix'] {
|
|
127
|
-
display: none;
|
|
146
|
+
display: none !important;
|
|
128
147
|
}
|
|
129
148
|
|
|
130
149
|
/* ─── Pulse Animation ─── */
|
|
@@ -133,7 +152,7 @@ const v = c`
|
|
|
133
152
|
0%,
|
|
134
153
|
100% {
|
|
135
154
|
opacity: 1;
|
|
136
|
-
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color, currentColor);
|
|
155
|
+
box-shadow: 0 0 0 2px var(--hx-badge-pulse-color-internal, currentColor);
|
|
137
156
|
}
|
|
138
157
|
50% {
|
|
139
158
|
opacity: var(--hx-opacity-75, 0.75);
|
|
@@ -182,9 +201,9 @@ const v = c`
|
|
|
182
201
|
}
|
|
183
202
|
`;
|
|
184
203
|
var f = Object.defineProperty, m = Object.getOwnPropertyDescriptor, o = (a, r, n, t) => {
|
|
185
|
-
for (var
|
|
186
|
-
(b = a[h]) && (
|
|
187
|
-
return t &&
|
|
204
|
+
for (var l = t > 1 ? void 0 : t ? m(r, n) : r, h = a.length - 1, b; h >= 0; h--)
|
|
205
|
+
(b = a[h]) && (l = (t ? b(r, n, l) : b(l)) || l);
|
|
206
|
+
return t && l && f(r, n, l), l;
|
|
188
207
|
};
|
|
189
208
|
let e = class extends g {
|
|
190
209
|
constructor() {
|
|
@@ -237,12 +256,12 @@ let e = class extends g {
|
|
|
237
256
|
<span
|
|
238
257
|
part="badge"
|
|
239
258
|
class=${u(n)}
|
|
240
|
-
role=${r && this.dotLabel ? "img" :
|
|
241
|
-
aria-label=${r && this.dotLabel ? this.dotLabel :
|
|
242
|
-
aria-live=${a ? "polite" :
|
|
259
|
+
role=${r && this.dotLabel ? "img" : s}
|
|
260
|
+
aria-label=${r && this.dotLabel ? this.dotLabel : s}
|
|
261
|
+
aria-live=${a ? "polite" : s}
|
|
243
262
|
>
|
|
244
|
-
${t ? d`<span class="badge__variant-label">${t}: </span>` :
|
|
245
|
-
${r ?
|
|
263
|
+
${t ? d`<span class="badge__variant-label">${t}: </span>` : s}
|
|
264
|
+
${r ? s : d`<slot name="prefix"></slot>`}
|
|
246
265
|
${a ? this._countDisplay : d`<slot @slotchange=${this._handleSlotChange}></slot>`}
|
|
247
266
|
${this.removable ? d`<button
|
|
248
267
|
part="remove-button"
|
|
@@ -256,7 +275,7 @@ let e = class extends g {
|
|
|
256
275
|
fill="currentColor"
|
|
257
276
|
/>
|
|
258
277
|
</svg>
|
|
259
|
-
</button>` :
|
|
278
|
+
</button>` : s}
|
|
260
279
|
</span>
|
|
261
280
|
`;
|
|
262
281
|
}
|
|
@@ -304,4 +323,4 @@ e = o([
|
|
|
304
323
|
export {
|
|
305
324
|
e as H
|
|
306
325
|
};
|
|
307
|
-
//# sourceMappingURL=hx-badge-
|
|
326
|
+
//# sourceMappingURL=hx-badge-RPzd-t5l.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hx-badge-RPzd-t5l.js","sources":["../../src/components/hx-badge/hx-badge.styles.ts","../../src/components/hx-badge/hx-badge.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixBadgeStyles = css`\n :host {\n display: inline-block;\n }\n\n .badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--hx-space-1, 0.25rem);\n border-radius: var(--hx-badge-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-badge-bg, var(--hx-color-primary-500, #2563eb));\n color: var(--hx-badge-color, var(--hx-color-neutral-0, #ffffff));\n font-family: var(--hx-badge-font-family, var(--hx-font-family-sans, sans-serif));\n font-weight: var(--hx-badge-font-weight, var(--hx-font-weight-semibold, 600));\n line-height: var(--hx-line-height-tight, 1.25);\n white-space: nowrap;\n vertical-align: middle;\n position: relative;\n }\n\n /* ─── Size Variants ─── */\n\n .badge--sm {\n font-size: var(--hx-badge-font-size, var(--hx-font-size-2xs, 0.625rem));\n padding: var(--hx-badge-padding-y, var(--hx-space-0-5, 0.125rem))\n var(--hx-badge-padding-x, var(--hx-space-1-5, 0.375rem));\n }\n\n .badge--md {\n font-size: var(--hx-badge-font-size, var(--hx-font-size-xs, 0.75rem));\n padding: var(--hx-badge-padding-y, var(--hx-space-1, 0.25rem))\n var(--hx-badge-padding-x, var(--hx-space-2, 0.5rem));\n }\n\n .badge--lg {\n font-size: var(--hx-badge-font-size, var(--hx-font-size-sm, 0.875rem));\n padding: var(--hx-badge-padding-y, var(--hx-space-1, 0.25rem))\n var(--hx-badge-padding-x, var(--hx-space-3, 0.75rem));\n }\n\n /* ─── Style Variants ─── */\n\n .badge--primary {\n --hx-badge-bg: var(--hx-color-primary-500, #2563eb);\n --hx-badge-color: var(--hx-color-neutral-0, #ffffff);\n --hx-badge-pulse-color-internal: var(\n --hx-badge-pulse-color,\n var(--hx-color-primary-500, #2563eb)\n );\n }\n\n .badge--secondary {\n --hx-badge-bg: var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6));\n --hx-badge-color: var(--hx-badge-secondary-color, var(--hx-color-neutral-700, #374151));\n --hx-badge-pulse-color-internal: var(\n --hx-badge-pulse-color,\n var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6))\n );\n }\n\n .badge--success {\n --hx-badge-bg: var(--hx-color-success-700, #15803d);\n --hx-badge-color: var(--hx-color-neutral-0, #ffffff);\n --hx-badge-pulse-color-internal: var(\n --hx-badge-pulse-color,\n var(--hx-color-success-700, #15803d)\n );\n }\n\n .badge--warning {\n --hx-badge-bg: var(--hx-color-warning-500, #eab308);\n --hx-badge-color: var(--hx-color-neutral-900, #1a1a1a);\n --hx-badge-pulse-color-internal: var(\n --hx-badge-pulse-color,\n var(--hx-color-warning-500, #eab308)\n );\n }\n\n .badge--error {\n --hx-badge-bg: var(--hx-color-error-500, #dc2626);\n --hx-badge-color: var(--hx-color-neutral-0, #ffffff);\n --hx-badge-pulse-color-internal: var(\n --hx-badge-pulse-color,\n var(--hx-color-error-500, #dc2626)\n );\n }\n\n .badge--neutral {\n --hx-badge-bg: var(--hx-color-neutral-200, #e5e7eb);\n --hx-badge-color: var(--hx-color-neutral-700, #374151);\n --hx-badge-pulse-color-internal: var(\n --hx-badge-pulse-color,\n var(--hx-color-neutral-200, #e5e7eb)\n );\n }\n\n .badge--info {\n --hx-badge-bg: var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1));\n --hx-badge-color: var(--hx-badge-info-color, var(--hx-color-neutral-0, #ffffff));\n --hx-badge-pulse-color-internal: var(\n --hx-badge-pulse-color,\n var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1))\n );\n }\n\n /* ─── Semantic Variant Label (WCAG 1.4.1) ─── */\n /* Visually hidden text prefix for semantic variants (success/warning/error/info). */\n /* Ensures the variant is not conveyed by color alone. */\n\n .badge__variant-label {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Pill Mode ─── */\n\n .badge--pill {\n border-radius: var(--hx-badge-border-radius, var(--hx-border-radius-full, 9999px));\n }\n\n /* ─── Dot Indicator (empty + pulse) ─── */\n\n .badge--dot {\n width: var(--hx-badge-dot-size, var(--hx-space-2, 0.5rem));\n height: var(--hx-badge-dot-size, var(--hx-space-2, 0.5rem));\n padding: 0;\n border-radius: var(--hx-border-radius-full, 9999px);\n }\n\n /* Guard: hide all inner content in dot mode — the dot is purely visual */\n .badge--dot ::slotted(*),\n .badge--dot slot,\n .badge--dot slot[name='prefix'] {\n display: none !important;\n }\n\n /* ─── Pulse Animation ─── */\n\n @keyframes hx-badge-pulse {\n 0%,\n 100% {\n opacity: 1;\n box-shadow: 0 0 0 2px var(--hx-badge-pulse-color-internal, currentColor);\n }\n 50% {\n opacity: var(--hx-opacity-75, 0.75);\n box-shadow: 0 0 0 6px transparent;\n }\n }\n\n .badge--pulse {\n animation: hx-badge-pulse var(--hx-badge-pulse-duration, var(--hx-duration-slow, 2s))\n var(--hx-badge-pulse-easing, var(--hx-easing-in-out, ease-in-out)) infinite;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .badge--pulse {\n animation: none;\n }\n }\n\n /* ─── Remove Button ─── */\n\n .badge__remove-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 0;\n margin-inline-start: var(--hx-space-1, 0.25rem);\n cursor: pointer;\n color: inherit;\n opacity: var(--hx-opacity-75, 0.75);\n border-radius: var(--hx-border-radius-sm, 0.125rem);\n line-height: 0;\n /* WCAG 2.5.5: minimum 44×44px touch target */\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n }\n\n .badge__remove-button:hover {\n opacity: var(--hx-opacity-100, 1);\n }\n\n .badge__remove-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid var(--hx-focus-ring-color, currentColor);\n outline-offset: var(--hx-focus-ring-offset, 1px);\n }\n`;\n","import { LitElement, html, nothing } 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 { helixBadgeStyles } from './hx-badge.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/**\n * A small status indicator for notifications, counts, and labels.\n *\n * @summary Presentational badge for status indicators, notification counts, and labels.\n *\n * @tag hx-badge\n *\n * @slot - Default slot for badge content (text, number). When empty with pulse enabled, renders as a dot indicator.\n * @slot prefix - Icon or content rendered before the badge text.\n *\n * @fires {CustomEvent<void>} hx-remove - Dispatched when the user clicks the remove button.\n *\n * @csspart badge - The badge element.\n * @csspart remove-button - The remove/dismiss button.\n *\n * @cssprop [--hx-badge-bg=var(--hx-color-primary-500)] - Badge background color. The primary override point.\n * @cssprop [--hx-badge-color=var(--hx-color-neutral-0)] - Badge text color. The primary override point.\n * @cssprop [--hx-badge-font-size] - Badge font size (set per size variant).\n * @cssprop [--hx-badge-font-weight=var(--hx-font-weight-semibold)] - Badge font weight.\n * @cssprop [--hx-badge-font-family=var(--hx-font-family-sans)] - Badge font family.\n * @cssprop [--hx-badge-border-radius=var(--hx-border-radius-md)] - Badge border radius.\n * @cssprop [--hx-badge-padding-x] - Badge horizontal padding (set per size variant).\n * @cssprop [--hx-badge-padding-y] - Badge vertical padding (set per size variant).\n * @cssprop [--hx-badge-pulse-color] - Pulse color matching variant background with reduced opacity.\n * @cssprop [--hx-badge-dot-size=var(--hx-size-2)] - Dot indicator size when rendered without content.\n * @cssprop [--hx-badge-secondary-bg=var(--hx-color-neutral-100)] - Background for the secondary variant.\n * @cssprop [--hx-badge-secondary-color=var(--hx-color-neutral-700)] - Text color for the secondary variant.\n * @cssprop [--hx-badge-info-bg=var(--hx-color-info-700)] - Background for the info variant.\n * @cssprop [--hx-badge-info-color=var(--hx-color-neutral-0)] - Text color for the info variant.\n */\n@customElement('hx-badge')\nexport class HelixBadge extends LitElement {\n static override styles = [helixBadgeStyles];\n\n /**\n * Visual style variant of the badge.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'neutral' | 'info' =\n 'primary';\n\n /**\n * Size of the badge.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Whether the badge uses fully rounded (pill) styling.\n * @attr pill\n */\n @property({ type: Boolean, reflect: true })\n pill = false;\n\n /**\n * Whether the badge displays an animated pulse for attention.\n * @attr pulse\n */\n @property({ type: Boolean, reflect: true })\n pulse = false;\n\n /**\n * Whether the badge renders a dismiss button.\n * @attr removable\n */\n @property({ type: Boolean, reflect: true })\n removable = false;\n\n /**\n * Numeric count to display. When set, renders the count as badge content.\n * When count exceeds `max`, displays `${max}+` (e.g. `99+`).\n * @attr count\n */\n @property({ type: Number, reflect: true })\n count: number | undefined = undefined;\n\n /**\n * Maximum count value before truncation to `${max}+`. Defaults to 99.\n * @attr max\n */\n @property({ type: Number, reflect: true })\n max = 99;\n\n /**\n * Accessible label for the dot indicator mode (pulse + empty slot).\n * Required for WCAG 4.1.2 compliance when using the dot indicator pattern.\n * Example: `dot-label=\"3 new messages\"`.\n * @attr dot-label\n */\n @property({ type: String, attribute: 'dot-label' })\n dotLabel = '';\n\n /**\n * Accessible label for the remove button. Should describe what is being removed.\n * Defaults to \"Remove\". For better accessibility, include context: e.g. \"Remove Critical badge\".\n * @attr remove-label\n */\n @property({ type: String, attribute: 'remove-label' })\n removeLabel = 'Remove';\n\n /**\n * Tracks whether the default slot has assigned content.\n * @internal\n */\n @state()\n private _hasSlotContent = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-badge', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as 'sm' | 'md' | 'lg';\n }\n }\n\n // ─── Slot Change Handling ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const nodes = slot.assignedNodes({ flatten: true });\n // Check if any assigned node has non-whitespace content\n this._hasSlotContent = nodes.some((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) return true;\n if (node.nodeType === Node.TEXT_NODE) {\n return (node.textContent ?? '').trim().length > 0;\n }\n return false;\n });\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleRemove(): void {\n this.dispatchEvent(\n new CustomEvent<void>('hx-remove', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n // ─── Count Display ───\n\n /** @internal */\n private get _countDisplay(): string {\n if (this.count === undefined) return '';\n return this.count > this.max ? `${this.max}+` : String(this.count);\n }\n\n // ─── WCAG 1.4.1: Semantic variant label map ───\n // Variants that carry semantic meaning beyond decoration need a non-color cue.\n // Visually-hidden text is prepended so screen reader users and color-blind\n // users get the variant context even when no icon is slotted.\n\n /** @internal */\n private static readonly _SEMANTIC_VARIANT_LABELS: Partial<Record<HelixBadge['variant'], string>> =\n {\n success: 'Success',\n warning: 'Warning',\n error: 'Error',\n info: 'Info',\n };\n\n /** @internal */\n private get _semanticVariantLabel(): string {\n return HelixBadge._SEMANTIC_VARIANT_LABELS[this.variant] ?? '';\n }\n\n // ─── Render ───\n\n override render() {\n const hasCount = this.count !== undefined;\n const isDot = !this._hasSlotContent && !hasCount && this.pulse;\n\n if (isDot && !this.dotLabel) {\n devWarn(\n 'hx-badge',\n 'Dot badge is missing an accessible label. Set `dotLabel` so screen readers can announce the badge purpose (WCAG 4.1.2).',\n );\n }\n\n const classes = {\n badge: true,\n [`badge--${this.variant}`]: true,\n [`badge--${this.size}`]: true,\n 'badge--pill': this.pill,\n 'badge--pulse': this.pulse,\n 'badge--dot': isDot,\n };\n\n const variantLabel = this._semanticVariantLabel;\n\n return html`\n <span\n part=\"badge\"\n class=${classMap(classes)}\n role=${isDot && this.dotLabel ? 'img' : nothing}\n aria-label=${isDot && this.dotLabel ? this.dotLabel : nothing}\n aria-live=${hasCount ? 'polite' : nothing}\n >\n ${variantLabel\n ? html`<span class=\"badge__variant-label\">${variantLabel}: </span>`\n : nothing}\n ${isDot ? nothing : html`<slot name=\"prefix\"></slot>`}\n ${hasCount ? this._countDisplay : html`<slot @slotchange=${this._handleSlotChange}></slot>`}\n ${this.removable\n ? html`<button\n part=\"remove-button\"\n class=\"badge__remove-button\"\n aria-label=${this.removeLabel}\n @click=${this._handleRemove}\n >\n <svg viewBox=\"0 0 12 12\" aria-hidden=\"true\" width=\"10\" height=\"10\">\n <path\n d=\"M2.22 2.22a.75.75 0 011.06 0L6 4.94l2.72-2.72a.75.75 0 011.06 1.06L7.06 6l2.72 2.72a.75.75 0 01-1.06 1.06L6 7.06 3.28 9.78a.75.75 0 01-1.06-1.06L4.94 6 2.22 3.28a.75.75 0 010-1.06z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>`\n : nothing}\n </span>\n `;\n }\n}\n\n/**\n * @deprecated Use `HelixBadge` instead. This alias will be removed in a future\n * major version as part of the project-wide migration from `Wc` to `Hx` prefixes.\n * @since 0.1.0\n * @removal-target 1.0.0\n */\nexport type WcBadge = HelixBadge;\n\n/** Canonical type alias for the hx-badge component. */\nexport type HxBadge = HelixBadge;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-badge': HelixBadge;\n }\n}\n"],"names":["helixBadgeStyles","css","HelixBadge","LitElement","legacySize","e","nodes","node","hasCount","isDot","classes","variantLabel","html","classMap","nothing","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -109,9 +109,9 @@ const m = v`
|
|
|
109
109
|
border: 0;
|
|
110
110
|
}
|
|
111
111
|
`;
|
|
112
|
-
var g = Object.defineProperty,
|
|
113
|
-
for (var t = l > 1 ? void 0 : l ?
|
|
114
|
-
(
|
|
112
|
+
var g = Object.defineProperty, b = Object.getOwnPropertyDescriptor, i = (r, n, s, l) => {
|
|
113
|
+
for (var t = l > 1 ? void 0 : l ? b(n, s) : n, d = r.length - 1, h; d >= 0; d--)
|
|
114
|
+
(h = r[d]) && (t = (l ? h(n, s, t) : h(t)) || t);
|
|
115
115
|
return l && t && g(n, s, t), t;
|
|
116
116
|
};
|
|
117
117
|
let e = class extends x {
|
|
@@ -171,6 +171,7 @@ let e = class extends x {
|
|
|
171
171
|
class=${p(r)}
|
|
172
172
|
role="link"
|
|
173
173
|
aria-disabled="true"
|
|
174
|
+
tabindex="0"
|
|
174
175
|
@click=${this._handleClick}
|
|
175
176
|
>
|
|
176
177
|
<slot></slot>
|
|
@@ -216,4 +217,4 @@ e = i([
|
|
|
216
217
|
export {
|
|
217
218
|
e as H
|
|
218
219
|
};
|
|
219
|
-
//# sourceMappingURL=hx-link-
|
|
220
|
+
//# sourceMappingURL=hx-link-B8IwUMSc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-link-IVsXmsKx.js","sources":["../../src/components/hx-link/hx-link.styles.ts","../../src/components/hx-link/hx-link.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixLinkStyles = css`\n :host {\n display: inline;\n }\n\n :host([disabled]) {\n cursor: not-allowed;\n }\n\n /* --- Base Link --- */\n\n .link {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n color: var(--hx-link-color, var(--hx-color-primary-500, #2563eb));\n font-family: var(--hx-link-font-family, var(--hx-font-family-sans, inherit));\n font-size: inherit;\n line-height: inherit;\n text-decoration: var(--hx-link-text-decoration, underline);\n text-underline-offset: var(--hx-link-underline-offset, 2px);\n cursor: pointer;\n outline: 0;\n transition:\n color var(--hx-transition-fast, 150ms ease),\n text-decoration-color var(--hx-transition-fast, 150ms ease);\n }\n\n .link:hover {\n color: var(--hx-link-color-hover, var(--hx-color-primary-700, #1d4ed8));\n text-decoration: var(--hx-link-text-decoration-hover, underline);\n }\n\n .link:active {\n color: var(--hx-link-color-active, var(--hx-color-primary-800, #1e40af));\n }\n\n .link:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-link-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #60a5fa))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.125rem);\n }\n\n /* --- Variant: subtle --- */\n\n .link--subtle {\n color: var(--hx-link-color-subtle, var(--hx-color-neutral-600, #475569));\n text-decoration: none;\n }\n\n .link--subtle:hover {\n color: var(--hx-link-color-hover, var(--hx-color-primary-700, #1d4ed8));\n text-decoration: underline;\n }\n\n /* --- Variant: danger --- */\n\n .link--danger {\n color: var(--hx-link-color-danger, var(--hx-color-error-text, #b91c1c));\n }\n\n .link--danger:hover {\n color: var(--hx-link-color-danger-hover, var(--hx-color-error-700, #b91c1c));\n }\n\n /* --- Disabled --- */\n\n .link--disabled {\n color: var(--hx-link-color-disabled, var(--hx-color-neutral-400, #94a3b8));\n text-decoration: none;\n pointer-events: none;\n }\n\n /* --- External link icon --- */\n\n .link__external-icon {\n display: inline-flex;\n width: 0.75em;\n height: 0.75em;\n flex-shrink: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .link {\n transition: none;\n }\n }\n\n /* --- Visually hidden (sr-only) --- */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n`;\n","import { LitElement, html, nothing, svg } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { helixLinkStyles } from './hx-link.styles.js';\n\n/**\n * Variant options for the link component.\n */\nexport type LinkVariant = 'default' | 'subtle' | 'danger';\n\n/**\n * A semantic hyperlink component with accessibility-first design.\n * Renders a native `<a>` element for enabled state and a `<span>` for\n * disabled state with full keyboard and screen reader support.\n *\n * @summary Accessible hyperlink with external-link detection, disabled state,\n * and download support.\n *\n * @tag hx-link\n *\n * @slot - Default slot for link label text or content.\n *\n * @fires {CustomEvent<{originalEvent: MouseEvent}>} hx-click - Dispatched when\n * the link is clicked and is not disabled.\n *\n * @csspart link - The inner anchor or span element.\n * @csspart external-icon - The external link icon SVG (when target=\"_blank\").\n *\n * @cssprop [--hx-link-color=var(--hx-color-primary-500)] - Default link color.\n * @cssprop [--hx-link-color-hover=var(--hx-color-primary-700)] - Hover color.\n * @cssprop [--hx-link-color-active=var(--hx-color-primary-800)] - Active color.\n * @cssprop [--hx-link-color-disabled=var(--hx-color-neutral-400)] - Disabled color.\n * @cssprop [--hx-link-color-subtle=var(--hx-color-neutral-600)] - Subtle variant color.\n * @cssprop [--hx-link-color-danger=var(--hx-color-error-text)] - Danger variant color.\n * @cssprop [--hx-link-color-danger-hover=var(--hx-color-error-700)] - Danger variant hover color.\n * @cssprop [--hx-link-font-family=var(--hx-font-family-sans)] - Link font family.\n * @cssprop [--hx-link-text-decoration=underline] - Link text decoration.\n * @cssprop [--hx-link-text-decoration-hover=underline] - Hover text decoration.\n * @cssprop [--hx-link-underline-offset=2px] - Text underline offset.\n * @cssprop [--hx-link-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n *\n * @note The `:visited` pseudo-class does not work inside Shadow DOM due to\n * browser privacy restrictions. This is a known platform limitation.\n */\n@customElement('hx-link')\nexport class HelixLink extends LitElement {\n static override styles = [helixLinkStyles];\n\n /**\n * The URL the link points to.\n * @attr href\n */\n @property({ type: String })\n href: string | undefined = undefined;\n\n /**\n * Where to display the linked URL (_self, _blank, etc.).\n * When set to \"_blank\", automatically adds rel=\"noopener noreferrer\"\n * and shows an external-link indicator.\n * @attr target\n */\n @property({ type: String })\n target: string | undefined = undefined;\n\n /**\n * Visual style variant of the link.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'subtle' | 'danger' = 'default';\n\n /**\n * Whether the link is disabled. Renders a span instead of an anchor.\n * The disabled span is keyboard-focusable (tabindex=\"0\") and announces\n * as a disabled link to screen readers.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Prompts the user to download the linked URL. When set to a string,\n * the value is used as the suggested filename.\n * @attr download\n */\n @property({ type: String })\n download: string | undefined = undefined;\n\n /**\n * Relationship between the current document and the linked URL.\n * Automatically set to \"noopener noreferrer\" when target=\"_blank\".\n * @attr rel\n */\n @property({ type: String })\n rel: string | undefined = undefined;\n\n // --- Event Handling ---\n\n /** @internal */\n private _handleClick(e: MouseEvent): void {\n if (this.disabled) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n this.dispatchEvent(\n new CustomEvent<{ originalEvent: MouseEvent }>('hx-click', {\n bubbles: true,\n composed: true,\n detail: { originalEvent: e },\n }),\n );\n }\n\n // --- Render Helpers ---\n\n /** @internal */\n private _computeRel(): string | undefined {\n if (this.rel) return this.rel;\n if (this.target === '_blank') return 'noopener noreferrer';\n return undefined;\n }\n\n /** @internal */\n private _renderExternalIcon() {\n if (this.target !== '_blank') return nothing;\n\n return html`\n <svg\n class=\"link__external-icon\"\n part=\"external-icon\"\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n ${svg`<path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" /><polyline points=\"15 3 21 3 21 9\" /><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />`}\n </svg>\n <span class=\"sr-only\">(opens in new tab)</span>\n `;\n }\n\n // --- Render ---\n\n override render() {\n const classes = {\n link: true,\n [`link--${this.variant}`]: this.variant !== 'default',\n 'link--disabled': this.disabled,\n };\n\n if (this.disabled) {\n return html`\n <span\n part=\"link\"\n class=${classMap(classes)}\n role=\"link\"\n aria-disabled=\"true\"\n @click=${this._handleClick}\n >\n <slot></slot>\n </span>\n `;\n }\n\n return html`\n <a\n part=\"link\"\n class=${classMap(classes)}\n href=${ifDefined(this.href)}\n target=${ifDefined(this.target)}\n rel=${ifDefined(this._computeRel())}\n download=${ifDefined(this.download)}\n @click=${this._handleClick}\n >\n <slot></slot>\n ${this._renderExternalIcon()}\n </a>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-link': HelixLink;\n }\n}\n"],"names":["helixLinkStyles","css","HelixLink","LitElement","e","nothing","html","svg","classes","classMap","ifDefined","__decorateClass","property","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-link-B8IwUMSc.js","sources":["../../src/components/hx-link/hx-link.styles.ts","../../src/components/hx-link/hx-link.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixLinkStyles = css`\n :host {\n display: inline;\n }\n\n :host([disabled]) {\n cursor: not-allowed;\n }\n\n /* --- Base Link --- */\n\n .link {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n color: var(--hx-link-color, var(--hx-color-primary-500, #2563eb));\n font-family: var(--hx-link-font-family, var(--hx-font-family-sans, inherit));\n font-size: inherit;\n line-height: inherit;\n text-decoration: var(--hx-link-text-decoration, underline);\n text-underline-offset: var(--hx-link-underline-offset, 2px);\n cursor: pointer;\n outline: 0;\n transition:\n color var(--hx-transition-fast, 150ms ease),\n text-decoration-color var(--hx-transition-fast, 150ms ease);\n }\n\n .link:hover {\n color: var(--hx-link-color-hover, var(--hx-color-primary-700, #1d4ed8));\n text-decoration: var(--hx-link-text-decoration-hover, underline);\n }\n\n .link:active {\n color: var(--hx-link-color-active, var(--hx-color-primary-800, #1e40af));\n }\n\n .link:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-link-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #60a5fa))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.125rem);\n }\n\n /* --- Variant: subtle --- */\n\n .link--subtle {\n color: var(--hx-link-color-subtle, var(--hx-color-neutral-600, #475569));\n text-decoration: none;\n }\n\n .link--subtle:hover {\n color: var(--hx-link-color-hover, var(--hx-color-primary-700, #1d4ed8));\n text-decoration: underline;\n }\n\n /* --- Variant: danger --- */\n\n .link--danger {\n color: var(--hx-link-color-danger, var(--hx-color-error-text, #b91c1c));\n }\n\n .link--danger:hover {\n color: var(--hx-link-color-danger-hover, var(--hx-color-error-700, #b91c1c));\n }\n\n /* --- Disabled --- */\n\n .link--disabled {\n color: var(--hx-link-color-disabled, var(--hx-color-neutral-400, #94a3b8));\n text-decoration: none;\n pointer-events: none;\n }\n\n /* --- External link icon --- */\n\n .link__external-icon {\n display: inline-flex;\n width: 0.75em;\n height: 0.75em;\n flex-shrink: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .link {\n transition: none;\n }\n }\n\n /* --- Visually hidden (sr-only) --- */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n`;\n","import { LitElement, html, nothing, svg } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { helixLinkStyles } from './hx-link.styles.js';\n\n/**\n * Variant options for the link component.\n */\nexport type LinkVariant = 'default' | 'subtle' | 'danger';\n\n/**\n * A semantic hyperlink component with accessibility-first design.\n * Renders a native `<a>` element for enabled state and a `<span>` for\n * disabled state with full keyboard and screen reader support.\n *\n * @summary Accessible hyperlink with external-link detection, disabled state,\n * and download support.\n *\n * @tag hx-link\n *\n * @slot - Default slot for link label text or content.\n *\n * @fires {CustomEvent<{originalEvent: MouseEvent}>} hx-click - Dispatched when\n * the link is clicked and is not disabled.\n *\n * @csspart link - The inner anchor or span element.\n * @csspart external-icon - The external link icon SVG (when target=\"_blank\").\n *\n * @cssprop [--hx-link-color=var(--hx-color-primary-500)] - Default link color.\n * @cssprop [--hx-link-color-hover=var(--hx-color-primary-700)] - Hover color.\n * @cssprop [--hx-link-color-active=var(--hx-color-primary-800)] - Active color.\n * @cssprop [--hx-link-color-disabled=var(--hx-color-neutral-400)] - Disabled color.\n * @cssprop [--hx-link-color-subtle=var(--hx-color-neutral-600)] - Subtle variant color.\n * @cssprop [--hx-link-color-danger=var(--hx-color-error-text)] - Danger variant color.\n * @cssprop [--hx-link-color-danger-hover=var(--hx-color-error-700)] - Danger variant hover color.\n * @cssprop [--hx-link-font-family=var(--hx-font-family-sans)] - Link font family.\n * @cssprop [--hx-link-text-decoration=underline] - Link text decoration.\n * @cssprop [--hx-link-text-decoration-hover=underline] - Hover text decoration.\n * @cssprop [--hx-link-underline-offset=2px] - Text underline offset.\n * @cssprop [--hx-link-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n *\n * @note The `:visited` pseudo-class does not work inside Shadow DOM due to\n * browser privacy restrictions. This is a known platform limitation.\n */\n@customElement('hx-link')\nexport class HelixLink extends LitElement {\n static override styles = [helixLinkStyles];\n\n /**\n * The URL the link points to.\n * @attr href\n */\n @property({ type: String })\n href: string | undefined = undefined;\n\n /**\n * Where to display the linked URL (_self, _blank, etc.).\n * When set to \"_blank\", automatically adds rel=\"noopener noreferrer\"\n * and shows an external-link indicator.\n * @attr target\n */\n @property({ type: String })\n target: string | undefined = undefined;\n\n /**\n * Visual style variant of the link.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'subtle' | 'danger' = 'default';\n\n /**\n * Whether the link is disabled. Renders a span instead of an anchor.\n * The disabled span is keyboard-focusable (tabindex=\"0\") and announces\n * as a disabled link to screen readers.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Prompts the user to download the linked URL. When set to a string,\n * the value is used as the suggested filename.\n * @attr download\n */\n @property({ type: String })\n download: string | undefined = undefined;\n\n /**\n * Relationship between the current document and the linked URL.\n * Automatically set to \"noopener noreferrer\" when target=\"_blank\".\n * @attr rel\n */\n @property({ type: String })\n rel: string | undefined = undefined;\n\n // --- Event Handling ---\n\n /** @internal */\n private _handleClick(e: MouseEvent): void {\n if (this.disabled) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n this.dispatchEvent(\n new CustomEvent<{ originalEvent: MouseEvent }>('hx-click', {\n bubbles: true,\n composed: true,\n detail: { originalEvent: e },\n }),\n );\n }\n\n // --- Render Helpers ---\n\n /** @internal */\n private _computeRel(): string | undefined {\n if (this.rel) return this.rel;\n if (this.target === '_blank') return 'noopener noreferrer';\n return undefined;\n }\n\n /** @internal */\n private _renderExternalIcon() {\n if (this.target !== '_blank') return nothing;\n\n return html`\n <svg\n class=\"link__external-icon\"\n part=\"external-icon\"\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n ${svg`<path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" /><polyline points=\"15 3 21 3 21 9\" /><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />`}\n </svg>\n <span class=\"sr-only\">(opens in new tab)</span>\n `;\n }\n\n // --- Render ---\n\n override render() {\n const classes = {\n link: true,\n [`link--${this.variant}`]: this.variant !== 'default',\n 'link--disabled': this.disabled,\n };\n\n if (this.disabled) {\n return html`\n <span\n part=\"link\"\n class=${classMap(classes)}\n role=\"link\"\n aria-disabled=\"true\"\n tabindex=\"0\"\n @click=${this._handleClick}\n >\n <slot></slot>\n </span>\n `;\n }\n\n return html`\n <a\n part=\"link\"\n class=${classMap(classes)}\n href=${ifDefined(this.href)}\n target=${ifDefined(this.target)}\n rel=${ifDefined(this._computeRel())}\n download=${ifDefined(this.download)}\n @click=${this._handleClick}\n >\n <slot></slot>\n ${this._renderExternalIcon()}\n </a>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-link': HelixLink;\n }\n}\n"],"names":["helixLinkStyles","css","HelixLink","LitElement","e","nothing","html","svg","classes","classMap","ifDefined","__decorateClass","property","customElement"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helixui/library",
|
|
3
|
-
"version": "2.1.2-next.
|
|
3
|
+
"version": "2.1.2-next.45",
|
|
4
4
|
"description": "Enterprise Web Component Library built with Lit 3.x",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"customElements": "custom-elements.json",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"lit": "^3.3.2",
|
|
48
|
-
"@helixui/tokens": "2.1.2-next.
|
|
48
|
+
"@helixui/tokens": "2.1.2-next.45"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@floating-ui/dom": "^1.7.6"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-action-bar-BpY1Z1UV.js","sources":["../../src/components/hx-action-bar/hx-action-bar.styles.ts","../../src/components/hx-action-bar/hx-action-bar.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixActionBarStyles = css`\n :host {\n display: block;\n }\n\n /* ─── Base ─── */\n\n .base {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--hx-action-bar-gap, var(--hx-space-2, 0.5rem));\n padding: var(--hx-action-bar-padding, var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem));\n background: var(--hx-action-bar-bg, transparent);\n border: var(--hx-action-bar-border, none);\n box-sizing: border-box;\n width: 100%;\n }\n\n /* ─── Sticky (top) ─── */\n\n .base--sticky {\n position: sticky;\n top: 0;\n padding-top: max(var(--hx-action-bar-padding-block-start, 0px), env(safe-area-inset-top, 0px));\n z-index: var(--hx-action-bar-z-index, 10);\n /*\n * Consumers: when this bar is sticky, add scroll-padding-top to the scroll container\n * equal to the bar's rendered height so anchor targets are not hidden behind the bar.\n * Example: .scroll-container { scroll-padding-top: 2.5rem; }\n */\n }\n\n /* ─── Bottom sticky ─── */\n\n .base--bottom {\n position: sticky;\n bottom: 0;\n /*\n * Respect iOS home-indicator safe area on devices with notch/home bar.\n * Falls back to 0px on devices that do not support env().\n */\n padding-bottom: max(\n var(--hx-action-bar-padding-block-end, 0px),\n env(safe-area-inset-bottom, 0px)\n );\n z-index: var(--hx-action-bar-z-index, 10);\n }\n\n /* ─── Variant: outlined ─── */\n\n .base--outlined {\n background: var(--hx-action-bar-bg, var(--hx-color-neutral-0, #fff));\n border: var(\n --hx-action-bar-border,\n var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #e5e7eb)\n );\n border-radius: var(--hx-border-radius-md, 0.375rem);\n }\n\n /* ─── Variant: filled ─── */\n\n .base--filled {\n background: var(--hx-action-bar-bg, var(--hx-color-neutral-50, #f9fafb));\n border-radius: var(--hx-border-radius-md, 0.375rem);\n }\n\n /* ─── Size modifiers ─── */\n\n .base--sm {\n padding: var(--hx-action-bar-padding, var(--hx-space-1, 0.25rem) var(--hx-space-2, 0.5rem));\n gap: var(--hx-action-bar-gap, var(--hx-space-1, 0.25rem));\n min-height: var(--hx-size-8, 2rem);\n }\n\n .base--md {\n min-height: var(--hx-size-10, 2.5rem);\n }\n\n .base--lg {\n padding: var(--hx-action-bar-padding, var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem));\n gap: var(--hx-action-bar-gap, var(--hx-space-3, 0.75rem));\n min-height: var(--hx-size-12, 3rem);\n }\n\n /* ─── Sections ─── */\n\n .section {\n display: flex;\n align-items: center;\n gap: inherit;\n }\n\n /*\n * Equal flex-basis on start and end guarantees the center section is visually centered\n * within the full bar width, regardless of how wide start and end content are.\n */\n .section--start {\n flex: 1 1 0;\n justify-content: flex-start;\n }\n\n .section--center {\n flex: 0 0 auto;\n justify-content: center;\n }\n\n .section--end {\n flex: 1 1 0;\n justify-content: flex-end;\n }\n\n /* ─── Slotted content ─── */\n\n ::slotted(*) {\n flex-shrink: 0;\n }\n`;\n","import { LitElement, html } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { helixActionBarStyles } from './hx-action-bar.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// Re-export size type for external consumers.\nexport type ActionBarSize = 'sm' | 'md' | 'lg';\n\n/**\n * A horizontal toolbar container for grouping related action buttons and controls.\n * Implements the ARIA toolbar pattern with roving tabindex keyboard navigation.\n *\n * @summary Horizontal action bar for grouping related controls.\n *\n * @tag hx-action-bar\n *\n * @slot start - Left-aligned actions.\n * @slot - Center content (default slot).\n * @slot end - Right-aligned actions.\n * @slot overflow - Actions revealed when the bar is constrained for space.\n *\n * @csspart base - The root toolbar container element.\n * @csspart start - The start (left) slot wrapper.\n * @csspart center - The center (default) slot wrapper.\n * @csspart end - The end (right) slot wrapper.\n * @csspart overflow - The overflow slot wrapper (hidden when no overflow content).\n *\n * @cssprop [--hx-action-bar-bg=transparent] - Bar background color (default variant).\n * @cssprop [--hx-action-bar-border=none] - Bar border (default variant).\n * @cssprop [--hx-action-bar-padding=var(--hx-space-2,0.5rem) var(--hx-space-3,0.75rem)] - Inner padding.\n * @cssprop [--hx-action-bar-gap=var(--hx-space-2,0.5rem)] - Gap between slotted items.\n * @cssprop [--hx-action-bar-z-index=10] - Z-index when sticky or bottom position.\n *\n * @attr {string} aria-label - Required. Identifies the toolbar to assistive technology.\n * When multiple toolbars appear on the same page, each must have a unique, descriptive label.\n *\n * @example\n * ```html\n * <hx-action-bar aria-label=\"Patient actions\">\n * <hx-button slot=\"start\">Save</hx-button>\n * <hx-button slot=\"end\" variant=\"ghost\">Cancel</hx-button>\n * </hx-action-bar>\n * ```\n */\n@customElement('hx-action-bar')\nexport class HelixActionBar extends LitElement {\n static override styles = [helixActionBarStyles];\n\n /**\n * Size of the action bar — propagated as a data attribute to slotted children.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Visual variant controlling the bar background.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'outlined' | 'filled' = 'default';\n\n /**\n * Position and sticky behavior of the action bar.\n * - `top` — normal flow (default)\n * - `sticky` — sticks to the top of the scroll container; add `scroll-padding-top` to the\n * scroll container equal to the bar height to prevent anchor targets from scrolling behind it\n * - `bottom` — sticks to the bottom of the scroll container with iOS safe-area-inset support\n * @attr position\n */\n @property({ type: String, reflect: true })\n position: 'top' | 'bottom' | 'sticky' = 'top';\n\n /**\n * @deprecated Use `position=\"sticky\"` instead.\n * When true, the bar sticks to the top of its scroll container.\n * @attr sticky\n */\n @property({ type: Boolean, reflect: true })\n get sticky(): boolean {\n return this._sticky;\n }\n set sticky(value: boolean) {\n if (value) {\n devWarn(\n 'hx-action-bar',\n 'The `sticky` property is deprecated. Use `position=\"sticky\"` instead.',\n );\n }\n const old = this._sticky;\n this._sticky = value;\n this.requestUpdate('sticky', old);\n }\n /** @internal */\n private _sticky = false;\n\n /**\n * Accessible label for the toolbar.\n * Required when multiple toolbars appear on the same page.\n * @attr aria-label\n */\n @property({ attribute: 'aria-label' })\n ariaLabel: string = 'Actions';\n\n /** Cached list of focusable items — invalidated on slot change. */\n /** @internal */\n private _focusableCache: HTMLElement[] | null = null;\n\n /** Whether the overflow slot has assigned content. * @internal\n */\n @state()\n private _hasOverflow = false;\n\n // ─── Lifecycle ───\n\n /** Arrow function field — stable reference for add/removeEventListener. */\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n if (e.key === 'ArrowRight') {\n e.preventDefault();\n this._moveFocus('next');\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n this._moveFocus('prev');\n } else if (e.key === 'Home') {\n e.preventDefault();\n // Move directly to first item — do NOT call _moveFocus which would visit other items first.\n const items = this._getFocusableItems();\n if (items.length) {\n items.forEach((el, i) => el.setAttribute('tabindex', i === 0 ? '0' : '-1'));\n items[0]?.focus();\n }\n } else if (e.key === 'End') {\n e.preventDefault();\n const items = this._getFocusableItems();\n const last = items.length - 1;\n if (items.length) {\n items.forEach((el, i) => el.setAttribute('tabindex', i === last ? '0' : '-1'));\n items[last]?.focus();\n }\n }\n };\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-action-bar', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as ActionBarSize;\n }\n // Prevent dual aria-label announcement: the host carries the consumer's\n // aria-label attribute while the inner div[role=\"toolbar\"] receives the\n // same value. Setting role=\"none\" on the host hides it from the\n // accessibility tree so only the toolbar is announced.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'none');\n } else if (this.getAttribute('role') !== 'none') {\n devWarn(\n 'hx-action-bar',\n `Setting role=\"${this.getAttribute('role')}\" on the host creates a duplicate toolbar announcement. ` +\n 'The shadow DOM already contains role=\"toolbar\". Set role=\"none\" on the host to suppress it.',\n );\n }\n this.addEventListener('keydown', this._handleKeydown);\n }\n\n override firstUpdated(): void {\n // Slot assignments are complete by firstUpdated; initialize roving tabindex\n // immediately rather than waiting for the async slotchange event.\n this._initRovingTabindex();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n }\n\n // ─── Focusable item discovery ───\n\n /** @internal */\n private _isFocusable(el: HTMLElement): boolean {\n // Check disabled via DOM attribute (native elements) or property (custom elements)\n if (el.hasAttribute('disabled')) return false;\n const elWithDisabled = el as HTMLElement & { disabled?: boolean };\n if (elWithDisabled.disabled === true) return false;\n\n // Use the IDL tabIndex property — covers both DOM attribute and ElementInternals settings.\n // Custom elements (e.g. hx-button) that set tabIndex via ElementInternals are discoverable.\n if (el.tabIndex >= 0) return true;\n\n const tag = el.tagName.toLowerCase();\n return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea';\n }\n\n /** @internal */\n private _getFocusableItems(): HTMLElement[] {\n if (this._focusableCache) return this._focusableCache;\n\n const slots = this.shadowRoot?.querySelectorAll('slot') ?? [];\n const items: HTMLElement[] = [];\n\n for (const slot of Array.from(slots)) {\n const assigned = (slot as HTMLSlotElement).assignedElements({ flatten: true });\n for (const el of assigned) {\n if (!(el instanceof HTMLElement)) continue;\n if (this._isFocusable(el)) {\n // Element is itself focusable — include it and do NOT also recurse into its children\n // to prevent double-counting compound components (e.g. <a><button>).\n items.push(el);\n } else {\n // Element is a non-focusable wrapper (e.g. <div>, <span>) — find focusable children.\n const descendants = el.querySelectorAll<HTMLElement>('*');\n for (const d of Array.from(descendants)) {\n if (this._isFocusable(d)) {\n items.push(d);\n }\n }\n }\n }\n }\n\n this._focusableCache = items;\n return items;\n }\n\n // ─── Roving tabindex helpers ───\n\n /** @internal */\n private _initRovingTabindex(): void {\n this._focusableCache = null; // invalidate cache on slot change\n const items = this._getFocusableItems();\n if (!items.length) return;\n // Find the currently active item. If none exists (e.g. first render or active item was\n // removed), fall back to index 0. Then set ALL items explicitly so newly added items and\n // items whose tabindex changed externally are always in a correct state.\n const activeIndex = items.findIndex((el) => el.getAttribute('tabindex') === '0');\n const targetIndex = activeIndex === -1 ? 0 : activeIndex;\n items.forEach((el, i) => el.setAttribute('tabindex', i === targetIndex ? '0' : '-1'));\n }\n\n /** @internal */\n private _moveFocus(direction: 'next' | 'prev'): void {\n const items = this._getFocusableItems();\n if (!items.length) return;\n\n const focused = document.activeElement as HTMLElement | null;\n const currentIndex = items.indexOf(focused as HTMLElement);\n\n let nextIndex: number;\n if (direction === 'next') {\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n } else {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n }\n\n items.forEach((el, i) => {\n el.setAttribute('tabindex', i === nextIndex ? '0' : '-1');\n });\n\n items[nextIndex]?.focus();\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n if (slot.name === 'overflow') {\n this._hasOverflow = slot.assignedElements({ flatten: true }).length > 0;\n }\n this._initRovingTabindex();\n }\n\n // ─── Render ───\n\n override render() {\n const isSticky = this.position === 'sticky' || this.sticky;\n const isBottom = this.position === 'bottom';\n const positionClass = isSticky ? ' base--sticky' : isBottom ? ' base--bottom' : '';\n\n return html`\n <div\n part=\"base\"\n role=\"toolbar\"\n aria-label=${this.ariaLabel}\n aria-orientation=\"horizontal\"\n class=\"base base--${this.size} base--${this.variant}${positionClass}\"\n >\n <div part=\"start\" class=\"section section--start\">\n <slot name=\"start\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n <div part=\"center\" class=\"section section--center\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n <div part=\"end\" class=\"section section--end\">\n <slot name=\"end\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n <div part=\"overflow\" class=\"section section--overflow\" ?hidden=${!this._hasOverflow}>\n <slot name=\"overflow\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-action-bar': HelixActionBar;\n }\n}\n"],"names":["helixActionBarStyles","css","HelixActionBar","LitElement","e","items","el","i","_a","last","_b","value","old","legacySize","devWarn","tag","slots","slot","assigned","descendants","d","activeIndex","targetIndex","direction","focused","currentIndex","nextIndex","isSticky","isBottom","positionClass","html","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-badge-DDXTLoWi.js","sources":["../../src/components/hx-badge/hx-badge.styles.ts","../../src/components/hx-badge/hx-badge.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixBadgeStyles = css`\n :host {\n display: inline-block;\n }\n\n .badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--hx-space-1, 0.25rem);\n border-radius: var(--hx-badge-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-badge-bg, var(--hx-color-primary-500, #2563eb));\n color: var(--hx-badge-color, var(--hx-color-neutral-0, #ffffff));\n font-family: var(--hx-badge-font-family, var(--hx-font-family-sans, sans-serif));\n font-weight: var(--hx-badge-font-weight, var(--hx-font-weight-semibold, 600));\n line-height: var(--hx-line-height-tight, 1.25);\n white-space: nowrap;\n vertical-align: middle;\n position: relative;\n }\n\n /* ─── Size Variants ─── */\n\n .badge--sm {\n font-size: var(--hx-badge-font-size, var(--hx-font-size-2xs, 0.625rem));\n padding: var(--hx-badge-padding-y, var(--hx-space-0-5, 0.125rem))\n var(--hx-badge-padding-x, var(--hx-space-1-5, 0.375rem));\n }\n\n .badge--md {\n font-size: var(--hx-badge-font-size, var(--hx-font-size-xs, 0.75rem));\n padding: var(--hx-badge-padding-y, var(--hx-space-1, 0.25rem))\n var(--hx-badge-padding-x, var(--hx-space-2, 0.5rem));\n }\n\n .badge--lg {\n font-size: var(--hx-badge-font-size, var(--hx-font-size-sm, 0.875rem));\n padding: var(--hx-badge-padding-y, var(--hx-space-1, 0.25rem))\n var(--hx-badge-padding-x, var(--hx-space-3, 0.75rem));\n }\n\n /* ─── Style Variants ─── */\n\n .badge--primary {\n --hx-badge-bg: var(--hx-color-primary-500, #2563eb);\n --hx-badge-color: var(--hx-color-neutral-0, #ffffff);\n --hx-badge-pulse-color: var(--hx-color-primary-500, #2563eb);\n }\n\n .badge--secondary {\n --hx-badge-bg: var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6));\n --hx-badge-color: var(--hx-badge-secondary-color, var(--hx-color-neutral-700, #374151));\n --hx-badge-pulse-color: var(--hx-badge-secondary-bg, var(--hx-color-neutral-100, #f3f4f6));\n }\n\n .badge--success {\n --hx-badge-bg: var(--hx-color-success-700, #15803d);\n --hx-badge-color: var(--hx-color-neutral-0, #ffffff);\n --hx-badge-pulse-color: var(--hx-color-success-700, #15803d);\n }\n\n .badge--warning {\n --hx-badge-bg: var(--hx-color-warning-500, #eab308);\n --hx-badge-color: var(--hx-color-neutral-900, #1a1a1a);\n --hx-badge-pulse-color: var(--hx-color-warning-500, #eab308);\n }\n\n .badge--error {\n --hx-badge-bg: var(--hx-color-error-500, #dc2626);\n --hx-badge-color: var(--hx-color-neutral-0, #ffffff);\n --hx-badge-pulse-color: var(--hx-color-error-500, #dc2626);\n }\n\n .badge--neutral {\n --hx-badge-bg: var(--hx-color-neutral-200, #e5e7eb);\n --hx-badge-color: var(--hx-color-neutral-700, #374151);\n --hx-badge-pulse-color: var(--hx-color-neutral-200, #e5e7eb);\n }\n\n .badge--info {\n --hx-badge-bg: var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1));\n --hx-badge-color: var(--hx-badge-info-color, var(--hx-color-neutral-0, #ffffff));\n --hx-badge-pulse-color: var(--hx-badge-info-bg, var(--hx-color-info-700, #0369a1));\n }\n\n /* ─── Semantic Variant Label (WCAG 1.4.1) ─── */\n /* Visually hidden text prefix for semantic variants (success/warning/error/info). */\n /* Ensures the variant is not conveyed by color alone. */\n\n .badge__variant-label {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Pill Mode ─── */\n\n .badge--pill {\n border-radius: var(--hx-badge-border-radius, var(--hx-border-radius-full, 9999px));\n }\n\n /* ─── Dot Indicator (empty + pulse) ─── */\n\n .badge--dot {\n width: var(--hx-badge-dot-size, var(--hx-space-2, 0.5rem));\n height: var(--hx-badge-dot-size, var(--hx-space-2, 0.5rem));\n padding: 0;\n border-radius: var(--hx-border-radius-full, 9999px);\n }\n\n /* Guard: hide prefix slot and slotted content in dot mode to prevent overflow */\n .badge--dot ::slotted(*) {\n display: none;\n }\n\n .badge--dot slot[name='prefix'] {\n display: none;\n }\n\n /* ─── Pulse Animation ─── */\n\n @keyframes hx-badge-pulse {\n 0%,\n 100% {\n opacity: 1;\n box-shadow: 0 0 0 2px var(--hx-badge-pulse-color, currentColor);\n }\n 50% {\n opacity: var(--hx-opacity-75, 0.75);\n box-shadow: 0 0 0 6px transparent;\n }\n }\n\n .badge--pulse {\n animation: hx-badge-pulse var(--hx-badge-pulse-duration, var(--hx-duration-slow, 2s))\n var(--hx-badge-pulse-easing, var(--hx-easing-in-out, ease-in-out)) infinite;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .badge--pulse {\n animation: none;\n }\n }\n\n /* ─── Remove Button ─── */\n\n .badge__remove-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 0;\n margin-inline-start: var(--hx-space-1, 0.25rem);\n cursor: pointer;\n color: inherit;\n opacity: var(--hx-opacity-75, 0.75);\n border-radius: var(--hx-border-radius-sm, 0.125rem);\n line-height: 0;\n /* WCAG 2.5.5: minimum 44×44px touch target */\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n }\n\n .badge__remove-button:hover {\n opacity: var(--hx-opacity-100, 1);\n }\n\n .badge__remove-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid var(--hx-focus-ring-color, currentColor);\n outline-offset: var(--hx-focus-ring-offset, 1px);\n }\n`;\n","import { LitElement, html, nothing } 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 { helixBadgeStyles } from './hx-badge.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/**\n * A small status indicator for notifications, counts, and labels.\n *\n * @summary Presentational badge for status indicators, notification counts, and labels.\n *\n * @tag hx-badge\n *\n * @slot - Default slot for badge content (text, number). When empty with pulse enabled, renders as a dot indicator.\n * @slot prefix - Icon or content rendered before the badge text.\n *\n * @fires {CustomEvent<void>} hx-remove - Dispatched when the user clicks the remove button.\n *\n * @csspart badge - The badge element.\n * @csspart remove-button - The remove/dismiss button.\n *\n * @cssprop [--hx-badge-bg=var(--hx-color-primary-500)] - Badge background color. The primary override point.\n * @cssprop [--hx-badge-color=var(--hx-color-neutral-0)] - Badge text color. The primary override point.\n * @cssprop [--hx-badge-font-size] - Badge font size (set per size variant).\n * @cssprop [--hx-badge-font-weight=var(--hx-font-weight-semibold)] - Badge font weight.\n * @cssprop [--hx-badge-font-family=var(--hx-font-family-sans)] - Badge font family.\n * @cssprop [--hx-badge-border-radius=var(--hx-border-radius-md)] - Badge border radius.\n * @cssprop [--hx-badge-padding-x] - Badge horizontal padding (set per size variant).\n * @cssprop [--hx-badge-padding-y] - Badge vertical padding (set per size variant).\n * @cssprop [--hx-badge-pulse-color] - Pulse color matching variant background with reduced opacity.\n * @cssprop [--hx-badge-dot-size=var(--hx-size-2)] - Dot indicator size when rendered without content.\n * @cssprop [--hx-badge-secondary-bg=var(--hx-color-neutral-100)] - Background for the secondary variant.\n * @cssprop [--hx-badge-secondary-color=var(--hx-color-neutral-700)] - Text color for the secondary variant.\n * @cssprop [--hx-badge-info-bg=var(--hx-color-info-700)] - Background for the info variant.\n * @cssprop [--hx-badge-info-color=var(--hx-color-neutral-0)] - Text color for the info variant.\n */\n@customElement('hx-badge')\nexport class HelixBadge extends LitElement {\n static override styles = [helixBadgeStyles];\n\n /**\n * Visual style variant of the badge.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'neutral' | 'info' =\n 'primary';\n\n /**\n * Size of the badge.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Whether the badge uses fully rounded (pill) styling.\n * @attr pill\n */\n @property({ type: Boolean, reflect: true })\n pill = false;\n\n /**\n * Whether the badge displays an animated pulse for attention.\n * @attr pulse\n */\n @property({ type: Boolean, reflect: true })\n pulse = false;\n\n /**\n * Whether the badge renders a dismiss button.\n * @attr removable\n */\n @property({ type: Boolean, reflect: true })\n removable = false;\n\n /**\n * Numeric count to display. When set, renders the count as badge content.\n * When count exceeds `max`, displays `${max}+` (e.g. `99+`).\n * @attr count\n */\n @property({ type: Number, reflect: true })\n count: number | undefined = undefined;\n\n /**\n * Maximum count value before truncation to `${max}+`. Defaults to 99.\n * @attr max\n */\n @property({ type: Number, reflect: true })\n max = 99;\n\n /**\n * Accessible label for the dot indicator mode (pulse + empty slot).\n * Required for WCAG 4.1.2 compliance when using the dot indicator pattern.\n * Example: `dot-label=\"3 new messages\"`.\n * @attr dot-label\n */\n @property({ type: String, attribute: 'dot-label' })\n dotLabel = '';\n\n /**\n * Accessible label for the remove button. Should describe what is being removed.\n * Defaults to \"Remove\". For better accessibility, include context: e.g. \"Remove Critical badge\".\n * @attr remove-label\n */\n @property({ type: String, attribute: 'remove-label' })\n removeLabel = 'Remove';\n\n /**\n * Tracks whether the default slot has assigned content.\n * @internal\n */\n @state()\n private _hasSlotContent = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-badge', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as 'sm' | 'md' | 'lg';\n }\n }\n\n // ─── Slot Change Handling ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const nodes = slot.assignedNodes({ flatten: true });\n // Check if any assigned node has non-whitespace content\n this._hasSlotContent = nodes.some((node) => {\n if (node.nodeType === Node.ELEMENT_NODE) return true;\n if (node.nodeType === Node.TEXT_NODE) {\n return (node.textContent ?? '').trim().length > 0;\n }\n return false;\n });\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleRemove(): void {\n this.dispatchEvent(\n new CustomEvent<void>('hx-remove', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n // ─── Count Display ───\n\n /** @internal */\n private get _countDisplay(): string {\n if (this.count === undefined) return '';\n return this.count > this.max ? `${this.max}+` : String(this.count);\n }\n\n // ─── WCAG 1.4.1: Semantic variant label map ───\n // Variants that carry semantic meaning beyond decoration need a non-color cue.\n // Visually-hidden text is prepended so screen reader users and color-blind\n // users get the variant context even when no icon is slotted.\n\n /** @internal */\n private static readonly _SEMANTIC_VARIANT_LABELS: Partial<Record<HelixBadge['variant'], string>> =\n {\n success: 'Success',\n warning: 'Warning',\n error: 'Error',\n info: 'Info',\n };\n\n /** @internal */\n private get _semanticVariantLabel(): string {\n return HelixBadge._SEMANTIC_VARIANT_LABELS[this.variant] ?? '';\n }\n\n // ─── Render ───\n\n override render() {\n const hasCount = this.count !== undefined;\n const isDot = !this._hasSlotContent && !hasCount && this.pulse;\n\n if (isDot && !this.dotLabel) {\n devWarn(\n 'hx-badge',\n 'Dot badge is missing an accessible label. Set `dotLabel` so screen readers can announce the badge purpose (WCAG 4.1.2).',\n );\n }\n\n const classes = {\n badge: true,\n [`badge--${this.variant}`]: true,\n [`badge--${this.size}`]: true,\n 'badge--pill': this.pill,\n 'badge--pulse': this.pulse,\n 'badge--dot': isDot,\n };\n\n const variantLabel = this._semanticVariantLabel;\n\n return html`\n <span\n part=\"badge\"\n class=${classMap(classes)}\n role=${isDot && this.dotLabel ? 'img' : nothing}\n aria-label=${isDot && this.dotLabel ? this.dotLabel : nothing}\n aria-live=${hasCount ? 'polite' : nothing}\n >\n ${variantLabel\n ? html`<span class=\"badge__variant-label\">${variantLabel}: </span>`\n : nothing}\n ${isDot ? nothing : html`<slot name=\"prefix\"></slot>`}\n ${hasCount ? this._countDisplay : html`<slot @slotchange=${this._handleSlotChange}></slot>`}\n ${this.removable\n ? html`<button\n part=\"remove-button\"\n class=\"badge__remove-button\"\n aria-label=${this.removeLabel}\n @click=${this._handleRemove}\n >\n <svg viewBox=\"0 0 12 12\" aria-hidden=\"true\" width=\"10\" height=\"10\">\n <path\n d=\"M2.22 2.22a.75.75 0 011.06 0L6 4.94l2.72-2.72a.75.75 0 011.06 1.06L7.06 6l2.72 2.72a.75.75 0 01-1.06 1.06L6 7.06 3.28 9.78a.75.75 0 01-1.06-1.06L4.94 6 2.22 3.28a.75.75 0 010-1.06z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>`\n : nothing}\n </span>\n `;\n }\n}\n\n/**\n * @deprecated Use `HelixBadge` instead. This alias will be removed in a future\n * major version as part of the project-wide migration from `Wc` to `Hx` prefixes.\n * @since 0.1.0\n * @removal-target 1.0.0\n */\nexport type WcBadge = HelixBadge;\n\n/** Canonical type alias for the hx-badge component. */\nexport type HxBadge = HelixBadge;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-badge': HelixBadge;\n }\n}\n"],"names":["helixBadgeStyles","css","HelixBadge","LitElement","legacySize","e","nodes","node","hasCount","isDot","classes","variantLabel","html","classMap","nothing","__decorateClass","property","state","customElement"],"mappings":"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"}
|