@helixui/library 1.1.2-next.2 → 1.1.2-next.25
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 +387 -405
- package/dist/components/hx-avatar/hx-avatar.styles.d.ts.map +1 -1
- package/dist/components/hx-avatar/index.js +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb-item.d.ts +1 -0
- package/dist/components/hx-breadcrumb/hx-breadcrumb-item.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts +10 -8
- package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/index.js +1 -1
- package/dist/components/hx-button/hx-button.d.ts +12 -6
- package/dist/components/hx-button/hx-button.d.ts.map +1 -1
- package/dist/components/hx-button/hx-button.styles.d.ts.map +1 -1
- package/dist/components/hx-button/index.js +1 -1
- package/dist/components/hx-clinical-status/hx-clinical-status.d.ts +14 -6
- package/dist/components/hx-clinical-status/hx-clinical-status.d.ts.map +1 -1
- package/dist/components/hx-clinical-status/hx-clinical-status.styles.d.ts.map +1 -1
- package/dist/components/hx-clinical-status/index.d.ts +1 -1
- package/dist/components/hx-clinical-status/index.d.ts.map +1 -1
- package/dist/components/hx-clinical-status/index.js +1 -1
- package/dist/components/hx-menu/hx-menu-item.d.ts +5 -0
- package/dist/components/hx-menu/hx-menu-item.d.ts.map +1 -1
- package/dist/components/hx-menu/hx-menu.d.ts +1 -0
- package/dist/components/hx-menu/hx-menu.d.ts.map +1 -1
- package/dist/components/hx-menu/hx-menu.styles.d.ts.map +1 -1
- package/dist/components/hx-menu/index.js +1 -1
- package/dist/components/hx-nav/hx-nav.d.ts +10 -0
- package/dist/components/hx-nav/hx-nav.d.ts.map +1 -1
- package/dist/components/hx-nav/index.js +1 -1
- package/dist/components/hx-pagination/hx-pagination.d.ts.map +1 -1
- package/dist/components/hx-pagination/index.js +1 -1
- package/dist/components/hx-patient-banner/hx-patient-banner.d.ts +8 -0
- package/dist/components/hx-patient-banner/hx-patient-banner.d.ts.map +1 -1
- package/dist/components/hx-patient-banner/hx-patient-banner.styles.d.ts.map +1 -1
- package/dist/components/hx-patient-banner/index.js +1 -1
- package/dist/components/hx-phi-field/hx-phi-field.d.ts +27 -2
- package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
- package/dist/components/hx-phi-field/hx-phi-field.styles.d.ts.map +1 -1
- package/dist/components/hx-phi-field/index.js +1 -1
- package/dist/components/hx-select/hx-select.d.ts +1 -0
- package/dist/components/hx-select/hx-select.d.ts.map +1 -1
- package/dist/components/hx-select/hx-select.styles.d.ts.map +1 -1
- package/dist/components/hx-select/index.js +1 -1
- package/dist/components/hx-side-nav/hx-nav-item.d.ts +5 -0
- package/dist/components/hx-side-nav/hx-nav-item.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-side-nav.d.ts.map +1 -1
- package/dist/components/hx-side-nav/index.js +1 -1
- package/dist/components/hx-status-indicator/hx-status-indicator.d.ts +17 -1
- package/dist/components/hx-status-indicator/hx-status-indicator.d.ts.map +1 -1
- package/dist/components/hx-status-indicator/hx-status-indicator.styles.d.ts.map +1 -1
- package/dist/components/hx-status-indicator/index.js +1 -1
- package/dist/components/hx-steps/hx-step.d.ts +7 -0
- package/dist/components/hx-steps/hx-step.d.ts.map +1 -1
- package/dist/components/hx-steps/hx-steps.d.ts.map +1 -1
- package/dist/components/hx-steps/index.js +1 -1
- package/dist/components/hx-tabs/hx-tab.styles.d.ts.map +1 -1
- package/dist/components/hx-tabs/hx-tabs.d.ts +10 -0
- package/dist/components/hx-tabs/hx-tabs.d.ts.map +1 -1
- package/dist/components/hx-tabs/index.js +1 -1
- package/dist/components/hx-tree-view/hx-tree-item.d.ts +5 -0
- package/dist/components/hx-tree-view/hx-tree-item.d.ts.map +1 -1
- package/dist/components/hx-tree-view/hx-tree-view.d.ts +6 -0
- package/dist/components/hx-tree-view/hx-tree-view.d.ts.map +1 -1
- package/dist/components/hx-tree-view/index.js +1 -1
- package/dist/css/helix-all.css +202 -51
- package/dist/css/helix-core.css +52 -1
- package/dist/css/helix-feedback.css +33 -4
- package/dist/css/helix-forms.css +68 -41
- package/dist/css/helix-navigation.css +2 -0
- package/dist/css/hx-avatar.css +18 -1
- package/dist/css/hx-button.css +34 -0
- package/dist/css/hx-clinical-status.css +4 -2
- package/dist/css/hx-menu.css +2 -0
- package/dist/css/hx-patient-banner.css +31 -3
- package/dist/css/hx-phi-field.css +12 -0
- package/dist/css/hx-select.css +68 -41
- package/dist/css/hx-status-indicator.css +33 -4
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +13 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -15
- package/dist/shared/{hx-avatar-7p1cj3lG.js → hx-avatar-CZfA9KEl.js} +27 -10
- package/dist/shared/hx-avatar-CZfA9KEl.js.map +1 -0
- package/dist/shared/{hx-breadcrumb-item-B2rjepqy.js → hx-breadcrumb-item-CObc-WJl.js} +8 -6
- package/dist/shared/hx-breadcrumb-item-CObc-WJl.js.map +1 -0
- package/dist/shared/{hx-button-6S3DwuIj.js → hx-button-CC1YH9RZ.js} +52 -12
- package/dist/shared/hx-button-CC1YH9RZ.js.map +1 -0
- package/dist/shared/{hx-clinical-status-De8yrA5I.js → hx-clinical-status-D6eaplvs.js} +5 -3
- package/dist/shared/hx-clinical-status-D6eaplvs.js.map +1 -0
- package/dist/shared/{hx-menu-divider-DR4G_rqw.js → hx-menu-divider-puPmRAdN.js} +40 -20
- package/dist/shared/hx-menu-divider-puPmRAdN.js.map +1 -0
- package/dist/shared/{hx-nav-D377Ngz4.js → hx-nav-CiyqaW2I.js} +112 -99
- package/dist/shared/hx-nav-CiyqaW2I.js.map +1 -0
- package/dist/shared/{hx-nav-item-CuGiJPAf.js → hx-nav-item-tM_6bolB.js} +132 -92
- package/dist/shared/hx-nav-item-tM_6bolB.js.map +1 -0
- package/dist/shared/{hx-pagination-DYhYPqDn.js → hx-pagination-Cb9UEWXz.js} +74 -66
- package/dist/shared/{hx-pagination-DYhYPqDn.js.map → hx-pagination-Cb9UEWXz.js.map} +1 -1
- package/dist/shared/{hx-patient-banner-BoJHddAL.js → hx-patient-banner-wk4qWmsH.js} +88 -47
- package/dist/shared/hx-patient-banner-wk4qWmsH.js.map +1 -0
- package/dist/shared/{hx-phi-field-EDWna59z.js → hx-phi-field-DX9z3nu0.js} +67 -33
- package/dist/shared/hx-phi-field-DX9z3nu0.js.map +1 -0
- package/dist/shared/{hx-select-4-nHL0vd.js → hx-select-BWzxWZs_.js} +82 -55
- package/dist/shared/hx-select-BWzxWZs_.js.map +1 -0
- package/dist/shared/{hx-status-indicator-4ClvA5mU.js → hx-status-indicator-Dl3Y34mc.js} +76 -35
- package/dist/shared/hx-status-indicator-Dl3Y34mc.js.map +1 -0
- package/dist/shared/{hx-step-DlANlr2A.js → hx-step-CmNwfcJx.js} +30 -26
- package/dist/shared/hx-step-CmNwfcJx.js.map +1 -0
- package/dist/shared/{hx-tab-panel-GGjk6Qg4.js → hx-tab-panel-Dnt8aA74.js} +89 -61
- package/dist/shared/hx-tab-panel-Dnt8aA74.js.map +1 -0
- package/dist/shared/{hx-tree-item-DTDIBRrI.js → hx-tree-item-C1PhX-HE.js} +50 -19
- package/dist/shared/hx-tree-item-C1PhX-HE.js.map +1 -0
- package/package.json +2 -2
- package/dist/shared/hx-avatar-7p1cj3lG.js.map +0 -1
- package/dist/shared/hx-breadcrumb-item-B2rjepqy.js.map +0 -1
- package/dist/shared/hx-button-6S3DwuIj.js.map +0 -1
- package/dist/shared/hx-clinical-status-De8yrA5I.js.map +0 -1
- package/dist/shared/hx-menu-divider-DR4G_rqw.js.map +0 -1
- package/dist/shared/hx-nav-D377Ngz4.js.map +0 -1
- package/dist/shared/hx-nav-item-CuGiJPAf.js.map +0 -1
- package/dist/shared/hx-patient-banner-BoJHddAL.js.map +0 -1
- package/dist/shared/hx-phi-field-EDWna59z.js.map +0 -1
- package/dist/shared/hx-select-4-nHL0vd.js.map +0 -1
- package/dist/shared/hx-status-indicator-4ClvA5mU.js.map +0 -1
- package/dist/shared/hx-step-DlANlr2A.js.map +0 -1
- package/dist/shared/hx-tab-panel-GGjk6Qg4.js.map +0 -1
- package/dist/shared/hx-tree-item-DTDIBRrI.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-nav-D377Ngz4.js","sources":["../../src/components/hx-nav/hx-nav.styles.ts","../../src/components/hx-nav/hx-nav.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixNavStyles = css`\n :host {\n display: block;\n font-family: var(--hx-nav-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-nav-font-size, var(--hx-font-size-sm, 0.875rem));\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Nav Container ─── */\n\n [part='nav'] {\n position: relative;\n background-color: var(--hx-nav-bg, var(--hx-color-neutral-900, #111827));\n color: var(--hx-nav-color, var(--hx-color-neutral-100, #f3f4f6));\n padding: var(--hx-nav-padding, var(--hx-space-2, 0.5rem) var(--hx-space-4, 1rem));\n }\n\n /* ─── Hamburger Toggle ─── */\n\n [part='toggle'] {\n display: none;\n align-items: center;\n justify-content: center;\n padding: var(--hx-space-2, 0.5rem);\n background: transparent;\n border: none;\n border-radius: var(--hx-nav-border-radius, var(--hx-border-radius-sm, 0.25rem));\n color: var(--hx-nav-color, var(--hx-color-neutral-100, #f3f4f6));\n cursor: pointer;\n transition: background-color var(--hx-transition-fast, 150ms) ease;\n line-height: 0;\n }\n\n [part='toggle']:hover {\n background-color: var(--hx-nav-link-hover-bg, var(--hx-color-neutral-700, #374151));\n }\n\n [part='toggle']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-nav-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Navigation List ─── */\n\n [part='list'] {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n list-style: none;\n margin: 0;\n padding: 0;\n gap: var(--hx-space-1, 0.25rem);\n align-items: center;\n }\n\n /* ─── Nav Item ─── */\n\n [part='item'] {\n position: relative;\n }\n\n /* ─── Nav Link / Button ─── */\n\n .nav__link {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n padding: var(--hx-nav-item-padding, var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem));\n color: var(--hx-nav-link-color, var(--hx-color-neutral-100, #f3f4f6));\n text-decoration: none;\n border-radius: var(--hx-nav-border-radius, var(--hx-border-radius-sm, 0.25rem));\n border: none;\n background: transparent;\n cursor: pointer;\n font-family: inherit;\n font-size: inherit;\n font-weight: var(--hx-font-weight-medium, 500);\n line-height: var(--hx-line-height-normal, 1.5);\n white-space: nowrap;\n transition:\n background-color var(--hx-transition-fast, 150ms) ease,\n color var(--hx-transition-fast, 150ms) ease;\n }\n\n .nav__link:hover {\n background-color: var(--hx-nav-link-hover-bg, var(--hx-color-neutral-700, #374151));\n color: var(--hx-nav-link-hover-color, var(--hx-color-neutral-0, #ffffff));\n }\n\n .nav__link:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-nav-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .nav__link--active {\n background-color: var(--hx-nav-link-active-bg, var(--hx-color-primary-600, #2563eb));\n color: var(--hx-nav-link-active-color, var(--hx-color-neutral-0, #ffffff));\n }\n\n /* ─── Chevron Icon ─── */\n\n .nav__chevron {\n transition: transform var(--hx-transition-normal, 200ms) ease;\n flex-shrink: 0;\n }\n\n .nav__link--expanded .nav__chevron {\n transform: rotate(180deg);\n }\n\n /* ─── Submenu ─── */\n\n .nav__submenu {\n position: absolute;\n top: calc(100% + var(--hx-space-1, 0.25rem));\n left: 0;\n min-width: var(--hx-nav-submenu-min-width, 12rem);\n list-style: none;\n margin: 0;\n padding: var(--hx-space-1, 0.25rem) 0;\n background-color: var(--hx-nav-submenu-bg, var(--hx-color-neutral-800, #1f2937));\n border-radius: var(--hx-border-radius-md, 0.375rem);\n box-shadow: var(\n --hx-shadow-md,\n 0 4px 6px -1px rgb(0 0 0 / 0.1),\n 0 2px 4px -2px rgb(0 0 0 / 0.1)\n );\n z-index: var(--hx-z-index-dropdown, 1000);\n }\n\n .nav__submenu[hidden] {\n display: none;\n }\n\n .nav__submenu .nav__link {\n display: block;\n width: 100%;\n text-align: start;\n border-radius: 0;\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-4, 1rem);\n }\n\n /* ─── Vertical / Sidebar Orientation ─── */\n\n :host([orientation='vertical']) [part='nav'] {\n padding: var(--hx-space-4, 1rem) var(--hx-space-2, 0.5rem);\n }\n\n :host([orientation='vertical']) [part='list'] {\n flex-direction: column;\n align-items: stretch;\n gap: var(--hx-space-1, 0.25rem);\n }\n\n :host([orientation='vertical']) .nav__link {\n width: 100%;\n justify-content: flex-start;\n }\n\n :host([orientation='vertical']) .nav__submenu {\n position: static;\n box-shadow: none;\n border-radius: 0;\n background-color: transparent;\n padding: 0;\n padding-inline-start: var(--hx-space-4, 1rem);\n }\n\n :host([orientation='vertical']) .nav__submenu[hidden] {\n display: none;\n }\n\n :host([orientation='vertical']) .nav__submenu .nav__link {\n padding: var(--hx-space-1-5, 0.375rem) var(--hx-space-3, 0.75rem);\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-nav-link-color, var(--hx-color-neutral-300, #d1d5db));\n }\n\n /* ─── Mobile Responsive ─── */\n\n @media (max-width: 768px) {\n [part='nav'] {\n display: flex;\n flex-direction: column;\n padding: var(--hx-space-2, 0.5rem);\n }\n\n [part='toggle'] {\n display: inline-flex;\n align-self: flex-end;\n }\n\n [part='list'] {\n display: none;\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n margin-top: var(--hx-space-2, 0.5rem);\n gap: var(--hx-space-1, 0.25rem);\n }\n\n [part='list'].nav__list--open {\n display: flex;\n }\n\n [part='item'] {\n width: 100%;\n }\n\n .nav__link {\n width: 100%;\n justify-content: flex-start;\n }\n\n .nav__submenu {\n position: static;\n box-shadow: none;\n border-radius: 0;\n padding-inline-start: var(--hx-space-4, 1rem);\n background-color: transparent;\n }\n\n .nav__submenu .nav__link {\n padding: var(--hx-space-1-5, 0.375rem) var(--hx-space-3, 0.75rem);\n }\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .nav__link,\n .nav__chevron,\n [part='toggle'] {\n transition: none;\n animation: none;\n }\n }\n`;\n","import { LitElement, html, nothing, svg } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixNavStyles } from './hx-nav.styles.js';\n\n/** A single navigation item, optionally with nested children. */\nexport interface NavItem {\n /** Display label for the item. */\n label: string;\n /** Href for the item link. Required unless children are provided. */\n href?: string;\n /** Whether this item represents the current page. */\n current?: boolean;\n /** Nested sub-menu items. */\n children?: NavItem[];\n}\n\n/** Layout orientation for the navigation. */\ntype NavOrientation = 'horizontal' | 'vertical';\n\n/**\n * Primary and secondary navigation component.\n * Supports horizontal menu bar and vertical sidebar patterns.\n * Mobile responsive with hamburger toggle.\n *\n * @summary Navigation bar supporting horizontal and vertical layouts with nested submenus.\n *\n * @tag hx-nav\n *\n * @fires {CustomEvent<{item: NavItem}>} hx-nav-select - Dispatched when a nav item is activated.\n *\n * @csspart nav - The nav landmark element.\n * @csspart list - The top-level list element.\n * @csspart item - Each list item wrapper.\n * @csspart link - The anchor or button element inside each item.\n * @csspart toggle - The mobile hamburger toggle button.\n *\n * @cssprop [--hx-nav-bg=var(--hx-color-neutral-900)] - Navigation background color.\n * @cssprop [--hx-nav-color=var(--hx-color-neutral-100)] - Navigation text color.\n * @cssprop [--hx-nav-font-family=var(--hx-font-family-sans)] - Navigation font family.\n * @cssprop [--hx-nav-link-color=var(--hx-color-neutral-100)] - Link text color.\n * @cssprop [--hx-nav-link-hover-bg=var(--hx-color-neutral-700)] - Link hover background.\n * @cssprop [--hx-nav-link-hover-color=var(--hx-color-white)] - Link hover text color.\n * @cssprop [--hx-nav-link-active-bg=var(--hx-color-primary-600)] - Active link background.\n * @cssprop [--hx-nav-link-active-color=var(--hx-color-white)] - Active link text color.\n * @cssprop [--hx-nav-submenu-bg=var(--hx-color-neutral-800)] - Submenu background color.\n * @cssprop [--hx-nav-submenu-min-width=12rem] - Submenu minimum width.\n * @cssprop [--hx-nav-font-size=var(--hx-font-size-sm)] - Navigation font size.\n * @cssprop [--hx-nav-padding=var(--hx-space-2) var(--hx-space-4)] - Navigation padding.\n * @cssprop [--hx-nav-item-padding=var(--hx-space-2) var(--hx-space-3)] - Item padding.\n * @cssprop [--hx-nav-border-radius=var(--hx-border-radius-sm)] - Item border radius.\n */\n@customElement('hx-nav')\nexport class HelixNav extends LitElement {\n static override styles = [tokenStyles, helixNavStyles];\n\n // ─── Properties ───\n\n /**\n * Navigation items array.\n * @attr items\n */\n @property({\n type: Array,\n converter: {\n fromAttribute(value: string | null): NavItem[] {\n if (!value) return [];\n try {\n const parsed: unknown = JSON.parse(value);\n return Array.isArray(parsed) ? (parsed as NavItem[]) : [];\n } catch {\n return [];\n }\n },\n },\n })\n items: NavItem[] = [];\n\n /**\n * Layout orientation: 'horizontal' (menu bar) or 'vertical' (sidebar).\n * @attr orientation\n */\n @property({ type: String, reflect: true })\n orientation: NavOrientation = 'horizontal';\n\n /**\n * Accessible label for the nav landmark.\n * @attr label\n */\n @property({ type: String })\n label = 'Main navigation';\n\n /** Accessible label for the navigation toggle button when menu is closed. */\n @property({ type: String, attribute: 'label-open-menu' })\n labelOpenMenu = 'Open navigation menu';\n\n /** Accessible label for the navigation toggle button when menu is open. */\n @property({ type: String, attribute: 'label-close-menu' })\n labelCloseMenu = 'Close navigation menu';\n\n // ─── State ───\n\n /**\n * Tracks whether the mobile navigation menu is currently expanded.\n * @internal\n */\n @state() private _mobileOpen = false;\n /**\n * Index of the currently expanded top-level nav item with a submenu, or null if none is expanded.\n * @internal\n */\n @state() private _expandedIndex: number | null = null;\n\n // ─── Private: bound event handler reference ───\n\n /**\n * Stable bound reference to the outside-click handler, stored for addEventListener/removeEventListener symmetry.\n * @internal\n */\n private _boundOutsideClick: (e: MouseEvent) => void = this._handleOutsideClick.bind(this);\n\n /**\n * Sanitizes a URL to prevent XSS via javascript: or data: URIs.\n * Only allows http:, https:, relative paths, and fragment-only links.\n */\n /** @internal */\n private _sanitizeHref(href: string | undefined): string {\n if (!href || href === '#') return '#';\n // Allow relative paths, fragments, and http(s)\n if (\n href.startsWith('/') ||\n href.startsWith('./') ||\n href.startsWith('../') ||\n href.startsWith('#')\n ) {\n return href;\n }\n if (typeof window === 'undefined') return href;\n try {\n const url = new URL(href, window.location.href);\n if (url.protocol === 'http:' || url.protocol === 'https:') {\n return href;\n }\n } catch {\n // Invalid URL — fall through to safe default\n }\n return '#';\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleToggle(): void {\n this._mobileOpen = !this._mobileOpen;\n if (!this._mobileOpen) {\n this._expandedIndex = null;\n }\n }\n\n /** @internal */\n private _handleItemClick(item: NavItem, index: number, e: Event): void {\n e.preventDefault();\n if (item.children?.length) {\n this._expandedIndex = this._expandedIndex === index ? null : index;\n } else {\n this._mobileOpen = false;\n this._expandedIndex = null;\n this.dispatchEvent(\n new CustomEvent<{ item: NavItem }>('hx-nav-select', {\n bubbles: true,\n composed: true,\n detail: { item },\n }),\n );\n }\n }\n\n /** @internal */\n private _handleSubItemClick(item: NavItem, e: Event): void {\n e.preventDefault();\n this._mobileOpen = false;\n this._expandedIndex = null;\n this.dispatchEvent(\n new CustomEvent<{ item: NavItem }>('hx-nav-select', {\n bubbles: true,\n composed: true,\n detail: { item },\n }),\n );\n }\n\n /** @internal */\n private _handleKeydown(e: KeyboardEvent, index: number, item: NavItem): void {\n const items = this.shadowRoot?.querySelectorAll<HTMLElement>(\n '[part=\"list\"] > [part=\"item\"] > [part=\"link\"]',\n );\n if (!items) return;\n const itemsArr = Array.from(items);\n const current = itemsArr[index];\n\n switch (e.key) {\n case 'ArrowRight':\n case 'ArrowDown': {\n e.preventDefault();\n if (item.children?.length && e.key === 'ArrowDown' && this.orientation === 'horizontal') {\n // open submenu and focus first item\n this._expandedIndex = index;\n void this.updateComplete.then(() => {\n const firstSub = this.shadowRoot?.querySelector<HTMLElement>(\n `.nav__submenu [part=\"link\"]`,\n );\n firstSub?.focus();\n });\n } else {\n const next = itemsArr[index + 1] ?? itemsArr[0];\n next?.focus();\n }\n break;\n }\n case 'ArrowLeft':\n case 'ArrowUp': {\n e.preventDefault();\n const prev = itemsArr[index - 1] ?? itemsArr[itemsArr.length - 1];\n prev?.focus();\n break;\n }\n case 'Escape': {\n this._expandedIndex = null;\n current?.focus();\n break;\n }\n case 'Enter':\n case ' ': {\n if (item.children?.length) {\n e.preventDefault();\n const wasExpanded = this._expandedIndex === index;\n this._expandedIndex = wasExpanded ? null : index;\n if (!wasExpanded) {\n void this.updateComplete.then(() => {\n const firstSub = this.shadowRoot?.querySelector<HTMLElement>(\n `.nav__submenu:not([hidden]) [part=\"link\"]`,\n );\n firstSub?.focus();\n });\n }\n }\n break;\n }\n }\n }\n\n /** @internal */\n private _handleSubKeydown(e: KeyboardEvent, parentIndex: number): void {\n const subItems = this.shadowRoot?.querySelectorAll<HTMLElement>(\n `.nav__submenu:not([hidden]) [part=\"link\"]`,\n );\n if (!subItems) return;\n const arr = Array.from(subItems);\n const focused = (e.currentTarget ?? e.target) as HTMLElement;\n const currentIdx = arr.indexOf(focused);\n\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault();\n const next = arr[currentIdx + 1] ?? arr[0];\n next?.focus();\n break;\n }\n case 'ArrowUp': {\n e.preventDefault();\n const prev = arr[currentIdx - 1] ?? arr[arr.length - 1];\n prev?.focus();\n break;\n }\n case 'Escape': {\n e.preventDefault();\n this._expandedIndex = null;\n const parentLinks = this.shadowRoot?.querySelectorAll<HTMLElement>(\n '[part=\"list\"] > [part=\"item\"] > [part=\"link\"]',\n );\n parentLinks?.[parentIndex]?.focus();\n break;\n }\n }\n }\n\n /** @internal */\n private _handleOutsideClick(e: MouseEvent): void {\n const path = e.composedPath();\n if (!path.includes(this)) {\n this._expandedIndex = null;\n }\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n if (typeof document !== 'undefined') {\n document.addEventListener('click', this._boundOutsideClick);\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n document.removeEventListener('click', this._boundOutsideClick);\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderHamburgerIcon() {\n return html`<svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n aria-hidden=\"true\"\n >\n ${this._mobileOpen\n ? svg`<line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>`\n : svg`<line x1=\"3\" y1=\"12\" x2=\"21\" y2=\"12\"></line>\n <line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"></line>\n <line x1=\"3\" y1=\"18\" x2=\"21\" y2=\"18\"></line>`}\n </svg>`;\n }\n\n /** @internal */\n private _renderChevronIcon() {\n return html`<svg\n class=\"nav__chevron\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M4.5 6L8 9.5 11.5 6\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n fill=\"none\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderSubMenu(children: NavItem[], parentIndex: number, parentLabel: string) {\n const isExpanded = this._expandedIndex === parentIndex;\n return html`\n <ul\n class=\"nav__submenu\"\n role=\"list\"\n aria-label=\"${parentLabel} submenu\"\n ?hidden=${!isExpanded}\n >\n ${children.map(\n (child) => html`\n <li class=\"nav__submenu-item\">\n <a\n part=\"link\"\n href=${this._sanitizeHref(child.href)}\n class=${classMap({\n nav__link: true,\n 'nav__link--active': !!child.current,\n })}\n aria-current=${child.current ? 'page' : nothing}\n @click=${(e: Event) => this._handleSubItemClick(child, e)}\n @keydown=${(e: KeyboardEvent) => this._handleSubKeydown(e, parentIndex)}\n >\n ${child.label}\n </a>\n </li>\n `,\n )}\n </ul>\n `;\n }\n\n /** @internal */\n private _renderItem(item: NavItem, index: number) {\n const hasChildren = !!item.children?.length;\n const isExpanded = this._expandedIndex === index;\n\n const linkClasses = {\n nav__link: true,\n 'nav__link--active': !!item.current,\n 'nav__link--has-submenu': hasChildren,\n 'nav__link--expanded': isExpanded,\n };\n\n const content = hasChildren\n ? html`\n <button\n part=\"link\"\n class=${classMap(linkClasses)}\n aria-expanded=${isExpanded ? 'true' : 'false'}\n @click=${(e: Event) => this._handleItemClick(item, index, e)}\n @keydown=${(e: KeyboardEvent) => this._handleKeydown(e, index, item)}\n >\n ${item.label} ${this._renderChevronIcon()}\n </button>\n ${this._renderSubMenu(item.children ?? [], index, item.label)}\n `\n : html`\n <a\n part=\"link\"\n href=${this._sanitizeHref(item.href)}\n class=${classMap(linkClasses)}\n aria-current=${item.current ? 'page' : nothing}\n @click=${(e: Event) => this._handleItemClick(item, index, e)}\n @keydown=${(e: KeyboardEvent) => this._handleKeydown(e, index, item)}\n >\n ${item.label}\n </a>\n `;\n\n return html` <li part=\"item\" class=\"nav__item\">${content}</li> `;\n }\n\n // ─── Render ───\n\n override render() {\n const listClasses = {\n nav__list: true,\n 'nav__list--open': this._mobileOpen,\n };\n\n return html`\n <nav part=\"nav\" aria-label=${this.label}>\n <button\n part=\"toggle\"\n class=\"nav__toggle\"\n aria-expanded=${this._mobileOpen ? 'true' : 'false'}\n aria-controls=\"nav-list\"\n aria-label=${this._mobileOpen ? this.labelCloseMenu : this.labelOpenMenu}\n @click=${this._handleToggle}\n >\n ${this._renderHamburgerIcon()}\n </button>\n\n <ul part=\"list\" id=\"nav-list\" class=${classMap(listClasses)} role=\"list\">\n ${repeat(\n this.items,\n (_item, i) => i,\n (item, i) => this._renderItem(item, i),\n )}\n </ul>\n </nav>\n `;\n }\n}\n\n/** Canonical type alias for the hx-nav component. */\nexport type HxNav = HelixNav;\n\n/** @deprecated Use {@link HxNav} instead. The `Wc` prefix was a legacy naming convention. */\nexport type WcNav = HelixNav;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-nav': HelixNav;\n }\n}\n"],"names":["helixNavStyles","css","HelixNav","LitElement","href","url","item","index","e","_a","items","itemsArr","current","_b","firstSub","next","prev","_c","wasExpanded","parentIndex","subItems","arr","focused","currentIdx","parentLinks","html","svg","children","parentLabel","isExpanded","child","classMap","nothing","hasChildren","linkClasses","content","listClasses","repeat","_item","i","tokenStyles","__decorateClass","property","value","parsed","state","customElement"],"mappings":";;;;;AAEO,MAAMA,IAAiBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-nav-item-CuGiJPAf.js","sources":["../../src/components/hx-side-nav/hx-side-nav.styles.ts","../../src/components/hx-side-nav/hx-side-nav.ts","../../src/components/hx-side-nav/hx-nav-item.styles.ts","../../src/components/hx-side-nav/hx-nav-item.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixSideNavStyles = css`\n :host {\n display: block;\n height: 100%;\n /* Mirror the nav background and text on the host so slotted light-DOM\n content (header, footer slots) inherits the correct dark surface color.\n Without this, axe-core cannot resolve the background for slotted nodes\n and evaluates their text against the page white background, producing\n false-positive color-contrast violations (WCAG 2.1 AA). */\n background-color: var(--hx-side-nav-bg, var(--hx-color-neutral-900, #0f172a));\n color: var(--hx-side-nav-color, var(--hx-color-neutral-100, #f1f5f9));\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Nav Container ─── */\n\n .side-nav {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: var(--hx-side-nav-width, 16rem);\n background-color: var(--hx-side-nav-bg, var(--hx-color-neutral-900, #0f172a));\n color: var(--hx-side-nav-color, var(--hx-color-neutral-100, #f1f5f9));\n transition: width var(--hx-transition-normal, 300ms) ease;\n overflow: hidden;\n border-inline-end: var(--hx-border-width-thin, 1px) solid\n var(--hx-side-nav-border-color, var(--hx-color-neutral-700, #334155));\n }\n\n /* ─── Collapsed State ─── */\n\n :host([collapsed]) .side-nav {\n width: var(--hx-side-nav-collapsed-width, 3.5rem);\n }\n\n /* ─── Header ─── */\n\n .side-nav__header {\n display: flex;\n align-items: center;\n padding: var(--hx-side-nav-header-padding, var(--hx-space-4, 1rem));\n flex-shrink: 0;\n min-height: var(--hx-space-14, 3.5rem);\n border-bottom: var(--hx-border-width-thin, 1px) solid\n var(--hx-side-nav-border-color, var(--hx-color-neutral-700, #334155));\n overflow: hidden;\n }\n\n :host([collapsed]) .side-nav__header {\n justify-content: center;\n padding: var(--hx-space-3, 0.75rem);\n }\n\n /* ─── Body ─── */\n\n .side-nav__body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--hx-space-2, 0.5rem) 0;\n }\n\n /* ─── Footer ─── */\n\n .side-nav__footer {\n display: flex;\n align-items: center;\n padding: var(--hx-side-nav-footer-padding, var(--hx-space-4, 1rem));\n flex-shrink: 0;\n min-height: var(--hx-space-14, 3.5rem);\n border-top: var(--hx-border-width-thin, 1px) solid\n var(--hx-side-nav-border-color, var(--hx-color-neutral-700, #334155));\n overflow: hidden;\n }\n\n :host([collapsed]) .side-nav__footer {\n justify-content: center;\n padding: var(--hx-space-3, 0.75rem);\n }\n\n /* ─── Toggle Button ─── */\n\n .side-nav__toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--hx-space-8, 2rem);\n height: var(--hx-space-8, 2rem);\n margin-inline-start: auto;\n flex-shrink: 0;\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n background: transparent;\n color: var(--hx-side-nav-toggle-color, var(--hx-color-neutral-400, #94a3b8));\n cursor: pointer;\n transition:\n background-color var(--hx-transition-fast, 150ms) ease,\n color var(--hx-transition-fast, 150ms) ease;\n }\n\n .side-nav__toggle:hover {\n background-color: var(\n --hx-overlay-white-10,\n rgba(255, 255, 255, 0.1)\n ); /* fallback for browsers without color-mix() */\n color: var(--hx-color-neutral-100, #f1f5f9);\n }\n\n @supports (color: color-mix(in srgb, red 50%, blue)) {\n .side-nav__toggle:hover {\n background-color: color-mix(in srgb, currentColor 15%, transparent);\n }\n }\n\n .side-nav__toggle:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #60a5fa));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .side-nav__toggle svg {\n width: var(--hx-space-5, 1.25rem);\n height: var(--hx-space-5, 1.25rem);\n fill: currentColor;\n flex-shrink: 0;\n transition: transform var(--hx-transition-normal, 300ms) ease;\n }\n\n :host([collapsed]) .side-nav__toggle svg {\n transform: rotate(180deg);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .side-nav {\n transition: none;\n }\n\n .side-nav__toggle {\n transition: none;\n }\n\n .side-nav__toggle svg {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, type PropertyValues } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixSideNavStyles } from './hx-side-nav.styles.js';\n\n/**\n * A collapsible left-side navigation panel with nested menu item support.\n * Designed for clinical portals, admin dashboards, and department navigation.\n *\n * @summary Collapsible side navigation panel for enterprise healthcare applications.\n *\n * @tag hx-side-nav\n *\n * @slot - Default slot for hx-nav-item children.\n * @slot header - Logo or branding content.\n * @slot footer - User profile or settings content.\n *\n * @fires {CustomEvent<{ collapsed: boolean }>} hx-collapse - Dispatched when the nav collapses to icon-only mode.\n * @fires {CustomEvent<{ collapsed: boolean }>} hx-expand - Dispatched when the nav expands to full width.\n *\n * @csspart nav - The outer nav element.\n * @csspart header - The header section.\n * @csspart body - The scrollable body section.\n * @csspart footer - The footer section.\n * @csspart toggle - The collapse/expand toggle button.\n *\n * @cssprop [--hx-side-nav-width=16rem] - Full expanded width.\n * @cssprop [--hx-side-nav-collapsed-width=3.5rem] - Collapsed icon-only width.\n * @cssprop [--hx-side-nav-bg=var(--hx-color-neutral-900)] - Background color.\n * @cssprop [--hx-side-nav-color=var(--hx-color-neutral-100)] - Text color.\n * @cssprop [--hx-side-nav-border-color=var(--hx-color-neutral-700)] - Border color.\n * @cssprop [--hx-side-nav-header-padding=var(--hx-space-4)] - Header padding.\n * @cssprop [--hx-side-nav-footer-padding=var(--hx-space-4)] - Footer padding.\n * @cssprop [--hx-side-nav-toggle-color=var(--hx-color-neutral-400)] - Toggle button icon color.\n */\n@customElement('hx-side-nav')\nexport class HelixSideNav extends LitElement {\n static override styles = [tokenStyles, helixSideNavStyles];\n\n // ─── Properties ───\n\n /**\n * When true, the nav collapses to show icons only.\n * @attr collapsed\n */\n @property({ type: Boolean, reflect: true })\n collapsed = false;\n\n /**\n * The accessible label for the nav landmark.\n * @attr label\n */\n @property({ type: String })\n label = 'Main Navigation';\n\n // ─── Lifecycle ───\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('collapsed')) {\n this._propagateCollapsedToChildren();\n }\n }\n\n // ─── Collapsed State Propagation ───\n\n /**\n * Propagates the collapsed state to all slotted hx-nav-item children by\n * setting or removing the `data-collapsed` attribute. This allows child\n * items to respond to collapsed mode via their CSS selectors.\n */\n /** @internal */\n private _propagateCollapsedToChildren(): void {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!slot) return;\n\n const navItems = slot\n .assignedElements({ flatten: true })\n .filter((el) => el.tagName.toLowerCase() === 'hx-nav-item');\n\n for (const item of navItems) {\n if (!(item instanceof HTMLElement)) continue;\n if (this.collapsed) {\n item.setAttribute('data-collapsed', '');\n } else {\n item.removeAttribute('data-collapsed');\n }\n }\n }\n\n /**\n * Handles the default slot's slotchange event so that if items are added\n * after initial render, they immediately receive the correct collapsed state.\n */\n /** @internal */\n private _onDefaultSlotChange(): void {\n this._propagateCollapsedToChildren();\n }\n\n // ─── Keyboard Navigation ───\n\n /**\n * Implements roving tabindex-style ArrowUp/ArrowDown keyboard navigation\n * among direct hx-nav-item children in the body slot. Disabled items are\n * skipped. Focus is applied to the interactive element inside the shadow DOM\n * of each item (anchor or button with part=\"link\").\n */\n /** @internal */\n private _handleKeydown(e: KeyboardEvent): void {\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Home' && e.key !== 'End') return;\n\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!slot) return;\n\n const navItems = slot\n .assignedElements({ flatten: true })\n .filter(\n (el): el is HTMLElement =>\n el.tagName.toLowerCase() === 'hx-nav-item' && !el.hasAttribute('disabled'),\n );\n\n if (navItems.length === 0) return;\n\n // Find which item currently contains focus\n const activeEl = document.activeElement;\n let currentIndex = -1;\n for (let i = 0; i < navItems.length; i++) {\n const item = navItems[i];\n if (!item) continue;\n if (\n item === activeEl ||\n item.contains(activeEl) ||\n item.shadowRoot?.contains(activeEl) === true\n ) {\n currentIndex = i;\n break;\n }\n }\n\n e.preventDefault();\n\n let nextIndex: number;\n if (e.key === 'ArrowDown') {\n nextIndex = currentIndex < navItems.length - 1 ? currentIndex + 1 : 0;\n } else if (e.key === 'ArrowUp') {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : navItems.length - 1;\n } else if (e.key === 'Home') {\n nextIndex = 0;\n } else {\n nextIndex = navItems.length - 1;\n }\n\n const targetItem = navItems[nextIndex];\n if (!targetItem) return;\n // WCAG 2.1.1: call the public focus() method on the nav item rather than\n // piercing its Shadow DOM directly. hx-nav-item.focus() delegates to the\n // internal [part=\"link\"] element, preserving shadow encapsulation.\n targetItem.focus();\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleToggle(): void {\n this.collapsed = !this.collapsed;\n\n if (this.collapsed) {\n /**\n * Dispatched when the nav collapses to icon-only mode.\n * @event hx-collapse\n */\n this.dispatchEvent(\n new CustomEvent<{ collapsed: boolean }>('hx-collapse', {\n bubbles: true,\n composed: true,\n detail: { collapsed: true },\n }),\n );\n } else {\n /**\n * Dispatched when the nav expands to full width.\n * @event hx-expand\n */\n this.dispatchEvent(\n new CustomEvent<{ collapsed: boolean }>('hx-expand', {\n bubbles: true,\n composed: true,\n detail: { collapsed: false },\n }),\n );\n }\n }\n\n // ─── Render ───\n\n /** @internal */\n private _renderToggleIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z\"\n />\n </svg>`;\n }\n\n override render() {\n return html`\n <nav part=\"nav\" class=\"side-nav\" aria-label=${this.label}>\n <div part=\"header\" class=\"side-nav__header\">\n <slot name=\"header\"></slot>\n <button\n part=\"toggle\"\n class=\"side-nav__toggle\"\n aria-label=${this.collapsed ? 'Expand navigation' : 'Collapse navigation'}\n aria-expanded=${!this.collapsed}\n @click=${this._handleToggle}\n >\n ${this._renderToggleIcon()}\n </button>\n </div>\n\n <div part=\"body\" class=\"side-nav__body\" id=\"side-nav-body\" @keydown=${this._handleKeydown}>\n <slot @slotchange=${this._onDefaultSlotChange}></slot>\n </div>\n\n <div part=\"footer\" class=\"side-nav__footer\">\n <slot name=\"footer\"></slot>\n </div>\n </nav>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-side-nav': HelixSideNav;\n }\n}\n\nexport type { HelixSideNav as HxSideNav };\n","import { css } from 'lit';\n\nexport const helixNavItemStyles = css`\n :host {\n display: block;\n /* The host background must be a concrete color so that axe-core can\n resolve text contrast ratios for shadow-DOM content correctly.\n WCAG 2.1 AA: neutral-300 (#cbd5e1) on neutral-900 (#0f172a) = 12.02:1. */\n background-color: var(--hx-nav-item-host-bg, var(--hx-color-neutral-900, #0f172a));\n color: var(--hx-nav-item-color, var(--hx-color-neutral-300, #cbd5e1));\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Nav Item ─── */\n\n .nav-item {\n display: flex;\n flex-direction: column;\n }\n\n /* ─── Link / Button ─── */\n\n .nav-item__link {\n display: flex;\n align-items: center;\n gap: var(--hx-space-3, 0.75rem);\n padding: var(--hx-nav-item-padding, var(--hx-space-2, 0.5rem) var(--hx-space-4, 1rem));\n min-height: var(--hx-space-10, 2.5rem);\n text-decoration: none;\n color: var(--hx-nav-item-color, var(--hx-color-neutral-300, #cbd5e1));\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n margin: 0 var(--hx-space-2, 0.5rem);\n transition:\n background-color var(--hx-transition-fast, 150ms) ease,\n color var(--hx-transition-fast, 150ms) ease;\n white-space: nowrap;\n overflow: hidden;\n cursor: pointer;\n font-family: var(--hx-font-family-sans, sans-serif);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n line-height: var(--hx-line-height-normal, 1.5);\n position: relative;\n border: none;\n background: transparent;\n width: calc(100% - var(--hx-space-4, 1rem));\n text-align: start;\n }\n\n /* Link variant */\n a.nav-item__link {\n display: flex;\n }\n\n .nav-item__link:hover {\n background-color: var(\n --hx-nav-item-hover-bg,\n var(--hx-overlay-white-8, rgba(255, 255, 255, 0.08))\n ); /* fallback for browsers without color-mix() */\n color: var(--hx-nav-item-hover-color, var(--hx-color-neutral-100, #f1f5f9));\n }\n\n @supports (color: color-mix(in srgb, red 50%, blue)) {\n .nav-item__link:hover {\n background-color: var(\n --hx-nav-item-hover-bg,\n color-mix(in srgb, currentColor 10%, transparent)\n );\n }\n }\n\n .nav-item__link:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #60a5fa));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Active State ─── */\n\n :host([active]) .nav-item__link {\n /* neutral-50 (#f8fafc) on primary-600 (#1d4ed8) = 6.41:1 — WCAG AA ✓ */\n background-color: var(--hx-nav-item-active-bg, var(--hx-color-primary-600, #1d4ed8));\n color: var(--hx-nav-item-active-color, var(--hx-color-neutral-50, #f8fafc));\n }\n\n :host([active]) .nav-item__link:hover {\n /* neutral-50 (#f8fafc) on primary-700 (#1e40af) = 8.34:1 — WCAG AA ✓ */\n background-color: var(--hx-nav-item-active-hover-bg, var(--hx-color-primary-700, #1e40af));\n }\n\n /* ─── Disabled State ─── */\n\n :host([disabled]) .nav-item__link {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n cursor: not-allowed;\n }\n\n /* ─── Icon ─── */\n\n .nav-item__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--hx-space-5, 1.25rem);\n height: var(--hx-space-5, 1.25rem);\n }\n\n /* ─── Label ─── */\n\n .nav-item__label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n transition: opacity var(--hx-transition-fast, 150ms) ease;\n }\n\n /* ─── Badge ─── */\n\n .nav-item__badge {\n margin-inline-start: auto;\n flex-shrink: 0;\n }\n\n /* ─── Expand Arrow ─── */\n\n .nav-item__arrow {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-inline-start: auto;\n width: var(--hx-space-5, 1.25rem);\n height: var(--hx-space-5, 1.25rem);\n transition: transform var(--hx-transition-normal, 300ms) ease;\n }\n\n .nav-item__arrow svg {\n width: var(--hx-space-4, 1rem);\n height: var(--hx-space-4, 1rem);\n fill: currentColor;\n }\n\n :host([expanded]) .nav-item__arrow {\n transform: rotate(90deg);\n }\n\n /* ─── Children (sub-nav) ─── */\n\n .nav-item__children {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows var(--hx-transition-normal, 300ms ease);\n overflow: hidden;\n }\n\n :host([expanded]) .nav-item__children {\n grid-template-rows: 1fr;\n }\n\n .nav-item__children-inner {\n overflow: hidden;\n min-height: 0;\n display: flex;\n flex-direction: column;\n padding-inline-start: var(--hx-space-6, 1.5rem);\n }\n\n /* ─── Tooltip (collapsed mode) ─── */\n\n .nav-item__tooltip {\n position: absolute;\n left: calc(100% + var(--hx-space-2, 0.5rem));\n top: 50%;\n transform: translateY(-50%);\n /* neutral-100 (#f1f5f9) on neutral-800 (#1e293b) = 13.35:1 — WCAG AA ✓ */\n background-color: var(--hx-color-neutral-800, #1e293b);\n color: var(--hx-color-neutral-100, #f1f5f9);\n padding: var(--hx-space-1, 0.25rem) var(--hx-space-2, 0.5rem);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n font-size: var(--hx-font-size-xs, 0.75rem);\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--hx-transition-fast, 150ms) ease;\n z-index: var(--hx-z-index-tooltip, 1600);\n box-shadow: var(--hx-shadow-md, 0 2px 8px rgb(0 0 0 / 0.2));\n }\n\n :host([data-collapsed]) .nav-item__link:hover .nav-item__tooltip,\n :host([data-collapsed]) .nav-item__link:focus-visible .nav-item__tooltip {\n opacity: 1;\n }\n\n /* ─── Collapsed host state (propagated from parent) ─── */\n\n :host([data-collapsed]) .nav-item__label {\n width: 0;\n overflow: hidden;\n opacity: 0;\n }\n\n :host([data-collapsed]) .nav-item__badge {\n display: none;\n }\n\n :host([data-collapsed]) .nav-item__arrow {\n display: none;\n }\n\n :host([data-collapsed]) .nav-item__children {\n display: none !important;\n }\n\n :host([data-collapsed]) .nav-item__link {\n justify-content: center;\n margin: 0 var(--hx-space-1, 0.25rem);\n width: calc(100% - var(--hx-space-2, 0.5rem));\n padding: var(--hx-space-2, 0.5rem);\n position: relative;\n overflow: visible;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .nav-item__link,\n .nav-item__label,\n .nav-item__arrow,\n .nav-item__children,\n .nav-item__tooltip {\n transition: none;\n }\n\n :host([expanded]) .nav-item__children {\n grid-template-rows: 1fr;\n }\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixNavItemStyles } from './hx-nav-item.styles.js';\n\n/**\n * A navigation item for use inside hx-side-nav.\n * Supports icons, badges, sub-navigation, and active/disabled states.\n *\n * @summary Navigation item for hx-side-nav with support for icons, badges, and nested children.\n *\n * @tag hx-nav-item\n *\n * @slot - Default slot for item label text.\n * @slot icon - Icon to display before the label.\n * @slot badge - Badge content (e.g., notification count).\n * @slot children - Nested hx-nav-item children for sub-navigation.\n *\n * @csspart link - The anchor or button element.\n * @csspart icon - The icon container.\n * @csspart label - The label container.\n * @csspart badge - The badge container.\n * @csspart children - The children container.\n *\n * @cssprop [--hx-nav-item-color=var(--hx-color-neutral-300)] - Item text color.\n * @cssprop [--hx-nav-item-hover-bg] - Item hover background.\n * @cssprop [--hx-nav-item-hover-color=var(--hx-color-neutral-100)] - Item hover text color.\n * @cssprop [--hx-nav-item-active-bg=var(--hx-color-primary-600)] - Active item background.\n * @cssprop [--hx-nav-item-active-color=var(--hx-color-neutral-50)] - Active item text color.\n * @cssprop [--hx-nav-item-padding] - Item padding.\n * @cssprop [--hx-nav-item-host-bg=var(--hx-color-neutral-900)] - Component host background color.\n */\n@customElement('hx-nav-item')\nexport class HelixNavItem extends LitElement {\n static override styles = [tokenStyles, helixNavItemStyles];\n\n // ─── Properties ───\n\n /**\n * The URL this nav item links to.\n * @attr href\n */\n @property({ type: String })\n href = '';\n\n /**\n * Whether this item is the current/active page.\n * @attr active\n */\n @property({ type: Boolean, reflect: true })\n active = false;\n\n /**\n * Whether the sub-navigation is expanded.\n * @attr expanded\n */\n @property({ type: Boolean, reflect: true })\n expanded = false;\n\n /**\n * Whether this nav item is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n // ─── State ───\n\n /** Whether the children slot has assigned nodes. Updated via slotchange. */\n /** @internal */\n @state() private _hasChildren = false;\n\n /** Whether this item is in collapsed mode. Set externally by hx-side-nav via data-collapsed attribute. */\n /** @internal */\n @state() private _isCollapsed = false;\n\n // ─── Attribute Observer ───\n\n static override get observedAttributes(): string[] {\n return [...super.observedAttributes, 'data-collapsed'];\n }\n\n override attributeChangedCallback(name: string, old: string | null, value: string | null): void {\n super.attributeChangedCallback(name, old, value);\n if (name === 'data-collapsed') {\n this._isCollapsed = value !== null;\n }\n }\n\n // ─── Public API ───\n\n /**\n * Delegates focus to the internal link or button element (part=\"link\").\n * Allows parent components to focus nav items without piercing the Shadow DOM.\n * WCAG 2.1.1: keyboard navigation must not cross shadow boundaries via\n * direct shadowRoot queries.\n */\n override focus(options?: FocusOptions): void {\n const inner = this.shadowRoot?.querySelector<HTMLElement>('[part=\"link\"]');\n if (inner) {\n inner.focus(options);\n } else {\n super.focus(options);\n }\n }\n\n // ─── Slot Change Handler ───\n\n /** @internal */\n private _onChildrenSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasChildren = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _getDirectText(): string {\n return Array.from(this.childNodes)\n .filter((n) => n.nodeType === Node.TEXT_NODE)\n .map((n) => n.textContent?.trim() ?? '')\n .filter(Boolean)\n .join(' ');\n }\n\n /** @internal */\n private _handleToggle(e: Event): void {\n if (this.disabled) return;\n e.preventDefault();\n this.expanded = !this.expanded;\n }\n\n /** @internal */\n private _renderExpandArrow() {\n return html`<span class=\"nav-item__arrow\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 20 20\">\n <path\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n />\n </svg>\n </span>`;\n }\n\n // ─── Render ───\n\n override render() {\n const label = this._getDirectText();\n\n const innerContent = html`\n <span part=\"icon\" class=\"nav-item__icon\">\n <slot name=\"icon\"></slot>\n </span>\n <span part=\"label\" class=\"nav-item__label\">\n <slot></slot>\n </span>\n <span part=\"badge\" class=\"nav-item__badge\">\n <slot name=\"badge\"></slot>\n </span>\n ${this._hasChildren ? this._renderExpandArrow() : nothing}\n ${this._isCollapsed\n ? html`<span id=\"nav-item-tooltip\" class=\"nav-item__tooltip\" role=\"tooltip\">${label}</span>`\n : nothing}\n `;\n\n // Render as anchor when href provided and no expandable children\n const linkEl =\n this.href && !this._hasChildren\n ? html`<a\n part=\"link\"\n class=\"nav-item__link\"\n href=${this.href}\n aria-current=${this.active ? 'page' : nothing}\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-describedby=${this._isCollapsed ? 'nav-item-tooltip' : nothing}\n tabindex=${this.disabled ? '-1' : '0'}\n >\n ${innerContent}\n </a>`\n : html`<button\n part=\"link\"\n class=\"nav-item__link\"\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-expanded=${this._hasChildren ? String(this.expanded) : nothing}\n aria-describedby=${this._isCollapsed ? 'nav-item-tooltip' : nothing}\n tabindex=${this.disabled ? '-1' : '0'}\n @click=${this._handleToggle}\n >\n ${innerContent}\n </button>`;\n\n return html`\n <div class=\"nav-item\">\n ${linkEl}\n <div part=\"children\" class=\"nav-item__children\" role=\"group\">\n <div class=\"nav-item__children-inner\">\n <slot name=\"children\" @slotchange=${this._onChildrenSlotChange}></slot>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-nav-item': HelixNavItem;\n }\n}\n\nexport type { HelixNavItem as HxNavItem };\n"],"names":["helixSideNavStyles","css","HelixSideNav","LitElement","changedProperties","slot","_a","navItems","el","item","activeEl","currentIndex","i","_b","nextIndex","targetItem","html","tokenStyles","__decorateClass","property","customElement","helixNavItemStyles","HelixNavItem","name","old","value","options","inner","n","label","innerContent","nothing","linkEl","state"],"mappings":";;;AAEO,MAAMA,IAAqBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACkC3B,IAAMC,IAAN,cAA2BC,EAAW;AAAA,EAAtC,cAAA;AAAA,UAAA,GAAA,SAAA,GAUL,KAAA,YAAY,IAOZ,KAAA,QAAQ;AAAA,EAAA;AAAA;AAAA,EAIC,QAAQC,GAA+C;AAC9D,UAAM,QAAQA,CAAiB,GAC3BA,EAAkB,IAAI,WAAW,KACnC,KAAK,8BAAA;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,gCAAsC;;AAC5C,UAAMC,KAAOC,IAAA,KAAK,eAAL,gBAAAA,EAAiB,cAA+B;AAC7D,QAAI,CAACD,EAAM;AAEX,UAAME,IAAWF,EACd,iBAAiB,EAAE,SAAS,GAAA,CAAM,EAClC,OAAO,CAACG,MAAOA,EAAG,QAAQ,YAAA,MAAkB,aAAa;AAE5D,eAAWC,KAAQF;AACjB,MAAME,aAAgB,gBAClB,KAAK,YACPA,EAAK,aAAa,kBAAkB,EAAE,IAEtCA,EAAK,gBAAgB,gBAAgB;AAAA,EAG3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,uBAA6B;AACnC,SAAK,8BAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,eAAe,GAAwB;;AAC7C,QAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,aAAa,EAAE,QAAQ,UAAU,EAAE,QAAQ,MAAO;AAEzF,UAAMJ,KAAOC,IAAA,KAAK,eAAL,gBAAAA,EAAiB,cAA+B;AAC7D,QAAI,CAACD,EAAM;AAEX,UAAME,IAAWF,EACd,iBAAiB,EAAE,SAAS,GAAA,CAAM,EAClC;AAAA,MACC,CAACG,MACCA,EAAG,QAAQ,YAAA,MAAkB,iBAAiB,CAACA,EAAG,aAAa,UAAU;AAAA,IAAA;AAG/E,QAAID,EAAS,WAAW,EAAG;AAG3B,UAAMG,IAAW,SAAS;AAC1B,QAAIC,IAAe;AACnB,aAASC,IAAI,GAAGA,IAAIL,EAAS,QAAQK,KAAK;AACxC,YAAMH,IAAOF,EAASK,CAAC;AACvB,UAAKH,MAEHA,MAASC,KACTD,EAAK,SAASC,CAAQ,OACtBG,IAAAJ,EAAK,eAAL,gBAAAI,EAAiB,SAASH,QAAc,KACxC;AACA,QAAAC,IAAeC;AACf;AAAA,MACF;AAAA,IACF;AAEA,MAAE,eAAA;AAEF,QAAIE;AACJ,IAAI,EAAE,QAAQ,cACZA,IAAYH,IAAeJ,EAAS,SAAS,IAAII,IAAe,IAAI,IAC3D,EAAE,QAAQ,YACnBG,IAAYH,IAAe,IAAIA,IAAe,IAAIJ,EAAS,SAAS,IAC3D,EAAE,QAAQ,SACnBO,IAAY,IAEZA,IAAYP,EAAS,SAAS;AAGhC,UAAMQ,IAAaR,EAASO,CAAS;AACrC,IAAKC,KAILA,EAAW,MAAA;AAAA,EACb;AAAA;AAAA;AAAA,EAKQ,gBAAsB;AAC5B,SAAK,YAAY,CAAC,KAAK,WAEnB,KAAK,YAKP,KAAK;AAAA,MACH,IAAI,YAAoC,eAAe;AAAA,QACrD,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,WAAW,GAAA;AAAA,MAAK,CAC3B;AAAA,IAAA,IAOH,KAAK;AAAA,MACH,IAAI,YAAoC,aAAa;AAAA,QACnD,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,WAAW,GAAA;AAAA,MAAM,CAC5B;AAAA,IAAA;AAAA,EAGP;AAAA;AAAA;AAAA,EAKQ,oBAAoB;AAC1B,WAAOC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKT;AAAA,EAES,SAAS;AAChB,WAAOA;AAAA,oDACyC,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAMrC,KAAK,YAAY,sBAAsB,qBAAqB;AAAA,4BACzD,CAAC,KAAK,SAAS;AAAA,qBACtB,KAAK,aAAa;AAAA;AAAA,cAEzB,KAAK,mBAAmB;AAAA;AAAA;AAAA;AAAA,8EAIwC,KAAK,cAAc;AAAA,8BACnE,KAAK,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrD;AACF;AAlMad,EACK,SAAS,CAACe,GAAajB,CAAkB;AASzDkB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAT/BjB,EAUX,WAAA,aAAA,CAAA;AAOAgB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAhBfjB,EAiBX,WAAA,SAAA,CAAA;AAjBWA,IAANgB,EAAA;AAAA,EADNE,EAAc,aAAa;AAAA,GACflB,CAAA;AClCN,MAAMmB,IAAqBpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;AC+B3B,IAAMqB,IAAN,cAA2BnB,EAAW;AAAA,EAAtC,cAAA;AAAA,UAAA,GAAA,SAAA,GAUL,KAAA,OAAO,IAOP,KAAA,SAAS,IAOT,KAAA,WAAW,IAOX,KAAA,WAAW,IAMF,KAAQ,eAAe,IAIvB,KAAQ,eAAe;AAAA,EAAA;AAAA;AAAA,EAIhC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,GAAG,MAAM,oBAAoB,gBAAgB;AAAA,EACvD;AAAA,EAES,yBAAyBoB,GAAcC,GAAoBC,GAA4B;AAC9F,UAAM,yBAAyBF,GAAMC,GAAKC,CAAK,GAC3CF,MAAS,qBACX,KAAK,eAAeE,MAAU;AAAA,EAElC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUS,MAAMC,GAA8B;;AAC3C,UAAMC,KAAQrB,IAAA,KAAK,eAAL,gBAAAA,EAAiB,cAA2B;AAC1D,IAAIqB,IACFA,EAAM,MAAMD,CAAO,IAEnB,MAAM,MAAMA,CAAO;AAAA,EAEvB;AAAA;AAAA;AAAA,EAKQ,sBAAsB,GAAgB;AAC5C,UAAMrB,IAAO,EAAE;AACf,SAAK,eAAeA,EAAK,cAAc,EAAE,SAAS,GAAA,CAAM,EAAE,SAAS;AAAA,EACrE;AAAA;AAAA;AAAA,EAKQ,iBAAyB;AAC/B,WAAO,MAAM,KAAK,KAAK,UAAU,EAC9B,OAAO,CAACuB,MAAMA,EAAE,aAAa,KAAK,SAAS,EAC3C,IAAI,CAACA,MAAA;;AAAM,eAAAtB,IAAAsB,EAAE,gBAAF,gBAAAtB,EAAe,WAAU;AAAA,KAAE,EACtC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,EACb;AAAA;AAAA,EAGQ,cAAc,GAAgB;AACpC,IAAI,KAAK,aACT,EAAE,eAAA,GACF,KAAK,WAAW,CAAC,KAAK;AAAA,EACxB;AAAA;AAAA,EAGQ,qBAAqB;AAC3B,WAAOU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT;AAAA;AAAA,EAIS,SAAS;AAChB,UAAMa,IAAQ,KAAK,eAAA,GAEbC,IAAed;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAUjB,KAAK,eAAe,KAAK,mBAAA,IAAuBe,CAAO;AAAA,QACvD,KAAK,eACHf,yEAA4Ea,CAAK,YACjFE,CAAO;AAAA,OAIPC,IACJ,KAAK,QAAQ,CAAC,KAAK,eACfhB;AAAA;AAAA;AAAA,mBAGS,KAAK,IAAI;AAAA,2BACD,KAAK,SAAS,SAASe,CAAO;AAAA,4BAC7B,KAAK,WAAW,SAASA,CAAO;AAAA,+BAC7B,KAAK,eAAe,qBAAqBA,CAAO;AAAA,uBACxD,KAAK,WAAW,OAAO,GAAG;AAAA;AAAA,cAEnCD,CAAY;AAAA,kBAEhBd;AAAA;AAAA;AAAA,4BAGkB,KAAK,WAAW,SAASe,CAAO;AAAA,4BAChC,KAAK,eAAe,OAAO,KAAK,QAAQ,IAAIA,CAAO;AAAA,+BAChD,KAAK,eAAe,qBAAqBA,CAAO;AAAA,uBACxD,KAAK,WAAW,OAAO,GAAG;AAAA,qBAC5B,KAAK,aAAa;AAAA;AAAA,cAEzBD,CAAY;AAAA;AAGtB,WAAOd;AAAA;AAAA,UAEDgB,CAAM;AAAA;AAAA;AAAA,gDAGgC,KAAK,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKxE;AACF;AAxKaV,EACK,SAAS,CAACL,GAAaI,CAAkB;AASzDH,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GATfG,EAUX,WAAA,QAAA,CAAA;AAOAJ,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAhB/BG,EAiBX,WAAA,UAAA,CAAA;AAOAJ,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAvB/BG,EAwBX,WAAA,YAAA,CAAA;AAOAJ,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GA9B/BG,EA+BX,WAAA,YAAA,CAAA;AAMiBJ,EAAA;AAAA,EAAhBe,EAAA;AAAM,GArCIX,EAqCM,WAAA,gBAAA,CAAA;AAIAJ,EAAA;AAAA,EAAhBe,EAAA;AAAM,GAzCIX,EAyCM,WAAA,gBAAA,CAAA;AAzCNA,IAANJ,EAAA;AAAA,EADNE,EAAc,aAAa;AAAA,GACfE,CAAA;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-patient-banner-BoJHddAL.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 }\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 }\n\n /* ─── Photo Area ─── */\n\n .banner__photo-area {\n flex-shrink: 0;\n width: var(--_photo-size);\n height: var(--_photo-size);\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(--hx-color-neutral-200, #e5e7eb);\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 position: relative;\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","import { LitElement, html, 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 *\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 */\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 @state() private _identifierCount: number = 0;\n\n // ─── Slot Queries ───\n\n @query('slot[name=\"name\"]') private _nameSlot!: HTMLSlotElement;\n @query('slot[name=\"mrn\"]') private _mrnSlot!: HTMLSlotElement;\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.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.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 return html`\n <div part=\"banner\" class=\"banner\">\n <div part=\"photo-area\" class=\"banner__photo-area\">\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 }\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","html","tokenStyles","__decorateClass","property","value","state","query","customElement"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-phi-field-EDWna59z.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 /* ─── 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 auto-clear.\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 */\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 // ─── Internal State ───\n\n @state() private _masked = true;\n\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 private _cancelClipboardTimer(): void {\n if (this._clipboardTimer !== null) {\n clearTimeout(this._clipboardTimer);\n this._clipboardTimer = null;\n }\n }\n\n private _scheduleClipboardClear(): void {\n this._cancelClipboardTimer();\n this._clipboardTimer = setTimeout(() => {\n this._clearClipboard();\n }, this.clipboardTimeout);\n }\n\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: 'hide',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n this._masked = true;\n }\n\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 private _handleToggle(): void {\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 private _handleCopy(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n private _handlePaste(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n // ─── Render Helpers ───\n\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 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 return html`\n <div part=\"container\" class=\"phi-field\" @copy=${this._handleCopy} @paste=${this._handlePaste}>\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\n ? 'Protected health information is masked'\n : 'Protected health information is revealed'}\n </span>\n <button\n part=\"toggle\"\n class=\"phi-field__toggle\"\n type=\"button\"\n aria-label=${this._masked\n ? 'Reveal protected health information'\n : 'Hide protected health information'}\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 action: 'reveal' | 'hide';\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","tokenStyles","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-select-4-nHL0vd.js","sources":["../../src/components/hx-select/hx-select.styles.ts","../../src/components/hx-select/hx-select.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixSelectStyles = css`\n :host {\n display: block;\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(--hx-select-font-family, var(--hx-font-family-sans, sans-serif));\n position: relative;\n }\n\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-select-label-color, var(--hx-color-neutral-700, #343a40));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__required-marker {\n color: var(--hx-select-error-color, var(--hx-color-error-text, #b91c1c));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n .field__select-wrapper {\n position: relative;\n display: block;\n }\n\n .field__trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--hx-space-2, 0.5rem);\n width: 100%;\n min-height: var(--hx-input-height-md, var(--hx-size-10, 2.5rem));\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-select-border-color, var(--hx-color-neutral-300, #ced4da));\n border-radius: var(--hx-select-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-select-bg, var(--hx-color-neutral-0, #ffffff));\n color: var(--hx-select-color, var(--hx-color-neutral-800, #212529));\n font-family: inherit;\n font-size: var(--hx-font-size-md, 1rem);\n line-height: var(--hx-line-height-normal, 1.5);\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n cursor: pointer;\n text-align: start;\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n outline: none;\n }\n\n .field__trigger:focus,\n .field__trigger:focus-visible {\n border-color: var(\n --hx-select-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #60a5fa))\n );\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(\n --hx-select-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #60a5fa))\n )\n calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n .field__trigger[aria-disabled='true'] {\n cursor: not-allowed;\n }\n\n .field__trigger--sm {\n min-height: var(--hx-input-height-sm, var(--hx-size-8, 2rem));\n font-size: var(--hx-font-size-sm, 0.875rem);\n padding: var(--hx-space-1, 0.25rem) var(--hx-space-3, 0.75rem);\n }\n\n .field__trigger--lg {\n min-height: var(--hx-input-height-lg, var(--hx-size-12, 3rem));\n font-size: var(--hx-font-size-lg, 1.125rem);\n padding: var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem);\n }\n\n .field__trigger-value {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .field__trigger--placeholder .field__trigger-value {\n color: var(--hx-select-placeholder-color, var(--hx-color-neutral-400, #adb5bd));\n }\n\n .field__chevron {\n flex-shrink: 0;\n width: 12px;\n height: 8px;\n position: relative;\n color: var(--hx-select-chevron-color, var(--hx-color-neutral-500, #6c757d));\n pointer-events: none;\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n .field__chevron::after {\n content: '';\n position: absolute;\n top: 0;\n left: 2px;\n width: 7px;\n height: 7px;\n border-inline-end: 1.5px solid currentColor;\n border-bottom: 1.5px solid currentColor;\n transform: rotate(45deg);\n }\n\n .field--open .field__chevron {\n transform: rotate(180deg);\n }\n\n .field--error .field__trigger {\n border-color: var(--hx-select-error-color, var(--hx-color-error-500, #dc3545));\n }\n\n .field--error .field__trigger:focus,\n .field--error .field__trigger:focus-visible {\n border-color: var(--hx-select-error-color, var(--hx-color-error-500, #dc3545));\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(--hx-select-error-color, var(--hx-color-error-500, #dc3545))\n calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n .field__listbox {\n position: absolute;\n top: calc(100% + var(--hx-space-1, 0.25rem));\n left: 0;\n right: 0;\n z-index: var(--hx-z-index-dropdown, 1000);\n background-color: var(--hx-select-listbox-bg, var(--hx-color-neutral-0, #ffffff));\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-select-border-color, var(--hx-color-neutral-300, #ced4da));\n border-radius: var(--hx-select-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-select-listbox-shadow,\n 0 4px 16px var(--hx-overlay-neutral-12, rgba(13, 17, 23, 0.12))\n );\n max-height: var(--hx-select-listbox-max-height, 16rem);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .field__listbox[hidden] {\n display: none;\n }\n\n .field__options {\n overflow-y: auto;\n flex: 1;\n padding: var(--hx-space-1, 0.25rem) 0;\n }\n\n .field__option {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n font-size: var(--hx-font-size-md, 1rem);\n color: var(--hx-select-color, var(--hx-color-neutral-800, #212529));\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n transition: background-color var(--hx-transition-fast, 150ms ease);\n }\n\n .field__option:hover {\n background-color: var(--hx-select-option-hover-bg, var(--hx-color-primary-50, #eff6ff));\n }\n\n .field__option--selected {\n background-color: var(--hx-select-option-selected-bg, var(--hx-color-primary-100, #dbeafe));\n font-weight: var(--hx-font-weight-medium, 500);\n }\n\n .field__option--focused {\n background-color: var(--hx-select-option-hover-bg, var(--hx-color-primary-50, #eff6ff));\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-select-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-select-option-focus-ring-offset, -2px);\n }\n\n .field__option--focused.field__option--selected {\n background-color: var(--hx-select-option-selected-bg, var(--hx-color-primary-100, #dbeafe));\n }\n\n .field__option--disabled {\n opacity: var(--hx-opacity-disabled, 0.5);\n cursor: not-allowed;\n pointer-events: none;\n }\n\n .field__option-label {\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .field__no-options {\n padding: var(--hx-space-3, 0.75rem);\n text-align: center;\n color: var(--hx-color-neutral-400, #adb5bd);\n font-size: var(--hx-font-size-sm, 0.875rem);\n }\n\n .field__select {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n opacity: 0;\n pointer-events: none;\n clip: rect(0, 0, 0, 0);\n }\n\n .field__help-text,\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__help-text {\n color: var(--hx-color-neutral-500, #6c757d);\n }\n\n .field__error {\n color: var(--hx-select-error-color, var(--hx-color-error-text, #b91c1c));\n }\n\n @media (prefers-reduced-motion: reduce) {\n .field__trigger,\n .field__chevron,\n .field__option {\n transition: none;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { helixSelectStyles } from './hx-select.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// Module-level counter for stable, SSR-safe IDs (avoids Math.random() hydration mismatch)\nconst _nextSelectId = createIdCounter('hx-select');\n\n// ─── Internal option model ───\n\ninterface SelectOption {\n value: string;\n label: string;\n disabled: boolean;\n}\n\n/**\n * A form-associated select component with custom styling, label, error, and\n * help text. Options are provided via slotted `<option>` (and `<optgroup>`)\n * elements in the light DOM. The component wraps a hidden native `<select>`\n * for form participation and provides a combobox trigger for consistent\n * cross-browser styling.\n *\n * @remarks Multi-select is intentionally not supported. This component\n * implements a single-value select (combobox) pattern only. For multi-value\n * selection use a separate multi-select component.\n *\n * @remarks The listbox panel uses `position: absolute` and may be clipped by\n * ancestor elements with `overflow: hidden` or `overflow: auto`. This is a\n * known limitation when embedding the component inside cards, tables, or\n * dialogs. Use the CSS custom property `--hx-select-listbox-shadow` or\n * restructure the containing layout to avoid clipping.\n *\n * @summary Form-associated custom select with label, error, and help text.\n *\n * @tag hx-select\n *\n * @slot - Default slot for `<option>` and `<optgroup>` elements.\n * @slot label - Custom label content (overrides the label property).\n * @slot error - Custom error content (overrides the error property).\n * @slot help-text - Custom help text content (overrides the helpText property).\n *\n * @fires {CustomEvent<{value: string}>} hx-change - Dispatched when the selected option changes.\n *\n * @csspart field - The outer field container.\n * @csspart label - The label element.\n * @csspart select-wrapper - The wrapper containing the trigger and listbox.\n * @csspart select - The hidden native select element (kept for form participation).\n * @csspart trigger - The button that opens/closes the dropdown.\n * @csspart listbox - The dropdown panel containing options.\n * @csspart option - Individual option items in the listbox.\n * @csspart help-text - The help text container.\n * @csspart error - The error message container.\n *\n * @cssprop [--hx-select-bg=var(--hx-color-neutral-0)] - Select background color.\n * @cssprop [--hx-select-color=var(--hx-color-neutral-800)] - Select text color.\n * @cssprop [--hx-select-border-color=var(--hx-color-neutral-300)] - Select border color.\n * @cssprop [--hx-select-border-radius=var(--hx-border-radius-md)] - Select border radius.\n * @cssprop [--hx-select-font-family=var(--hx-font-family-sans)] - Select font family.\n * @cssprop [--hx-select-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-select-error-color=var(--hx-color-error-500)] - Error state color.\n * @cssprop [--hx-select-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-select-chevron-color=var(--hx-color-neutral-500)] - Chevron indicator color.\n * @cssprop [--hx-select-listbox-bg=var(--hx-color-neutral-0)] - Listbox panel background color.\n * @cssprop [--hx-select-option-hover-bg=var(--hx-color-primary-50)] - Option hover background color.\n * @cssprop [--hx-select-option-selected-bg=var(--hx-color-primary-100)] - Selected option background color.\n * @cssprop [--hx-select-placeholder-color=var(--hx-color-neutral-400)] - Placeholder text color.\n */\n@customElement('hx-select')\nexport class HelixSelect extends HelixElement {\n static override styles = [tokenStyles, helixSelectStyles];\n\n // ─── Form Association ───\n\n /** Marks this element as form-associated for ElementInternals support. @internal */\n static override formAssociated = true;\n\n // ─── Stable IDs ───\n\n /** @internal */\n private _selectId = _nextSelectId();\n /** @internal */\n private _listboxId = `${this._selectId}-listbox`;\n /** @internal */\n private _labelId = `${this._selectId}-label`;\n /** @internal */\n private _helpTextId = `${this._selectId}-help`;\n /** @internal */\n private _errorId = `${this._selectId}-error`;\n\n // ─── Public Properties ───\n\n /**\n * The visible label text for the select.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Placeholder text shown in the trigger when no option is selected.\n * @attr placeholder\n */\n @property({ type: String })\n placeholder = '';\n\n /**\n * The current value of the select.\n * @attr value\n */\n @property({ type: String, reflect: true })\n value = '';\n\n /**\n * Whether the select is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the select is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * The name used for form submission.\n * @attr name\n */\n @property({ type: String })\n name = '';\n\n /**\n * Error message to display. When set, the field enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the select for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * Size variant of the select trigger.\n * @attr hx-size\n */\n @property({ type: String, attribute: 'hx-size', reflect: true })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Accessible name for screen readers, if different from the visible label.\n * @attr aria-label\n */\n @property({ type: String, attribute: 'aria-label' })\n override ariaLabel: string | null = null;\n\n /**\n * Controls whether the dropdown listbox is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Validation message when no option is selected. Override for i18n.\n * @attr label-required\n */\n @property({ attribute: 'label-required' }) labelRequired = 'Please select an option.';\n\n /**\n * Label shown when no options are available. Override for i18n.\n * @attr label-no-options\n */\n @property({ attribute: 'label-no-options' }) labelNoOptions = 'No options found';\n\n // ─── Internal State ───\n\n /** Parsed option models derived from slotted `<option>` and `<optgroup>` elements. @internal */\n @state() private _options: SelectOption[] = [];\n /** Whether the named error slot contains projected content. @internal */\n @state() private _hasErrorSlot = false;\n /** Zero-based index of the keyboard-focused option in the listbox; -1 means none. @internal */\n @state() private _focusedOptionIndex = -1;\n\n // ─── Queries ───\n\n /** Reference to the hidden native select element used for form participation. @internal */\n @query('.field__select')\n private _select: HTMLSelectElement | undefined;\n\n /** Reference to the visible combobox trigger element that receives keyboard focus. @internal */\n @query('.field__trigger')\n private _trigger: HTMLElement | undefined;\n\n // ─── Computed helpers ───\n\n /** @internal */\n private get _displayValue(): string {\n if (!this.value) return '';\n const opt = this._options.find((o) => o.value === this.value);\n return opt ? opt.label : this.value;\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n // Safety net: remove listener if component is removed while dropdown is open\n document.removeEventListener('click', this._handleOutsideClick);\n // Reset open state to prevent persisted open state on reconnect\n if (this.open) {\n this.open = false;\n this._focusedOptionIndex = -1;\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n if (changedProperties.has('open')) {\n if (this.open) {\n document.addEventListener('click', this._handleOutsideClick);\n } else {\n document.removeEventListener('click', this._handleOutsideClick);\n }\n }\n if (changedProperties.has('value')) {\n this._syncNativeSelect();\n this._updateFormValue();\n this._updateValidity();\n }\n if (changedProperties.has('size')) {\n const validSizes: string[] = ['sm', 'md', 'lg'];\n if (!validSizes.includes(this.size)) {\n devWarn(\n 'hx-select',\n `Invalid size \"${this.size}\". Expected one of: ${validSizes.join(', ')}.`,\n );\n }\n }\n }\n\n // ─── Form Integration ───\n\n /** Returns the associated form element, if any. */\n get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n\n /** Returns the validation message. */\n get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Returns the ValidityState object. */\n get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** Checks whether the select satisfies its constraints. */\n checkValidity(): boolean {\n return this._internals.checkValidity();\n }\n\n /** Reports validity and shows the browser's constraint validation UI. */\n reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n /** @internal */\n private _updateFormValue(): void {\n this._internals.setFormValue(this.value || null);\n }\n\n /** @internal */\n private _updateValidity(): void {\n if (this.required && !this.value) {\n this._internals.setValidity(\n { valueMissing: true },\n this.error || this.labelRequired,\n this._trigger ?? this._select,\n );\n } else {\n this._internals.setValidity({});\n }\n }\n\n // ─── Form Lifecycle Hooks ───\n\n protected override _onFormReset(): void {\n this.value = '';\n this._internals.setFormValue(null);\n }\n\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.value = state;\n }\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Native Select Sync ───\n\n /** @internal */\n private _syncNativeSelect(): void {\n if (!this._select) return;\n if (this.value) {\n this._select.value = this.value;\n }\n }\n\n // ─── Option Syncing from Slot ───\n\n /** @internal */\n private _parseOption(el: HTMLOptionElement): SelectOption {\n return { value: el.value, label: el.textContent?.trim() ?? el.value, disabled: el.disabled };\n }\n\n /**\n * Single-pass slot handler: reads options into _options for the custom\n * listbox AND clones them into the native <select> for form participation.\n * Handles both top-level <option> and <optgroup> children.\n */\n /** @internal */\n private _handleSlotChange(): void {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (!slot) return;\n\n const parsed: SelectOption[] = [];\n\n // Remove previously cloned options from native select\n if (this._select) {\n this._select.querySelectorAll('option[data-cloned]').forEach((opt) => opt.remove());\n }\n\n const cloneIntoSelect = (optEl: HTMLOptionElement): void => {\n if (!this._select) return;\n const clone = optEl.cloneNode(true) as HTMLOptionElement;\n clone.setAttribute('data-cloned', '');\n this._select.appendChild(clone);\n };\n\n for (const el of slot.assignedElements({ flatten: true })) {\n if (el instanceof HTMLOptionElement) {\n parsed.push(this._parseOption(el));\n cloneIntoSelect(el);\n } else if (el instanceof HTMLOptGroupElement) {\n for (const child of Array.from(el.children)) {\n if (child instanceof HTMLOptionElement) {\n parsed.push(this._parseOption(child));\n cloneIntoSelect(child);\n }\n }\n }\n }\n\n this._options = parsed;\n\n if (parsed.length === 0) {\n devWarn(\n 'hx-select',\n 'hx-select has no options — add <option> or <optgroup> elements as children.',\n );\n }\n\n if (this._select) {\n if (this.value) {\n this._select.value = this.value;\n } else if (!this.placeholder && parsed.length > 0) {\n this.value = this._select.value;\n this._updateFormValue();\n }\n }\n }\n\n // ─── Slot Change Handlers ───\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Dropdown Control ───\n\n /** @internal */\n private _toggleDropdown(): void {\n if (!this.disabled) {\n this.open = !this.open;\n if (this.open) {\n // Pre-focus the currently selected option (or first enabled) when opening\n const selectedIndex = this._options.findIndex((o) => o.value === this.value);\n this._focusedOptionIndex = selectedIndex >= 0 ? selectedIndex : 0;\n } else {\n this._focusedOptionIndex = -1;\n }\n }\n }\n\n // ─── Keyboard Navigation ───\n\n /** @internal */\n private _handleKeydown(e: KeyboardEvent): void {\n if (this.disabled) return;\n\n const enabledIndices = this._options\n .map((o, i) => ({ o, i }))\n .filter(({ o }) => !o.disabled)\n .map(({ i }) => i);\n\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault();\n if (!this.open) {\n this.open = true;\n this._focusedOptionIndex = enabledIndices.length > 0 ? (enabledIndices[0] ?? 0) : 0;\n break;\n }\n const nextDown = enabledIndices.find((i) => i > this._focusedOptionIndex);\n this._focusedOptionIndex =\n nextDown !== undefined ? nextDown : (enabledIndices[0] ?? this._focusedOptionIndex);\n break;\n }\n case 'ArrowUp': {\n e.preventDefault();\n if (!this.open) {\n this.open = true;\n const lastEnabled = enabledIndices[enabledIndices.length - 1];\n this._focusedOptionIndex = lastEnabled !== undefined ? lastEnabled : 0;\n break;\n }\n const prevUp = [...enabledIndices].reverse().find((i) => i < this._focusedOptionIndex);\n const lastEnabledUp = enabledIndices[enabledIndices.length - 1];\n this._focusedOptionIndex =\n prevUp !== undefined ? prevUp : (lastEnabledUp ?? this._focusedOptionIndex);\n break;\n }\n case 'Home': {\n e.preventDefault();\n if (!this.open) {\n this.open = true;\n }\n this._focusedOptionIndex = enabledIndices.length > 0 ? (enabledIndices[0] ?? 0) : 0;\n break;\n }\n case 'End': {\n e.preventDefault();\n if (!this.open) {\n this.open = true;\n }\n const lastEnabled = enabledIndices[enabledIndices.length - 1];\n this._focusedOptionIndex = lastEnabled !== undefined ? lastEnabled : 0;\n break;\n }\n case 'Enter':\n case ' ': {\n e.preventDefault();\n if (!this.open) {\n this.open = true;\n const selIdx = this._options.findIndex((o) => o.value === this.value);\n this._focusedOptionIndex = selIdx >= 0 ? selIdx : (enabledIndices[0] ?? 0);\n break;\n }\n if (this._focusedOptionIndex >= 0 && this._focusedOptionIndex < this._options.length) {\n const opt = this._options[this._focusedOptionIndex];\n if (opt) this._selectOption(opt);\n }\n break;\n }\n case 'Escape': {\n e.preventDefault();\n this.open = false;\n this._focusedOptionIndex = -1;\n this._trigger?.focus();\n break;\n }\n case 'Tab': {\n // Close the dropdown but allow Tab to move focus naturally\n if (this.open) {\n this.open = false;\n this._focusedOptionIndex = -1;\n }\n break;\n }\n default: {\n // Typeahead: single printable character jumps to first matching option\n if (!e.ctrlKey && !e.metaKey && !e.altKey && e.key.length === 1) {\n const char = e.key.toLowerCase();\n const startIndex = this.open ? this._focusedOptionIndex + 1 : 0;\n const matching = this._options\n .map((o, i) => ({ o, i }))\n .filter(({ o }) => !o.disabled && o.label.toLowerCase().startsWith(char));\n const afterCurrent = matching.find(({ i }) => i >= startIndex);\n const target = afterCurrent ?? matching[0];\n if (target) {\n if (!this.open) {\n this.open = true;\n }\n this._focusedOptionIndex = target.i;\n e.preventDefault();\n }\n }\n break;\n }\n }\n }\n\n // ─── Selection ───\n\n /** @internal */\n private _selectOption(option: SelectOption): void {\n if (option.disabled) return;\n this.value = option.value; // triggers updated() → sync + formValue + validity\n this._dispatchChange();\n this.open = false;\n this._focusedOptionIndex = -1;\n }\n\n // ─── Event Dispatchers ───\n\n /** @internal */\n private _dispatchChange(): void {\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n /** @internal */\n private _handleNativeChange(e: Event): void {\n this.value = (e.target as HTMLSelectElement).value; // triggers updated()\n this._dispatchChange();\n }\n\n // ─── Outside Click Handler ───\n\n /** @internal */\n private _handleOutsideClick = (e: MouseEvent): void => {\n if (this.open && !e.composedPath().includes(this)) {\n this.open = false;\n }\n };\n\n // ─── Public Methods ───\n\n /** Moves focus to the visible trigger button. */\n override focus(options?: FocusOptions): void {\n this._trigger?.focus(options);\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _optionId(index: number): string {\n return `hx-select-option-${this._selectId}-${index}`;\n }\n\n /** @internal */\n private _renderOptions() {\n if (this._options.length === 0) {\n return html`<div class=\"field__no-options\">${this.labelNoOptions}</div>`;\n }\n\n return repeat(\n this._options,\n (opt) => opt.value,\n (opt, index) => {\n const isSelected = opt.value === this.value;\n const isFocused = index === this._focusedOptionIndex;\n\n return html`\n <div\n id=${this._optionId(index)}\n part=\"option\"\n role=\"option\"\n class=${classMap({\n field__option: true,\n 'field__option--selected': isSelected,\n 'field__option--focused': isFocused,\n 'field__option--disabled': opt.disabled,\n })}\n aria-selected=${isSelected ? 'true' : nothing}\n aria-disabled=${opt.disabled ? 'true' : nothing}\n @click=${() => this._selectOption(opt)}\n >\n <span class=\"field__option-label\">${opt.label}</span>\n </div>\n `;\n },\n );\n }\n\n // ─── Main Render ───\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n 'field--open': this.open,\n };\n\n const triggerClasses = {\n field__trigger: true,\n [`field__trigger--${this.size}`]: true,\n 'field__trigger--placeholder': !this.value,\n };\n\n const selectClasses = {\n field__select: true,\n [`field__select--${this.size}`]: true,\n };\n\n const describedBy =\n [\n hasError || this._hasErrorSlot ? this._errorId : null,\n this.helpText ? this._helpTextId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <!-- Label -->\n <slot name=\"label\">\n ${this.label\n ? html`<label\n part=\"label\"\n class=\"field__label\"\n id=${this._labelId}\n for=${this._selectId}\n >\n ${this.label}\n ${this.required\n ? html`<span class=\"field__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>`\n : nothing}\n </slot>\n\n <!-- Select Wrapper: trigger + listbox -->\n <div part=\"select-wrapper\" class=\"field__select-wrapper\">\n <!-- Custom Trigger (combobox — div to avoid native role conflicts per APG) -->\n <div\n part=\"trigger\"\n id=${this._selectId}\n class=${classMap(triggerClasses)}\n role=\"combobox\"\n tabindex=${this.disabled ? '-1' : '0'}\n aria-expanded=${this.open ? 'true' : 'false'}\n aria-haspopup=\"listbox\"\n aria-controls=${this._listboxId}\n aria-activedescendant=${this.open && this._focusedOptionIndex >= 0\n ? this._optionId(this._focusedOptionIndex)\n : nothing}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(describedBy)}\n aria-required=${this.required ? 'true' : nothing}\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-labelledby=${ifDefined(this.label ? this._labelId : undefined)}\n aria-label=${ifDefined(this.ariaLabel ?? undefined)}\n @click=${this._toggleDropdown}\n @keydown=${this._handleKeydown}\n >\n <span class=\"field__trigger-value\"\n >${this._displayValue || this.placeholder || nothing}</span\n >\n <span class=\"field__chevron\" aria-hidden=\"true\"></span>\n </div>\n\n <!-- Custom Listbox Panel -->\n <div\n part=\"listbox\"\n role=\"listbox\"\n id=${this._listboxId}\n class=\"field__listbox\"\n aria-label=${ifDefined(this.label || this.ariaLabel || undefined)}\n ?hidden=${!this.open}\n >\n <div class=\"field__options\">${this._renderOptions()}</div>\n </div>\n\n <!-- Hidden native select (form participation + test compat) -->\n <select\n part=\"select\"\n class=${classMap(selectClasses)}\n tabindex=\"-1\"\n aria-hidden=\"true\"\n ?required=${this.required}\n ?disabled=${this.disabled}\n name=${ifDefined(this.name || undefined)}\n aria-label=${ifDefined(this.ariaLabel ?? undefined)}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(describedBy)}\n aria-required=${this.required ? 'true' : nothing}\n @change=${this._handleNativeChange}\n >\n ${this.placeholder\n ? html`<option value=\"\" disabled selected>${this.placeholder}</option>`\n : nothing}\n </select>\n </div>\n\n <!-- Hidden slot (options are read from here) -->\n <slot @slotchange=${this._handleSlotChange} style=\"display:none;\"></slot>\n\n <!-- Error -->\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>\n ${hasError\n ? html`<div part=\"error\" class=\"field__error\" id=${this._errorId} role=\"alert\">\n ${this.error}\n </div>`\n : nothing}\n </slot>\n\n <!-- Help Text -->\n ${this.helpText && !hasError\n ? html`\n <div part=\"help-text\" class=\"field__help-text\" id=${this._helpTextId}>\n <slot name=\"help-text\">${this.helpText}</slot>\n </div>\n `\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-select': HelixSelect;\n }\n}\n\nexport type { HelixSelect as HxSelect };\n/** @deprecated Use HxSelect instead */\nexport type { HelixSelect as WcSelect };\n"],"names":["helixSelectStyles","css","_nextSelectId","createIdCounter","HelixSelect","HelixElement","opt","o","changedProperties","validSizes","devWarn","state","_mode","disabled","el","_a","slot","parsed","cloneIntoSelect","optEl","clone","child","selectedIndex","enabledIndices","i","nextDown","lastEnabled","prevUp","lastEnabledUp","selIdx","char","startIndex","matching","target","option","options","index","html","repeat","isSelected","isFocused","classMap","nothing","hasError","fieldClasses","triggerClasses","selectClasses","describedBy","ifDefined","tokenStyles","__decorateClass","property","query","customElement"],"mappings":";;;;;;;;AAEO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-status-indicator-4ClvA5mU.js","sources":["../../src/components/hx-status-indicator/hx-status-indicator.styles.ts","../../src/components/hx-status-indicator/hx-status-indicator.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixStatusIndicatorStyles = css`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n flex-shrink: 0;\n --_dot-color: var(--hx-status-indicator-color-default, var(--hx-color-neutral-300, #ced4da));\n }\n\n .indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n width: var(--_indicator-size);\n height: var(--_indicator-size);\n flex-shrink: 0;\n }\n\n .indicator__dot {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n background-color: var(--_dot-color);\n position: relative;\n z-index: 1; /* dot above pulse ring within shadow root */\n }\n\n .indicator__pulse-ring {\n display: none;\n position: absolute;\n inset: 0;\n border-radius: 50%;\n background-color: var(--hx-status-indicator-pulse-color, var(--_dot-color));\n opacity: var(--hx-state-focus-opacity, 0.12); /* intentional: pulse ring start opacity */\n animation: hx-status-pulse var(--hx-status-indicator-pulse-duration, 1.5s) ease-out infinite;\n z-index: 0; /* pulse ring beneath dot within shadow root */\n }\n\n :host([pulse]) .indicator__pulse-ring {\n display: block;\n }\n\n @keyframes hx-status-pulse {\n 0% {\n transform: scale(1);\n opacity: var(--hx-state-focus-opacity, 0.12); /* intentional: pulse ring start opacity */\n }\n 100% {\n transform: scale(var(--hx-status-indicator-pulse-scale, 2.5));\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host([pulse]) .indicator__pulse-ring {\n animation: none;\n display: none;\n }\n }\n\n /* ─── Size Variants ─── */\n\n :host([size='sm']) {\n --_indicator-size: var(--hx-status-indicator-size-sm, var(--hx-space-2, 0.5rem));\n }\n\n :host([size='md']) {\n --_indicator-size: var(--hx-status-indicator-size-md, var(--hx-space-3, 0.75rem));\n }\n\n :host([size='lg']) {\n --_indicator-size: var(--hx-status-indicator-size-lg, var(--hx-size-4));\n }\n\n /* ─── Status Colors ─── */\n\n :host([status='online']) {\n --_dot-color: var(--hx-status-indicator-color-online, var(--hx-color-success-500));\n }\n\n :host([status='offline']) {\n --_dot-color: var(--hx-status-indicator-color-offline, var(--hx-color-neutral-400));\n }\n\n :host([status='away']) {\n --_dot-color: var(--hx-status-indicator-color-away, var(--hx-color-warning-500));\n }\n\n :host([status='busy']) {\n --_dot-color: var(--hx-status-indicator-color-busy, var(--hx-color-error-500));\n }\n\n :host([status='unknown']) {\n --_dot-color: var(--hx-status-indicator-color-unknown, var(--hx-color-neutral-300));\n }\n`;\n","import { LitElement, html, type PropertyValues } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { helixStatusIndicatorStyles } from './hx-status-indicator.styles.js';\n\nexport type StatusIndicatorStatus = 'online' | 'offline' | 'away' | 'busy' | 'unknown';\nexport type StatusIndicatorSize = 'sm' | 'md' | 'lg';\n\nconst STATUS_LABELS: Record<StatusIndicatorStatus, string> = {\n online: 'Online',\n offline: 'Offline',\n away: 'Away',\n busy: 'Busy',\n unknown: 'Unknown',\n};\n\n/**\n * A colored dot/badge indicating system or entity health status.\n * Purely visual — no slots. Supports an animated pulse ring.\n *\n * Uses `role=\"img\"` with an auto-generated `aria-label` (e.g. \"Status: Online\").\n * When used decoratively alongside visible text that conveys the same status information\n * (e.g. \"Provider is available\"), set `aria-hidden=\"true\"` on the host element to prevent\n * duplicate announcements to screen reader users. This is the recommended composition\n * pattern in healthcare dashboards.\n *\n * @remarks\n * The status vocabulary (`online`, `offline`, `away`, `busy`, `unknown`) is the intentional\n * implementation canonical form for this component. Although a prior spec draft used\n * `active/inactive/error/warning`, the current vocabulary was approved as a deliberate\n * design decision for flexibility and UX clarity in healthcare dashboard contexts.\n *\n * @summary Status indicator dot component.\n *\n * @tag hx-status-indicator\n *\n * @csspart base - The dot element.\n * @csspart pulse-ring - The animated pulse ring element.\n *\n * @cssprop [--hx-status-indicator-color-online] - Override color for the \"online\" status dot.\n * @cssprop [--hx-status-indicator-color-offline] - Override color for the \"offline\" status dot.\n * @cssprop [--hx-status-indicator-color-away] - Override color for the \"away\" status dot.\n * @cssprop [--hx-status-indicator-color-busy] - Override color for the \"busy\" status dot.\n * @cssprop [--hx-status-indicator-color-unknown] - Override color for the \"unknown\" status dot.\n * @cssprop [--hx-status-indicator-size-sm] - Override size for the \"sm\" variant.\n * @cssprop [--hx-status-indicator-size-md] - Override size for the \"md\" variant.\n * @cssprop [--hx-status-indicator-size-lg] - Override size for the \"lg\" variant.\n * @cssprop [--hx-status-indicator-pulse-duration] - Override pulse animation duration.\n * @cssprop [--hx-status-indicator-pulse-scale] - Override pulse animation max scale.\n * @cssprop [--hx-status-indicator-pulse-color] - Override pulse ring color independently from dot color.\n */\n@customElement('hx-status-indicator')\nexport class HelixStatusIndicator extends LitElement {\n static override styles = [tokenStyles, helixStatusIndicatorStyles];\n\n /**\n * The status to display.\n * @attr status\n */\n @property({ type: String, reflect: true })\n status: 'online' | 'offline' | 'away' | 'busy' | 'unknown' = 'unknown';\n\n /**\n * Size of the indicator dot.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Whether to show an animated pulse ring around the dot.\n * Animation is suppressed when prefers-reduced-motion is active.\n * @attr pulse\n * @remarks\n * In Twig (Drupal) templates, render as a bare attribute: `pulse` — NOT `pulse=\"true\"`.\n * The value is ignored; only attribute presence matters.\n */\n @property({ type: Boolean, reflect: true })\n pulse = false;\n\n /**\n * Accessible label for the indicator. Defaults to \"Status: {Status}\".\n * Set aria-hidden=\"true\" on the host when status is conveyed by adjacent text.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /** @internal */\n private _getLabel(): string {\n if (this.label) return this.label;\n const statusText = STATUS_LABELS[this.status] ?? 'Unknown';\n return `Status: ${statusText}`;\n }\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-status-indicator', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as StatusIndicatorSize;\n }\n // T3-01-4: Place role=\"img\" on the host element for robust AT traversal.\n // Some screen reader + browser combinations skip shadow children; host-level\n // ARIA attributes are more reliable across the flat accessibility tree.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'img');\n }\n this.setAttribute('aria-label', this._getLabel());\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n // Keep host aria-label in sync when status or label properties change.\n if (changedProperties.has('status') || changedProperties.has('label')) {\n this.setAttribute('aria-label', this._getLabel());\n }\n }\n\n override render() {\n return html`\n <div class=\"indicator\">\n <div class=\"indicator__pulse-ring\" part=\"pulse-ring\"></div>\n <div class=\"indicator__dot\" part=\"base\"></div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-status-indicator': HelixStatusIndicator;\n }\n}\n"],"names":["helixStatusIndicatorStyles","css","STATUS_LABELS","HelixStatusIndicator","LitElement","legacySize","changedProperties","html","tokenStyles","__decorateClass","property","customElement"],"mappings":";;;AAEO,MAAMA,IAA6BC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACO1C,MAAMC,IAAuD;AAAA,EAC3D,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AACX;AAsCO,IAAMC,IAAN,cAAmCC,EAAW;AAAA,EAA9C,cAAA;AAAA,UAAA,GAAA,SAAA,GAQL,KAAA,SAA6D,WAO7D,KAAA,OAA2B,MAW3B,KAAA,QAAQ,IAQR,KAAA,QAAQ;AAAA,EAAA;AAAA;AAAA,EAGA,YAAoB;AAC1B,WAAI,KAAK,QAAc,KAAK,QAErB,WADYF,EAAc,KAAK,MAAM,KAAK,SACrB;AAAA,EAC9B;AAAA;AAAA,EAIS,oBAA0B;AACjC,UAAM,kBAAA;AAGN,UAAMG,IAAa,KAAK,aAAa,MAAM;AAC3C,IAAIA,MAAe,QAAQ,CAAC,KAAK,aAAa,SAAS,MAErD,KAAK,OAAOA,IAKT,KAAK,aAAa,MAAM,KAC3B,KAAK,aAAa,QAAQ,KAAK,GAEjC,KAAK,aAAa,cAAc,KAAK,UAAA,CAAW;AAAA,EAClD;AAAA,EAES,QAAQC,GAA+C;AAC9D,UAAM,QAAQA,CAAiB,IAE3BA,EAAkB,IAAI,QAAQ,KAAKA,EAAkB,IAAI,OAAO,MAClE,KAAK,aAAa,cAAc,KAAK,UAAA,CAAW;AAAA,EAEpD;AAAA,EAES,SAAS;AAChB,WAAOC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT;AACF;AA/EaJ,EACK,SAAS,CAACK,GAAaR,CAA0B;AAOjES,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAP9BP,EAQX,WAAA,UAAA,CAAA;AAOAM,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM,WAAW,WAAW;AAAA,GAdpDP,EAeX,WAAA,QAAA,CAAA;AAWAM,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAzB/BP,EA0BX,WAAA,SAAA,CAAA;AAQAM,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAjCfP,EAkCX,WAAA,SAAA,CAAA;AAlCWA,IAANM,EAAA;AAAA,EADNE,EAAc,qBAAqB;AAAA,GACvBR,CAAA;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-step-DlANlr2A.js","sources":["../../src/components/hx-steps/hx-steps.styles.ts","../../src/components/hx-steps/hx-steps.ts","../../src/components/hx-steps/hx-step.styles.ts","../../src/components/hx-steps/hx-step.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixStepsStyles = css`\n :host {\n display: block;\n\n /* ─── Size defaults (md) ─── */\n --hx-steps-indicator-size: var(--hx-size-8, 2rem);\n --hx-steps-indicator-font-size: var(--hx-font-size-sm, 0.875rem);\n --hx-steps-indicator-icon-size: var(--hx-size-4, 1rem);\n --hx-steps-label-font-size: var(--hx-font-size-sm, 0.875rem);\n --hx-steps-description-font-size: var(--hx-font-size-xs, 0.75rem);\n\n /* ─── Item layout defaults (horizontal) ─── */\n --hx-steps-item-flex: 1;\n --hx-steps-item-width: auto;\n }\n\n .steps {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n }\n\n /* ─── Orientation: vertical ─── */\n\n :host([orientation='vertical']) {\n --hx-steps-item-flex: initial;\n --hx-steps-item-width: 100%;\n }\n\n :host([orientation='vertical']) .steps {\n flex-direction: column;\n }\n\n /* ─── Size: sm ─── */\n\n :host([size='sm']) {\n --hx-steps-indicator-size: var(--hx-size-6, 1.5rem);\n --hx-steps-indicator-font-size: var(--hx-font-size-xs, 0.75rem);\n --hx-steps-indicator-icon-size: var(--hx-space-3, 0.75rem);\n --hx-steps-label-font-size: var(--hx-font-size-xs, 0.75rem);\n --hx-steps-description-font-size: var(--hx-font-size-xs, 0.75rem);\n }\n\n /* ─── Size: lg ─── */\n\n :host([size='lg']) {\n --hx-steps-indicator-size: var(--hx-size-10, 2.5rem);\n --hx-steps-indicator-font-size: var(--hx-font-size-md, 1rem);\n --hx-steps-indicator-icon-size: var(--hx-size-5, 1.25rem);\n --hx-steps-label-font-size: var(--hx-font-size-md, 1rem);\n --hx-steps-description-font-size: var(--hx-font-size-sm, 0.875rem);\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { helixStepsStyles } from './hx-steps.styles.js';\nimport type { HelixStep } from './hx-step.js';\n\n/**\n * A multi-step wizard / stepper progress indicator. Renders a sequence of\n * `<hx-step>` children as a horizontal or vertical step tracker with connector\n * lines and status-based styling.\n *\n * Provide an `aria-label` on `<hx-steps>` to describe the step process for assistive technology.\n *\n * @summary Multi-step progress indicator container.\n *\n * @tag hx-steps\n *\n * @slot - Default slot for `<hx-step>` elements.\n *\n * @fires {CustomEvent<{step: HelixStep, index: number}>} hx-step-click - Dispatched when\n * a step is clicked. Detail contains the clicked `step` element and its zero-based `index`.\n *\n * @csspart base - The inner wrapper element.\n *\n * @cssprop [--hx-steps-indicator-size=2rem] - Step indicator circle diameter.\n * @cssprop [--hx-steps-connector-color=var(--hx-color-neutral-200)] - Connector line color.\n * @cssprop [--hx-steps-label-color=var(--hx-color-neutral-600)] - Step label text color.\n * @cssprop [--hx-steps-description-color=var(--hx-color-neutral-500)] - Step description color.\n */\n@customElement('hx-steps')\nexport class HelixSteps extends LitElement {\n static override styles = [tokenStyles, helixStepsStyles];\n\n // ─── Public Properties ───\n\n /**\n * Layout orientation of the steps.\n * @attr orientation\n */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /**\n * Size variant of the steps.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Accessible label for the list. Forwarded to the inner list element.\n * @attr aria-label\n */\n @property({ type: String, attribute: 'aria-label' })\n ariaLabel: string | null = null;\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-steps', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as 'sm' | 'md' | 'lg';\n }\n // WCAG 4.1.2: suppress the host element's implicit ARIA role so only the\n // inner div[role=\"list\"] is announced. Mirrors the hx-action-bar pattern.\n // Without this, the consumer's aria-label attribute on the host causes dual\n // announcement — once for the host element and once for the inner list.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'none');\n }\n this.addEventListener('hx-step-click-internal', this._handleStepClickInternal);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('hx-step-click-internal', this._handleStepClickInternal);\n }\n\n override firstUpdated(): void {\n this._syncChildren();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('orientation') || changedProperties.has('size')) {\n this._syncChildren();\n }\n }\n\n // ─── Child Sync ───\n\n /** @internal */\n private _getSteps(): HelixStep[] {\n return Array.from(this.querySelectorAll(':scope > hx-step')) as HelixStep[];\n }\n\n /** @internal */\n private _syncChildren(): void {\n const steps = this._getSteps();\n steps.forEach((step, i) => {\n step.orientation = this.orientation;\n step.size = this.size;\n step.index = i;\n });\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleSlotChange = (): void => {\n this._syncChildren();\n };\n\n /** @internal */\n private _handleStepClickInternal = (e: Event): void => {\n e.stopPropagation();\n const steps = this._getSteps();\n const step = e\n .composedPath()\n .find(\n (el): el is HelixStep => el instanceof Element && el.tagName.toLowerCase() === 'hx-step',\n );\n if (!step) return;\n const index = steps.indexOf(step);\n\n /**\n * Dispatched when a step is clicked.\n * @event hx-step-click\n */\n this.dispatchEvent(\n new CustomEvent<{ step: HelixStep; index: number }>('hx-step-click', {\n bubbles: true,\n composed: true,\n detail: { step, index },\n }),\n );\n };\n\n // ─── Render ───\n\n override render() {\n return html`\n <div part=\"base\" class=\"steps\" role=\"list\" aria-label=${this.ariaLabel ?? nothing}>\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-steps': HelixSteps;\n }\n}\n","import { css } from 'lit';\n\nexport const helixStepStyles = css`\n :host {\n display: flex;\n flex: var(--hx-steps-item-flex, 1);\n width: var(--hx-steps-item-width, auto);\n min-width: 0;\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: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n\n /* ─── Step Wrapper ─── */\n\n .step {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n cursor: pointer;\n }\n\n /* ─── Focus ─── */\n\n :host(:focus-visible) .step__indicator {\n outline: var(--hx-focus-ring-width, 2px) solid var(--hx-color-primary-500);\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Track (indicator + connector) ─── */\n\n .step__track {\n display: flex;\n flex-direction: row;\n align-items: center;\n width: 100%;\n }\n\n /* ─── Indicator ─── */\n\n .step__indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--hx-steps-indicator-size, 2rem);\n height: var(--hx-steps-indicator-size, 2rem);\n border-radius: var(--hx-border-radius-full, 9999px);\n border: var(--hx-border-width-medium, 2px) solid var(--hx-color-neutral-300);\n background-color: var(--hx-color-neutral-0);\n color: var(--hx-color-neutral-500);\n font-size: var(--hx-steps-indicator-font-size, var(--hx-font-size-sm));\n font-weight: var(--hx-font-weight-semibold);\n font-family: var(--hx-font-family-sans);\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n border-color var(--hx-transition-fast, 150ms ease),\n color var(--hx-transition-fast, 150ms ease);\n position: relative;\n z-index: 1;\n }\n\n .step__indicator svg {\n width: var(--hx-steps-indicator-icon-size, 1rem);\n height: var(--hx-steps-indicator-icon-size, 1rem);\n }\n\n /* ─── Connector ─── */\n\n .step__connector {\n flex: 1;\n height: var(--hx-steps-connector-thickness, var(--hx-border-width, 2px));\n min-width: 0;\n background-color: var(--hx-steps-connector-color, var(--hx-color-neutral-200));\n transition: background-color var(--hx-transition-fast, 150ms ease);\n }\n\n :host(:last-child) .step__connector {\n display: none;\n }\n\n /* ─── Label Area ─── */\n\n .step__label-area {\n text-align: center;\n margin-top: var(--hx-space-2, 0.5rem);\n width: 100%;\n padding: 0 var(--hx-space-1, 0.25rem);\n }\n\n .step__label {\n font-family: var(--hx-font-family-sans);\n font-size: var(--hx-steps-label-font-size, var(--hx-font-size-sm));\n font-weight: var(--hx-font-weight-medium);\n color: var(--hx-steps-label-color, var(--hx-color-neutral-600));\n line-height: var(--hx-line-height-tight, 1.25);\n }\n\n .step__description {\n font-family: var(--hx-font-family-sans);\n font-size: var(--hx-steps-description-font-size, var(--hx-font-size-xs));\n color: var(--hx-steps-description-color, var(--hx-color-neutral-500));\n margin-top: var(--hx-space-1, 0.25rem);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Status: active ─── */\n\n /* Active: outlined indicator (in-progress) — visually distinct from complete (filled) */\n :host([status='active']) .step__indicator {\n border-color: var(--hx-color-primary-500);\n background-color: var(--hx-color-primary-500);\n color: var(--hx-color-neutral-0);\n }\n\n :host([status='active']) .step__label {\n color: var(--hx-color-primary-700);\n font-weight: var(--hx-font-weight-semibold);\n }\n\n /* ─── Status: complete ─── */\n\n /* Complete: filled indicator with darker shade — visually distinct from active */\n :host([status='complete']) .step__indicator {\n border-color: var(--hx-color-primary-700);\n background-color: var(--hx-color-primary-700);\n color: var(--hx-color-neutral-0);\n }\n\n :host([status='complete']) .step__connector {\n background-color: var(--hx-steps-connector-complete-color, var(--hx-color-primary-500));\n }\n\n :host([status='complete']) .step__label {\n color: var(--hx-color-neutral-700);\n }\n\n /* ─── Status: error ─── */\n\n :host([status='error']) .step__indicator {\n border-color: var(--hx-color-error-500);\n background-color: var(--hx-color-error-500);\n color: var(--hx-color-neutral-0);\n }\n\n :host([status='error']) .step__label {\n color: var(--hx-color-error-700);\n }\n\n /* ─── Status: disabled ─── */\n\n :host([disabled]) .step {\n cursor: not-allowed;\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n :host([disabled]) .step__indicator {\n border-color: var(--hx-color-neutral-300);\n background-color: var(--hx-color-neutral-100);\n color: var(--hx-color-neutral-400);\n }\n\n /* ─── Vertical Layout ─── */\n\n :host([orientation='vertical']) {\n flex: initial;\n width: 100%;\n }\n\n :host([orientation='vertical']) .step {\n flex-direction: row;\n align-items: flex-start;\n gap: var(--hx-space-3, 0.75rem);\n }\n\n :host([orientation='vertical']) .step__track {\n flex-direction: column;\n align-items: center;\n width: auto;\n flex-shrink: 0;\n }\n\n :host([orientation='vertical']) .step__connector {\n width: var(--hx-steps-connector-thickness, var(--hx-border-width, 2px));\n height: auto;\n min-height: var(--hx-space-8, 2rem);\n flex: 1;\n }\n\n :host([orientation='vertical']) .step__label-area {\n text-align: start;\n margin-top: 0;\n padding-bottom: var(--hx-space-4, 1rem);\n padding-inline-start: 0;\n }\n\n :host([orientation='vertical']:last-child) .step__label-area {\n padding-bottom: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .step__indicator {\n transition: none;\n }\n\n .step__connector {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, type PropertyValues } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixStepStyles } from './hx-step.styles.js';\n\n/**\n * An individual step, designed to be used inside an `<hx-steps>` container.\n * Represents a single step in a multi-step wizard or progress indicator.\n *\n * @summary Individual step item within an `<hx-steps>` progress indicator.\n *\n * @tag hx-step\n *\n * @slot icon - Custom icon for the step indicator. Shown when status is `pending` or `active`.\n * @slot label - Step label text. Falls back to the `label` property.\n * @slot description - Step description text. Falls back to the `description` property.\n *\n * @csspart base - The outermost wrapper element.\n * @csspart indicator - The circular step indicator.\n * @csspart connector - The line connecting this step to the next.\n * @csspart label - The step label element.\n * @csspart description - The step description element.\n *\n * @cssprop [--hx-steps-indicator-size=2rem] - Indicator circle diameter.\n * @cssprop [--hx-steps-indicator-font-size=var(--hx-font-size-sm)] - Indicator text size.\n * @cssprop [--hx-steps-indicator-icon-size=1rem] - Indicator icon size.\n * @cssprop [--hx-steps-label-font-size=var(--hx-font-size-sm)] - Label font size.\n * @cssprop [--hx-steps-description-font-size=var(--hx-font-size-xs)] - Description font size.\n * @cssprop [--hx-steps-connector-color=var(--hx-color-neutral-200)] - Connector line color.\n * @cssprop [--hx-steps-connector-complete-color=var(--hx-color-primary-500)] - Connector color when step is complete.\n * @cssprop [--hx-steps-connector-thickness=var(--hx-border-width,2px)] - Connector line thickness.\n * @cssprop [--hx-steps-label-color=var(--hx-color-neutral-600)] - Label text color.\n * @cssprop [--hx-steps-description-color=var(--hx-color-neutral-500)] - Description text color.\n */\n@customElement('hx-step')\nexport class HelixStep extends LitElement {\n static override styles = [tokenStyles, helixStepStyles];\n\n // ─── Public Properties ───\n\n /**\n * The step label text.\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = '';\n\n /**\n * Current status of the step.\n * @attr status\n */\n @property({ type: String, reflect: true })\n status: 'pending' | 'active' | 'complete' | 'error' = 'pending';\n\n /**\n * Optional description text shown below the label.\n * @attr description\n */\n @property({ type: String, reflect: true })\n description = '';\n\n /**\n * Whether the step is disabled and non-interactive.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n // ─── Internal Properties (set by parent hx-steps) ───\n\n /**\n * Layout orientation. Set by the parent `<hx-steps>` container via JS property.\n * Do not set this attribute directly on `<hx-step>` — use the `orientation`\n * property on the parent `<hx-steps>` container instead. The parent will\n * propagate the value to all child steps via `_syncChildren()`.\n * @internal\n */\n @property({ attribute: false })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /**\n * Size variant. Set by the parent `<hx-steps>` container via JS property.\n * Do not set this attribute directly on `<hx-step>` — use the `size` property\n * on the parent `<hx-steps>` container instead. The parent will propagate the\n * value to all child steps via `_syncChildren()`.\n * @internal\n */\n @property({ attribute: false })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Zero-based index of this step. Set by the parent `<hx-steps>` container.\n * @internal\n */\n @property({ type: Number })\n index = 0;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'listitem');\n }\n this.setAttribute('tabindex', this.disabled ? '-1' : '0');\n this.addEventListener('keydown', this._handleKeydown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('status')) {\n if (this.status === 'active') {\n this.setAttribute('aria-current', 'step');\n } else {\n this.removeAttribute('aria-current');\n }\n }\n if (changedProperties.has('disabled')) {\n if (this.disabled) {\n this.setAttribute('tabindex', '-1');\n this.setAttribute('aria-disabled', 'true');\n } else {\n this.setAttribute('tabindex', '0');\n this.removeAttribute('aria-disabled');\n }\n }\n if (changedProperties.has('orientation')) {\n this.setAttribute('orientation', this.orientation);\n }\n if (changedProperties.has('size')) {\n this.setAttribute('size', this.size);\n }\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleKeydown = (event: KeyboardEvent): void => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this._handleClick();\n }\n };\n\n /** @internal */\n private _handleClick(): void {\n if (this.disabled) {\n return;\n }\n\n /**\n * Internal event dispatched to signal step click to the parent container.\n * @internal\n */\n this.dispatchEvent(\n new CustomEvent<void>('hx-step-click-internal', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderCheckmark() {\n return html`\n <svg\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 <path d=\"M20 6L9 17l-5-5\" />\n </svg>\n <span class=\"sr-only\">Complete</span>\n `;\n }\n\n /** @internal */\n private _renderXMark() {\n return html`\n <svg\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 >\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">Error</span>\n `;\n }\n\n /** @internal */\n private _renderIndicatorContent() {\n if (this.status === 'complete') {\n return this._renderCheckmark();\n }\n if (this.status === 'error') {\n return this._renderXMark();\n }\n return html`<slot name=\"icon\">${this.index + 1}</slot>`;\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div part=\"base\" class=\"step\" role=\"button\" @click=${this._handleClick}>\n <div class=\"step__track\">\n <div part=\"indicator\" class=\"step__indicator\">${this._renderIndicatorContent()}</div>\n <div part=\"connector\" class=\"step__connector\" aria-hidden=\"true\"></div>\n </div>\n <div class=\"step__label-area\">\n <div part=\"label\" class=\"step__label\">\n <slot name=\"label\">${this.label}</slot>\n </div>\n <div part=\"description\" class=\"step__description\">\n <slot name=\"description\">${this.description}</slot>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-step': HelixStep;\n }\n}\n"],"names":["helixStepsStyles","css","HelixSteps","LitElement","e","steps","step","el","index","legacySize","changedProperties","html","nothing","tokenStyles","__decorateClass","property","customElement","helixStepStyles","HelixStep","event"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-tab-panel-GGjk6Qg4.js","sources":["../../src/components/hx-tabs/hx-tabs.styles.ts","../../src/components/hx-tabs/hx-tabs.ts","../../src/components/hx-tabs/hx-tab.styles.ts","../../src/components/hx-tabs/hx-tab.ts","../../src/components/hx-tabs/hx-tab-panel.styles.ts","../../src/components/hx-tabs/hx-tab-panel.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixTabsStyles = css`\n :host {\n display: block;\n font-family: var(--hx-font-family-sans, sans-serif);\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Container ─── */\n\n .tabs {\n display: flex;\n flex-direction: column;\n gap: var(--hx-tabs-gap, 0);\n }\n\n :host([orientation='vertical']) .tabs {\n flex-direction: row;\n }\n\n /* ─── Tablist ─── */\n\n .tablist {\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n gap: 0;\n border-bottom: var(--hx-tabs-border-width, 1px) solid\n var(--hx-tabs-border-color, var(--hx-color-neutral-200, #e9ecef));\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .tablist::-webkit-scrollbar {\n display: none;\n }\n\n /* ─── Vertical Orientation ─── */\n\n :host([orientation='vertical']) {\n --_tab-indicator-bottom: 0px;\n --_tab-indicator-end: var(--hx-tabs-indicator-size, 2px);\n --_tab-indicator-bottom-color: transparent;\n --_tab-indicator-end-color: var(\n --hx-tabs-indicator-color,\n var(--hx-color-primary-500, #2563eb)\n );\n }\n\n :host([orientation='vertical']) .tablist {\n flex-direction: column;\n border-bottom: none;\n border-inline-end: var(--hx-tabs-border-width, 1px) solid\n var(--hx-tabs-border-color, var(--hx-color-neutral-200, #e9ecef));\n overflow-x: visible;\n overflow-y: auto;\n min-width: var(--hx-tabs-vertical-width, 12rem);\n flex-shrink: 0;\n }\n\n /* ─── Panels Container ─── */\n\n .panels {\n flex: 1 1 auto;\n min-width: 0;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .tablist {\n scroll-behavior: auto;\n }\n }\n`;\n","import { LitElement, html, type PropertyValues } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixTabsStyles } from './hx-tabs.styles.js';\nimport type { HelixTab } from './hx-tab.js';\nimport type { HelixTabPanel } from './hx-tab-panel.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// Module-level counter for stable, SSR-safe IDs (avoids Math.random() hydration mismatch)\nlet _hxTabsIdCounter = 0;\n\n/**\n * A tabbed content organizer that manages a set of `<hx-tab>` and `<hx-tab-panel>` children.\n * Supports horizontal and vertical orientations, automatic and manual activation modes,\n * and full keyboard navigation per the ARIA Authoring Practices Guide.\n *\n * @summary Tab container that organizes content into selectable panels.\n *\n * @tag hx-tabs\n *\n * @slot tab - Slot for `<hx-tab>` elements. Rendered inside the tablist.\n * @slot - Default slot for `<hx-tab-panel>` elements.\n *\n * @fires {CustomEvent<{tabId: string, index: number}>} hx-tab-change - Dispatched when the active tab changes.\n *\n * @csspart tablist - The tablist container element.\n * @csspart panels - The panel content container element.\n *\n * @cssprop [--hx-tabs-border-color=var(--hx-color-neutral-200, #e9ecef)] - Tablist border color.\n * @cssprop [--hx-tabs-border-width=1px] - Tablist border width.\n * @cssprop [--hx-tabs-vertical-width=12rem] - Width of the tablist in vertical orientation.\n * @cssprop [--hx-tabs-gap=0] - Gap between the tablist and panels container.\n * @cssprop [--hx-tabs-tab-color=var(--hx-color-neutral-600, #495057)] - Inactive tab text color.\n * @cssprop [--hx-tabs-tab-active-color=var(--hx-color-primary-600, #1d4ed8)] - Active tab text color.\n * @cssprop [--hx-tabs-tab-hover-color=var(--hx-color-neutral-800, #212529)] - Tab hover text color.\n * @cssprop [--hx-tabs-tab-hover-bg=var(--hx-color-neutral-50, #f8f9fa)] - Tab hover background.\n * @cssprop [--hx-tabs-tab-font-size=var(--hx-font-size-md, 1rem)] - Tab font size.\n * @cssprop [--hx-tabs-tab-font-weight=var(--hx-font-weight-medium, 500)] - Tab font weight.\n * @cssprop [--hx-tabs-tab-active-font-weight=var(--hx-font-weight-semibold, 600)] - Active tab font weight.\n * @cssprop [--hx-tabs-tab-padding-x=var(--hx-space-4, 1rem)] - Horizontal tab padding.\n * @cssprop [--hx-tabs-tab-padding-y=var(--hx-space-2, 0.5rem)] - Vertical tab padding.\n * @cssprop [--hx-tabs-indicator-color=var(--hx-color-primary-500, #2563eb)] - Active indicator color.\n * @cssprop [--hx-tabs-indicator-size=2px] - Active indicator thickness.\n * @cssprop [--hx-tabs-focus-ring-color=var(--hx-focus-ring-color, #2563eb)] - Focus ring color for tabs and panels.\n * @cssprop [--hx-tabs-panel-padding=var(--hx-space-4, 1rem)] - Panel inner padding.\n * @cssprop [--hx-tabs-panel-color=var(--hx-color-neutral-700, #343a40)] - Panel text color.\n */\n@customElement('hx-tabs')\nexport class HelixTabs extends LitElement {\n static override styles = [tokenStyles, helixTabsStyles];\n\n // ─── Internal ID ───\n\n /** @internal */\n private _id = `hx-tabs-${++_hxTabsIdCounter}`;\n\n // ─── Properties ───\n\n /**\n * The layout orientation of the tabs.\n * @attr orientation\n */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /**\n * Controls how keyboard navigation activates tabs.\n * In `automatic` mode, focus also activates the tab.\n * In `manual` mode, focus moves independently; Space or Enter activates.\n * @attr activation\n */\n @property({ type: String, attribute: 'activation', reflect: true })\n activation: 'manual' | 'automatic' = 'automatic';\n\n /**\n * Accessible label for the tablist. Rendered as `aria-label` on the tablist container.\n * Provide a brief description of what the tabs represent (e.g., \"Patient record sections\").\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = '';\n\n // ─── State ───\n\n /** @internal */\n @state() private _activePanel = '';\n\n // ─── Child Accessors ───\n\n /** @internal */\n private _cachedTabs: HelixTab[] | null = null;\n /** @internal */\n private _cachedPanels: HelixTabPanel[] | null = null;\n /** @internal */\n private _observer: MutationObserver | null = null;\n\n // ─── Public API ───\n\n /**\n * Gets or sets the zero-based index of the currently selected tab.\n * Setting this programmatically activates the tab at the given index.\n */\n get selectedIndex(): number {\n return this._getTabs().findIndex((tab) => tab.panel === this._activePanel);\n }\n\n set selectedIndex(index: number) {\n const tab = this._getTabs()[index];\n if (tab && !tab.disabled) {\n this._activateTab(tab, true);\n }\n }\n\n /** @internal */\n private _getTabs(): HelixTab[] {\n if (!this._cachedTabs) {\n this._cachedTabs = Array.from(this.querySelectorAll(':scope > hx-tab')).filter(\n (el): el is HelixTab => el.tagName.toLowerCase() === 'hx-tab',\n );\n }\n return this._cachedTabs;\n }\n\n /** @internal */\n private _getPanels(): HelixTabPanel[] {\n if (!this._cachedPanels) {\n this._cachedPanels = Array.from(this.querySelectorAll(':scope > hx-tab-panel')).filter(\n (el): el is HelixTabPanel => el.tagName.toLowerCase() === 'hx-tab-panel',\n );\n }\n return this._cachedPanels;\n }\n\n /** @internal */\n private _getEnabledTabs(): HelixTab[] {\n return this._getTabs().filter((tab) => !tab.disabled);\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('hx-tab-select', this._handleTabSelect);\n this.addEventListener('keydown', this._handleKeydown);\n // Watch for panel/name attribute changes on child tabs and panels\n if (typeof MutationObserver !== 'undefined') {\n this._observer = new MutationObserver(() => {\n this._cachedTabs = null;\n this._cachedPanels = null;\n this._syncTabsAndPanels();\n });\n this._observer.observe(this, {\n subtree: false,\n attributeFilter: ['panel', 'name'],\n });\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('hx-tab-select', this._handleTabSelect);\n this.removeEventListener('keydown', this._handleKeydown);\n this._observer?.disconnect();\n this._observer = null;\n }\n\n override firstUpdated(): void {\n if (this.label === '') {\n devWarn(\n 'hx-tabs',\n 'No accessible label provided. Set the `label` attribute on hx-tabs to describe what the tabs represent (e.g., \"Patient record sections\"). An unlabeled tablist violates WCAG 4.1.2.',\n );\n }\n\n this._syncTabsAndPanels();\n // Activate the first enabled tab if none is selected\n if (!this._activePanel) {\n const firstEnabled = this._getEnabledTabs()[0];\n if (firstEnabled) {\n this._activateTab(firstEnabled, false);\n }\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if ((changedProperties as Map<PropertyKey, unknown>).has('_activePanel')) {\n this._updateTabsAndPanels();\n }\n }\n\n // ─── Tab / Panel Sync ───\n\n /** @internal */\n private _syncTabsAndPanels(): void {\n const tabs = this._getTabs();\n const panels = this._getPanels();\n\n tabs.forEach((tab, i) => {\n const tabId = tab.id || `hx-tab-${this._id}-${i}`;\n tab.id = tabId;\n\n // Connect tab to its panel by aria-controls\n const panelName = tab.panel;\n const panel = panels.find((p) => p.name === panelName) ?? panels[i];\n if (panel) {\n const panelId = panel.id || `hx-panel-${this._id}-${i}`;\n panel.id = panelId;\n // Set controls on the tab so aria-controls lands on the inner button (role=\"tab\")\n tab.controls = panelId;\n // Use aria-label instead of aria-labelledby to avoid shadow boundary failures.\n // aria-labelledby pointing to hx-tab host IDs fails because the host element's\n // accessible text is inside its shadow DOM (the inner <button>), which AT cannot\n // traverse via aria-labelledby references across shadow roots.\n // Extract only default-slot children (no `slot` attribute) to exclude prefix/suffix\n // slot content (e.g. badge counts) from the panel accessible name (WCAG 1.3.1).\n const tabLabel = Array.from(tab.childNodes)\n .filter(\n (node) =>\n node.nodeType === Node.TEXT_NODE ||\n (node.nodeType === Node.ELEMENT_NODE && !(node as Element).hasAttribute('slot')),\n )\n .map((node) => node.textContent ?? '')\n .join('')\n .trim();\n if (tabLabel) {\n panel.setAttribute('aria-label', tabLabel);\n panel.removeAttribute('aria-labelledby');\n } else {\n // Fall back to aria-labelledby if no text content is yet available;\n // this will be corrected on slotchange once content is assigned.\n panel.setAttribute('aria-labelledby', tabId);\n }\n }\n });\n\n this._updateTabsAndPanels();\n }\n\n /** @internal */\n private _updateTabsAndPanels(): void {\n const tabs = this._getTabs();\n const panels = this._getPanels();\n\n tabs.forEach((tab) => {\n const isSelected = tab.panel === this._activePanel;\n tab.selected = isSelected;\n // Dual tabindex is intentional: the inner button in hx-tab manages its own tabindex\n // via the `selected` property. We also set it on the host element for the roving\n // tabindex pattern so document.activeElement comparisons work correctly when the\n // inner button is focused. This is safe because the inner button is the only\n // focusable element in hx-tab's shadow DOM (WCAG 2.4.3).\n tab.tabIndex = isSelected ? 0 : -1;\n });\n\n panels.forEach((panel) => {\n const isActive = panel.name === this._activePanel;\n if (isActive) {\n panel.removeAttribute('hidden');\n panel.setAttribute('tabindex', '0');\n } else {\n panel.setAttribute('hidden', '');\n panel.setAttribute('tabindex', '-1');\n }\n });\n }\n\n // ─── Tab Activation ───\n\n /** @internal */\n private _activateTab(tab: HelixTab, dispatchEvent = true): void {\n if (tab.disabled) {\n return;\n }\n\n const tabs = this._getTabs();\n const previousPanel = this._activePanel;\n this._activePanel = tab.panel;\n\n if (dispatchEvent && previousPanel !== this._activePanel) {\n const index = tabs.indexOf(tab);\n /**\n * Dispatched when the active tab changes.\n * @event hx-tab-change\n */\n this.dispatchEvent(\n new CustomEvent<{ tabId: string; index: number }>('hx-tab-change', {\n bubbles: true,\n composed: true,\n detail: { tabId: tab.id, index },\n }),\n );\n }\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleTabSelect = (e: Event): void => {\n if (!(e instanceof CustomEvent)) return;\n e.stopPropagation();\n const tab = e\n .composedPath()\n .find((el): el is HelixTab => el instanceof Element && el.tagName.toLowerCase() === 'hx-tab');\n if (tab) {\n this._activateTab(tab);\n }\n };\n\n /** @internal */\n private _warnInvalidSlotContent(): void {\n const tabSlot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"tab\"]');\n const panelSlot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (tabSlot) {\n const invalid = tabSlot\n .assignedElements()\n .filter((el) => el.tagName.toLowerCase() !== 'hx-tab');\n if (invalid.length > 0) {\n devWarn(\n 'hx-tabs',\n `Slot \"tab\" expects <hx-tab> elements. Found unexpected: ${invalid.map((el) => `<${el.tagName.toLowerCase()}>`).join(', ')}`,\n );\n }\n }\n if (panelSlot) {\n const invalid = panelSlot\n .assignedElements()\n .filter((el) => el.tagName.toLowerCase() !== 'hx-tab-panel');\n if (invalid.length > 0) {\n devWarn(\n 'hx-tabs',\n `Default slot expects <hx-tab-panel> elements. Found unexpected: ${invalid.map((el) => `<${el.tagName.toLowerCase()}>`).join(', ')}`,\n );\n }\n }\n }\n\n /** @internal */\n private _handleSlotChange = (): void => {\n this._warnInvalidSlotContent();\n this._cachedTabs = null;\n this._cachedPanels = null;\n this._syncTabsAndPanels();\n // If the active panel was removed, fall back to the first enabled tab\n const panels = this._getPanels();\n const activePanelExists = panels.some((p) => p.name === this._activePanel);\n if (!activePanelExists) {\n const firstEnabled = this._getEnabledTabs()[0];\n if (firstEnabled) {\n this._activateTab(firstEnabled, false);\n } else {\n this._activePanel = '';\n }\n }\n };\n\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n const enabledTabs = this._getEnabledTabs();\n if (enabledTabs.length === 0) {\n return;\n }\n\n const isHorizontal = this.orientation === 'horizontal';\n const prevKey = isHorizontal ? 'ArrowLeft' : 'ArrowUp';\n const nextKey = isHorizontal ? 'ArrowRight' : 'ArrowDown';\n\n const isNavigationKey = [prevKey, nextKey, 'Home', 'End', ' ', 'Enter'].includes(e.key);\n if (!isNavigationKey) {\n return;\n }\n\n // Determine focused tab — when a button inside shadow DOM is focused,\n // document.activeElement returns the shadow host (hx-tab), not the inner button.\n const focusedTab = enabledTabs.find((tab) => tab === document.activeElement);\n\n if (e.key === ' ' || e.key === 'Enter') {\n if (focusedTab) {\n e.preventDefault();\n this._activateTab(focusedTab);\n focusedTab.shadowRoot?.querySelector('button')?.focus();\n }\n return;\n }\n\n e.preventDefault();\n\n let currentIndex = focusedTab ? enabledTabs.indexOf(focusedTab) : -1;\n // Fall back to the active tab's index if nothing is focused yet\n if (currentIndex === -1) {\n const activeTab = enabledTabs.find((tab) => tab.panel === this._activePanel);\n currentIndex = activeTab ? enabledTabs.indexOf(activeTab) : 0;\n }\n\n let nextIndex: number;\n\n if (e.key === 'Home') {\n nextIndex = 0;\n } else if (e.key === 'End') {\n nextIndex = enabledTabs.length - 1;\n } else if (e.key === nextKey) {\n nextIndex = (currentIndex + 1) % enabledTabs.length;\n } else {\n // prevKey\n nextIndex = currentIndex <= 0 ? enabledTabs.length - 1 : currentIndex - 1;\n }\n\n const targetTab = enabledTabs[nextIndex];\n if (!targetTab) {\n return;\n }\n\n // Focus the tab button inside the shadow root\n targetTab.shadowRoot?.querySelector('button')?.focus();\n\n if (this.activation === 'automatic') {\n this._activateTab(targetTab);\n }\n };\n\n // ─── Render ───\n\n override render() {\n return html`\n <div class=\"tabs\">\n <div\n part=\"tablist\"\n class=\"tablist\"\n role=\"tablist\"\n aria-orientation=${this.orientation}\n aria-label=${this.label || 'Tabs'}\n >\n <slot name=\"tab\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n <div part=\"panels\" class=\"panels\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tabs': HelixTabs;\n }\n}\n","import { css } from 'lit';\n\nexport const helixTabStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n * {\n box-sizing: border-box;\n }\n\n .tab {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n padding: var(--hx-tabs-tab-padding-y, var(--hx-space-2, 0.5rem))\n var(--hx-tabs-tab-padding-x, var(--hx-space-4, 1rem));\n border: none;\n border-bottom: var(--_tab-indicator-bottom, var(--hx-tabs-indicator-size, 2px)) solid\n transparent;\n border-inline-end: var(--_tab-indicator-end, 0px) solid transparent;\n background: none;\n font-family: var(--hx-tabs-tab-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-tabs-tab-font-size, var(--hx-font-size-md, 1rem));\n font-weight: var(--hx-tabs-tab-font-weight, var(--hx-font-weight-medium, 500));\n color: var(--hx-tabs-tab-color, var(--hx-color-neutral-600, #495057));\n line-height: var(--hx-line-height-tight, 1.25);\n cursor: pointer;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n transition:\n color var(--hx-transition-fast, 150ms ease),\n border-color var(--hx-transition-fast, 150ms ease),\n border-inline-end-color var(--hx-transition-fast, 150ms ease),\n background-color var(--hx-transition-fast, 150ms ease);\n position: relative;\n }\n\n /* ─── Hover State ─── */\n\n .tab:not([aria-selected='true']):not([aria-disabled='true']):hover {\n color: var(--hx-tabs-tab-hover-color, var(--hx-color-neutral-800, #212529));\n background-color: var(--hx-tabs-tab-hover-bg, var(--hx-color-neutral-50, #f8f9fa));\n }\n\n /* ─── Selected State ─── */\n\n .tab[aria-selected='true'] {\n color: var(--hx-tabs-tab-active-color, var(--hx-color-primary-600, #1d4ed8));\n border-bottom-color: var(\n --_tab-indicator-bottom-color,\n var(--hx-tabs-indicator-color, var(--hx-color-primary-500, #2563eb))\n );\n border-inline-end-color: var(--_tab-indicator-end-color, transparent);\n font-weight: var(--hx-tabs-tab-active-font-weight, var(--hx-font-weight-semibold, 600));\n }\n\n /* ─── Focus State ─── */\n\n .tab:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-tabs-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 /* ─── Disabled State ─── */\n\n .tab[aria-disabled='true'] {\n cursor: not-allowed;\n color: var(--hx-color-neutral-400, #adb5bd);\n }\n\n /* ─── Prefix / Suffix Slots ─── */\n\n .tab__prefix,\n .tab__suffix {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .tab {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixTabStyles } from './hx-tab.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/**\n * An individual tab button, designed to be used inside an `<hx-tabs>` container.\n * Must be placed in the `tab` named slot of `<hx-tabs>`.\n *\n * @summary Presentational tab button that activates a corresponding panel.\n *\n * @tag hx-tab\n *\n * @slot - Default slot for the tab label text or content.\n * @slot prefix - Icon or content rendered before the label.\n * @slot suffix - Icon or content rendered after the label.\n *\n * @csspart tab - The underlying button element.\n * @csspart prefix - The container for prefix slot content (e.g. icons).\n * @csspart suffix - The container for suffix slot content (e.g. badges).\n *\n * @cssprop [--hx-tabs-tab-color=var(--hx-color-neutral-600, #495057)] - Inactive tab text color.\n * @cssprop [--hx-tabs-tab-active-color=var(--hx-color-primary-600, #1d4ed8)] - Active tab text color.\n * @cssprop [--hx-tabs-tab-hover-color=var(--hx-color-neutral-800, #212529)] - Tab hover text color.\n * @cssprop [--hx-tabs-tab-hover-bg=var(--hx-color-neutral-50, #f8f9fa)] - Tab hover background.\n * @cssprop [--hx-tabs-tab-font-size=var(--hx-font-size-md, 1rem)] - Tab font size.\n * @cssprop [--hx-tabs-tab-font-weight=var(--hx-font-weight-medium, 500)] - Tab font weight.\n * @cssprop [--hx-tabs-tab-active-font-weight=var(--hx-font-weight-semibold, 600)] - Active tab font weight.\n * @cssprop [--hx-tabs-tab-padding-x=var(--hx-space-4, 1rem)] - Horizontal tab padding.\n * @cssprop [--hx-tabs-tab-padding-y=var(--hx-space-2, 0.5rem)] - Vertical tab padding.\n * @cssprop [--hx-tabs-indicator-color=var(--hx-color-primary-500, #2563eb)] - Active indicator color.\n * @cssprop [--hx-tabs-indicator-size=2px] - Active indicator thickness.\n * @cssprop [--hx-tabs-focus-ring-color=var(--hx-focus-ring-color, #2563eb)] - Focus ring color.\n */\n@customElement('hx-tab')\nexport class HelixTab extends LitElement {\n static override styles = [tokenStyles, helixTabStyles];\n\n // ─── Properties ───\n\n /**\n * The name of the `<hx-tab-panel>` this tab controls. Must match the `name`\n * attribute on the corresponding `<hx-tab-panel>`.\n * @attr panel\n */\n @property({ type: String, reflect: true })\n panel = '';\n\n /**\n * Whether this tab is currently selected. Managed by the parent `<hx-tabs>`.\n * @attr selected\n */\n @property({ type: Boolean, reflect: true })\n selected = false;\n\n /**\n * Whether this tab is disabled. Prevents selection and keyboard navigation.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * The id of the panel this tab controls. Set by the parent `<hx-tabs>` to establish the\n * aria-controls relationship on the inner button element (which carries role=\"tab\").\n * @internal\n */\n @property({ type: String, attribute: false })\n controls = '';\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n if (!this.closest('hx-tabs')) {\n devWarn('hx-tab', 'hx-tab must be a direct child of hx-tabs to function correctly.');\n }\n }\n\n // ─── Slot Visibility ───\n\n /** @internal */\n @state() private _hasPrefixSlot = false;\n /** @internal */\n @state() private _hasSuffixSlot = false;\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleClick(): void {\n if (this.disabled) {\n return;\n }\n /**\n * Internal event dispatched to signal tab selection to the parent container.\n * Not part of the public API.\n * @internal\n */\n this.dispatchEvent(\n new CustomEvent<{ panel: string }>('hx-tab-select', {\n bubbles: true,\n composed: true,\n detail: { panel: this.panel },\n }),\n );\n }\n\n /** @internal */\n private _handlePrefixSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasPrefixSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleSuffixSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasSuffixSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <button\n part=\"tab\"\n class=\"tab\"\n role=\"tab\"\n aria-selected=${this.selected ? 'true' : 'false'}\n aria-disabled=${this.disabled ? 'true' : 'false'}\n aria-controls=${this.controls || nothing}\n tabindex=${this.selected ? '0' : '-1'}\n @click=${this._handleClick}\n >\n <span part=\"prefix\" class=\"tab__prefix\" ?hidden=${!this._hasPrefixSlot}>\n <slot name=\"prefix\" @slotchange=${this._handlePrefixSlotChange}></slot>\n </span>\n <slot></slot>\n <span part=\"suffix\" class=\"tab__suffix\" ?hidden=${!this._hasSuffixSlot}>\n <slot name=\"suffix\" @slotchange=${this._handleSuffixSlotChange}></slot>\n </span>\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tab': HelixTab;\n }\n}\n","import { css } from 'lit';\n\nexport const helixTabPanelStyles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n :host(:focus-visible) {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-tabs-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 .panel {\n padding: var(--hx-tabs-panel-padding, var(--hx-space-4, 1rem));\n font-family: var(--hx-font-family-sans, sans-serif);\n font-size: var(--hx-font-size-md, 1rem);\n color: var(--hx-tabs-panel-color, var(--hx-color-neutral-700, #343a40));\n line-height: var(--hx-line-height-normal, 1.5);\n outline: none;\n }\n`;\n","import { LitElement, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { tokenStyles } from '@helixui/tokens/lit';\nimport { helixTabPanelStyles } from './hx-tab-panel.styles.js';\n\n/**\n * A content panel associated with an `<hx-tab>`, managed by a parent `<hx-tabs>`.\n *\n * @summary Tab content panel shown when its corresponding tab is selected.\n *\n * @tag hx-tab-panel\n *\n * @slot - Default slot for panel content.\n *\n * @csspart panel - The panel content wrapper.\n *\n * @cssprop [--hx-tabs-panel-padding=var(--hx-space-4, 1rem)] - Panel inner padding.\n * @cssprop [--hx-tabs-panel-color=var(--hx-color-neutral-700, #343a40)] - Panel text color.\n * @cssprop [--hx-tabs-focus-ring-color=var(--hx-focus-ring-color, #2563eb)] - Focus ring color.\n */\n@customElement('hx-tab-panel')\nexport class HelixTabPanel extends LitElement {\n static override styles = [tokenStyles, helixTabPanelStyles];\n\n // ─── Properties ───\n\n /**\n * The name that corresponds to the `panel` attribute on the associated `<hx-tab>`.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'tabpanel');\n // tabindex is managed dynamically by the parent hx-tabs component:\n // active panels get tabindex=\"0\", hidden panels get tabindex=\"-1\"\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div part=\"panel\" class=\"panel\">\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tab-panel': HelixTabPanel;\n }\n}\n"],"names":["helixTabsStyles","css","_hxTabsIdCounter","HelixTabs","LitElement","tab","el","p","firstEnabled","enabledTabs","isHorizontal","prevKey","nextKey","focusedTab","_b","_a","currentIndex","activeTab","nextIndex","targetTab","_d","_c","index","changedProperties","tabs","panels","tabId","panelName","panel","panelId","tabLabel","node","isSelected","dispatchEvent","previousPanel","tabSlot","panelSlot","invalid","devWarn","html","tokenStyles","__decorateClass","property","state","customElement","helixTabStyles","HelixTab","slot","nothing","helixTabPanelStyles","HelixTabPanel"],"mappings":"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"}
|