@helixui/library 1.1.2-next.4 → 1.1.2-next.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/custom-elements.json +691 -755
  2. package/dist/components/hx-patient-banner/hx-patient-banner.d.ts +8 -0
  3. package/dist/components/hx-patient-banner/hx-patient-banner.d.ts.map +1 -1
  4. package/dist/components/hx-patient-banner/hx-patient-banner.styles.d.ts.map +1 -1
  5. package/dist/components/hx-patient-banner/index.js +1 -1
  6. package/dist/components/hx-phi-field/hx-phi-field.d.ts +27 -2
  7. package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
  8. package/dist/components/hx-phi-field/hx-phi-field.styles.d.ts.map +1 -1
  9. package/dist/components/hx-phi-field/index.js +1 -1
  10. package/dist/components/hx-select/hx-select.d.ts +1 -0
  11. package/dist/components/hx-select/hx-select.d.ts.map +1 -1
  12. package/dist/components/hx-select/hx-select.styles.d.ts.map +1 -1
  13. package/dist/components/hx-select/index.js +1 -1
  14. package/dist/components/hx-status-indicator/hx-status-indicator.d.ts +17 -1
  15. package/dist/components/hx-status-indicator/hx-status-indicator.d.ts.map +1 -1
  16. package/dist/components/hx-status-indicator/hx-status-indicator.styles.d.ts.map +1 -1
  17. package/dist/components/hx-status-indicator/index.js +1 -1
  18. package/dist/css/helix-all.css +144 -48
  19. package/dist/css/helix-feedback.css +33 -4
  20. package/dist/css/helix-forms.css +68 -41
  21. package/dist/css/hx-patient-banner.css +31 -3
  22. package/dist/css/hx-phi-field.css +12 -0
  23. package/dist/css/hx-select.css +68 -41
  24. package/dist/css/hx-status-indicator.css +33 -4
  25. package/dist/css/index.css +1 -1
  26. package/dist/css/manifest.json +11 -5
  27. package/dist/index.js +4 -4
  28. package/dist/shared/{hx-patient-banner-BoJHddAL.js → hx-patient-banner-wk4qWmsH.js} +88 -47
  29. package/dist/shared/hx-patient-banner-wk4qWmsH.js.map +1 -0
  30. package/dist/shared/{hx-phi-field-EDWna59z.js → hx-phi-field-DX9z3nu0.js} +67 -33
  31. package/dist/shared/hx-phi-field-DX9z3nu0.js.map +1 -0
  32. package/dist/shared/{hx-select-4-nHL0vd.js → hx-select-BWzxWZs_.js} +82 -55
  33. package/dist/shared/hx-select-BWzxWZs_.js.map +1 -0
  34. package/dist/shared/{hx-status-indicator-4ClvA5mU.js → hx-status-indicator-Dl3Y34mc.js} +76 -35
  35. package/dist/shared/hx-status-indicator-Dl3Y34mc.js.map +1 -0
  36. package/package.json +2 -2
  37. package/dist/shared/hx-patient-banner-BoJHddAL.js.map +0 -1
  38. package/dist/shared/hx-phi-field-EDWna59z.js.map +0 -1
  39. package/dist/shared/hx-select-4-nHL0vd.js.map +0 -1
  40. package/dist/shared/hx-status-indicator-4ClvA5mU.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  {
2
- "generated": "2026-03-26T21:57:25.689Z",
2
+ "generated": "2026-03-27T00:04:06.643Z",
3
3
  "components": [
4
4
  {
5
5
  "name": "hx-accordion",
@@ -1435,6 +1435,7 @@
1435
1435
  "--hx-patient-banner-gap",
1436
1436
  "--hx-patient-banner-label-color",
1437
1437
  "--hx-patient-banner-label-font-size",
1438
+ "--hx-patient-banner-photo-bg",
1438
1439
  "--hx-patient-banner-photo-size",
1439
1440
  "--hx-patient-banner-value-color",
1440
1441
  "--hx-patient-banner-value-font-size",
@@ -1458,6 +1459,7 @@
1458
1459
  "--hx-font-family-mono",
1459
1460
  "--hx-opacity-50",
1460
1461
  "--hx-opacity-90",
1462
+ "--hx-phi-field-disabled-opacity",
1461
1463
  "--hx-phi-field-font-family",
1462
1464
  "--hx-phi-field-masked-color",
1463
1465
  "--hx-phi-field-toggle-color",
@@ -1653,16 +1655,15 @@
1653
1655
  "--hx-select-border-color",
1654
1656
  "--hx-select-border-radius",
1655
1657
  "--hx-select-chevron-color",
1658
+ "--hx-select-chevron-size",
1656
1659
  "--hx-select-color",
1657
1660
  "--hx-select-error-color",
1658
- "--hx-select-focus-ring-color",
1659
1661
  "--hx-select-font-family",
1660
1662
  "--hx-select-label-color",
1661
1663
  "--hx-select-listbox-bg",
1662
1664
  "--hx-select-listbox-max-height",
1663
1665
  "--hx-select-option-focus-ring-offset",
1664
1666
  "--hx-select-option-hover-bg",
1665
- "--hx-select-option-selected-bg",
1666
1667
  "--hx-select-placeholder-color",
1667
1668
  "--hx-size-10",
1668
1669
  "--hx-size-12",
@@ -1671,6 +1672,7 @@
1671
1672
  "--hx-space-2",
1672
1673
  "--hx-space-3",
1673
1674
  "--hx-space-4",
1675
+ "--hx-space-px",
1674
1676
  "--hx-transition-fast",
1675
1677
  "--hx-z-index-dropdown"
1676
1678
  ]
@@ -1940,11 +1942,13 @@
1940
1942
  "--hx-color-error-500",
1941
1943
  "--hx-color-neutral-300",
1942
1944
  "--hx-color-neutral-400",
1945
+ "--hx-color-neutral-700",
1943
1946
  "--hx-color-success-500",
1944
1947
  "--hx-color-warning-500",
1945
- "--hx-size-4",
1948
+ "--hx-font-size-sm",
1946
1949
  "--hx-space-2",
1947
1950
  "--hx-space-3",
1951
+ "--hx-space-4",
1948
1952
  "--hx-state-focus-opacity",
1949
1953
  "--hx-status-indicator-color-away",
1950
1954
  "--hx-status-indicator-color-busy",
@@ -1952,12 +1956,14 @@
1952
1956
  "--hx-status-indicator-color-offline",
1953
1957
  "--hx-status-indicator-color-online",
1954
1958
  "--hx-status-indicator-color-unknown",
1959
+ "--hx-status-indicator-label-color",
1955
1960
  "--hx-status-indicator-pulse-color",
1956
1961
  "--hx-status-indicator-pulse-duration",
1957
1962
  "--hx-status-indicator-pulse-scale",
1958
1963
  "--hx-status-indicator-size-lg",
1959
1964
  "--hx-status-indicator-size-md",
1960
- "--hx-status-indicator-size-sm"
1965
+ "--hx-status-indicator-size-sm",
1966
+ "--hx-text-sm"
1961
1967
  ]
1962
1968
  },
1963
1969
  {
package/dist/index.js CHANGED
@@ -42,8 +42,8 @@ import { H as qe } from "./shared/hx-nav-D377Ngz4.js";
42
42
  import { H as Je } from "./shared/hx-number-input-BPgrlMLN.js";
43
43
  import { H as Qe } from "./shared/hx-overflow-menu-Bz02LPPk.js";
44
44
  import { H as eo } from "./shared/hx-pagination-DYhYPqDn.js";
45
- import { H as to } from "./shared/hx-patient-banner-BoJHddAL.js";
46
- import { H as ao } from "./shared/hx-phi-field-EDWna59z.js";
45
+ import { H as to } from "./shared/hx-patient-banner-wk4qWmsH.js";
46
+ import { H as ao } from "./shared/hx-phi-field-DX9z3nu0.js";
47
47
  import { H as so } from "./shared/hx-popover-D6kYQkt3.js";
48
48
  import { H as Ho } from "./shared/hx-popup-RQb6HUXc.js";
49
49
  import { H as po } from "./shared/hx-progress-bar-ByEmxq1V.js";
@@ -51,7 +51,7 @@ import { H as mo } from "./shared/hx-progress-ring-CtVnNRQx.js";
51
51
  import { H as co } from "./shared/hx-prose-Ml_L2zje.js";
52
52
  import { H as uo, a as bo } from "./shared/hx-radio-jgeW92SV.js";
53
53
  import { H as So } from "./shared/hx-rating-g_iy-DW_.js";
54
- import { H as go } from "./shared/hx-select-4-nHL0vd.js";
54
+ import { H as go } from "./shared/hx-select-BWzxWZs_.js";
55
55
  import { H as vo, a as _o } from "./shared/hx-nav-item-CuGiJPAf.js";
56
56
  import { H as Do } from "./shared/hx-skeleton-BHvALyd7.js";
57
57
  import { H as Bo } from "./shared/hx-slider-7Q-e0_pc.js";
@@ -60,7 +60,7 @@ import { H as Ao } from "./shared/hx-split-button-BA7P_ly5.js";
60
60
  import { H as Lo } from "./shared/hx-split-panel-Bss54UN8.js";
61
61
  import { H as No } from "./shared/hx-stack-BStY1RmV.js";
62
62
  import { H as Go } from "./shared/hx-stat-CmkCUI8v.js";
63
- import { H as $o } from "./shared/hx-status-indicator-4ClvA5mU.js";
63
+ import { H as $o } from "./shared/hx-status-indicator-Dl3Y34mc.js";
64
64
  import { H as Oo, a as Wo } from "./shared/hx-step-DlANlr2A.js";
65
65
  import { H as Yo, a as jo } from "./shared/hx-structured-list-Db9rwLI_.js";
66
66
  import { H as zo } from "./shared/hx-style-scope-BroUu83L.js";
@@ -1,7 +1,7 @@
1
- import { css as b, LitElement as h, html as f } from "lit";
2
- import { property as l, state as c, query as p, customElement as v } from "lit/decorators.js";
3
- import { tokenStyles as u } from "@helixui/tokens/lit";
4
- const _ = b`
1
+ import { css as c, LitElement as v, nothing as p, html as b } from "lit";
2
+ import { property as a, state as f, query as h, customElement as u } from "lit/decorators.js";
3
+ import { tokenStyles as _ } from "@helixui/tokens/lit";
4
+ const m = c`
5
5
  :host {
6
6
  display: block;
7
7
  width: 100%;
@@ -20,6 +20,7 @@ const _ = b`
20
20
  --_value-color: var(--hx-patient-banner-value-color, var(--hx-color-neutral-900, #111827));
21
21
  --_value-font-size: var(--hx-patient-banner-value-font-size, var(--hx-font-size-sm, 0.875rem));
22
22
  --_photo-size: var(--hx-patient-banner-photo-size, var(--hx-space-10, 2.5rem));
23
+ --_photo-bg: var(--hx-patient-banner-photo-bg, var(--hx-color-neutral-200, #e5e7eb));
23
24
  }
24
25
 
25
26
  * {
@@ -37,6 +38,7 @@ const _ = b`
37
38
  border-bottom: var(--hx-border-width-thin, 1px) solid var(--_border-color);
38
39
  font-family: var(--_font-family);
39
40
  width: 100%;
41
+ position: relative;
40
42
  }
41
43
 
42
44
  /* ─── Photo Area ─── */
@@ -45,12 +47,15 @@ const _ = b`
45
47
  flex-shrink: 0;
46
48
  width: var(--_photo-size);
47
49
  height: var(--_photo-size);
50
+ /* Minimum 44x44px touch target for interactive photo content. */
51
+ min-width: 44px;
52
+ min-height: 44px;
48
53
  border-radius: var(--hx-border-radius-full, 9999px);
49
54
  overflow: hidden;
50
55
  display: flex;
51
56
  align-items: center;
52
57
  justify-content: center;
53
- background-color: var(--hx-color-neutral-200, #e5e7eb);
58
+ background-color: var(--_photo-bg);
54
59
  }
55
60
 
56
61
  /* ─── Fields Grid ─── */
@@ -96,9 +101,8 @@ const _ = b`
96
101
  :host([aria-invalid='true']) .banner {
97
102
  border-bottom-color: var(--hx-color-error-400, #f87171);
98
103
  background-color: var(--hx-color-error-50, #fef2f2);
99
- /* Darken label color to maintain 4.5:1 contrast on error-50 background */
104
+ /* Darken label color to maintain 4.5:1 contrast on error-50 background. */
100
105
  --_label-color: var(--hx-patient-banner-label-color, var(--hx-color-neutral-700, #374151));
101
- position: relative;
102
106
  }
103
107
 
104
108
  :host([aria-invalid='true']) .banner::before {
@@ -112,15 +116,39 @@ const _ = b`
112
116
  background-color: var(--hx-color-error-500, #ef4444);
113
117
  border-radius: 0;
114
118
  }
119
+
120
+ /* ─── Visually-hidden violation live region ─── */
121
+ /* Announces identifier rule violations to screen readers without visible text. */
122
+
123
+ .violation-message {
124
+ position: absolute;
125
+ width: 1px;
126
+ height: 1px;
127
+ padding: 0;
128
+ margin: -1px;
129
+ overflow: hidden;
130
+ clip: rect(0, 0, 0, 0);
131
+ white-space: nowrap;
132
+ border-width: 0;
133
+ }
134
+
135
+ /* ─── Motion reduction ─── */
136
+
137
+ @media (prefers-reduced-motion: reduce) {
138
+ * {
139
+ transition: none !important;
140
+ animation: none !important;
141
+ }
142
+ }
115
143
  `;
116
- var m = Object.defineProperty, x = Object.getOwnPropertyDescriptor, a = (e, r, n, o) => {
117
- for (var i = o > 1 ? void 0 : o ? x(r, n) : r, s = e.length - 1, d; s >= 0; s--)
118
- (d = e[s]) && (i = (o ? d(r, n, i) : d(i)) || i);
119
- return o && i && m(r, n, i), i;
144
+ var g = Object.defineProperty, x = Object.getOwnPropertyDescriptor, i = (e, l, n, o) => {
145
+ for (var r = o > 1 ? void 0 : o ? x(l, n) : l, s = e.length - 1, d; s >= 0; s--)
146
+ (d = e[s]) && (r = (o ? d(l, n, r) : d(r)) || r);
147
+ return o && r && g(l, n, r), r;
120
148
  };
121
- let t = class extends h {
149
+ let t = class extends v {
122
150
  constructor() {
123
- super(...arguments), this.patientId = "", this.labelPatient = "Patient identification", this.labelName = "Patient name", this.labelMrn = "MRN", this.labelDob = "Date of birth", this.labelAllergies = "Allergies", this.labelCodeStatus = "Code status", this.enforceIdentifierRule = !0, this._identifierCount = 0;
151
+ super(...arguments), this.patientId = "", this.labelPatient = "Patient identification", this.labelName = "Patient name", this.labelMrn = "MRN", this.labelDob = "Date of birth", this.labelAllergies = "Allergies", this.labelCodeStatus = "Code status", this.enforceIdentifierRule = !0, this._identifierCount = 0, this._isViolating = !1;
124
152
  }
125
153
  // ─── Lifecycle ───
126
154
  connectedCallback() {
@@ -132,14 +160,14 @@ let t = class extends h {
132
160
  // ─── Private Helpers ───
133
161
  _countPopulatedIdentifiers() {
134
162
  let e = 0;
135
- const r = [this._nameSlot, this._mrnSlot, this._dobSlot];
136
- for (const n of r)
163
+ const l = [this._nameSlot, this._mrnSlot, this._dobSlot];
164
+ for (const n of l)
137
165
  n && n.assignedNodes({ flatten: !0 }).length > 0 && e++;
138
166
  return e;
139
167
  }
140
168
  _checkIdentifierRule() {
141
169
  const e = this._countPopulatedIdentifiers();
142
- this._identifierCount = e, this.enforceIdentifierRule && e < 2 ? (this.setAttribute("aria-invalid", "true"), this.dispatchEvent(
170
+ this._identifierCount = e, this.enforceIdentifierRule && e < 2 ? (this._isViolating = !0, this.setAttribute("aria-invalid", "true"), this.dispatchEvent(
143
171
  new CustomEvent("hx-identifier-rule-violation", {
144
172
  bubbles: !0,
145
173
  composed: !0,
@@ -149,7 +177,7 @@ let t = class extends h {
149
177
  patientId: this.patientId
150
178
  }
151
179
  })
152
- )) : this.removeAttribute("aria-invalid");
180
+ )) : (this._isViolating = !1, this.removeAttribute("aria-invalid"));
153
181
  }
154
182
  // ─── Event Handlers ───
155
183
  _handleSlotChange() {
@@ -157,9 +185,10 @@ let t = class extends h {
157
185
  }
158
186
  // ─── Render ───
159
187
  render() {
160
- return f`
188
+ const e = this._isViolating ? `Warning: patient identification incomplete. ${this._identifierCount} of 2 required identifiers present.` : p;
189
+ return b`
161
190
  <div part="banner" class="banner">
162
- <div part="photo-area" class="banner__photo-area">
191
+ <div part="photo-area" class="banner__photo-area" aria-hidden="true">
163
192
  <slot name="photo"></slot>
164
193
  </div>
165
194
 
@@ -200,33 +229,42 @@ let t = class extends h {
200
229
  </div>
201
230
  </div>
202
231
  </div>
232
+
233
+ ${e !== p ? b`<div
234
+ part="violation-message"
235
+ class="violation-message"
236
+ role="alert"
237
+ aria-live="assertive"
238
+ >
239
+ ${e}
240
+ </div>` : p}
203
241
  `;
204
242
  }
205
243
  };
206
- t.styles = [u, _];
207
- a([
208
- l({ type: String, attribute: "patient-id" })
244
+ t.styles = [_, m];
245
+ i([
246
+ a({ type: String, attribute: "patient-id" })
209
247
  ], t.prototype, "patientId", 2);
210
- a([
211
- l({ type: String, attribute: "label-patient" })
248
+ i([
249
+ a({ type: String, attribute: "label-patient" })
212
250
  ], t.prototype, "labelPatient", 2);
213
- a([
214
- l({ type: String, attribute: "label-name" })
251
+ i([
252
+ a({ type: String, attribute: "label-name" })
215
253
  ], t.prototype, "labelName", 2);
216
- a([
217
- l({ type: String, attribute: "label-mrn" })
254
+ i([
255
+ a({ type: String, attribute: "label-mrn" })
218
256
  ], t.prototype, "labelMrn", 2);
219
- a([
220
- l({ type: String, attribute: "label-dob" })
257
+ i([
258
+ a({ type: String, attribute: "label-dob" })
221
259
  ], t.prototype, "labelDob", 2);
222
- a([
223
- l({ type: String, attribute: "label-allergies" })
260
+ i([
261
+ a({ type: String, attribute: "label-allergies" })
224
262
  ], t.prototype, "labelAllergies", 2);
225
- a([
226
- l({ type: String, attribute: "label-code-status" })
263
+ i([
264
+ a({ type: String, attribute: "label-code-status" })
227
265
  ], t.prototype, "labelCodeStatus", 2);
228
- a([
229
- l({
266
+ i([
267
+ a({
230
268
  attribute: "enforce-identifier-rule",
231
269
  reflect: !0,
232
270
  converter: {
@@ -235,22 +273,25 @@ a([
235
273
  }
236
274
  })
237
275
  ], t.prototype, "enforceIdentifierRule", 2);
238
- a([
239
- c()
276
+ i([
277
+ f()
240
278
  ], t.prototype, "_identifierCount", 2);
241
- a([
242
- p('slot[name="name"]')
279
+ i([
280
+ f()
281
+ ], t.prototype, "_isViolating", 2);
282
+ i([
283
+ h('slot[name="name"]')
243
284
  ], t.prototype, "_nameSlot", 2);
244
- a([
245
- p('slot[name="mrn"]')
285
+ i([
286
+ h('slot[name="mrn"]')
246
287
  ], t.prototype, "_mrnSlot", 2);
247
- a([
248
- p('slot[name="dob"]')
288
+ i([
289
+ h('slot[name="dob"]')
249
290
  ], t.prototype, "_dobSlot", 2);
250
- t = a([
251
- v("hx-patient-banner")
291
+ t = i([
292
+ u("hx-patient-banner")
252
293
  ], t);
253
294
  export {
254
295
  t as H
255
296
  };
256
- //# sourceMappingURL=hx-patient-banner-BoJHddAL.js.map
297
+ //# sourceMappingURL=hx-patient-banner-wk4qWmsH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-patient-banner-wk4qWmsH.js","sources":["../../src/components/hx-patient-banner/hx-patient-banner.styles.ts","../../src/components/hx-patient-banner/hx-patient-banner.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPatientBannerStyles = css`\n :host {\n display: block;\n width: 100%;\n\n /* ─── Private token vars (3-tier cascade) ─── */\n --_bg: var(--hx-patient-banner-bg, var(--hx-color-neutral-50, #f9fafb));\n --_border-color: var(--hx-patient-banner-border-color, var(--hx-color-neutral-200, #e5e7eb));\n --_padding: var(\n --hx-patient-banner-padding,\n var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem)\n );\n --_gap: var(--hx-patient-banner-gap, var(--hx-space-4, 1rem));\n --_font-family: var(--hx-patient-banner-font-family, var(--hx-font-family-sans, sans-serif));\n --_label-color: var(--hx-patient-banner-label-color, var(--hx-color-neutral-500, #6b7280));\n --_label-font-size: var(--hx-patient-banner-label-font-size, var(--hx-font-size-xs, 0.75rem));\n --_value-color: var(--hx-patient-banner-value-color, var(--hx-color-neutral-900, #111827));\n --_value-font-size: var(--hx-patient-banner-value-font-size, var(--hx-font-size-sm, 0.875rem));\n --_photo-size: var(--hx-patient-banner-photo-size, var(--hx-space-10, 2.5rem));\n --_photo-bg: var(--hx-patient-banner-photo-bg, var(--hx-color-neutral-200, #e5e7eb));\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Banner Container ─── */\n\n .banner {\n display: flex;\n align-items: center;\n gap: var(--_gap);\n padding: var(--_padding);\n background-color: var(--_bg);\n border-bottom: var(--hx-border-width-thin, 1px) solid var(--_border-color);\n font-family: var(--_font-family);\n width: 100%;\n position: relative;\n }\n\n /* ─── Photo Area ─── */\n\n .banner__photo-area {\n flex-shrink: 0;\n width: var(--_photo-size);\n height: var(--_photo-size);\n /* Minimum 44x44px touch target for interactive photo content. */\n min-width: 44px;\n min-height: 44px;\n border-radius: var(--hx-border-radius-full, 9999px);\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--_photo-bg);\n }\n\n /* ─── Fields Grid ─── */\n\n .banner__fields {\n display: flex;\n flex-wrap: wrap;\n gap: var(--_gap);\n flex: 1;\n min-width: 0;\n }\n\n /* ─── Individual Field ─── */\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n min-width: 0;\n }\n\n .field__label {\n font-size: var(--_label-font-size);\n color: var(--_label-color);\n font-weight: var(--hx-font-weight-medium, 500);\n line-height: var(--hx-line-height-tight, 1.25);\n white-space: nowrap;\n }\n\n .field__value {\n font-size: var(--_value-font-size);\n color: var(--_value-color);\n font-weight: var(--hx-font-weight-normal, 400);\n line-height: var(--hx-line-height-normal, 1.5);\n display: flex;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n }\n\n /* ─── Identifier Rule Violation ─── */\n /* Visual indicator when Joint Commission two-identifier rule is not met. */\n\n :host([aria-invalid='true']) .banner {\n border-bottom-color: var(--hx-color-error-400, #f87171);\n background-color: var(--hx-color-error-50, #fef2f2);\n /* Darken label color to maintain 4.5:1 contrast on error-50 background. */\n --_label-color: var(--hx-patient-banner-label-color, var(--hx-color-neutral-700, #374151));\n }\n\n :host([aria-invalid='true']) .banner::before {\n content: '';\n display: block;\n position: absolute;\n inset-inline-start: 0;\n top: 0;\n bottom: 0;\n width: var(--hx-border-width-thick, 4px);\n background-color: var(--hx-color-error-500, #ef4444);\n border-radius: 0;\n }\n\n /* ─── Visually-hidden violation live region ─── */\n /* Announces identifier rule violations to screen readers without visible text. */\n\n .violation-message {\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-width: 0;\n }\n\n /* ─── Motion reduction ─── */\n\n @media (prefers-reduced-motion: reduce) {\n * {\n transition: none !important;\n animation: none !important;\n }\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport { customElement, property, state, query } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixPatientBannerStyles } from './hx-patient-banner.styles.js';\n\n/**\n * Patient identification banner implementing Joint Commission NPSG.01.01.01 two-identifier rule.\n * Renders as a landmark region containing named slots for patient identification fields.\n * Integrates with hx-phi-field for HIPAA-compliant display of masked identifiers.\n * Note: hx-phi-access events fired by slotted hx-phi-field elements bubble through this\n * component via composed: true — no re-dispatch is required.\n *\n * @summary Patient identification banner with two-identifier rule enforcement.\n *\n * @tag hx-patient-banner\n *\n * @slot photo - Optional patient photo slot.\n * @slot name - Patient name field content.\n * @slot mrn - Medical record number field content. Use hx-phi-field for HIPAA compliance.\n * @slot dob - Date of birth field content. Use hx-phi-field for HIPAA compliance.\n * @slot allergies - Allergy status/flag content.\n * @slot code-status - Code status content.\n *\n * @csspart banner - The outer banner container.\n * @csspart photo-area - The photo slot wrapper.\n * @csspart fields - The fields grid container.\n * @csspart field - An individual field container (applied to all field wrappers).\n * @csspart field-label - The field label element.\n * @csspart field-value - The field value slot wrapper.\n * @csspart violation-message - The visually-hidden identifier rule violation status message.\n *\n * @fires {CustomEvent<PatientIdentifierRuleViolationDetail>} hx-identifier-rule-violation - Fired when fewer than 2 identifier slots are populated and enforce-identifier-rule is true.\n *\n * @cssprop [--hx-patient-banner-bg=var(--hx-color-neutral-50,#f9fafb)] - Banner background color.\n * @cssprop [--hx-patient-banner-border-color=var(--hx-color-neutral-200,#e5e7eb)] - Banner border color.\n * @cssprop [--hx-patient-banner-padding=var(--hx-space-3,0.75rem) var(--hx-space-4,1rem)] - Banner padding.\n * @cssprop [--hx-patient-banner-gap=var(--hx-space-4,1rem)] - Gap between banner fields.\n * @cssprop [--hx-patient-banner-font-family=var(--hx-font-family-sans,sans-serif)] - Banner font family.\n * @cssprop [--hx-patient-banner-label-color=var(--hx-color-neutral-500,#6b7280)] - Field label color.\n * @cssprop [--hx-patient-banner-label-font-size=var(--hx-font-size-xs,0.75rem)] - Field label font size.\n * @cssprop [--hx-patient-banner-value-color=var(--hx-color-neutral-900,#111827)] - Field value color.\n * @cssprop [--hx-patient-banner-value-font-size=var(--hx-font-size-sm,0.875rem)] - Field value font size.\n * @cssprop [--hx-patient-banner-photo-size=var(--hx-space-10,2.5rem)] - Photo area size.\n * @cssprop [--hx-patient-banner-photo-bg=var(--hx-color-neutral-200,#e5e7eb)] - Photo area background color when empty.\n */\n@customElement('hx-patient-banner')\nexport class HelixPatientBanner extends LitElement {\n static override styles = [tokenStyles, helixPatientBannerStyles];\n\n // ─── Public Properties ───\n\n /**\n * Optional patient ID used as context in identifier rule violation events.\n * @attr patient-id\n */\n @property({ type: String, attribute: 'patient-id' })\n patientId: string = '';\n\n /**\n * Accessible label for the banner landmark region.\n * @attr label-patient\n */\n @property({ type: String, attribute: 'label-patient' })\n labelPatient: string = 'Patient identification';\n\n /**\n * Visible label for the name field.\n * @attr label-name\n */\n @property({ type: String, attribute: 'label-name' })\n labelName: string = 'Patient name';\n\n /**\n * Visible label for the MRN field.\n * @attr label-mrn\n */\n @property({ type: String, attribute: 'label-mrn' })\n labelMrn: string = 'MRN';\n\n /**\n * Visible label for the date of birth field.\n * @attr label-dob\n */\n @property({ type: String, attribute: 'label-dob' })\n labelDob: string = 'Date of birth';\n\n /**\n * Visible label for the allergies field.\n * @attr label-allergies\n */\n @property({ type: String, attribute: 'label-allergies' })\n labelAllergies: string = 'Allergies';\n\n /**\n * Visible label for the code status field.\n * @attr label-code-status\n */\n @property({ type: String, attribute: 'label-code-status' })\n labelCodeStatus: string = 'Code status';\n\n /**\n * Whether to enforce the Joint Commission NPSG.01.01.01 two-identifier rule.\n * When true, fires hx-identifier-rule-violation if fewer than 2 identifier\n * slots (name, mrn, dob) are populated.\n * @attr enforce-identifier-rule\n */\n @property({\n attribute: 'enforce-identifier-rule',\n reflect: true,\n converter: {\n fromAttribute: (value: string | null) => value !== 'false',\n toAttribute: (value: boolean) => String(value),\n },\n })\n enforceIdentifierRule: boolean = true;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _identifierCount: number = 0;\n\n /** @internal */\n @state() private _isViolating: boolean = false;\n\n // ─── Slot Queries ───\n\n /** @internal */\n @query('slot[name=\"name\"]') private _nameSlot!: HTMLSlotElement;\n\n /** @internal */\n @query('slot[name=\"mrn\"]') private _mrnSlot!: HTMLSlotElement;\n\n /** @internal */\n @query('slot[name=\"dob\"]') private _dobSlot!: HTMLSlotElement;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'banner');\n this.setAttribute('aria-label', this.labelPatient);\n }\n\n protected override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('labelPatient')) {\n this.setAttribute('aria-label', this.labelPatient);\n }\n\n if (changedProperties.has('enforceIdentifierRule')) {\n this._checkIdentifierRule();\n }\n }\n\n // ─── Private Helpers ───\n\n private _countPopulatedIdentifiers(): number {\n let count = 0;\n\n const slots = [this._nameSlot, this._mrnSlot, this._dobSlot];\n for (const slot of slots) {\n if (slot && slot.assignedNodes({ flatten: true }).length > 0) {\n count++;\n }\n }\n\n return count;\n }\n\n private _checkIdentifierRule(): void {\n const count = this._countPopulatedIdentifiers();\n this._identifierCount = count;\n\n if (this.enforceIdentifierRule && count < 2) {\n this._isViolating = true;\n this.setAttribute('aria-invalid', 'true');\n this.dispatchEvent(\n new CustomEvent<PatientIdentifierRuleViolationDetail>('hx-identifier-rule-violation', {\n bubbles: true,\n composed: true,\n detail: {\n populatedIdentifiers: count,\n requiredIdentifiers: 2,\n patientId: this.patientId,\n },\n }),\n );\n } else {\n this._isViolating = false;\n this.removeAttribute('aria-invalid');\n }\n }\n\n // ─── Event Handlers ───\n\n private _handleSlotChange(): void {\n this._checkIdentifierRule();\n }\n\n // ─── Render ───\n\n override render() {\n const violationMessage = this._isViolating\n ? `Warning: patient identification incomplete. ${this._identifierCount} of 2 required identifiers present.`\n : nothing;\n\n return html`\n <div part=\"banner\" class=\"banner\">\n <div part=\"photo-area\" class=\"banner__photo-area\" aria-hidden=\"true\">\n <slot name=\"photo\"></slot>\n </div>\n\n <div part=\"fields\" class=\"banner__fields\">\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelName}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"name\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelMrn}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"mrn\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelDob}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"dob\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelAllergies}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"allergies\"></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelCodeStatus}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"code-status\"></slot>\n </div>\n </div>\n </div>\n </div>\n\n ${violationMessage !== nothing\n ? html`<div\n part=\"violation-message\"\n class=\"violation-message\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n ${violationMessage}\n </div>`\n : nothing}\n `;\n }\n}\n\nexport interface PatientIdentifierRuleViolationDetail {\n populatedIdentifiers: number;\n requiredIdentifiers: number;\n patientId: string;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-patient-banner': HelixPatientBanner;\n }\n}\n"],"names":["helixPatientBannerStyles","css","HelixPatientBanner","LitElement","changedProperties","count","slots","slot","violationMessage","nothing","html","tokenStyles","__decorateClass","property","value","state","query","customElement"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { css as c, LitElement as p, html as n } from "lit";
2
- import { property as h, state as u, customElement as f } from "lit/decorators.js";
1
+ import { css as c, LitElement as p, html as h } from "lit";
2
+ import { property as n, state as u, customElement as f } from "lit/decorators.js";
3
3
  import { tokenStyles as m } from "@helixui/tokens/lit";
4
4
  const _ = c`
5
5
  :host {
@@ -79,6 +79,18 @@ const _ = c`
79
79
  pointer-events: none;
80
80
  }
81
81
 
82
+ /* ─── Disabled State ─── */
83
+
84
+ :host([disabled]) {
85
+ opacity: var(--hx-phi-field-disabled-opacity, var(--hx-opacity-50, 0.5));
86
+ pointer-events: none;
87
+ cursor: not-allowed;
88
+ }
89
+
90
+ .phi-field--disabled .phi-field__toggle {
91
+ cursor: not-allowed;
92
+ }
93
+
82
94
  /* ─── Reduced Motion ─── */
83
95
 
84
96
  @media (prefers-reduced-motion: reduce) {
@@ -87,14 +99,14 @@ const _ = c`
87
99
  }
88
100
  }
89
101
  `;
90
- var v = Object.defineProperty, g = Object.getOwnPropertyDescriptor, o = (e, t, d, l) => {
91
- for (var i = l > 1 ? void 0 : l ? g(t, d) : t, r = e.length - 1, s; r >= 0; r--)
92
- (s = e[r]) && (i = (l ? s(t, d, i) : s(i)) || i);
93
- return l && i && v(t, d, i), i;
102
+ var b = Object.defineProperty, v = Object.getOwnPropertyDescriptor, s = (e, t, l, r) => {
103
+ for (var i = r > 1 ? void 0 : r ? v(t, l) : t, o = e.length - 1, d; o >= 0; o--)
104
+ (d = e[o]) && (i = (r ? d(t, l, i) : d(i)) || i);
105
+ return r && i && b(t, l, i), i;
94
106
  };
95
107
  let a = class extends p {
96
108
  constructor() {
97
- super(...arguments), this.data = "", this.fieldType = "ssn", this.fieldId = "", this.clipboardTimeout = 3e4, this._masked = !0, this._clipboardTimer = null;
109
+ super(...arguments), this.data = "", this.fieldType = "ssn", this.fieldId = "", this.clipboardTimeout = 3e4, this.label = "", this.disabled = !1, this._masked = !0, this._clipboardTimer = null;
98
110
  }
99
111
  // ─── Lifecycle ───
100
112
  connectedCallback() {
@@ -104,14 +116,17 @@ let a = class extends p {
104
116
  super.disconnectedCallback(), this._cancelClipboardTimer();
105
117
  }
106
118
  // ─── Private Helpers ───
119
+ /** @internal */
107
120
  _cancelClipboardTimer() {
108
121
  this._clipboardTimer !== null && (clearTimeout(this._clipboardTimer), this._clipboardTimer = null);
109
122
  }
123
+ /** @internal */
110
124
  _scheduleClipboardClear() {
111
125
  this._cancelClipboardTimer(), this._clipboardTimer = setTimeout(() => {
112
126
  this._clearClipboard();
113
127
  }, this.clipboardTimeout);
114
128
  }
129
+ /** @internal */
115
130
  _clearClipboard() {
116
131
  var e;
117
132
  this._clipboardTimer = null, typeof navigator < "u" && navigator.clipboard && ((e = navigator == null ? void 0 : navigator.clipboard) == null || e.writeText("").catch(() => {
@@ -121,13 +136,14 @@ let a = class extends p {
121
136
  composed: !0,
122
137
  detail: {
123
138
  fieldId: this.fieldId || this.id || "",
124
- action: "hide",
139
+ action: "clipboard-clear",
125
140
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
126
141
  fieldType: this.fieldType
127
142
  }
128
143
  })
129
144
  ), this._masked = !0;
130
145
  }
146
+ /** @internal */
131
147
  _getMaskedValue() {
132
148
  if (!this.data) return "";
133
149
  switch (this.fieldType) {
@@ -137,11 +153,11 @@ let a = class extends p {
137
153
  }
138
154
  case "mrn": {
139
155
  const e = this.data.split(""), t = [];
140
- e.forEach((r, s) => {
141
- /[a-zA-Z0-9]/.test(r) && t.push(s);
156
+ e.forEach((o, d) => {
157
+ /[a-zA-Z0-9]/.test(o) && t.push(d);
142
158
  });
143
- const d = Math.min(4, t.length), l = t.length - d, i = new Set(t.slice(0, l));
144
- return e.map((r, s) => i.has(s) ? "*" : r).join("");
159
+ const l = Math.min(4, t.length), r = t.length - l, i = new Set(t.slice(0, r));
160
+ return e.map((o, d) => i.has(d) ? "*" : o).join("");
145
161
  }
146
162
  case "dob":
147
163
  return this.data.replace(/\d/g, "*");
@@ -154,8 +170,9 @@ let a = class extends p {
154
170
  }
155
171
  }
156
172
  // ─── Event Handlers ───
173
+ /** @internal */
157
174
  _handleToggle() {
158
- this.dispatchEvent(
175
+ this.disabled || (this.dispatchEvent(
159
176
  new CustomEvent("hx-phi-access", {
160
177
  bubbles: !0,
161
178
  composed: !0,
@@ -166,17 +183,20 @@ let a = class extends p {
166
183
  fieldType: this.fieldType
167
184
  }
168
185
  })
169
- ), this._masked ? (this._masked = !1, this._scheduleClipboardClear()) : (this._cancelClipboardTimer(), this._masked = !0);
186
+ ), this._masked ? (this._masked = !1, this._scheduleClipboardClear()) : (this._cancelClipboardTimer(), this._masked = !0));
170
187
  }
188
+ /** @internal */
171
189
  _handleCopy(e) {
172
190
  this._masked && e.preventDefault();
173
191
  }
192
+ /** @internal */
174
193
  _handlePaste(e) {
175
194
  this._masked && e.preventDefault();
176
195
  }
177
196
  // ─── Render Helpers ───
197
+ /** @internal */
178
198
  _renderEyeIcon() {
179
- return n`
199
+ return h`
180
200
  <svg
181
201
  xmlns="http://www.w3.org/2000/svg"
182
202
  viewBox="0 0 24 24"
@@ -192,8 +212,9 @@ let a = class extends p {
192
212
  </svg>
193
213
  `;
194
214
  }
215
+ /** @internal */
195
216
  _renderEyeOffIcon() {
196
- return n`
217
+ return h`
197
218
  <svg
198
219
  xmlns="http://www.w3.org/2000/svg"
199
220
  viewBox="0 0 24 24"
@@ -212,21 +233,28 @@ let a = class extends p {
212
233
  }
213
234
  // ─── Render ───
214
235
  render() {
215
- return n`
216
- <div part="container" class="phi-field" @copy=${this._handleCopy} @paste=${this._handlePaste}>
217
- ${this._masked ? n`<span part="value" class="phi-field__value phi-field__value--masked"
236
+ const e = this.label || "Protected health information", t = `${e} is masked`, l = `${e} is revealed`, r = `Reveal ${e.toLowerCase()}`, i = `Hide ${e.toLowerCase()}`;
237
+ return h`
238
+ <div
239
+ part="container"
240
+ class="phi-field${this.disabled ? " phi-field--disabled" : ""}"
241
+ @copy=${this._handleCopy}
242
+ @paste=${this._handlePaste}
243
+ >
244
+ ${this._masked ? h`<span part="value" class="phi-field__value phi-field__value--masked"
218
245
  >${this._getMaskedValue()}</span
219
- >` : n`<span part="value" class="phi-field__value phi-field__value--revealed"
246
+ >` : h`<span part="value" class="phi-field__value phi-field__value--revealed"
220
247
  >${this.data}</span
221
248
  >`}
222
249
  <span role="status" aria-live="polite" aria-atomic="true" class="phi-field__status">
223
- ${this._masked ? "Protected health information is masked" : "Protected health information is revealed"}
250
+ ${this._masked ? t : l}
224
251
  </span>
225
252
  <button
226
253
  part="toggle"
227
254
  class="phi-field__toggle"
228
255
  type="button"
229
- aria-label=${this._masked ? "Reveal protected health information" : "Hide protected health information"}
256
+ ?disabled=${this.disabled}
257
+ aria-label=${this._masked ? r : i}
230
258
  aria-pressed=${String(!this._masked)}
231
259
  @click=${this._handleToggle}
232
260
  >
@@ -237,25 +265,31 @@ let a = class extends p {
237
265
  }
238
266
  };
239
267
  a.styles = [m, _];
240
- o([
241
- h({ type: String })
268
+ s([
269
+ n({ type: String })
242
270
  ], a.prototype, "data", 2);
243
- o([
244
- h({ type: String, reflect: !0, attribute: "field-type" })
271
+ s([
272
+ n({ type: String, reflect: !0, attribute: "field-type" })
245
273
  ], a.prototype, "fieldType", 2);
246
- o([
247
- h({ type: String, attribute: "field-id" })
274
+ s([
275
+ n({ type: String, attribute: "field-id" })
248
276
  ], a.prototype, "fieldId", 2);
249
- o([
250
- h({ type: Number, attribute: "clipboard-timeout" })
277
+ s([
278
+ n({ type: Number, attribute: "clipboard-timeout" })
251
279
  ], a.prototype, "clipboardTimeout", 2);
252
- o([
280
+ s([
281
+ n({ type: String })
282
+ ], a.prototype, "label", 2);
283
+ s([
284
+ n({ type: Boolean, reflect: !0 })
285
+ ], a.prototype, "disabled", 2);
286
+ s([
253
287
  u()
254
288
  ], a.prototype, "_masked", 2);
255
- a = o([
289
+ a = s([
256
290
  f("hx-phi-field")
257
291
  ], a);
258
292
  export {
259
293
  a as H
260
294
  };
261
- //# sourceMappingURL=hx-phi-field-EDWna59z.js.map
295
+ //# sourceMappingURL=hx-phi-field-DX9z3nu0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-phi-field-DX9z3nu0.js","sources":["../../src/components/hx-phi-field/hx-phi-field.styles.ts","../../src/components/hx-phi-field/hx-phi-field.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPhiFieldStyles = css`\n :host {\n display: inline-flex;\n }\n\n /* ─── Container ─── */\n\n .phi-field {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n font-family: var(--hx-phi-field-font-family, var(--hx-font-family-mono, monospace));\n }\n\n /* ─── Value ─── */\n\n .phi-field__value--masked {\n user-select: none;\n -webkit-user-select: none;\n color: var(--hx-phi-field-masked-color, var(--hx-color-neutral-500, #6b7280));\n letter-spacing: 0.1em;\n }\n\n .phi-field__value--revealed {\n color: var(--hx-phi-field-value-color, var(--hx-color-neutral-900, #111827));\n }\n\n /* ─── Screen Reader Status ─── */\n\n .phi-field__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n padding: 0;\n margin: -1px;\n }\n\n /* ─── Toggle Button ─── */\n\n .phi-field__toggle {\n display: inline-flex;\n align-items: center;\n background: none;\n border: none;\n padding: var(--hx-space-1, 0.25rem);\n color: var(--hx-phi-field-toggle-color, var(--hx-color-primary-500, #2563eb));\n cursor: pointer;\n line-height: 1;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n .phi-field__toggle:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-phi-field-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500, #2563eb))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .phi-field__toggle:hover {\n opacity: var(--hx-opacity-90, 0.9);\n }\n\n .phi-field__toggle:active {\n opacity: var(--hx-opacity-50, 0.5);\n }\n\n .phi-field__toggle svg {\n width: 1em;\n height: 1em;\n pointer-events: none;\n }\n\n /* ─── Disabled State ─── */\n\n :host([disabled]) {\n opacity: var(--hx-phi-field-disabled-opacity, var(--hx-opacity-50, 0.5));\n pointer-events: none;\n cursor: not-allowed;\n }\n\n .phi-field--disabled .phi-field__toggle {\n cursor: not-allowed;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .phi-field__toggle {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, type TemplateResult } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixPhiFieldStyles } from './hx-phi-field.styles.js';\n\n/**\n * HIPAA-compliant field component for rendering masked Protected Health Information (PHI).\n * PHI is masked by default and only rendered to the DOM when explicitly revealed. Access\n * events are fired on reveal, hide, and clipboard auto-clear for audit trail purposes.\n *\n * @summary HIPAA-compliant field for rendering masked Protected Health Information.\n *\n * @tag hx-phi-field\n *\n * @csspart container - The outer wrapper element.\n * @csspart value - The value display span (masked or revealed).\n * @csspart toggle - The reveal/hide toggle button.\n *\n * @fires {CustomEvent<PhiAccessEventDetail>} hx-phi-access - Fired on reveal, hide, and clipboard-clear actions.\n *\n * @cssprop [--hx-phi-field-font-family=var(--hx-font-family-mono,monospace)] - Font family for the masked value.\n * @cssprop [--hx-phi-field-value-color=var(--hx-color-neutral-900,#111827)] - Value text color.\n * @cssprop [--hx-phi-field-masked-color=var(--hx-color-neutral-500,#6b7280)] - Masked value text color.\n * @cssprop [--hx-phi-field-toggle-color=var(--hx-color-primary-500,#2563eb)] - Toggle button color.\n * @cssprop [--hx-phi-field-focus-ring-color=var(--hx-focus-ring-color,var(--hx-color-primary-500,#2563eb))] - Focus ring color.\n * @cssprop [--hx-phi-field-disabled-opacity=var(--hx-opacity-50,0.5)] - Opacity applied when the field is disabled.\n */\n@customElement('hx-phi-field')\nexport class HelixPhiField extends LitElement {\n static override styles = [tokenStyles, helixPhiFieldStyles];\n\n // ─── Public Properties ───\n\n /**\n * The Protected Health Information value to display or mask.\n * @attr data\n */\n @property({ type: String })\n data: string = '';\n\n /**\n * The type of PHI field. Controls the masking pattern applied.\n * @attr field-type\n */\n @property({ type: String, reflect: true, attribute: 'field-type' })\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance' = 'ssn';\n\n /**\n * Identifier used in audit events. Falls back to the element's id attribute.\n * @attr field-id\n */\n @property({ type: String, attribute: 'field-id' })\n fieldId: string = '';\n\n /**\n * Milliseconds after clipboard write before the clipboard is automatically cleared.\n * Defaults to 30000 (30 seconds).\n * @attr clipboard-timeout\n */\n @property({ type: Number, attribute: 'clipboard-timeout' })\n clipboardTimeout: number = 30000;\n\n /**\n * Accessible label describing the PHI field. Used as a prefix in screen reader\n * announcements (e.g., \"Social Security Number is masked\").\n * @attr label\n */\n @property({ type: String })\n label: string = '';\n\n /**\n * When set, disables all interaction with the field and prevents reveal.\n * @attr disabled\n * @reflect\n */\n @property({ type: Boolean, reflect: true })\n disabled: boolean = false;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _masked = true;\n\n /** @internal */\n private _clipboardTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Enforce HIPAA compliance: prevent browser autofill on the host element\n this.setAttribute('autocomplete', 'off');\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._cancelClipboardTimer();\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _cancelClipboardTimer(): void {\n if (this._clipboardTimer !== null) {\n clearTimeout(this._clipboardTimer);\n this._clipboardTimer = null;\n }\n }\n\n /** @internal */\n private _scheduleClipboardClear(): void {\n this._cancelClipboardTimer();\n this._clipboardTimer = setTimeout(() => {\n this._clearClipboard();\n }, this.clipboardTimeout);\n }\n\n /** @internal */\n private _clearClipboard(): void {\n this._clipboardTimer = null;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n navigator?.clipboard?.writeText('').catch(() => {\n // Clipboard clear failure is non-fatal — silently ignore\n });\n }\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: 'clipboard-clear',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n this._masked = true;\n }\n\n /** @internal */\n private _getMaskedValue(): string {\n if (!this.data) return '';\n\n switch (this.fieldType) {\n case 'ssn': {\n // Format: xxx-xx-xxxx → ***-**-xxxx (show last 4 digits)\n // Match the separator-delimited pattern first\n const ssnMatch = this.data.match(/^(\\d{3})(-?)(\\d{2})(-?)(\\d{4})$/);\n if (ssnMatch) {\n return `***${ssnMatch[2]}**${ssnMatch[4]}${ssnMatch[5]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/\\d/g, '*') + this.data.slice(-4);\n }\n\n case 'mrn': {\n // Mask all but last 4 alphanumeric characters, preserve separators\n const chars = this.data.split('');\n const alphanumericIndices: number[] = [];\n chars.forEach((ch, i) => {\n if (/[a-zA-Z0-9]/.test(ch)) {\n alphanumericIndices.push(i);\n }\n });\n const revealCount = Math.min(4, alphanumericIndices.length);\n const maskUntilIdx = alphanumericIndices.length - revealCount;\n const indicesToMask = new Set(alphanumericIndices.slice(0, maskUntilIdx));\n return chars.map((ch, i) => (indicesToMask.has(i) ? '*' : ch)).join('');\n }\n\n case 'dob': {\n // Replace ALL digits with *, preserve separators\n return this.data.replace(/\\d/g, '*');\n }\n\n case 'insurance': {\n // Format: xxxx-xxxx-xxxx-xxxx → ****-****-****-xxxx (show last 4 digits)\n const insMatch = this.data.match(/^(\\d{4})(-?)(\\d{4})(-?)(\\d{4})(-?)(\\d{4})$/);\n if (insMatch) {\n return `****${insMatch[2]}****${insMatch[4]}****${insMatch[6]}${insMatch[7]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/[a-zA-Z0-9]/g, '*') + this.data.slice(-4);\n }\n\n default: {\n // Exhaustive check — fieldType is typed, but guard defensively\n const _exhaustive: never = this.fieldType;\n return _exhaustive;\n }\n }\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleToggle(): void {\n if (this.disabled) return;\n\n // Dispatch BEFORE toggling state so action reflects the upcoming state\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: this._masked ? 'reveal' : 'hide',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n\n if (this._masked) {\n // Revealing: start clipboard clear timer\n this._masked = false;\n this._scheduleClipboardClear();\n } else {\n // Hiding: cancel any pending clipboard clear\n this._cancelClipboardTimer();\n this._masked = true;\n }\n }\n\n /** @internal */\n private _handleCopy(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n /** @internal */\n private _handlePaste(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderEyeIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n `;\n }\n\n /** @internal */\n private _renderEyeOffIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n </svg>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const fieldLabel = this.label || 'Protected health information';\n const maskedLabel = `${fieldLabel} is masked`;\n const revealedLabel = `${fieldLabel} is revealed`;\n const revealActionLabel = `Reveal ${fieldLabel.toLowerCase()}`;\n const hideActionLabel = `Hide ${fieldLabel.toLowerCase()}`;\n\n return html`\n <div\n part=\"container\"\n class=\"phi-field${this.disabled ? ' phi-field--disabled' : ''}\"\n @copy=${this._handleCopy}\n @paste=${this._handlePaste}\n >\n ${this._masked\n ? html`<span part=\"value\" class=\"phi-field__value phi-field__value--masked\"\n >${this._getMaskedValue()}</span\n >`\n : html`<span part=\"value\" class=\"phi-field__value phi-field__value--revealed\"\n >${this.data}</span\n >`}\n <span role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"phi-field__status\">\n ${this._masked ? maskedLabel : revealedLabel}\n </span>\n <button\n part=\"toggle\"\n class=\"phi-field__toggle\"\n type=\"button\"\n ?disabled=${this.disabled}\n aria-label=${this._masked ? revealActionLabel : hideActionLabel}\n aria-pressed=${String(!this._masked)}\n @click=${this._handleToggle}\n >\n ${this._masked ? this._renderEyeIcon() : this._renderEyeOffIcon()}\n </button>\n </div>\n `;\n }\n}\n\nexport interface PhiAccessEventDetail {\n fieldId: string;\n /** The action that triggered the audit event. */\n action: 'reveal' | 'hide' | 'clipboard-clear';\n timestamp: string;\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance';\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-phi-field': HelixPhiField;\n }\n}\n"],"names":["helixPhiFieldStyles","css","HelixPhiField","LitElement","_a","ssnMatch","chars","alphanumericIndices","ch","i","revealCount","maskUntilIdx","indicesToMask","insMatch","html","fieldLabel","maskedLabel","revealedLabel","revealActionLabel","hideActionLabel","tokenStyles","__decorateClass","property","state","customElement"],"mappings":"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"}