@ds-mo/ui 2.3.0 → 2.4.1
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/dist/.build-stamp +1 -1
- package/dist/components/ds-app-shell.js +1 -1
- package/dist/components/ds-app-shell.js.map +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-nav.js.map +1 -1
- package/dist/components/ds-panel-tools.js +1 -1
- package/dist/components/ds-panel-tools.js.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/types/components/AppShell/AppShell.d.ts +3 -0
- package/dist/types/components/PanelNav/PanelNav.d.ts +2 -1
- package/dist/types/components/PanelTools/PanelTools.d.ts +4 -0
- package/dist/types/components/PanelTools/panel-tools-utils.d.ts +7 -1
- package/dist/types/components.d.ts +23 -0
- package/dist/types/nav/shell-shortcuts.d.ts +10 -0
- package/package.json +2 -2
- package/src/angular/proxies.ts +6 -4
- package/src/wc/components/AppShell/AppShell.tsx +38 -1
- package/src/wc/components/PanelNav/PanelNav.tsx +20 -22
- package/src/wc/components/PanelTools/PanelTools.tsx +29 -11
- package/src/wc/components/PanelTools/panel-tools-utils.ts +13 -1
- package/src/wc/components.d.ts +23 -0
- package/src/wc/nav/shell-shortcuts.ts +63 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NAV_STYLE_HINT_ATTR","readNavStyleAttr","attr","undefined","resolveNavChromeStyle","styleProp","hostAttr","docHint","fromHost","hint","document","documentElement","getAttribute","fromHint","shouldResyncNavChromeStyle","renderedStyle","style","hrefMatchesPath","path","href","startsWith","deriveActiveIdFromUrl","items","bestId","bestLen","item","length","id","countPanelNavItems","groups","reduce","sum","g","parsePanelNavGroups","Array","isArray","parsed","JSON","parse","resolvePanelNavDisableVt","prop","shouldResyncPanelNavGroups","parsedGroups","PANEL_NAV_USER_MENU_ANCHOR_ID","scrollEdgeFadeCss","panelNavCss","PanelNav","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","navStyle","disableViewTransition","routerMode","activeId","collapsed","breakpoint","storageKey","currentUrl","userName","userInitial","atBottom","isAnimating","rovingIndex","viewportNarrow","urlDerivedActiveId","isDragging","dragStartX","didSnap","lastDeltaX","edgeOverlayTimer","showEdgeOverlay","effectiveActiveId","effectiveDisableViewTransition","el","onCollapsedChange","_next","prev","startCollapseAnimation","onViewportNarrowChange","onBreakpointChange","disconnectResizeObserver","connectResizeObserver","onGroupsChange","val","syncActiveFromUrl","onActiveIdChange","onCurrentUrlChange","onNavStyleChange","newVal","componentWillLoad","resolvePanelNavStyle","stored","localStorage","getItem","componentDidLoad","syncHostPropsIfNeeded","scheduleDeferredHostPropSync","checkScroll","disconnectedCallback","clearEdgeOverlayTimer","globalMouseMoveHandler","window","removeEventListener","globalMouseUpHandler","dsChromeTransitionStart","emit","source","panel","querySelector","widthBefore","getBoundingClientRect","width","transitionEndHandler","e","propertyName","finishCollapseAnimation","addEventListener","requestAnimationFrame","widthAfter","Math","abs","dsChromeTransitionEnd","innerWidth","resizeObserver","ResizeObserver","observe","disconnect","getAllItems","shouldResyncPanelNavStyle","remaining","HOST_PROP_SYNC_BUDGET","tick","queueMicrotask","applyToggle","next","setItem","String","dsNavToggle","flatMap","getRovingTotal","getFooterRovingIndex","getUserRovingIndex","getRovingElement","index","itemCount","querySelectorAll","focusRovingAt","focus","preventScroll","activateRovingIndex","handleToggle","handleItemClick","handleFooterAction","anchor","dsNavUserAction","handleRovingKeyDown","key","preventDefault","total","footerIdx","userIdx","body","scrollHeight","scrollTop","clientHeight","handleBodyScroll","target","dsNavSelect","dsNavFooterAction","handleUserAction","currentTarget","clearTimeout","handleResizeHandleMouseEnter","setTimeout","handleResizeHandleMouseLeave","handleResizeHandleMouseDown","stopPropagation","wasCollapsed","clientX","cursor","userSelect","onMove","ev","deltaX","onUp","renderNavItem","idx","isActive","rovingPosition","itemContent","h","class","name","icon","size","color","flag","as","variant","label","dot","background","sharedProps","title","tabIndex","onClick","onKeyDown","onFocus","useAnchor","type","render","chromeStyle","isDashboardChrome","isDashboard","navCls","Host","display","position","viewBox","fill","xmlns","focusable","d","onScroll","flatIdx","map","group","activeFill","focusTabIndex","onDsClick","onFocusin","onMouseEnter","onMouseLeave","onMouseDown"],"sources":["src/wc/nav/nav-chrome.ts","src/wc/components/PanelNav/panel-nav-utils.ts","src/wc/components/PanelNav/panel-nav-types.ts","src/wc/utils/scroll-edge-fade.css?tag=ds-panel-nav&encapsulation=scoped","src/wc/components/PanelNav/PanelNav.css?tag=ds-panel-nav&encapsulation=scoped","src/wc/components/PanelNav/PanelNav.tsx"],"sourcesContent":["/** Nav chrome style slot — dashboard vs settings. Colors unified for now; texture hooks use the class. */\nexport type NavChromeStyle = 'dashboard' | 'settings';\n\n/** Document hint for first paint before framework props land. */\nexport const NAV_STYLE_HINT_ATTR = 'data-nav-style';\n\nexport function readNavStyleAttr(attr: string | null): NavChromeStyle | undefined {\n if (attr === 'dashboard' || attr === 'settings') return attr;\n return undefined;\n}\n\nexport function setNavStyleHint(style: NavChromeStyle): void {\n if (typeof document === 'undefined') return;\n document.documentElement.setAttribute(NAV_STYLE_HINT_ATTR, style);\n}\n\nexport function clearNavStyleHint(): void {\n if (typeof document === 'undefined') return;\n document.documentElement.removeAttribute(NAV_STYLE_HINT_ATTR);\n}\n\nexport function resolveNavChromeStyle(\n styleProp: NavChromeStyle,\n hostAttr: string | null,\n docHint?: string | null,\n): NavChromeStyle {\n const fromHost = readNavStyleAttr(hostAttr);\n if (fromHost) return fromHost;\n\n const hint =\n docHint !== undefined\n ? docHint\n : typeof document !== 'undefined'\n ? document.documentElement.getAttribute(NAV_STYLE_HINT_ATTR)\n : null;\n const fromHint = readNavStyleAttr(hint);\n if (fromHint) return fromHint;\n\n return styleProp;\n}\n\nexport function shouldResyncNavChromeStyle(\n renderedStyle: NavChromeStyle,\n style: NavChromeStyle,\n): boolean {\n return renderedStyle !== style;\n}\n","import type { PanelNavGroup, PanelNavItem } from './panel-nav-types';\nimport {\n NAV_STYLE_HINT_ATTR,\n clearNavStyleHint,\n readNavStyleAttr,\n resolveNavChromeStyle,\n setNavStyleHint,\n shouldResyncNavChromeStyle,\n} from '../../nav/nav-chrome';\n\nexport type { NavChromeStyle } from '../../nav/nav-chrome';\nexport {\n NAV_STYLE_HINT_ATTR,\n readNavStyleAttr,\n setNavStyleHint,\n clearNavStyleHint,\n resolveNavChromeStyle as resolvePanelNavStyle,\n shouldResyncNavChromeStyle as shouldResyncPanelNavStyle,\n};\n\n/** Whether `path` matches `href` at a segment boundary (exact or child path). */\nexport function hrefMatchesPath(path: string, href: string): boolean {\n return path === href || path.startsWith(`${href}/`);\n}\n\n/** Derive the active nav item id from a URL using longest segment-boundary prefix match. */\nexport function deriveActiveIdFromUrl(path: string, items: PanelNavItem[]): string {\n if (!path) return '';\n\n let bestId = '';\n let bestLen = 0;\n\n for (const item of items) {\n if (!item.href) continue;\n if (hrefMatchesPath(path, item.href) && item.href.length > bestLen) {\n bestId = item.id;\n bestLen = item.href.length;\n }\n }\n\n return bestId;\n}\n\n/** Total nav item count across all groups. */\nexport function countPanelNavItems(groups: PanelNavGroup[]): number {\n return groups.reduce((sum, g) => sum + g.items.length, 0);\n}\n\n/** Parse `groups` from either a JSON attribute string or a JS property array. */\nexport function parsePanelNavGroups(groups: string | unknown): PanelNavGroup[] {\n if (Array.isArray(groups)) return groups;\n if (typeof groups === 'string') {\n try {\n const parsed = JSON.parse(groups);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n return [];\n}\n\n/** Resolve whether VT is disabled from prop and/or host attribute. */\nexport function resolvePanelNavDisableVt(prop: boolean, attr: string | null): boolean {\n if (prop) return true;\n if (attr === null) return false;\n return attr !== 'false';\n}\n\n/** True when host `groups` has items but internal parsed state is still empty. */\nexport function shouldResyncPanelNavGroups(\n parsedGroups: PanelNavGroup[],\n groups: string | unknown,\n): boolean {\n return (\n countPanelNavItems(parsedGroups) === 0 &&\n countPanelNavItems(parsePanelNavGroups(groups)) > 0\n );\n}\n","import type { NavChromeStyle } from '../../nav/nav-chrome';\n\nexport type { NavChromeStyle };\nexport type PanelNavRouterMode = 'anchor' | 'event';\n\nexport interface PanelNavItem {\n id: string;\n icon: string;\n label: string;\n /** Show a notification dot badge on the item */\n dot?: boolean;\n flag?: boolean;\n /** Route path used for `currentUrl` matching. In `anchor` mode also sets `<a href>`.\n * In `event` mode navigation is delegated to the host via `dsNavSelect`. */\n href?: string;\n}\n\nexport interface PanelNavGroup {\n id?: string;\n label?: string;\n items: PanelNavItem[];\n}\n\n/** Stable `id` on the footer user button — use with `ds-menu` `anchor-id`. */\nexport const PANEL_NAV_USER_MENU_ANCHOR_ID = 'ds-panel-nav-user-menu-anchor';\n\n/** Detail for `dsNavUserAction` — anchor element for an external `ds-menu`. */\nexport interface PanelNavUserActionDetail {\n anchor: HTMLElement;\n}\n","/**\n * Scroll-edge alpha fade — apply to overflow scroll containers.\n * Pair with `.scroll-edge-fade--at-end` when the relevant edge is flush (no fade).\n *\n * @see scroll-edge-fade.ts for programmatic mask helpers.\n */\n\n.scroll-edge-fade {\n --ds-scroll-edge-fade-size: var(--dimension-size-600);\n}\n\n.scroll-edge-fade--top {\n -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 50%, transparent 100%);\n mask-image: linear-gradient(to bottom, #000 0, #000 50%, transparent 100%);\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--bottom {\n -webkit-mask-image: linear-gradient(\n to bottom,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n mask-image: linear-gradient(\n to bottom,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--left {\n -webkit-mask-image: linear-gradient(\n to right,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n mask-image: linear-gradient(\n to right,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--right {\n -webkit-mask-image: linear-gradient(\n to left,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n mask-image: linear-gradient(\n to left,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--at-end {\n -webkit-mask-image: none;\n mask-image: none;\n}\n","@import '../../utils/focus-ring.css';\n\n/* ── Theme variables ──────────────────────────────────────────────────────── */\n\n.panel-nav {\n /* ─ Sizes ─ */\n --_nav-width: var(--dimension-panel-width-2xs);\n --_nav-width-collapsed: var(--dimension-size-600);\n --_nav-item-height: var(--dimension-size-400, 32px);\n --_nav-padding-x: var(--dimension-space-100, 8px);\n --_nav-padding-y: var(--dimension-space-100, 8px);\n /* gear button outer width = padding*2 + icon */\n --_nav-footer-btn-w: calc(var(--dimension-space-075, 6px) * 2 + var(--dimension-iconography-md, 20px));\n\n /* ─ Motion ─ */\n /* --ds-panel-nav-speed: unitless multiplier; override in Storybook to slow-mo (e.g. 10 = 10×).\n *-dur vars are duration-only (needed for calc); *-motion vars add easing for use in transitions. */\n --_nav-speed: var(--ds-panel-nav-speed, 1);\n --_nav-expand-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-expand-motion: var(--_nav-expand-dur) var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-label-fade-motion: var(--_nav-label-fade-dur) var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-out-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-label-fade-out-motion: var(--_nav-label-fade-out-dur) var(--effect-animation-easing-ease-in-out, ease);\n\n /* ─ Colours – default chrome (app surfaces) ─ */\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Default chrome overrides ────────────────────────────────────────────── */\n\n/* Shell-owned chrome (bg + wash +/or grid) — panel is a transparent frame. */\n:host-context(ds-app-shell[gradient]) .panel-nav,\n:host-context(ds-app-shell[grid]) .panel-nav {\n background-color: transparent;\n}\n\n/* Style slots — same app tokens for now; hook texture/glyph layers on these classes later. */\n.panel-nav--dashboard,\n.panel-nav--settings {\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n}\n\n/* ── Shell ───────────────────────────────────────────────────────────────── */\n\n.panel-nav {\n display: flex;\n flex-direction: column;\n position: relative;\n width: var(--_nav-width);\n min-width: var(--_nav-width);\n height: 100%;\n background-color: var(--_nav-bg);\n border-right: var(--dimension-stroke-width-012, 1px) solid var(--_nav-border);\n box-sizing: border-box;\n overflow: visible;\n transition:\n width var(--_nav-expand-motion),\n min-width var(--_nav-expand-motion),\n background-color var(--effect-motion-short-3, 200ms ease),\n border-color var(--effect-motion-short-3, 200ms ease);\n font-family: var(--typography-font-family, system-ui);\n isolation: isolate;\n}\n\n.panel-nav__header,\n.panel-nav__body,\n.panel-nav__footer {\n position: relative;\n z-index: 3;\n}\n\n.panel-nav--collapsed {\n width: var(--_nav-width-collapsed);\n min-width: var(--_nav-width-collapsed);\n}\n\n/* ── Header ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__header {\n display: flex;\n align-items: center;\n height: var(--dimension-size-600, 48px);\n padding: var(--dimension-space-100, 8px);\n flex-shrink: 0;\n box-sizing: border-box;\n border-bottom: var(--dimension-stroke-width-012, 1px) solid var(--_nav-divider);\n transition: border-color var(--effect-motion-short-3, 200ms ease);\n}\n\n.panel-nav__header-btn {\n all: unset;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--dimension-space-075, 6px);\n border-radius: var(--dimension-radius-025, 2px);\n cursor: pointer;\n color: var(--_nav-fg-primary);\n position: relative;\n flex-shrink: 0;\n box-sizing: border-box;\n transition: color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* Interaction pseudo-element */\n.panel-nav__header-btn::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--dimension-radius-025, 2px);\n background: transparent;\n pointer-events: none;\n transition: none;\n}\n\n.panel-nav__header-btn:hover::after { background: var(--_nav-hover); transition: none; }\n.panel-nav__header-btn:active::after { background: var(--_nav-pressed); transition: none; }\n\n/* Logo — visible by default; instant swap to toggle on hover (no crossfade overlap) */\n.panel-nav__header-logo {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n z-index: 1;\n opacity: 1;\n}\n\n.panel-nav__m-mark {\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n display: block;\n}\n\n/* Toggle icon — stacked on logo; opacity swap matches hover bg (instant) */\n.panel-nav__header-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n inset: 0;\n z-index: 2;\n opacity: 0;\n pointer-events: none;\n}\n\n.panel-nav__header-btn:hover .panel-nav__header-logo { opacity: 0; }\n.panel-nav__header-btn:hover .panel-nav__header-toggle { opacity: 1; }\n\n/* ── Scrollable body ─────────────────────────────────────────────────────── */\n\n.panel-nav__body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-200, 16px);\n padding: var(--dimension-space-100, 8px);\n box-sizing: border-box;\n scrollbar-width: none;\n}\n\n.panel-nav__body::-webkit-scrollbar { display: none; }\n\n/* ── Group ───────────────────────────────────────────────────────────────── */\n\n.panel-nav__group {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050, 4px);\n}\n\n.panel-nav__group-label {\n /* Typography via ds-text (text-caption-emphasis) */\n display: flex;\n align-items: center;\n text-transform: uppercase;\n color: var(--_nav-fg-secondary);\n user-select: none;\n height: var(--dimension-size-300, 24px);\n line-height: var(--typography-lineheight-xs, 12px);\n padding: 0 var(--dimension-space-075, 6px);\n white-space: nowrap;\n overflow: hidden;\n max-height: var(--dimension-size-300, 24px);\n opacity: 1;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n max-height var(--_nav-label-fade-motion) 0ms,\n padding var(--_nav-label-fade-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Item ────────────────────────────────────────────────────────────────── */\n\n.panel-nav__item {\n all: unset;\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050, 4px);\n padding: 0 var(--dimension-space-075, 6px);\n height: var(--dimension-size-400, 32px);\n border-radius: var(--dimension-radius-025, 2px);\n cursor: pointer;\n color: var(--_nav-fg-secondary);\n position: relative;\n box-sizing: border-box;\n width: 100%;\n user-select: none;\n transition: color var(--effect-motion-short-1, 50ms ease-in-out);\n}\n\n/* Interaction layer */\n.panel-nav__item::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--dimension-radius-025, 2px);\n background: transparent;\n pointer-events: none;\n transition: none;\n}\n\n.panel-nav__item:hover::after { background: var(--_nav-hover); transition: none; }\n.panel-nav__item:active::after { background: var(--_nav-pressed); transition: none; }\n\n/* ── Active item ─────────────────────────────────────────────────────────── */\n\n.panel-nav__item--active {\n color: var(--_nav-fg-primary);\n /* Bold typography via ds-text (text-body-medium-emphasis) on the label */\n}\n\n/* ── Item icon ───────────────────────────────────────────────────────────── */\n\n.panel-nav__item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n position: relative;\n}\n\n/* ── Item label ──────────────────────────────────────────────────────────── */\n\n.panel-nav__item-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n height: var(--typography-lineheight-md, 20px);\n line-height: var(--typography-lineheight-md, 20px);\n opacity: 1;\n /* Gradient wipe: mask sweeps left-to-right on expand, right-to-left on collapse */\n mask-image: linear-gradient(to right, black 50%, transparent 100%);\n -webkit-mask-image: linear-gradient(to right, black 50%, transparent 100%);\n mask-size: 200% 100%;\n -webkit-mask-size: 200% 100%;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n mask-position var(--_nav-label-fade-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-motion) 0ms;\n}\n\n.panel-nav__item-label-text {\n padding: 0 var(--dimension-space-025, 2px);\n}\n\n/* ── Item notification dot — single element, moves between positions ──────── */\n\n.panel-nav__item-dot {\n position: absolute;\n right: calc(var(--dimension-space-100, 8px) + var(--dimension-space-050, 4px) + var(--dimension-stroke-width-012, 1px));\n top: calc(var(--dimension-space-100, 8px) + var(--dimension-space-050, 4px) + var(--dimension-stroke-width-012, 1px));\n pointer-events: none;\n transition:\n right var(--_nav-expand-motion),\n top var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__item-dot {\n right: var(--dimension-space-075);\n top: var(--dimension-space-075);\n}\n\n.panel-nav--animating .panel-nav__item-label {\n text-overflow: clip;\n}\n\n.panel-nav--collapsed .panel-nav__item-label {\n opacity: 0;\n pointer-events: none;\n text-overflow: clip;\n mask-position: 100% 0;\n -webkit-mask-position: 100% 0;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n mask-position var(--_nav-label-fade-out-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-out-motion) 0ms;\n}\n\n.panel-nav--collapsed .panel-nav__group-label {\n opacity: 0;\n max-height: 0;\n padding: 0 var(--dimension-space-075, 6px);\n pointer-events: none;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n max-height var(--_nav-label-fade-out-motion) 0ms,\n padding var(--_nav-label-fade-out-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Footer ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__footer {\n position: relative;\n flex-shrink: 0;\n /* single row: padding*2 + item */\n height: calc(var(--_nav-padding-y) * 2 + var(--_nav-item-height));\n transition: height var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer {\n /* two rows: padding*2 + item*2 + gap */\n height: calc(var(--_nav-padding-y) * 2 + var(--_nav-item-height) * 2 + var(--dimension-space-050, 4px));\n}\n\n/* ── Footer icon button (gear / dashboard) ───────────────────────────────── */\n\n.panel-nav__footer-btn {\n position: absolute;\n left: var(--_nav-padding-x);\n top: var(--_nav-padding-y);\n --ds-button-unfilled-icon-fg: var(--_nav-fg-secondary);\n --ds-button-unfilled-icon-fg-active: var(--_nav-fg-primary);\n --ds-button-unfilled-icon-hover-bg: var(--_nav-hover);\n --ds-button-unfilled-icon-pressed-bg: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Footer user — absolutely positioned, slides from row to below gear ───── */\n\n.panel-nav__footer-user {\n position: absolute;\n /* row position: right of gear button */\n left: calc(var(--_nav-padding-x) + var(--_nav-footer-btn-w) + var(--dimension-space-050, 4px));\n right: calc(var(--_nav-padding-x) - var(--dimension-stroke-width-012, 1px));\n top: var(--_nav-padding-y);\n width: auto;\n min-width: 0;\n transition:\n left var(--_nav-expand-motion),\n right var(--_nav-expand-motion),\n top var(--_nav-expand-motion),\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user {\n /* column position: full-width row below gear */\n left: var(--_nav-padding-x);\n top: calc(var(--_nav-padding-y) + var(--_nav-item-height) + var(--dimension-space-050, 4px));\n}\n\n/* Label: absolute so it stays in place and only fades — no mask slide */\n.panel-nav__footer-user-label {\n text-align: right;\n position: absolute;\n left: var(--dimension-space-075, 6px);\n right: calc(var(--dimension-space-075, 6px) + var(--dimension-iconography-md, 20px) + var(--dimension-space-050, 4px));\n top: 50%;\n transform: translateY(-50%);\n flex: none;\n height: var(--typography-lineheight-md, 20px);\n mask-image: none;\n -webkit-mask-image: none;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-label {\n opacity: 0;\n pointer-events: none;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n}\n\n/* ── Footer user icon — cross-fades chevron ↔ circle+initial ────────────── */\n\n/* Absolute — right-anchored in expanded, left-anchored in collapsed to match regular item icon position */\n.panel-nav__footer-user-icon {\n position: absolute;\n left: calc(100% - var(--dimension-iconography-md, 20px) - var(--dimension-space-075, 6px));\n top: 0;\n bottom: 0;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: left var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-icon {\n left: var(--dimension-space-075, 6px);\n}\n\n.panel-nav__footer-icon-expanded,\n.panel-nav__footer-icon-collapsed {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.panel-nav__footer-icon-expanded {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav__footer-icon-collapsed {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-expanded {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-collapsed {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n/* ── User initial — overlaid on the circle icon ─────────────────────────── */\n\n.panel-nav__user-initial {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--_nav-fg-secondary);\n text-transform: uppercase;\n line-height: 1;\n pointer-events: none;\n transition: color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Drag-to-resize handle ───────────────────────────────────────────────── */\n\n/* The resize overlay line — extends past the right edge; keep above workspace content */\n.panel-nav__resize-handle {\n position: absolute;\n top: 0;\n /* Centered on the right edge: --dimension-space-050 outside + inside = --dimension-space-100 hit zone */\n right: var(--dimension-space-n050, -4px);\n bottom: 0;\n width: var(--dimension-space-100, 8px);\n z-index: 20;\n cursor: ew-resize;\n touch-action: none;\n /* Needs a real background for Safari hit-testing */\n background: transparent;\n}\n\n/* Safari requires non-transparent fill for hit testing */\n.panel-nav__resize-handle::before {\n content: '';\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.001);\n}\n\n/* Resize overlay line */\n.panel-nav__resize-handle::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: var(--dimension-stroke-width-025, 2px);\n background: var(--color-foreground-primary);\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--effect-motion-short-2, 100ms ease-in-out);\n}\n\n.panel-nav__resize-handle--overlay::after {\n opacity: 1;\n}\n\n/* ── Reduced motion ──────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .panel-nav,\n .panel-nav *,\n .panel-nav *::before,\n .panel-nav *::after,\n .panel-nav__resize-handle,\n .panel-nav__resize-handle::before,\n .panel-nav__resize-handle::after {\n transition-duration: 0.01ms !important;\n animation-duration: 0.01ms !important;\n transition-delay: 0.01ms !important;\n }\n}\n","import { Component, Prop, Event, EventEmitter, Watch, State, Element, h, Host } from '@stencil/core';\nimport type { ChromeTransitionDetail } from '../../nav/chrome-transition';\nimport type { NavChromeStyle } from '../../nav/nav-chrome';\nimport {\n deriveActiveIdFromUrl,\n parsePanelNavGroups,\n resolvePanelNavDisableVt,\n resolvePanelNavStyle,\n shouldResyncPanelNavGroups,\n shouldResyncPanelNavStyle,\n} from './panel-nav-utils';\nimport {\n PANEL_NAV_USER_MENU_ANCHOR_ID,\n type PanelNavGroup,\n type PanelNavItem,\n type PanelNavRouterMode,\n type PanelNavUserActionDetail,\n} from './panel-nav-types';\n\n@Component({\n tag: 'ds-panel-nav',\n styleUrl: 'PanelNav.css',\n styleUrls: ['../../utils/scroll-edge-fade.css'],\n scoped: true,\n})\nexport class PanelNav {\n /** Style slot: `dashboard` or `settings`. Colors match for now;\n * class hooks reserved for texture/glyph layers. Property: `navStyle`. Attribute: `nav-style`. */\n @Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'dashboard';\n\n /** When `true`, style changes apply synchronously — host app owns view transitions. */\n @Prop() disableViewTransition: boolean = false;\n\n /** Nav groups — set via JS property (`el.groups = [...]`) or JSON string attribute. */\n @Prop() groups: string | PanelNavGroup[] = '[]';\n\n /** How items with `href` render:\n * - `anchor` (default): native `<a href>` — works with routers that intercept anchors.\n * - `event`: always `<button>`; host handles navigation via `dsNavSelect`. */\n @Prop() routerMode: PanelNavRouterMode = 'anchor';\n\n /** ID of the currently active/selected nav item. Overridden by `currentUrl` matching when set. */\n @Prop() activeId: string = '';\n\n /** Whether the nav is in collapsed (icon-only) state.\n * Set `storageKey` to persist across reloads. `dsNavToggle` still fires on change. */\n @Prop({ mutable: true }) collapsed: boolean = false;\n\n /** Viewport width (px) below which the nav auto-collapses to icon-only mode. 0 = disabled. */\n @Prop() breakpoint: number = 0;\n\n /** `localStorage` key used to persist the collapsed state across page loads.\n * When set, collapsed state is restored on mount and written on each toggle. */\n @Prop() storageKey: string = '';\n\n /** Current route URL (e.g. `window.location.pathname` or the router's active URL).\n * When set the component derives the active item by matching item `href` values\n * against this string (longest segment-boundary prefix wins), overriding `activeId`. */\n @Prop() currentUrl: string = '';\n\n /** Display name for the footer user section */\n @Prop() userName: string = '';\n\n /** Single character shown in the collapsed avatar */\n @Prop() userInitial: string = '';\n\n /** Emitted when a nav item is clicked. Detail = the item's `id`. */\n @Event() dsNavSelect!: EventEmitter<string>;\n\n /** Emitted when the collapse toggle is clicked. Detail = new collapsed state. */\n @Event() dsNavToggle!: EventEmitter<boolean>;\n\n /** Bubbling lifecycle — `ds-app-shell` pauses chrome metrics during width motion. */\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionStart!: EventEmitter<ChromeTransitionDetail>;\n\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionEnd!: EventEmitter<ChromeTransitionDetail>;\n\n /** Emitted when the footer left button (gear / dashboard) is clicked. */\n @Event() dsNavFooterAction!: EventEmitter<void>;\n\n /** Emitted when the footer user button is clicked. Detail includes the anchor for `ds-menu`. */\n @Event() dsNavUserAction!: EventEmitter<PanelNavUserActionDetail>;\n\n @Element() el!: HTMLElement;\n\n @State() private renderedStyle: NavChromeStyle = 'dashboard';\n @State() private parsedGroups: PanelNavGroup[] = [];\n @State() private atBottom = false;\n @State() private isAnimating = false;\n @State() private rovingIndex: number = 0;\n @State() private viewportNarrow: boolean = false;\n @State() private urlDerivedActiveId: string = '';\n\n private transitionEndHandler?: (e: TransitionEvent) => void;\n private resizeObserver?: ResizeObserver;\n\n // Drag-to-resize state (not @State — no re-render needed)\n private isDragging = false;\n private dragStartX = 0;\n private didSnap = false;\n private lastDeltaX = 0;\n private edgeOverlayTimer: number | null = null;\n private globalMouseMoveHandler?: (e: MouseEvent) => void;\n private globalMouseUpHandler?: () => void;\n\n @State() private showEdgeOverlay = false;\n\n private static readonly HOST_PROP_SYNC_BUDGET = 8;\n\n /** The ID that should be treated as active. `currentUrl` matching takes precedence\n * over `activeId` when both are present. */\n private get effectiveActiveId(): string {\n return this.urlDerivedActiveId || this.activeId;\n }\n\n private get effectiveDisableViewTransition(): boolean {\n return resolvePanelNavDisableVt(\n this.disableViewTransition,\n this.el.getAttribute('disable-view-transition'),\n );\n }\n\n @Watch('collapsed')\n onCollapsedChange(_next: boolean, prev: boolean | undefined) {\n if (prev === undefined) return;\n this.startCollapseAnimation();\n }\n\n @Watch('viewportNarrow')\n onViewportNarrowChange(_next: boolean, prev: boolean | undefined) {\n if (prev === undefined) return;\n this.startCollapseAnimation();\n }\n\n @Watch('breakpoint')\n onBreakpointChange() {\n this.disconnectResizeObserver();\n if (this.breakpoint > 0) this.connectResizeObserver();\n }\n\n @Watch('groups')\n onGroupsChange(val: string | PanelNavGroup[]) {\n this.parsedGroups = parsePanelNavGroups(val);\n this.rovingIndex = 0;\n this.syncActiveFromUrl();\n }\n\n @Watch('activeId')\n @Watch('urlDerivedActiveId')\n onActiveIdChange() {\n /* Active route updates aria-current only — roving tab stop stays user-controlled. */\n }\n\n @Watch('currentUrl')\n onCurrentUrlChange() {\n this.syncActiveFromUrl();\n }\n\n @Watch('navStyle')\n onNavStyleChange(newVal: NavChromeStyle) {\n this.renderedStyle = newVal;\n }\n\n componentWillLoad() {\n this.renderedStyle = resolvePanelNavStyle(this.navStyle, this.el.getAttribute('nav-style'));\n if (this.storageKey) {\n try {\n const stored = localStorage.getItem(this.storageKey);\n if (stored !== null) this.collapsed = stored === 'true';\n } catch { /* localStorage unavailable */ }\n }\n this.onGroupsChange(this.groups);\n this.syncActiveFromUrl();\n }\n\n componentDidLoad() {\n this.syncHostPropsIfNeeded();\n this.scheduleDeferredHostPropSync();\n this.checkScroll();\n if (this.breakpoint > 0) this.connectResizeObserver();\n }\n\n disconnectedCallback() {\n this.disconnectResizeObserver();\n this.clearEdgeOverlayTimer();\n if (this.globalMouseMoveHandler) {\n window.removeEventListener('mousemove', this.globalMouseMoveHandler);\n }\n if (this.globalMouseUpHandler) {\n window.removeEventListener('mouseup', this.globalMouseUpHandler);\n }\n }\n\n private startCollapseAnimation() {\n this.isAnimating = true;\n this.dsChromeTransitionStart.emit({ source: 'panel-nav' });\n const panel = this.el.querySelector('.panel-nav') as HTMLElement | null;\n const widthBefore = panel?.getBoundingClientRect().width ?? 0;\n if (this.transitionEndHandler) {\n panel?.removeEventListener('transitionend', this.transitionEndHandler);\n }\n this.transitionEndHandler = (e: TransitionEvent) => {\n if (e.propertyName === 'width') {\n this.finishCollapseAnimation(panel);\n }\n };\n panel?.addEventListener('transitionend', this.transitionEndHandler);\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (!this.isAnimating) return;\n const widthAfter = panel?.getBoundingClientRect().width ?? 0;\n if (Math.abs(widthAfter - widthBefore) < 1) {\n this.finishCollapseAnimation(panel);\n }\n });\n });\n }\n\n private finishCollapseAnimation(panel: HTMLElement | null) {\n if (!this.isAnimating) return;\n this.isAnimating = false;\n this.dsChromeTransitionEnd.emit({ source: 'panel-nav' });\n if (this.transitionEndHandler) {\n panel?.removeEventListener('transitionend', this.transitionEndHandler);\n }\n }\n\n private connectResizeObserver() {\n this.viewportNarrow = window.innerWidth < this.breakpoint;\n this.resizeObserver = new ResizeObserver(() => {\n this.viewportNarrow = window.innerWidth < this.breakpoint;\n });\n this.resizeObserver.observe(document.documentElement);\n }\n\n private disconnectResizeObserver() {\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n }\n\n /** Derive active ID from the current URL by matching item `href` values.\n * Uses longest segment-boundary prefix match. */\n private syncActiveFromUrl() {\n if (!this.currentUrl) {\n this.urlDerivedActiveId = '';\n return;\n }\n this.urlDerivedActiveId = deriveActiveIdFromUrl(this.currentUrl, this.getAllItems());\n }\n\n /** Re-parse props assigned by the host after componentWillLoad (Angular ngAfterViewInit). */\n private syncHostPropsIfNeeded() {\n if (shouldResyncPanelNavStyle(this.renderedStyle, this.navStyle)) {\n this.renderedStyle = this.navStyle;\n }\n\n if (shouldResyncPanelNavGroups(this.parsedGroups, this.groups)) {\n this.onGroupsChange(this.groups);\n } else if (this.currentUrl) {\n this.syncActiveFromUrl();\n }\n }\n\n /** Poll across animation frames — host props may land without triggering @Watch. */\n private scheduleDeferredHostPropSync() {\n let remaining = PanelNav.HOST_PROP_SYNC_BUDGET;\n const tick = () => {\n this.syncHostPropsIfNeeded();\n if (--remaining > 0) {\n requestAnimationFrame(tick);\n }\n };\n queueMicrotask(tick);\n }\n\n /** Centralised toggle: updates `collapsed`, emits `dsNavToggle`, optionally persists. */\n private applyToggle(next: boolean) {\n this.collapsed = next;\n if (this.storageKey) {\n try { localStorage.setItem(this.storageKey, String(next)); } catch { /* unavailable */ }\n }\n this.dsNavToggle.emit(next);\n }\n\n private getAllItems(): PanelNavItem[] {\n return this.parsedGroups.flatMap(g => g.items);\n }\n\n private getRovingTotal(): number {\n return 1 + this.getAllItems().length + 2;\n }\n\n private getFooterRovingIndex(): number {\n return 1 + this.getAllItems().length;\n }\n\n private getUserRovingIndex(): number {\n return this.getFooterRovingIndex() + 1;\n }\n\n private getRovingElement(index: number): HTMLElement | null {\n const itemCount = this.getAllItems().length;\n if (index === 0) {\n return this.el.querySelector('.panel-nav__header-btn');\n }\n if (index >= 1 && index <= itemCount) {\n const items = this.el.querySelectorAll<HTMLElement>('.panel-nav__body .panel-nav__item');\n return items[index - 1] ?? null;\n }\n if (index === this.getFooterRovingIndex()) {\n return this.el.querySelector('.panel-nav__footer-btn .button-icon');\n }\n if (index === this.getUserRovingIndex()) {\n return this.el.querySelector('.panel-nav__footer-user');\n }\n return null;\n }\n\n private focusRovingAt(index: number) {\n this.rovingIndex = index;\n this.getRovingElement(index)?.focus({ preventScroll: true });\n }\n\n private activateRovingIndex(index: number) {\n const itemCount = this.getAllItems().length;\n const items = this.getAllItems();\n if (index === 0) {\n this.handleToggle();\n return;\n }\n if (index >= 1 && index <= itemCount) {\n this.handleItemClick(items[index - 1].id);\n return;\n }\n if (index === this.getFooterRovingIndex()) {\n this.handleFooterAction();\n return;\n }\n if (index === this.getUserRovingIndex()) {\n const anchor = this.el.querySelector(`#${PANEL_NAV_USER_MENU_ANCHOR_ID}`) as HTMLElement | null;\n if (anchor) this.dsNavUserAction.emit({ anchor });\n }\n }\n\n private handleRovingKeyDown(e: KeyboardEvent, index: number) {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.activateRovingIndex(index);\n return;\n }\n\n const total = this.getRovingTotal();\n const footerIdx = this.getFooterRovingIndex();\n const userIdx = this.getUserRovingIndex();\n let next: number;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (index === footerIdx) next = userIdx;\n else if (index === userIdx) next = 0;\n else next = (index + 1) % total;\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (index === 0) next = userIdx;\n else if (index === userIdx) next = footerIdx;\n else next = (index - 1 + total) % total;\n break;\n case 'ArrowRight':\n if (index === footerIdx) {\n e.preventDefault();\n next = userIdx;\n } else return;\n break;\n case 'ArrowLeft':\n if (index === userIdx) {\n e.preventDefault();\n next = footerIdx;\n } else return;\n break;\n case 'Home':\n e.preventDefault();\n next = 0;\n break;\n case 'End':\n e.preventDefault();\n next = userIdx;\n break;\n default:\n return;\n }\n\n this.focusRovingAt(next);\n }\n\n private checkScroll() {\n const body = this.el.querySelector('.panel-nav__body') as HTMLElement | null;\n if (!body) return;\n const remaining = body.scrollHeight - body.scrollTop - body.clientHeight;\n this.atBottom = remaining < 2;\n }\n\n private handleBodyScroll(e: Event) {\n const body = e.target as HTMLElement;\n const remaining = body.scrollHeight - body.scrollTop - body.clientHeight;\n this.atBottom = remaining < 2;\n }\n\n private handleItemClick(id: string) {\n this.dsNavSelect.emit(id);\n }\n\n private handleToggle() {\n this.applyToggle(!this.collapsed);\n }\n\n private handleFooterAction() {\n this.dsNavFooterAction.emit();\n }\n\n private handleUserAction(e: MouseEvent) {\n const anchor = e.currentTarget as HTMLElement;\n this.dsNavUserAction.emit({ anchor });\n }\n\n private clearEdgeOverlayTimer() {\n if (this.edgeOverlayTimer !== null) {\n window.clearTimeout(this.edgeOverlayTimer);\n this.edgeOverlayTimer = null;\n }\n }\n\n private handleResizeHandleMouseEnter() {\n this.clearEdgeOverlayTimer();\n this.edgeOverlayTimer = window.setTimeout(() => {\n this.showEdgeOverlay = true;\n this.edgeOverlayTimer = null;\n }, 500);\n }\n\n private handleResizeHandleMouseLeave() {\n if (this.isDragging) return;\n this.clearEdgeOverlayTimer();\n this.showEdgeOverlay = false;\n }\n\n private handleResizeHandleMouseDown(e: MouseEvent) {\n e.preventDefault();\n e.stopPropagation();\n\n const wasCollapsed = this.collapsed || this.viewportNarrow;\n this.isDragging = true;\n this.dragStartX = e.clientX;\n this.didSnap = false;\n this.lastDeltaX = 0;\n this.clearEdgeOverlayTimer();\n this.showEdgeOverlay = false;\n\n document.body.style.cursor = 'ew-resize';\n document.body.style.userSelect = 'none';\n\n const onMove = (ev: MouseEvent) => {\n const deltaX = ev.clientX - this.dragStartX;\n this.lastDeltaX = Math.abs(deltaX);\n if (this.didSnap) return;\n if (!wasCollapsed && deltaX < -8) {\n this.applyToggle(true);\n this.didSnap = true;\n } else if (wasCollapsed && deltaX > 8) {\n this.applyToggle(false);\n this.didSnap = true;\n }\n };\n\n const onUp = () => {\n if (!this.didSnap && this.lastDeltaX < 3) {\n this.applyToggle(!wasCollapsed);\n }\n this.isDragging = false;\n this.showEdgeOverlay = false;\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n this.globalMouseMoveHandler = undefined;\n this.globalMouseUpHandler = undefined;\n };\n\n this.globalMouseMoveHandler = onMove;\n this.globalMouseUpHandler = onUp;\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n }\n\n private renderNavItem(item: PanelNavItem, idx: number, collapsed: boolean) {\n const isActive = item.id === this.effectiveActiveId;\n const rovingPosition = idx + 1;\n\n const itemContent = [\n <span class=\"panel-nav__item-icon\">\n <ds-icon name={item.icon} size=\"md\" color=\"inherit\" flag={item.flag} />\n </span>,\n <span class=\"panel-nav__item-label\">\n <span class=\"panel-nav__item-label-text\">\n <ds-text\n as=\"span\"\n variant={isActive ? 'text-body-medium-emphasis' : 'text-body-medium'}\n color=\"inherit\"\n >\n {item.label}\n </ds-text>\n </span>\n </span>,\n item.dot && (\n <ds-badge\n class=\"panel-nav__item-dot\"\n variant=\"dot\"\n background=\"var(--_nav-bg)\"\n label=\"\"\n aria-hidden=\"true\"\n />\n ),\n ];\n\n const sharedProps = {\n class: {\n 'panel-nav__item': true,\n 'panel-nav__item--active': isActive,\n 'ds-focus-ring-inset': true,\n },\n 'aria-current': isActive ? ('page' as const) : undefined,\n title: collapsed ? item.label : undefined,\n tabIndex: rovingPosition === this.rovingIndex ? 0 : -1,\n onClick: () => this.handleItemClick(item.id),\n onKeyDown: (e: KeyboardEvent) => this.handleRovingKeyDown(e, rovingPosition),\n onFocus: () => { this.rovingIndex = rovingPosition; },\n };\n\n const useAnchor = this.routerMode === 'anchor' && item.href;\n\n return useAnchor\n ? <a {...sharedProps} href={item.href}>{itemContent}</a>\n : <button {...sharedProps} type=\"button\">{itemContent}</button>;\n }\n\n render() {\n const chromeStyle = this.renderedStyle;\n const isDashboardChrome = chromeStyle === 'dashboard';\n const isDashboard = this.navStyle === 'dashboard';\n const collapsed = this.collapsed || this.viewportNarrow;\n const { userName, userInitial } = this;\n\n const navCls: Record<string, boolean> = {\n 'panel-nav': true,\n 'panel-nav--dashboard': isDashboard,\n 'panel-nav--settings': !isDashboard,\n 'panel-nav--collapsed': collapsed,\n 'panel-nav--animating': this.isAnimating,\n 'panel-nav--at-bottom': this.atBottom,\n };\n\n return (\n <Host style={{ display: 'block', position: 'relative' }}>\n <nav\n class={navCls}\n aria-label={isDashboardChrome ? 'Dashboard navigation' : 'Settings navigation'}\n >\n\n {/* ── Header: Motive logo, reveals collapse toggle on hover ── */}\n <div class=\"panel-nav__header\">\n <button\n type=\"button\"\n class=\"panel-nav__header-btn ds-focus-ring-inset\"\n tabIndex={this.rovingIndex === 0 ? 0 : -1}\n onClick={() => this.handleToggle()}\n onKeyDown={(e: KeyboardEvent) => this.handleRovingKeyDown(e, 0)}\n onFocus={() => { this.rovingIndex = 0; }}\n aria-label={collapsed ? 'Expand navigation' : 'Collapse navigation'}\n aria-expanded={collapsed ? 'false' : 'true'}\n >\n {/* Motive M mark — fades out on hover to reveal collapse toggle */}\n <span class=\"panel-nav__header-logo\" aria-hidden=\"true\">\n <svg class=\"panel-nav__m-mark\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" focusable=\"false\" aria-hidden=\"true\">\n <path d=\"M11.1159 4.31537H7.67021L2.53401 13.0703H0V15.6875H4.02716L8.24319 8.49978V15.6846H11.6342L15.8289 8.47829V15.6846H18.7122V4.3125H15.2559L11.1159 11.3648V4.31537Z\" fill=\"currentColor\"/>\n </svg>\n </span>\n {/* Collapse / expand icon — revealed on hover via CSS */}\n <span class=\"panel-nav__header-toggle\" aria-hidden=\"true\">\n <ds-icon\n name={collapsed ? 'LeftExpandB' : 'LeftCollapseB'}\n size=\"md\"\n color=\"inherit\"\n />\n </span>\n </button>\n </div>\n\n {/* ── Scrollable body ── */}\n <div\n class={{\n 'panel-nav__body': true,\n 'scroll-edge-fade': true,\n 'scroll-edge-fade--bottom': true,\n 'scroll-edge-fade--at-end': this.atBottom,\n }}\n onScroll={e => this.handleBodyScroll(e)}\n >\n {(() => {\n let flatIdx = 0;\n return this.parsedGroups.map(group => (\n <div class=\"panel-nav__group\">\n {group.label && (\n <span class=\"panel-nav__group-label\">\n <span class=\"panel-nav__item-label-text\">\n <ds-text as=\"span\" variant=\"text-caption-emphasis\" color=\"inherit\">\n {group.label}\n </ds-text>\n </span>\n </span>\n )}\n {group.items.map(item => this.renderNavItem(item, flatIdx++, collapsed))}\n </div>\n ));\n })()}\n </div>\n\n {/* ── Footer ── */}\n <div class=\"panel-nav__footer\">\n <ds-button-unfilled-icon\n class=\"panel-nav__footer-btn\"\n icon={isDashboardChrome ? 'Gear' : 'Dashboard'}\n activeFill={false}\n focusTabIndex={this.rovingIndex === this.getFooterRovingIndex() ? 0 : -1}\n title={isDashboardChrome ? 'Settings' : 'Dashboard'}\n aria-label={isDashboardChrome ? 'Open settings' : 'Go to dashboard'}\n onDsClick={() => this.handleFooterAction()}\n onKeyDown={(e: KeyboardEvent) => this.handleRovingKeyDown(e, this.getFooterRovingIndex())}\n onFocusin={() => { this.rovingIndex = this.getFooterRovingIndex(); }}\n />\n\n {/* Right user — label fades like nav items; right icon cross-fades chevron ↔ circle+initial */}\n <button\n type=\"button\"\n id={PANEL_NAV_USER_MENU_ANCHOR_ID}\n class=\"panel-nav__item panel-nav__footer-user ds-focus-ring-inset\"\n tabIndex={this.rovingIndex === this.getUserRovingIndex() ? 0 : -1}\n aria-label={collapsed ? `User: ${userName}` : `User menu for ${userName}`}\n onClick={(e) => this.handleUserAction(e)}\n onKeyDown={(e: KeyboardEvent) => this.handleRovingKeyDown(e, this.getUserRovingIndex())}\n onFocus={() => { this.rovingIndex = this.getUserRovingIndex(); }}\n >\n <span class=\"panel-nav__item-label panel-nav__footer-user-label\">\n <span class=\"panel-nav__item-label-text\">\n <ds-text as=\"span\" variant=\"text-body-medium-emphasis\" color=\"inherit\">\n {userName}\n </ds-text>\n </span>\n </span>\n <span class=\"panel-nav__item-icon panel-nav__footer-user-icon\" aria-hidden=\"true\">\n <span class=\"panel-nav__footer-icon-expanded\">\n <ds-icon name=\"ChevronUpDown\" size=\"md\" color=\"inherit\" />\n </span>\n <span class=\"panel-nav__footer-icon-collapsed\">\n <ds-icon name=\"Circle\" size=\"md\" color=\"inherit\" />\n <span class=\"panel-nav__user-initial\">\n <ds-text as=\"span\" variant=\"text-caption-emphasis\" color=\"inherit\">\n {userInitial}\n </ds-text>\n </span>\n </span>\n </span>\n </button>\n </div>\n\n </nav>\n\n {/* Drag-to-resize handle — always rendered, hidden only when auto-collapsed by breakpoint */}\n {!this.viewportNarrow && (\n <div\n class={{\n 'panel-nav__resize-handle': true,\n 'panel-nav__resize-handle--overlay': this.showEdgeOverlay,\n }}\n onMouseEnter={() => this.handleResizeHandleMouseEnter()}\n onMouseLeave={() => this.handleResizeHandleMouseLeave()}\n onMouseDown={(e: MouseEvent) => this.handleResizeHandleMouseDown(e)}\n aria-hidden=\"true\"\n />\n )}\n </Host>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["NAV_STYLE_HINT_ATTR","readNavStyleAttr","attr","undefined","resolveNavChromeStyle","styleProp","hostAttr","docHint","fromHost","hint","document","documentElement","getAttribute","fromHint","shouldResyncNavChromeStyle","renderedStyle","style","hrefMatchesPath","path","href","startsWith","deriveActiveIdFromUrl","items","bestId","bestLen","item","length","id","countPanelNavItems","groups","reduce","sum","g","parsePanelNavGroups","Array","isArray","parsed","JSON","parse","resolvePanelNavDisableVt","prop","shouldResyncPanelNavGroups","parsedGroups","PANEL_NAV_USER_MENU_ANCHOR_ID","scrollEdgeFadeCss","panelNavCss","PanelNav","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","navStyle","disableViewTransition","routerMode","activeId","collapsed","breakpoint","storageKey","currentUrl","userName","userInitial","atBottom","isAnimating","rovingIndex","viewportNarrow","urlDerivedActiveId","isDragging","dragStartX","didSnap","lastDeltaX","edgeOverlayTimer","showEdgeOverlay","effectiveActiveId","effectiveDisableViewTransition","el","onCollapsedChange","_next","prev","startCollapseAnimation","onViewportNarrowChange","onBreakpointChange","disconnectResizeObserver","connectResizeObserver","onGroupsChange","val","syncActiveFromUrl","onActiveIdChange","onCurrentUrlChange","onNavStyleChange","newVal","componentWillLoad","resolvePanelNavStyle","stored","localStorage","getItem","componentDidLoad","syncHostPropsIfNeeded","scheduleDeferredHostPropSync","checkScroll","disconnectedCallback","clearEdgeOverlayTimer","globalMouseMoveHandler","window","removeEventListener","globalMouseUpHandler","dsChromeTransitionStart","emit","source","panel","querySelector","widthBefore","getBoundingClientRect","width","transitionEndHandler","e","propertyName","finishCollapseAnimation","addEventListener","requestAnimationFrame","widthAfter","Math","abs","dsChromeTransitionEnd","innerWidth","resizeObserver","ResizeObserver","observe","disconnect","getAllItems","shouldResyncPanelNavStyle","remaining","HOST_PROP_SYNC_BUDGET","tick","queueMicrotask","applyToggle","next","setItem","String","dsNavToggle","flatMap","getFooterRovingIndex","getUserRovingIndex","getRovingElement","index","itemCount","querySelectorAll","focusRovingAt","focus","preventScroll","activateRovingIndex","handleToggle","handleItemClick","handleFooterAction","anchor","dsNavUserAction","handleRovingKeyDown","key","preventDefault","footerIdx","userIdx","body","scrollHeight","scrollTop","clientHeight","handleBodyScroll","target","dsNavSelect","toggleCollapsed","dsNavFooterAction","handleUserAction","currentTarget","clearTimeout","handleResizeHandleMouseEnter","setTimeout","handleResizeHandleMouseLeave","handleResizeHandleMouseDown","stopPropagation","wasCollapsed","clientX","cursor","userSelect","onMove","ev","deltaX","onUp","renderNavItem","idx","isActive","rovingPosition","itemContent","h","class","name","icon","size","color","flag","as","variant","label","dot","background","sharedProps","title","tabIndex","onClick","onKeyDown","onFocus","useAnchor","type","render","chromeStyle","isDashboardChrome","isDashboard","navCls","Host","display","position","viewBox","fill","xmlns","focusable","d","onScroll","flatIdx","map","group","activeFill","focusTabIndex","onDsClick","onFocusin","onMouseEnter","onMouseLeave","onMouseDown"],"sources":["src/wc/nav/nav-chrome.ts","src/wc/components/PanelNav/panel-nav-utils.ts","src/wc/components/PanelNav/panel-nav-types.ts","src/wc/utils/scroll-edge-fade.css?tag=ds-panel-nav&encapsulation=scoped","src/wc/components/PanelNav/PanelNav.css?tag=ds-panel-nav&encapsulation=scoped","src/wc/components/PanelNav/PanelNav.tsx"],"sourcesContent":["/** Nav chrome style slot — dashboard vs settings. Colors unified for now; texture hooks use the class. */\nexport type NavChromeStyle = 'dashboard' | 'settings';\n\n/** Document hint for first paint before framework props land. */\nexport const NAV_STYLE_HINT_ATTR = 'data-nav-style';\n\nexport function readNavStyleAttr(attr: string | null): NavChromeStyle | undefined {\n if (attr === 'dashboard' || attr === 'settings') return attr;\n return undefined;\n}\n\nexport function setNavStyleHint(style: NavChromeStyle): void {\n if (typeof document === 'undefined') return;\n document.documentElement.setAttribute(NAV_STYLE_HINT_ATTR, style);\n}\n\nexport function clearNavStyleHint(): void {\n if (typeof document === 'undefined') return;\n document.documentElement.removeAttribute(NAV_STYLE_HINT_ATTR);\n}\n\nexport function resolveNavChromeStyle(\n styleProp: NavChromeStyle,\n hostAttr: string | null,\n docHint?: string | null,\n): NavChromeStyle {\n const fromHost = readNavStyleAttr(hostAttr);\n if (fromHost) return fromHost;\n\n const hint =\n docHint !== undefined\n ? docHint\n : typeof document !== 'undefined'\n ? document.documentElement.getAttribute(NAV_STYLE_HINT_ATTR)\n : null;\n const fromHint = readNavStyleAttr(hint);\n if (fromHint) return fromHint;\n\n return styleProp;\n}\n\nexport function shouldResyncNavChromeStyle(\n renderedStyle: NavChromeStyle,\n style: NavChromeStyle,\n): boolean {\n return renderedStyle !== style;\n}\n","import type { PanelNavGroup, PanelNavItem } from './panel-nav-types';\nimport {\n NAV_STYLE_HINT_ATTR,\n clearNavStyleHint,\n readNavStyleAttr,\n resolveNavChromeStyle,\n setNavStyleHint,\n shouldResyncNavChromeStyle,\n} from '../../nav/nav-chrome';\n\nexport type { NavChromeStyle } from '../../nav/nav-chrome';\nexport {\n NAV_STYLE_HINT_ATTR,\n readNavStyleAttr,\n setNavStyleHint,\n clearNavStyleHint,\n resolveNavChromeStyle as resolvePanelNavStyle,\n shouldResyncNavChromeStyle as shouldResyncPanelNavStyle,\n};\n\n/** Whether `path` matches `href` at a segment boundary (exact or child path). */\nexport function hrefMatchesPath(path: string, href: string): boolean {\n return path === href || path.startsWith(`${href}/`);\n}\n\n/** Derive the active nav item id from a URL using longest segment-boundary prefix match. */\nexport function deriveActiveIdFromUrl(path: string, items: PanelNavItem[]): string {\n if (!path) return '';\n\n let bestId = '';\n let bestLen = 0;\n\n for (const item of items) {\n if (!item.href) continue;\n if (hrefMatchesPath(path, item.href) && item.href.length > bestLen) {\n bestId = item.id;\n bestLen = item.href.length;\n }\n }\n\n return bestId;\n}\n\n/** Total nav item count across all groups. */\nexport function countPanelNavItems(groups: PanelNavGroup[]): number {\n return groups.reduce((sum, g) => sum + g.items.length, 0);\n}\n\n/** Parse `groups` from either a JSON attribute string or a JS property array. */\nexport function parsePanelNavGroups(groups: string | unknown): PanelNavGroup[] {\n if (Array.isArray(groups)) return groups;\n if (typeof groups === 'string') {\n try {\n const parsed = JSON.parse(groups);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n return [];\n}\n\n/** Resolve whether VT is disabled from prop and/or host attribute. */\nexport function resolvePanelNavDisableVt(prop: boolean, attr: string | null): boolean {\n if (prop) return true;\n if (attr === null) return false;\n return attr !== 'false';\n}\n\n/** True when host `groups` has items but internal parsed state is still empty. */\nexport function shouldResyncPanelNavGroups(\n parsedGroups: PanelNavGroup[],\n groups: string | unknown,\n): boolean {\n return (\n countPanelNavItems(parsedGroups) === 0 &&\n countPanelNavItems(parsePanelNavGroups(groups)) > 0\n );\n}\n","import type { NavChromeStyle } from '../../nav/nav-chrome';\n\nexport type { NavChromeStyle };\nexport type PanelNavRouterMode = 'anchor' | 'event';\n\nexport interface PanelNavItem {\n id: string;\n icon: string;\n label: string;\n /** Show a notification dot badge on the item */\n dot?: boolean;\n flag?: boolean;\n /** Route path used for `currentUrl` matching. In `anchor` mode also sets `<a href>`.\n * In `event` mode navigation is delegated to the host via `dsNavSelect`. */\n href?: string;\n}\n\nexport interface PanelNavGroup {\n id?: string;\n label?: string;\n items: PanelNavItem[];\n}\n\n/** Stable `id` on the footer user button — use with `ds-menu` `anchor-id`. */\nexport const PANEL_NAV_USER_MENU_ANCHOR_ID = 'ds-panel-nav-user-menu-anchor';\n\n/** Detail for `dsNavUserAction` — anchor element for an external `ds-menu`. */\nexport interface PanelNavUserActionDetail {\n anchor: HTMLElement;\n}\n","/**\n * Scroll-edge alpha fade — apply to overflow scroll containers.\n * Pair with `.scroll-edge-fade--at-end` when the relevant edge is flush (no fade).\n *\n * @see scroll-edge-fade.ts for programmatic mask helpers.\n */\n\n.scroll-edge-fade {\n --ds-scroll-edge-fade-size: var(--dimension-size-600);\n}\n\n.scroll-edge-fade--top {\n -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 50%, transparent 100%);\n mask-image: linear-gradient(to bottom, #000 0, #000 50%, transparent 100%);\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--bottom {\n -webkit-mask-image: linear-gradient(\n to bottom,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n mask-image: linear-gradient(\n to bottom,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--left {\n -webkit-mask-image: linear-gradient(\n to right,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n mask-image: linear-gradient(\n to right,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--right {\n -webkit-mask-image: linear-gradient(\n to left,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n mask-image: linear-gradient(\n to left,\n #000 0,\n #000 calc(100% - var(--ds-scroll-edge-fade-size)),\n transparent 100%\n );\n -webkit-mask-size: 100% 100%;\n mask-size: 100% 100%;\n}\n\n.scroll-edge-fade--at-end {\n -webkit-mask-image: none;\n mask-image: none;\n}\n","@import '../../utils/focus-ring.css';\n\n/* ── Theme variables ──────────────────────────────────────────────────────── */\n\n.panel-nav {\n /* ─ Sizes ─ */\n --_nav-width: var(--dimension-panel-width-2xs);\n --_nav-width-collapsed: var(--dimension-size-600);\n --_nav-item-height: var(--dimension-size-400, 32px);\n --_nav-padding-x: var(--dimension-space-100, 8px);\n --_nav-padding-y: var(--dimension-space-100, 8px);\n /* gear button outer width = padding*2 + icon */\n --_nav-footer-btn-w: calc(var(--dimension-space-075, 6px) * 2 + var(--dimension-iconography-md, 20px));\n\n /* ─ Motion ─ */\n /* --ds-panel-nav-speed: unitless multiplier; override in Storybook to slow-mo (e.g. 10 = 10×).\n *-dur vars are duration-only (needed for calc); *-motion vars add easing for use in transitions. */\n --_nav-speed: var(--ds-panel-nav-speed, 1);\n --_nav-expand-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-expand-motion: var(--_nav-expand-dur) var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-label-fade-motion: var(--_nav-label-fade-dur) var(--effect-animation-easing-ease-in-out, ease);\n --_nav-label-fade-out-dur: calc(var(--_nav-speed) * var(--effect-animation-duration-medium-1, 300ms));\n --_nav-label-fade-out-motion: var(--_nav-label-fade-out-dur) var(--effect-animation-easing-ease-in-out, ease);\n\n /* ─ Colours – default chrome (app surfaces) ─ */\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Default chrome overrides ────────────────────────────────────────────── */\n\n/* Shell-owned chrome (bg + wash +/or grid) — panel is a transparent frame. */\n:host-context(ds-app-shell[gradient]) .panel-nav,\n:host-context(ds-app-shell[grid]) .panel-nav {\n background-color: transparent;\n}\n\n/* Style slots — same app tokens for now; hook texture/glyph layers on these classes later. */\n.panel-nav--dashboard,\n.panel-nav--settings {\n --_nav-bg: var(--color-background-secondary);\n --_nav-border: var(--color-border-tertiary);\n --_nav-divider: var(--color-border-tertiary);\n --_nav-fg-primary: var(--color-foreground-primary);\n --_nav-fg-secondary: var(--color-foreground-secondary);\n --_nav-fg-tertiary: var(--color-foreground-tertiary);\n --_nav-hover: var(--color-interaction-hover);\n --_nav-pressed: var(--color-interaction-pressed);\n --_nav-focus: var(--color-interaction-focus);\n --_nav-dot: var(--color-foreground-bold-brand);\n}\n\n/* ── Shell ───────────────────────────────────────────────────────────────── */\n\n.panel-nav {\n display: flex;\n flex-direction: column;\n position: relative;\n width: var(--_nav-width);\n min-width: var(--_nav-width);\n height: 100%;\n background-color: var(--_nav-bg);\n border-right: var(--dimension-stroke-width-012, 1px) solid var(--_nav-border);\n box-sizing: border-box;\n overflow: visible;\n transition:\n width var(--_nav-expand-motion),\n min-width var(--_nav-expand-motion),\n background-color var(--effect-motion-short-3, 200ms ease),\n border-color var(--effect-motion-short-3, 200ms ease);\n font-family: var(--typography-font-family, system-ui);\n isolation: isolate;\n}\n\n.panel-nav__header,\n.panel-nav__body,\n.panel-nav__footer {\n position: relative;\n z-index: 3;\n}\n\n.panel-nav--collapsed {\n width: var(--_nav-width-collapsed);\n min-width: var(--_nav-width-collapsed);\n}\n\n/* ── Header ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__header {\n display: flex;\n align-items: center;\n height: var(--dimension-size-600, 48px);\n padding: var(--dimension-space-100, 8px);\n flex-shrink: 0;\n box-sizing: border-box;\n border-bottom: var(--dimension-stroke-width-012, 1px) solid var(--_nav-divider);\n transition: border-color var(--effect-motion-short-3, 200ms ease);\n}\n\n.panel-nav__header-btn {\n all: unset;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--dimension-space-075, 6px);\n border-radius: var(--dimension-radius-025, 2px);\n cursor: pointer;\n color: var(--_nav-fg-primary);\n position: relative;\n flex-shrink: 0;\n box-sizing: border-box;\n transition: color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* Interaction pseudo-element */\n.panel-nav__header-btn::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--dimension-radius-025, 2px);\n background: transparent;\n pointer-events: none;\n transition: none;\n}\n\n.panel-nav__header-btn:hover::after { background: var(--_nav-hover); transition: none; }\n.panel-nav__header-btn:active::after { background: var(--_nav-pressed); transition: none; }\n\n/* Logo — visible by default; instant swap to toggle on hover (no crossfade overlap) */\n.panel-nav__header-logo {\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n z-index: 1;\n opacity: 1;\n}\n\n.panel-nav__m-mark {\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n display: block;\n}\n\n/* Toggle icon — stacked on logo; opacity swap matches hover bg (instant) */\n.panel-nav__header-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n inset: 0;\n z-index: 2;\n opacity: 0;\n pointer-events: none;\n}\n\n.panel-nav__header-btn:hover .panel-nav__header-logo { opacity: 0; }\n.panel-nav__header-btn:hover .panel-nav__header-toggle { opacity: 1; }\n\n/* ── Scrollable body ─────────────────────────────────────────────────────── */\n\n.panel-nav__body {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-200, 16px);\n padding: var(--dimension-space-100, 8px);\n box-sizing: border-box;\n scrollbar-width: none;\n}\n\n.panel-nav__body::-webkit-scrollbar { display: none; }\n\n/* ── Group ───────────────────────────────────────────────────────────────── */\n\n.panel-nav__group {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050, 4px);\n}\n\n.panel-nav__group-label {\n /* Typography via ds-text (text-caption-emphasis) */\n display: flex;\n align-items: center;\n text-transform: uppercase;\n color: var(--_nav-fg-secondary);\n user-select: none;\n height: var(--dimension-size-300, 24px);\n line-height: var(--typography-lineheight-xs, 12px);\n padding: 0 var(--dimension-space-075, 6px);\n white-space: nowrap;\n overflow: hidden;\n max-height: var(--dimension-size-300, 24px);\n opacity: 1;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n max-height var(--_nav-label-fade-motion) 0ms,\n padding var(--_nav-label-fade-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Item ────────────────────────────────────────────────────────────────── */\n\n.panel-nav__item {\n all: unset;\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050, 4px);\n padding: 0 var(--dimension-space-075, 6px);\n height: var(--dimension-size-400, 32px);\n border-radius: var(--dimension-radius-025, 2px);\n cursor: pointer;\n color: var(--_nav-fg-secondary);\n position: relative;\n box-sizing: border-box;\n width: 100%;\n user-select: none;\n transition: color var(--effect-motion-short-1, 50ms ease-in-out);\n}\n\n/* Interaction layer */\n.panel-nav__item::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--dimension-radius-025, 2px);\n background: transparent;\n pointer-events: none;\n transition: none;\n}\n\n.panel-nav__item:hover::after { background: var(--_nav-hover); transition: none; }\n.panel-nav__item:active::after { background: var(--_nav-pressed); transition: none; }\n\n/* ── Active item ─────────────────────────────────────────────────────────── */\n\n.panel-nav__item--active {\n color: var(--_nav-fg-primary);\n /* Bold typography via ds-text (text-body-medium-emphasis) on the label */\n}\n\n/* ── Item icon ───────────────────────────────────────────────────────────── */\n\n.panel-nav__item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--dimension-iconography-md, 20px);\n height: var(--dimension-iconography-md, 20px);\n position: relative;\n}\n\n/* ── Item label ──────────────────────────────────────────────────────────── */\n\n.panel-nav__item-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n height: var(--typography-lineheight-md, 20px);\n line-height: var(--typography-lineheight-md, 20px);\n opacity: 1;\n /* Gradient wipe: mask sweeps left-to-right on expand, right-to-left on collapse */\n mask-image: linear-gradient(to right, black 50%, transparent 100%);\n -webkit-mask-image: linear-gradient(to right, black 50%, transparent 100%);\n mask-size: 200% 100%;\n -webkit-mask-size: 200% 100%;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n transition:\n opacity var(--_nav-label-fade-motion) 0ms,\n mask-position var(--_nav-label-fade-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-motion) 0ms;\n}\n\n.panel-nav__item-label-text {\n padding: 0 var(--dimension-space-025, 2px);\n}\n\n/* ── Item notification dot — single element, moves between positions ──────── */\n\n.panel-nav__item-dot {\n position: absolute;\n right: calc(var(--dimension-space-100, 8px) + var(--dimension-space-050, 4px) + var(--dimension-stroke-width-012, 1px));\n top: calc(var(--dimension-space-100, 8px) + var(--dimension-space-050, 4px) + var(--dimension-stroke-width-012, 1px));\n pointer-events: none;\n transition:\n right var(--_nav-expand-motion),\n top var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__item-dot {\n right: var(--dimension-space-075);\n top: var(--dimension-space-075);\n}\n\n.panel-nav--animating .panel-nav__item-label {\n text-overflow: clip;\n}\n\n.panel-nav--collapsed .panel-nav__item-label {\n opacity: 0;\n pointer-events: none;\n text-overflow: clip;\n mask-position: 100% 0;\n -webkit-mask-position: 100% 0;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n mask-position var(--_nav-label-fade-out-motion) 0ms,\n -webkit-mask-position var(--_nav-label-fade-out-motion) 0ms;\n}\n\n.panel-nav--collapsed .panel-nav__group-label {\n opacity: 0;\n max-height: 0;\n padding: 0 var(--dimension-space-075, 6px);\n pointer-events: none;\n transition:\n opacity var(--_nav-label-fade-out-motion) 0ms,\n max-height var(--_nav-label-fade-out-motion) 0ms,\n padding var(--_nav-label-fade-out-motion) 0ms,\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Footer ──────────────────────────────────────────────────────────────── */\n\n.panel-nav__footer {\n position: relative;\n flex-shrink: 0;\n /* single row: padding*2 + item */\n height: calc(var(--_nav-padding-y) * 2 + var(--_nav-item-height));\n transition: height var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer {\n /* two rows: padding*2 + item*2 + gap */\n height: calc(var(--_nav-padding-y) * 2 + var(--_nav-item-height) * 2 + var(--dimension-space-050, 4px));\n}\n\n/* ── Footer icon button (gear / dashboard) ───────────────────────────────── */\n\n.panel-nav__footer-btn {\n position: absolute;\n left: var(--_nav-padding-x);\n top: var(--_nav-padding-y);\n --ds-button-unfilled-icon-fg: var(--_nav-fg-secondary);\n --ds-button-unfilled-icon-fg-active: var(--_nav-fg-primary);\n --ds-button-unfilled-icon-hover-bg: var(--_nav-hover);\n --ds-button-unfilled-icon-pressed-bg: var(--_nav-pressed);\n --ds-focus-ring-color: var(--_nav-focus);\n}\n\n/* ── Footer user — absolutely positioned, slides from row to below gear ───── */\n\n.panel-nav__footer-user {\n position: absolute;\n /* row position: right of gear button */\n left: calc(var(--_nav-padding-x) + var(--_nav-footer-btn-w) + var(--dimension-space-050, 4px));\n right: calc(var(--_nav-padding-x) - var(--dimension-stroke-width-012, 1px));\n top: var(--_nav-padding-y);\n width: auto;\n min-width: 0;\n transition:\n left var(--_nav-expand-motion),\n right var(--_nav-expand-motion),\n top var(--_nav-expand-motion),\n color var(--effect-motion-short-3, 200ms ease);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user {\n /* column position: full-width row below gear */\n left: var(--_nav-padding-x);\n top: calc(var(--_nav-padding-y) + var(--_nav-item-height) + var(--dimension-space-050, 4px));\n}\n\n/* Label: absolute so it stays in place and only fades — no mask slide */\n.panel-nav__footer-user-label {\n text-align: right;\n position: absolute;\n left: var(--dimension-space-075, 6px);\n right: calc(var(--dimension-space-075, 6px) + var(--dimension-iconography-md, 20px) + var(--dimension-space-050, 4px));\n top: 50%;\n transform: translateY(-50%);\n flex: none;\n height: var(--typography-lineheight-md, 20px);\n mask-image: none;\n -webkit-mask-image: none;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-label {\n opacity: 0;\n pointer-events: none;\n mask-position: 0% 0;\n -webkit-mask-position: 0% 0;\n}\n\n/* ── Footer user icon — cross-fades chevron ↔ circle+initial ────────────── */\n\n/* Absolute — right-anchored in expanded, left-anchored in collapsed to match regular item icon position */\n.panel-nav__footer-user-icon {\n position: absolute;\n left: calc(100% - var(--dimension-iconography-md, 20px) - var(--dimension-space-075, 6px));\n top: 0;\n bottom: 0;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: left var(--_nav-expand-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-user-icon {\n left: var(--dimension-space-075, 6px);\n}\n\n.panel-nav__footer-icon-expanded,\n.panel-nav__footer-icon-collapsed {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.panel-nav__footer-icon-expanded {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav__footer-icon-collapsed {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-expanded {\n opacity: 0;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n.panel-nav--collapsed .panel-nav__footer-icon-collapsed {\n opacity: 1;\n transition: opacity var(--_nav-label-fade-out-motion);\n}\n\n/* ── User initial — overlaid on the circle icon ─────────────────────────── */\n\n.panel-nav__user-initial {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--_nav-fg-secondary);\n text-transform: uppercase;\n line-height: 1;\n pointer-events: none;\n transition: color var(--effect-motion-short-3, 200ms ease);\n}\n\n/* ── Drag-to-resize handle ───────────────────────────────────────────────── */\n\n/* The resize overlay line — extends past the right edge; keep above workspace content */\n.panel-nav__resize-handle {\n position: absolute;\n top: 0;\n /* Centered on the right edge: --dimension-space-050 outside + inside = --dimension-space-100 hit zone */\n right: var(--dimension-space-n050, -4px);\n bottom: 0;\n width: var(--dimension-space-100, 8px);\n z-index: 20;\n cursor: ew-resize;\n touch-action: none;\n /* Needs a real background for Safari hit-testing */\n background: transparent;\n}\n\n/* Safari requires non-transparent fill for hit testing */\n.panel-nav__resize-handle::before {\n content: '';\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.001);\n}\n\n/* Resize overlay line */\n.panel-nav__resize-handle::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: var(--dimension-stroke-width-025, 2px);\n background: var(--color-foreground-primary);\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--effect-motion-short-2, 100ms ease-in-out);\n}\n\n.panel-nav__resize-handle--overlay::after {\n opacity: 1;\n}\n\n/* ── Reduced motion ──────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .panel-nav,\n .panel-nav *,\n .panel-nav *::before,\n .panel-nav *::after,\n .panel-nav__resize-handle,\n .panel-nav__resize-handle::before,\n .panel-nav__resize-handle::after {\n transition-duration: 0.01ms !important;\n animation-duration: 0.01ms !important;\n transition-delay: 0.01ms !important;\n }\n}\n","import { Component, Prop, Event, EventEmitter, Watch, State, Element, Method, h, Host } from '@stencil/core';\nimport type { ChromeTransitionDetail } from '../../nav/chrome-transition';\nimport type { NavChromeStyle } from '../../nav/nav-chrome';\nimport {\n deriveActiveIdFromUrl,\n parsePanelNavGroups,\n resolvePanelNavDisableVt,\n resolvePanelNavStyle,\n shouldResyncPanelNavGroups,\n shouldResyncPanelNavStyle,\n} from './panel-nav-utils';\nimport {\n PANEL_NAV_USER_MENU_ANCHOR_ID,\n type PanelNavGroup,\n type PanelNavItem,\n type PanelNavRouterMode,\n type PanelNavUserActionDetail,\n} from './panel-nav-types';\n\n@Component({\n tag: 'ds-panel-nav',\n styleUrl: 'PanelNav.css',\n styleUrls: ['../../utils/scroll-edge-fade.css'],\n scoped: true,\n})\nexport class PanelNav {\n /** Style slot: `dashboard` or `settings`. Colors match for now;\n * class hooks reserved for texture/glyph layers. Property: `navStyle`. Attribute: `nav-style`. */\n @Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'dashboard';\n\n /** When `true`, style changes apply synchronously — host app owns view transitions. */\n @Prop() disableViewTransition: boolean = false;\n\n /** Nav groups — set via JS property (`el.groups = [...]`) or JSON string attribute. */\n @Prop() groups: string | PanelNavGroup[] = '[]';\n\n /** How items with `href` render:\n * - `anchor` (default): native `<a href>` — works with routers that intercept anchors.\n * - `event`: always `<button>`; host handles navigation via `dsNavSelect`. */\n @Prop() routerMode: PanelNavRouterMode = 'anchor';\n\n /** ID of the currently active/selected nav item. Overridden by `currentUrl` matching when set. */\n @Prop() activeId: string = '';\n\n /** Whether the nav is in collapsed (icon-only) state.\n * Set `storageKey` to persist across reloads. `dsNavToggle` still fires on change. */\n @Prop({ mutable: true }) collapsed: boolean = false;\n\n /** Viewport width (px) below which the nav auto-collapses to icon-only mode. 0 = disabled. */\n @Prop() breakpoint: number = 0;\n\n /** `localStorage` key used to persist the collapsed state across page loads.\n * When set, collapsed state is restored on mount and written on each toggle. */\n @Prop() storageKey: string = '';\n\n /** Current route URL (e.g. `window.location.pathname` or the router's active URL).\n * When set the component derives the active item by matching item `href` values\n * against this string (longest segment-boundary prefix wins), overriding `activeId`. */\n @Prop() currentUrl: string = '';\n\n /** Display name for the footer user section */\n @Prop() userName: string = '';\n\n /** Single character shown in the collapsed avatar */\n @Prop() userInitial: string = '';\n\n /** Emitted when a nav item is clicked. Detail = the item's `id`. */\n @Event() dsNavSelect!: EventEmitter<string>;\n\n /** Emitted when the collapse toggle is clicked. Detail = new collapsed state. */\n @Event() dsNavToggle!: EventEmitter<boolean>;\n\n /** Bubbling lifecycle — `ds-app-shell` pauses chrome metrics during width motion. */\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionStart!: EventEmitter<ChromeTransitionDetail>;\n\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionEnd!: EventEmitter<ChromeTransitionDetail>;\n\n /** Emitted when the footer left button (gear / dashboard) is clicked. */\n @Event() dsNavFooterAction!: EventEmitter<void>;\n\n /** Emitted when the footer user button is clicked. Detail includes the anchor for `ds-menu`. */\n @Event() dsNavUserAction!: EventEmitter<PanelNavUserActionDetail>;\n\n @Element() el!: HTMLElement;\n\n @State() private renderedStyle: NavChromeStyle = 'dashboard';\n @State() private parsedGroups: PanelNavGroup[] = [];\n @State() private atBottom = false;\n @State() private isAnimating = false;\n @State() private rovingIndex: number = 0;\n @State() private viewportNarrow: boolean = false;\n @State() private urlDerivedActiveId: string = '';\n\n private transitionEndHandler?: (e: TransitionEvent) => void;\n private resizeObserver?: ResizeObserver;\n\n // Drag-to-resize state (not @State — no re-render needed)\n private isDragging = false;\n private dragStartX = 0;\n private didSnap = false;\n private lastDeltaX = 0;\n private edgeOverlayTimer: number | null = null;\n private globalMouseMoveHandler?: (e: MouseEvent) => void;\n private globalMouseUpHandler?: () => void;\n\n @State() private showEdgeOverlay = false;\n\n private static readonly HOST_PROP_SYNC_BUDGET = 8;\n\n /** The ID that should be treated as active. `currentUrl` matching takes precedence\n * over `activeId` when both are present. */\n private get effectiveActiveId(): string {\n return this.urlDerivedActiveId || this.activeId;\n }\n\n private get effectiveDisableViewTransition(): boolean {\n return resolvePanelNavDisableVt(\n this.disableViewTransition,\n this.el.getAttribute('disable-view-transition'),\n );\n }\n\n @Watch('collapsed')\n onCollapsedChange(_next: boolean, prev: boolean | undefined) {\n if (prev === undefined) return;\n this.startCollapseAnimation();\n }\n\n @Watch('viewportNarrow')\n onViewportNarrowChange(_next: boolean, prev: boolean | undefined) {\n if (prev === undefined) return;\n this.startCollapseAnimation();\n }\n\n @Watch('breakpoint')\n onBreakpointChange() {\n this.disconnectResizeObserver();\n if (this.breakpoint > 0) this.connectResizeObserver();\n }\n\n @Watch('groups')\n onGroupsChange(val: string | PanelNavGroup[]) {\n this.parsedGroups = parsePanelNavGroups(val);\n this.rovingIndex = 0;\n this.syncActiveFromUrl();\n }\n\n @Watch('activeId')\n @Watch('urlDerivedActiveId')\n onActiveIdChange() {\n /* Active route updates aria-current only — roving tab stop stays user-controlled. */\n }\n\n @Watch('currentUrl')\n onCurrentUrlChange() {\n this.syncActiveFromUrl();\n }\n\n @Watch('navStyle')\n onNavStyleChange(newVal: NavChromeStyle) {\n this.renderedStyle = newVal;\n }\n\n componentWillLoad() {\n this.renderedStyle = resolvePanelNavStyle(this.navStyle, this.el.getAttribute('nav-style'));\n if (this.storageKey) {\n try {\n const stored = localStorage.getItem(this.storageKey);\n if (stored !== null) this.collapsed = stored === 'true';\n } catch { /* localStorage unavailable */ }\n }\n this.onGroupsChange(this.groups);\n this.syncActiveFromUrl();\n }\n\n componentDidLoad() {\n this.syncHostPropsIfNeeded();\n this.scheduleDeferredHostPropSync();\n this.checkScroll();\n if (this.breakpoint > 0) this.connectResizeObserver();\n }\n\n disconnectedCallback() {\n this.disconnectResizeObserver();\n this.clearEdgeOverlayTimer();\n if (this.globalMouseMoveHandler) {\n window.removeEventListener('mousemove', this.globalMouseMoveHandler);\n }\n if (this.globalMouseUpHandler) {\n window.removeEventListener('mouseup', this.globalMouseUpHandler);\n }\n }\n\n private startCollapseAnimation() {\n this.isAnimating = true;\n this.dsChromeTransitionStart.emit({ source: 'panel-nav' });\n const panel = this.el.querySelector('.panel-nav') as HTMLElement | null;\n const widthBefore = panel?.getBoundingClientRect().width ?? 0;\n if (this.transitionEndHandler) {\n panel?.removeEventListener('transitionend', this.transitionEndHandler);\n }\n this.transitionEndHandler = (e: TransitionEvent) => {\n if (e.propertyName === 'width') {\n this.finishCollapseAnimation(panel);\n }\n };\n panel?.addEventListener('transitionend', this.transitionEndHandler);\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (!this.isAnimating) return;\n const widthAfter = panel?.getBoundingClientRect().width ?? 0;\n if (Math.abs(widthAfter - widthBefore) < 1) {\n this.finishCollapseAnimation(panel);\n }\n });\n });\n }\n\n private finishCollapseAnimation(panel: HTMLElement | null) {\n if (!this.isAnimating) return;\n this.isAnimating = false;\n this.dsChromeTransitionEnd.emit({ source: 'panel-nav' });\n if (this.transitionEndHandler) {\n panel?.removeEventListener('transitionend', this.transitionEndHandler);\n }\n }\n\n private connectResizeObserver() {\n this.viewportNarrow = window.innerWidth < this.breakpoint;\n this.resizeObserver = new ResizeObserver(() => {\n this.viewportNarrow = window.innerWidth < this.breakpoint;\n });\n this.resizeObserver.observe(document.documentElement);\n }\n\n private disconnectResizeObserver() {\n this.resizeObserver?.disconnect();\n this.resizeObserver = undefined;\n }\n\n /** Derive active ID from the current URL by matching item `href` values.\n * Uses longest segment-boundary prefix match. */\n private syncActiveFromUrl() {\n if (!this.currentUrl) {\n this.urlDerivedActiveId = '';\n return;\n }\n this.urlDerivedActiveId = deriveActiveIdFromUrl(this.currentUrl, this.getAllItems());\n }\n\n /** Re-parse props assigned by the host after componentWillLoad (Angular ngAfterViewInit). */\n private syncHostPropsIfNeeded() {\n if (shouldResyncPanelNavStyle(this.renderedStyle, this.navStyle)) {\n this.renderedStyle = this.navStyle;\n }\n\n if (shouldResyncPanelNavGroups(this.parsedGroups, this.groups)) {\n this.onGroupsChange(this.groups);\n } else if (this.currentUrl) {\n this.syncActiveFromUrl();\n }\n }\n\n /** Poll across animation frames — host props may land without triggering @Watch. */\n private scheduleDeferredHostPropSync() {\n let remaining = PanelNav.HOST_PROP_SYNC_BUDGET;\n const tick = () => {\n this.syncHostPropsIfNeeded();\n if (--remaining > 0) {\n requestAnimationFrame(tick);\n }\n };\n queueMicrotask(tick);\n }\n\n /** Centralised toggle: updates `collapsed`, emits `dsNavToggle`, optionally persists. */\n private applyToggle(next: boolean) {\n this.collapsed = next;\n if (this.storageKey) {\n try { localStorage.setItem(this.storageKey, String(next)); } catch { /* unavailable */ }\n }\n this.dsNavToggle.emit(next);\n }\n\n private getAllItems(): PanelNavItem[] {\n return this.parsedGroups.flatMap(g => g.items);\n }\n\n private getFooterRovingIndex(): number {\n return 1 + this.getAllItems().length;\n }\n\n private getUserRovingIndex(): number {\n return this.getFooterRovingIndex() + 1;\n }\n\n private getRovingElement(index: number): HTMLElement | null {\n const itemCount = this.getAllItems().length;\n if (index === 0) {\n return this.el.querySelector('.panel-nav__header-btn');\n }\n if (index >= 1 && index <= itemCount) {\n const items = this.el.querySelectorAll<HTMLElement>('.panel-nav__body .panel-nav__item');\n return items[index - 1] ?? null;\n }\n if (index === this.getFooterRovingIndex()) {\n return this.el.querySelector('.panel-nav__footer-btn .button-icon');\n }\n if (index === this.getUserRovingIndex()) {\n return this.el.querySelector('.panel-nav__footer-user');\n }\n return null;\n }\n\n private focusRovingAt(index: number) {\n this.rovingIndex = index;\n this.getRovingElement(index)?.focus({ preventScroll: true });\n }\n\n private activateRovingIndex(index: number) {\n const itemCount = this.getAllItems().length;\n const items = this.getAllItems();\n if (index === 0) {\n this.handleToggle();\n return;\n }\n if (index >= 1 && index <= itemCount) {\n this.handleItemClick(items[index - 1].id);\n return;\n }\n if (index === this.getFooterRovingIndex()) {\n this.handleFooterAction();\n return;\n }\n if (index === this.getUserRovingIndex()) {\n const anchor = this.el.querySelector(`#${PANEL_NAV_USER_MENU_ANCHOR_ID}`) as HTMLElement | null;\n if (anchor) this.dsNavUserAction.emit({ anchor });\n }\n }\n\n private handleRovingKeyDown(e: KeyboardEvent, index: number) {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.activateRovingIndex(index);\n return;\n }\n\n const footerIdx = this.getFooterRovingIndex();\n const userIdx = this.getUserRovingIndex();\n let next: number | undefined;\n\n switch (e.key) {\n case 'ArrowDown':\n if (index === userIdx) return;\n if (index === footerIdx) next = userIdx;\n else next = index + 1;\n break;\n case 'ArrowUp':\n if (index === 0) return;\n if (index === userIdx) next = footerIdx;\n else if (index === footerIdx) next = footerIdx - 1;\n else next = index - 1;\n break;\n case 'ArrowRight':\n if (index === footerIdx) next = userIdx;\n else return;\n break;\n case 'ArrowLeft':\n if (index === userIdx) next = footerIdx;\n else return;\n break;\n case 'Home':\n e.preventDefault();\n next = 0;\n break;\n case 'End':\n e.preventDefault();\n next = userIdx;\n break;\n default:\n return;\n }\n\n if (next === undefined || next === index) return;\n e.preventDefault();\n this.focusRovingAt(next);\n }\n\n private checkScroll() {\n const body = this.el.querySelector('.panel-nav__body') as HTMLElement | null;\n if (!body) return;\n const remaining = body.scrollHeight - body.scrollTop - body.clientHeight;\n this.atBottom = remaining < 2;\n }\n\n private handleBodyScroll(e: Event) {\n const body = e.target as HTMLElement;\n const remaining = body.scrollHeight - body.scrollTop - body.clientHeight;\n this.atBottom = remaining < 2;\n }\n\n private handleItemClick(id: string) {\n this.dsNavSelect.emit(id);\n }\n\n private handleToggle() {\n this.applyToggle(!this.collapsed);\n }\n\n /** Toggle expanded/collapsed panel nav — used by shell keyboard shortcuts. */\n @Method()\n async toggleCollapsed() {\n this.handleToggle();\n }\n\n private handleFooterAction() {\n this.dsNavFooterAction.emit();\n }\n\n private handleUserAction(e: MouseEvent) {\n const anchor = e.currentTarget as HTMLElement;\n this.dsNavUserAction.emit({ anchor });\n }\n\n private clearEdgeOverlayTimer() {\n if (this.edgeOverlayTimer !== null) {\n window.clearTimeout(this.edgeOverlayTimer);\n this.edgeOverlayTimer = null;\n }\n }\n\n private handleResizeHandleMouseEnter() {\n this.clearEdgeOverlayTimer();\n this.edgeOverlayTimer = window.setTimeout(() => {\n this.showEdgeOverlay = true;\n this.edgeOverlayTimer = null;\n }, 500);\n }\n\n private handleResizeHandleMouseLeave() {\n if (this.isDragging) return;\n this.clearEdgeOverlayTimer();\n this.showEdgeOverlay = false;\n }\n\n private handleResizeHandleMouseDown(e: MouseEvent) {\n e.preventDefault();\n e.stopPropagation();\n\n const wasCollapsed = this.collapsed || this.viewportNarrow;\n this.isDragging = true;\n this.dragStartX = e.clientX;\n this.didSnap = false;\n this.lastDeltaX = 0;\n this.clearEdgeOverlayTimer();\n this.showEdgeOverlay = false;\n\n document.body.style.cursor = 'ew-resize';\n document.body.style.userSelect = 'none';\n\n const onMove = (ev: MouseEvent) => {\n const deltaX = ev.clientX - this.dragStartX;\n this.lastDeltaX = Math.abs(deltaX);\n if (this.didSnap) return;\n if (!wasCollapsed && deltaX < -8) {\n this.applyToggle(true);\n this.didSnap = true;\n } else if (wasCollapsed && deltaX > 8) {\n this.applyToggle(false);\n this.didSnap = true;\n }\n };\n\n const onUp = () => {\n if (!this.didSnap && this.lastDeltaX < 3) {\n this.applyToggle(!wasCollapsed);\n }\n this.isDragging = false;\n this.showEdgeOverlay = false;\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n this.globalMouseMoveHandler = undefined;\n this.globalMouseUpHandler = undefined;\n };\n\n this.globalMouseMoveHandler = onMove;\n this.globalMouseUpHandler = onUp;\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n }\n\n private renderNavItem(item: PanelNavItem, idx: number, collapsed: boolean) {\n const isActive = item.id === this.effectiveActiveId;\n const rovingPosition = idx + 1;\n\n const itemContent = [\n <span class=\"panel-nav__item-icon\">\n <ds-icon name={item.icon} size=\"md\" color=\"inherit\" flag={item.flag} />\n </span>,\n <span class=\"panel-nav__item-label\">\n <span class=\"panel-nav__item-label-text\">\n <ds-text\n as=\"span\"\n variant={isActive ? 'text-body-medium-emphasis' : 'text-body-medium'}\n color=\"inherit\"\n >\n {item.label}\n </ds-text>\n </span>\n </span>,\n item.dot && (\n <ds-badge\n class=\"panel-nav__item-dot\"\n variant=\"dot\"\n background=\"var(--_nav-bg)\"\n label=\"\"\n aria-hidden=\"true\"\n />\n ),\n ];\n\n const sharedProps = {\n class: {\n 'panel-nav__item': true,\n 'panel-nav__item--active': isActive,\n 'ds-focus-ring-inset': true,\n },\n 'aria-current': isActive ? ('page' as const) : undefined,\n title: collapsed ? item.label : undefined,\n tabIndex: rovingPosition === this.rovingIndex ? 0 : -1,\n onClick: () => this.handleItemClick(item.id),\n onKeyDown: (e: KeyboardEvent) => this.handleRovingKeyDown(e, rovingPosition),\n onFocus: () => { this.rovingIndex = rovingPosition; },\n };\n\n const useAnchor = this.routerMode === 'anchor' && item.href;\n\n return useAnchor\n ? <a {...sharedProps} href={item.href}>{itemContent}</a>\n : <button {...sharedProps} type=\"button\">{itemContent}</button>;\n }\n\n render() {\n const chromeStyle = this.renderedStyle;\n const isDashboardChrome = chromeStyle === 'dashboard';\n const isDashboard = this.navStyle === 'dashboard';\n const collapsed = this.collapsed || this.viewportNarrow;\n const { userName, userInitial } = this;\n\n const navCls: Record<string, boolean> = {\n 'panel-nav': true,\n 'panel-nav--dashboard': isDashboard,\n 'panel-nav--settings': !isDashboard,\n 'panel-nav--collapsed': collapsed,\n 'panel-nav--animating': this.isAnimating,\n 'panel-nav--at-bottom': this.atBottom,\n };\n\n return (\n <Host style={{ display: 'block', position: 'relative' }}>\n <nav\n class={navCls}\n aria-label={isDashboardChrome ? 'Dashboard navigation' : 'Settings navigation'}\n >\n\n {/* ── Header: Motive logo, reveals collapse toggle on hover ── */}\n <div class=\"panel-nav__header\">\n <button\n type=\"button\"\n class=\"panel-nav__header-btn ds-focus-ring-inset\"\n tabIndex={this.rovingIndex === 0 ? 0 : -1}\n onClick={() => this.handleToggle()}\n onKeyDown={(e: KeyboardEvent) => this.handleRovingKeyDown(e, 0)}\n onFocus={() => { this.rovingIndex = 0; }}\n aria-label={collapsed ? 'Expand navigation' : 'Collapse navigation'}\n aria-expanded={collapsed ? 'false' : 'true'}\n >\n {/* Motive M mark — fades out on hover to reveal collapse toggle */}\n <span class=\"panel-nav__header-logo\" aria-hidden=\"true\">\n <svg class=\"panel-nav__m-mark\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" focusable=\"false\" aria-hidden=\"true\">\n <path d=\"M11.1159 4.31537H7.67021L2.53401 13.0703H0V15.6875H4.02716L8.24319 8.49978V15.6846H11.6342L15.8289 8.47829V15.6846H18.7122V4.3125H15.2559L11.1159 11.3648V4.31537Z\" fill=\"currentColor\"/>\n </svg>\n </span>\n {/* Collapse / expand icon — revealed on hover via CSS */}\n <span class=\"panel-nav__header-toggle\" aria-hidden=\"true\">\n <ds-icon\n name={collapsed ? 'LeftExpandB' : 'LeftCollapseB'}\n size=\"md\"\n color=\"inherit\"\n />\n </span>\n </button>\n </div>\n\n {/* ── Scrollable body ── */}\n <div\n class={{\n 'panel-nav__body': true,\n 'scroll-edge-fade': true,\n 'scroll-edge-fade--bottom': true,\n 'scroll-edge-fade--at-end': this.atBottom,\n }}\n onScroll={e => this.handleBodyScroll(e)}\n >\n {(() => {\n let flatIdx = 0;\n return this.parsedGroups.map(group => (\n <div class=\"panel-nav__group\">\n {group.label && (\n <span class=\"panel-nav__group-label\">\n <span class=\"panel-nav__item-label-text\">\n <ds-text as=\"span\" variant=\"text-caption-emphasis\" color=\"inherit\">\n {group.label}\n </ds-text>\n </span>\n </span>\n )}\n {group.items.map(item => this.renderNavItem(item, flatIdx++, collapsed))}\n </div>\n ));\n })()}\n </div>\n\n {/* ── Footer ── */}\n <div class=\"panel-nav__footer\">\n <ds-button-unfilled-icon\n class=\"panel-nav__footer-btn\"\n icon={isDashboardChrome ? 'Gear' : 'Dashboard'}\n activeFill={false}\n focusTabIndex={this.rovingIndex === this.getFooterRovingIndex() ? 0 : -1}\n title={isDashboardChrome ? 'Settings' : 'Dashboard'}\n aria-label={isDashboardChrome ? 'Open settings' : 'Go to dashboard'}\n onDsClick={() => this.handleFooterAction()}\n onKeyDown={(e: KeyboardEvent) => this.handleRovingKeyDown(e, this.getFooterRovingIndex())}\n onFocusin={() => { this.rovingIndex = this.getFooterRovingIndex(); }}\n />\n\n {/* Right user — label fades like nav items; right icon cross-fades chevron ↔ circle+initial */}\n <button\n type=\"button\"\n id={PANEL_NAV_USER_MENU_ANCHOR_ID}\n class=\"panel-nav__item panel-nav__footer-user ds-focus-ring-inset\"\n tabIndex={this.rovingIndex === this.getUserRovingIndex() ? 0 : -1}\n aria-label={collapsed ? `User: ${userName}` : `User menu for ${userName}`}\n onClick={(e) => this.handleUserAction(e)}\n onKeyDown={(e: KeyboardEvent) => this.handleRovingKeyDown(e, this.getUserRovingIndex())}\n onFocus={() => { this.rovingIndex = this.getUserRovingIndex(); }}\n >\n <span class=\"panel-nav__item-label panel-nav__footer-user-label\">\n <span class=\"panel-nav__item-label-text\">\n <ds-text as=\"span\" variant=\"text-body-medium-emphasis\" color=\"inherit\">\n {userName}\n </ds-text>\n </span>\n </span>\n <span class=\"panel-nav__item-icon panel-nav__footer-user-icon\" aria-hidden=\"true\">\n <span class=\"panel-nav__footer-icon-expanded\">\n <ds-icon name=\"ChevronUpDown\" size=\"md\" color=\"inherit\" />\n </span>\n <span class=\"panel-nav__footer-icon-collapsed\">\n <ds-icon name=\"Circle\" size=\"md\" color=\"inherit\" />\n <span class=\"panel-nav__user-initial\">\n <ds-text as=\"span\" variant=\"text-caption-emphasis\" color=\"inherit\">\n {userInitial}\n </ds-text>\n </span>\n </span>\n </span>\n </button>\n </div>\n\n </nav>\n\n {/* Drag-to-resize handle — always rendered, hidden only when auto-collapsed by breakpoint */}\n {!this.viewportNarrow && (\n <div\n class={{\n 'panel-nav__resize-handle': true,\n 'panel-nav__resize-handle--overlay': this.showEdgeOverlay,\n }}\n onMouseEnter={() => this.handleResizeHandleMouseEnter()}\n onMouseLeave={() => this.handleResizeHandleMouseLeave()}\n onMouseDown={(e: MouseEvent) => this.handleResizeHandleMouseDown(e)}\n aria-hidden=\"true\"\n />\n )}\n </Host>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{p as e,H as s,c as t,h as o,a,t as i}from"./index.js";import{p as n}from"./p-BOQnc-M4.js";import{d as l}from"./p-CiEc8Nwx.js";import{d as r}from"./p-BTndnbR_.js";import{d}from"./p-DqBCQRRd.js";const c="search";const p={search:"Search",messages:"Messages",stacks:"Stacks",activity:"Activity",agents:"Agents"};function h(e,s){if(s){return n(s,[])}return e??[]}function f(e,s){return!e&&s==="idle"}const b=()=>`.sc-ds-panel-tools-h{display:block;flex:0 0 auto;box-sizing:border-box;height:100%;min-height:0;overflow:hidden;--_panel-tools-rail-width:var(--dimension-size-600);--_panel-tools-drawer-width:var(--dimension-panel-width-sm);--_panel-tools-border:var(--dimension-stroke-width-012, 1px) solid var(--color-border-tertiary);--_panel-tools-surface-bg:var(--color-background-secondary);--_panel-tools-expand-dur:var(--effect-animation-duration-medium-1, 300ms)}.panel-tools__layout.sc-ds-panel-tools{display:flex;flex-direction:row-reverse;align-items:stretch;height:100%;min-height:0;box-sizing:border-box}.panel-tools__drawer.sc-ds-panel-tools{flex:0 0 auto;max-width:0;min-width:0;height:100%;min-height:0;overflow:hidden;box-sizing:border-box;transition:none}.panel-tools--ready.panel-tools--motion-opening.sc-ds-panel-tools-h .panel-tools__drawer.sc-ds-panel-tools{transition:max-width var(--_panel-tools-expand-dur) var(--effect-animation-easing-ease-out, ease-out)}.panel-tools--ready.panel-tools--motion-closing.sc-ds-panel-tools-h .panel-tools__drawer.sc-ds-panel-tools{transition:max-width var(--_panel-tools-expand-dur) var(--effect-animation-easing-ease-in, ease-in)}.panel-tools--open.sc-ds-panel-tools-h .panel-tools__drawer.sc-ds-panel-tools{max-width:var(--_panel-tools-drawer-width)}.panel-tools__drawer--visible.sc-ds-panel-tools{border-left:var(--_panel-tools-border)}.panel-tools__drawer-surface.sc-ds-panel-tools{display:flex;flex-direction:column;width:var(--_panel-tools-drawer-width);height:100%;min-height:0;box-sizing:border-box;background-color:var(--_panel-tools-surface-bg)}ds-app-shell[gradient].sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[gradient] .sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[grid].sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[grid] .sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[gradient].sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools,ds-app-shell[gradient] .sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools,ds-app-shell[grid].sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools,ds-app-shell[grid] .sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools{background-color:transparent}.panel-tools__header.sc-ds-panel-tools{flex:0 0 auto;display:flex;align-items:center;height:var(--dimension-size-600);padding:var(--dimension-space-100);border-bottom:var(--_panel-tools-border);color:var(--color-foreground-primary);box-sizing:border-box;-webkit-user-select:none;user-select:none}.panel-tools__title.sc-ds-panel-tools{display:inline-flex;align-items:center;height:var(--dimension-size-400);padding-inline:var(--dimension-space-100);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-tools__body.sc-ds-panel-tools{flex:1 1 auto;min-height:0;overflow:auto;position:relative}.panel-tools--drawer-resting.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{content-visibility:auto;contain-intrinsic-size:auto 200px}.panel-tools__view.sc-ds-panel-tools{display:none;height:100%;min-height:0;box-sizing:border-box;padding:var(--dimension-space-200);color:var(--color-foreground-secondary);font-family:var(--typography-font-family);font-size:var(--typography-fontsize-md);line-height:var(--typography-lineheight-md);font-weight:var(--typography-weight-regular);letter-spacing:var(--typography-letterspacing-negative-half)}.panel-tools__view.sc-ds-panel-tools-s>*,.panel-tools__view .sc-ds-panel-tools-s>*{margin:0;color:var(--color-foreground-secondary);font-family:var(--typography-font-family);font-size:var(--typography-fontsize-md);line-height:var(--typography-lineheight-md);font-weight:var(--typography-weight-regular);letter-spacing:var(--typography-letterspacing-negative-half)}.panel-tools__view--active.sc-ds-panel-tools{display:block}.panel-tools__rail.sc-ds-panel-tools{flex:0 0 var(--_panel-tools-rail-width);width:var(--_panel-tools-rail-width);min-width:var(--_panel-tools-rail-width);display:flex;flex-direction:column;box-sizing:border-box;height:100%;min-height:0;border-left:var(--_panel-tools-border);background-color:var(--_panel-tools-surface-bg)}.panel-tools__rail-header.sc-ds-panel-tools{display:flex;align-items:center;justify-content:center;height:var(--dimension-size-600);padding:var(--dimension-space-100);flex-shrink:0;box-sizing:border-box;border-bottom:var(--_panel-tools-border)}.panel-tools__rail-body.sc-ds-panel-tools{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:var(--dimension-space-050);padding:var(--dimension-space-100);box-sizing:border-box;scrollbar-width:none}.panel-tools__rail-body.sc-ds-panel-tools::-webkit-scrollbar{display:none}.panel-tools__rail-action.sc-ds-panel-tools{display:flex;align-items:center;justify-content:center;width:100%;height:var(--dimension-size-400);flex-shrink:0}`;const g=e(class e extends s{constructor(e){super();if(e!==false){this.__registerHost()}this.dsToolChange=t(this,"dsToolChange");this.dsChromeTransitionStart=t(this,"dsChromeTransitionStart");this.dsChromeTransitionEnd=t(this,"dsChromeTransitionEnd");this.open=false;this.activeTool="";this.items=[];this.itemsJson="";this.motion="idle";this.readyForMotion=false;this.rovingIndex=0;this.motionEnableGeneration=0;this.handleTransitionEnd=e=>{if(e.target!==this.el.querySelector(".panel-tools__drawer"))return;if(e.propertyName!=="max-width")return;this.motion="idle";this.dsChromeTransitionEnd.emit({source:"panel-tools"})};this.handleToolChange=e=>{const s=!this.isRailSelected(e);if(s){this.open=true;this.activeTool=e}else{this.open=false}this.dsToolChange.emit({id:e,selected:s})};this.handleRailKeyDown=(e,s)=>{const t=this.orderedRailItems;if(!t.length)return;if(e.key==="Enter"||e.key===" "){e.preventDefault();this.handleToolChange(t[s].id);return}if(e.key==="ArrowDown"){e.preventDefault();this.focusRailAt(s+1);return}if(e.key==="ArrowUp"){e.preventDefault();this.focusRailAt(s-1)}}}get railItems(){return h(this.items,this.itemsJson)}get orderedRailItems(){const e=this.railItems;const s=e.find((e=>e.id===c));const t=e.filter((e=>e.id!==c));return s?[s,...t]:t}disconnectedCallback(){this.el.removeEventListener("transitionend",this.handleTransitionEnd);this.motionEnableGeneration+=1}deferMotionEnable(){if(this.readyForMotion)return;const e=++this.motionEnableGeneration;requestAnimationFrame((()=>{if(e!==this.motionEnableGeneration)return;requestAnimationFrame((()=>{if(e!==this.motionEnableGeneration)return;this.readyForMotion=true}))}))}connectedCallback(){this.el.addEventListener("transitionend",this.handleTransitionEnd)}openChanged(e,s){if(this.readyForMotion&&s!==undefined&&s!==e){this.motion=e?"opening":"closing";this.dsChromeTransitionStart.emit({source:"panel-tools",phase:e?"opening":"closing"})}this.deferMotionEnable()}activeToolChanged(){this.deferMotionEnable()}componentDidLoad(){this.deferMotionEnable()}itemsChanged(){this.rovingIndex=0;this.deferMotionEnable()}isRailSelected(e){return this.open&&this.activeTool===e}isDrawerPresent(){return this.open||this.motion==="closing"}isViewActive(e){return this.isDrawerPresent()&&this.activeTool===e}headerLabel(){if(!this.isDrawerPresent()||!this.activeTool)return"";return p[this.activeTool]??""}focusRailAt(e){const s=this.orderedRailItems;if(!s.length)return;const t=(e%s.length+s.length)%s.length;this.rovingIndex=t;const o=Array.from(this.el.querySelectorAll(".panel-tools__rail-action .button-icon"));o[t]?.focus({preventScroll:true})}renderRailAction(e,s){return o("ds-button-unfilled-icon",{key:e.id,class:"panel-tools__rail-action",icon:e.icon,isActive:this.isRailSelected(e.id),activeFill:false,dot:e.dot??false,inactive:e.inactive,focusTabIndex:s===this.rovingIndex?0:-1,"aria-label":e.ariaLabel??p[e.id],pressed:this.isRailSelected(e.id),onFocusin:()=>{this.rovingIndex=s},onKeyDown:e=>this.handleRailKeyDown(e,s),onDsClick:()=>this.handleToolChange(e.id)})}render(){const e=this.headerLabel();const s=this.orderedRailItems;const t=s.find((e=>e.id===c));const i=s.filter((e=>e.id!==c));const n=this.isDrawerPresent();const l=f(this.open,this.motion);return o(a,{key:"7cfea061b232bdba30999feaa788fa2ad239d06a",class:{"panel-tools":true,"panel-tools--open":this.open,"panel-tools--ready":this.readyForMotion,"panel-tools--motion-opening":this.motion==="opening","panel-tools--motion-closing":this.motion==="closing","panel-tools--drawer-resting":l},role:"complementary","aria-label":"Tools"},o("div",{key:"e216098ccedfc9c1acae0a11f4111178fadb68c4",class:"panel-tools__layout"},o("nav",{key:"825c0dd1a9b4fc0e721950abfa17a3058b7026ae",class:"panel-tools__rail","aria-label":"Tool shortcuts"},t?o("div",{class:"panel-tools__rail-header"},this.renderRailAction(t,0)):null,o("div",{key:"bb971ac52f3c809d01b54ca15172b05cc30089e1",class:"panel-tools__rail-body"},i.map(((e,s)=>this.renderRailAction(e,t?s+1:s))))),o("div",{key:"6f2f5fa7397badae7cca33054827a136dc27f489",class:{"panel-tools__drawer":true,"panel-tools__drawer--visible":n},"aria-hidden":n?null:"true",inert:n?undefined:true},o("div",{key:"c67d193e4ead6628fe23f5719b10012f16d1c658",class:"panel-tools__drawer-surface"},o("header",{key:"f227af7be503862e781b49ea46863dbd02025404",class:"panel-tools__header"},o("span",{key:"698466db2e9cf4ff7dc0776c64697d3d61dd6724",class:"panel-tools__title text-body-medium-emphasis"},e)),o("div",{key:"01abad893819e728fc6717ca6ecc9911732257ad",class:"panel-tools__body"},o("div",{key:"1a2995166ec9632b7023a38ff3d8383a33fbff0a",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("search"),"text-body-medium":true},hidden:!this.isViewActive("search")},o("slot",{key:"95640486740eda5d525f2601c0b407da7444002c",name:"search"})),o("div",{key:"11af6a6c4c8c3ede7e105ac8f57d01d3e73a9d94",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("messages"),"text-body-medium":true},hidden:!this.isViewActive("messages")},o("slot",{key:"ac7d54bf69ab564b0aa7f9ef47052ffd932836a3",name:"messages"})),o("div",{key:"e7598b297bde8cbda35a039e68979677080a3013",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("stacks"),"text-body-medium":true},hidden:!this.isViewActive("stacks")},o("slot",{key:"163558ca982ad5111b03ba01d99d86855c10db54",name:"stacks"})),o("div",{key:"ef9a3a02a226cfb93a8dc20c8e995482b2b7673b",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("activity"),"text-body-medium":true},hidden:!this.isViewActive("activity")},o("slot",{key:"ea3bb11bd2ad5a9f951bc9d4e9dcb2c9db4d80c3",name:"activity"})),o("div",{key:"c19f43ea62ed21c985b10c3e2e4819b985ba2487",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("agents"),"text-body-medium":true},hidden:!this.isViewActive("agents")},o("slot",{key:"10f826808aca855d4e34ca55cc56689eb2aa6031",name:"agents"})))))))}get el(){return this}static get watchers(){return{open:[{openChanged:0}],activeTool:[{activeToolChanged:0}],items:[{itemsChanged:0}],itemsJson:[{itemsChanged:0}]}}static get style(){return b()}},[262,"ds-panel-tools",{open:[1540],activeTool:[1537,"active-tool"],items:[16],itemsJson:[1,"items-json"],motion:[32],readyForMotion:[32],rovingIndex:[32]},undefined,{open:[{openChanged:0}],activeTool:[{activeToolChanged:0}],items:[{itemsChanged:0}],itemsJson:[{itemsChanged:0}]}]);function m(){if(typeof customElements==="undefined"){return}const e=["ds-panel-tools","ds-badge","ds-button-unfilled-icon","ds-icon"];e.forEach((e=>{switch(e){case"ds-panel-tools":if(!customElements.get(i(e))){customElements.define(i(e),g)}break;case"ds-badge":if(!customElements.get(i(e))){l()}break;case"ds-button-unfilled-icon":if(!customElements.get(i(e))){r()}break;case"ds-icon":if(!customElements.get(i(e))){d()}break}}))}m();const u=g;const _=m;export{u as DsPanelTools,_ as defineCustomElement};
|
|
1
|
+
import{p as e,H as s,c as t,h as o,a,t as i}from"./index.js";import{p as n}from"./p-BOQnc-M4.js";import{d as l}from"./p-CiEc8Nwx.js";import{d as r}from"./p-BTndnbR_.js";import{d}from"./p-DqBCQRRd.js";const c="search";const h={search:"Search",messages:"Messages",stacks:"Stacks",activity:"Activity",agents:"Agents"};function p(e,s){if(s){return n(s,[])}return e??[]}function f(e,s){return!e&&s==="idle"}function u(e,s,t){if(e&&s===t){return{open:false,activeTool:t,selected:false}}return{open:true,activeTool:t,selected:true}}const g=()=>`.sc-ds-panel-tools-h{display:block;flex:0 0 auto;box-sizing:border-box;height:100%;min-height:0;overflow:hidden;--_panel-tools-rail-width:var(--dimension-size-600);--_panel-tools-drawer-width:var(--dimension-panel-width-sm);--_panel-tools-border:var(--dimension-stroke-width-012, 1px) solid var(--color-border-tertiary);--_panel-tools-surface-bg:var(--color-background-secondary);--_panel-tools-expand-dur:var(--effect-animation-duration-medium-1, 300ms)}.panel-tools__layout.sc-ds-panel-tools{display:flex;flex-direction:row-reverse;align-items:stretch;height:100%;min-height:0;box-sizing:border-box}.panel-tools__drawer.sc-ds-panel-tools{flex:0 0 auto;max-width:0;min-width:0;height:100%;min-height:0;overflow:hidden;box-sizing:border-box;transition:none}.panel-tools--ready.panel-tools--motion-opening.sc-ds-panel-tools-h .panel-tools__drawer.sc-ds-panel-tools{transition:max-width var(--_panel-tools-expand-dur) var(--effect-animation-easing-ease-out, ease-out)}.panel-tools--ready.panel-tools--motion-closing.sc-ds-panel-tools-h .panel-tools__drawer.sc-ds-panel-tools{transition:max-width var(--_panel-tools-expand-dur) var(--effect-animation-easing-ease-in, ease-in)}.panel-tools--open.sc-ds-panel-tools-h .panel-tools__drawer.sc-ds-panel-tools{max-width:var(--_panel-tools-drawer-width)}.panel-tools__drawer--visible.sc-ds-panel-tools{border-left:var(--_panel-tools-border)}.panel-tools__drawer-surface.sc-ds-panel-tools{display:flex;flex-direction:column;width:var(--_panel-tools-drawer-width);height:100%;min-height:0;box-sizing:border-box;background-color:var(--_panel-tools-surface-bg)}ds-app-shell[gradient].sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[gradient] .sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[grid].sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[grid] .sc-ds-panel-tools-h .panel-tools__drawer-surface.sc-ds-panel-tools,ds-app-shell[gradient].sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools,ds-app-shell[gradient] .sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools,ds-app-shell[grid].sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools,ds-app-shell[grid] .sc-ds-panel-tools-h .panel-tools__rail.sc-ds-panel-tools{background-color:transparent}.panel-tools__header.sc-ds-panel-tools{flex:0 0 auto;display:flex;align-items:center;height:var(--dimension-size-600);padding:var(--dimension-space-100);border-bottom:var(--_panel-tools-border);color:var(--color-foreground-primary);box-sizing:border-box;-webkit-user-select:none;user-select:none}.panel-tools__title.sc-ds-panel-tools{display:inline-flex;align-items:center;height:var(--dimension-size-400);padding-inline:var(--dimension-space-100);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-tools__body.sc-ds-panel-tools{flex:1 1 auto;min-height:0;overflow:auto;position:relative}.panel-tools--drawer-resting.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{content-visibility:auto;contain-intrinsic-size:auto 200px}.panel-tools__view.sc-ds-panel-tools{display:none;height:100%;min-height:0;box-sizing:border-box;padding:var(--dimension-space-200);color:var(--color-foreground-secondary);font-family:var(--typography-font-family);font-size:var(--typography-fontsize-md);line-height:var(--typography-lineheight-md);font-weight:var(--typography-weight-regular);letter-spacing:var(--typography-letterspacing-negative-half)}.panel-tools__view.sc-ds-panel-tools-s>*,.panel-tools__view .sc-ds-panel-tools-s>*{margin:0;color:var(--color-foreground-secondary);font-family:var(--typography-font-family);font-size:var(--typography-fontsize-md);line-height:var(--typography-lineheight-md);font-weight:var(--typography-weight-regular);letter-spacing:var(--typography-letterspacing-negative-half)}.panel-tools__view--active.sc-ds-panel-tools{display:block}.panel-tools__rail.sc-ds-panel-tools{flex:0 0 var(--_panel-tools-rail-width);width:var(--_panel-tools-rail-width);min-width:var(--_panel-tools-rail-width);display:flex;flex-direction:column;box-sizing:border-box;height:100%;min-height:0;border-left:var(--_panel-tools-border);background-color:var(--_panel-tools-surface-bg)}.panel-tools__rail-header.sc-ds-panel-tools{display:flex;align-items:center;justify-content:center;height:var(--dimension-size-600);padding:var(--dimension-space-100);flex-shrink:0;box-sizing:border-box;border-bottom:var(--_panel-tools-border)}.panel-tools__rail-body.sc-ds-panel-tools{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:var(--dimension-space-050);padding:var(--dimension-space-100);box-sizing:border-box;scrollbar-width:none}.panel-tools__rail-body.sc-ds-panel-tools::-webkit-scrollbar{display:none}.panel-tools__rail-action.sc-ds-panel-tools{display:flex;align-items:center;justify-content:center;width:100%;height:var(--dimension-size-400);flex-shrink:0}`;const m=e(class e extends s{constructor(e){super();if(e!==false){this.__registerHost()}this.dsToolChange=t(this,"dsToolChange");this.dsChromeTransitionStart=t(this,"dsChromeTransitionStart");this.dsChromeTransitionEnd=t(this,"dsChromeTransitionEnd");this.open=false;this.activeTool="";this.items=[];this.itemsJson="";this.motion="idle";this.readyForMotion=false;this.rovingIndex=0;this.motionEnableGeneration=0;this.handleTransitionEnd=e=>{if(e.target!==this.el.querySelector(".panel-tools__drawer"))return;if(e.propertyName!=="max-width")return;this.motion="idle";this.dsChromeTransitionEnd.emit({source:"panel-tools"})};this.handleToolChange=e=>{const s=u(this.open,this.activeTool,e);this.open=s.open;this.activeTool=s.activeTool;this.dsToolChange.emit({id:e,selected:s.selected})};this.handleRailKeyDown=(e,s)=>{const t=this.orderedRailItems;if(!t.length)return;if(e.key==="Enter"||e.key===" "){e.preventDefault();this.handleToolChange(t[s].id);return}if(e.key==="ArrowDown"){if(s>=t.length-1)return;e.preventDefault();this.focusRailAt(s+1);return}if(e.key==="ArrowUp"){if(s<=0)return;e.preventDefault();this.focusRailAt(s-1)}}}get railItems(){return p(this.items,this.itemsJson)}get orderedRailItems(){const e=this.railItems;const s=e.find((e=>e.id===c));const t=e.filter((e=>e.id!==c));return s?[s,...t]:t}disconnectedCallback(){this.el.removeEventListener("transitionend",this.handleTransitionEnd);this.motionEnableGeneration+=1}deferMotionEnable(){if(this.readyForMotion)return;const e=++this.motionEnableGeneration;requestAnimationFrame((()=>{if(e!==this.motionEnableGeneration)return;requestAnimationFrame((()=>{if(e!==this.motionEnableGeneration)return;this.readyForMotion=true}))}))}connectedCallback(){this.el.addEventListener("transitionend",this.handleTransitionEnd)}openChanged(e,s){if(this.readyForMotion&&s!==undefined&&s!==e){this.motion=e?"opening":"closing";this.dsChromeTransitionStart.emit({source:"panel-tools",phase:e?"opening":"closing"})}this.deferMotionEnable()}activeToolChanged(){this.deferMotionEnable()}componentDidLoad(){this.deferMotionEnable()}itemsChanged(){this.rovingIndex=0;this.deferMotionEnable()}isRailSelected(e){return this.open&&this.activeTool===e}isDrawerPresent(){return this.open||this.motion==="closing"}isViewActive(e){return this.isDrawerPresent()&&this.activeTool===e}headerLabel(){if(!this.isDrawerPresent()||!this.activeTool)return"";return h[this.activeTool]??""}async activateTool(e){const s=this.railItems.find((s=>s.id===e));if(!s||s.inactive)return;this.handleToolChange(e)}async closeDrawer(){if(!this.open)return;const e=this.activeTool;this.open=false;if(e){this.dsToolChange.emit({id:e,selected:false})}}focusRailAt(e){const s=this.orderedRailItems;if(!s.length)return;const t=Math.max(0,Math.min(e,s.length-1));if(t===this.rovingIndex)return;this.rovingIndex=t;const o=Array.from(this.el.querySelectorAll(".panel-tools__rail-action .button-icon"));o[t]?.focus({preventScroll:true})}renderRailAction(e,s){return o("ds-button-unfilled-icon",{key:e.id,class:"panel-tools__rail-action",icon:e.icon,isActive:this.isRailSelected(e.id),activeFill:false,dot:e.dot??false,inactive:e.inactive,focusTabIndex:s===this.rovingIndex?0:-1,"aria-label":e.ariaLabel??h[e.id],pressed:this.isRailSelected(e.id),onFocusin:()=>{this.rovingIndex=s},onKeyDown:e=>this.handleRailKeyDown(e,s),onDsClick:()=>this.handleToolChange(e.id)})}render(){const e=this.headerLabel();const s=this.orderedRailItems;const t=s.find((e=>e.id===c));const i=s.filter((e=>e.id!==c));const n=this.isDrawerPresent();const l=f(this.open,this.motion);return o(a,{key:"3a03a7796177bc4c35679b0c1f0d59c168c6632f",class:{"panel-tools":true,"panel-tools--open":this.open,"panel-tools--ready":this.readyForMotion,"panel-tools--motion-opening":this.motion==="opening","panel-tools--motion-closing":this.motion==="closing","panel-tools--drawer-resting":l},role:"complementary","aria-label":"Tools"},o("div",{key:"60a85f7995518fd8a2cea1da55c4ef19e71b7af1",class:"panel-tools__layout"},o("nav",{key:"45208e1bbc6d18ff012c2d043738844ecad423bd",class:"panel-tools__rail","aria-label":"Tool shortcuts"},t?o("div",{class:"panel-tools__rail-header"},this.renderRailAction(t,0)):null,o("div",{key:"8ae84262aa3eca333ff44c7cced8dd3740e15c4b",class:"panel-tools__rail-body"},i.map(((e,s)=>this.renderRailAction(e,t?s+1:s))))),o("div",{key:"82d2d99f5a7a65f4773544049f5139bb6163b56d",class:{"panel-tools__drawer":true,"panel-tools__drawer--visible":n},"aria-hidden":n?null:"true",inert:n?undefined:true},o("div",{key:"9e805c5f27cdbfe0b56a57739a9a8f141c30fc96",class:"panel-tools__drawer-surface"},o("header",{key:"6ccfe2c7a8f79b06c12f5bcad3ccfc2a50e554aa",class:"panel-tools__header"},o("span",{key:"29e56d604f046126427087f49cbce7d8873c657c",class:"panel-tools__title text-body-medium-emphasis"},e)),o("div",{key:"c697a333561dba12fc112005773128428b93376d",class:"panel-tools__body"},o("div",{key:"cdadef06be4406f540ad2feedc4450b90924b0cc",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("search"),"text-body-medium":true},hidden:!this.isViewActive("search")},o("slot",{key:"cea999e30107bde89a49c45865eac64dcbe38bc6",name:"search"})),o("div",{key:"717e8dae8f494917ce6b8618d6229b7d298b3163",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("messages"),"text-body-medium":true},hidden:!this.isViewActive("messages")},o("slot",{key:"e20cb76f14c7c06be856a8456a8fbcdf5e3829d4",name:"messages"})),o("div",{key:"8f4a525710061e435d165ae781d62a18e3e145b7",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("stacks"),"text-body-medium":true},hidden:!this.isViewActive("stacks")},o("slot",{key:"1a98e5c768962759f1f95426deca712c24a119c5",name:"stacks"})),o("div",{key:"c1b72cf8129f72540c2889524e28171d92c54722",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("activity"),"text-body-medium":true},hidden:!this.isViewActive("activity")},o("slot",{key:"dffe6de0a5a0f8eb87a0a39752af8e08b322b389",name:"activity"})),o("div",{key:"50487f7253b7960b24037aeddf0e527b82487a73",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("agents"),"text-body-medium":true},hidden:!this.isViewActive("agents")},o("slot",{key:"73f3eb9a2509bd1041fced6e9e3bf060f6e84285",name:"agents"})))))))}get el(){return this}static get watchers(){return{open:[{openChanged:0}],activeTool:[{activeToolChanged:0}],items:[{itemsChanged:0}],itemsJson:[{itemsChanged:0}]}}static get style(){return g()}},[262,"ds-panel-tools",{open:[1540],activeTool:[1537,"active-tool"],items:[16],itemsJson:[1,"items-json"],motion:[32],readyForMotion:[32],rovingIndex:[32],activateTool:[64],closeDrawer:[64]},undefined,{open:[{openChanged:0}],activeTool:[{activeToolChanged:0}],items:[{itemsChanged:0}],itemsJson:[{itemsChanged:0}]}]);function b(){if(typeof customElements==="undefined"){return}const e=["ds-panel-tools","ds-badge","ds-button-unfilled-icon","ds-icon"];e.forEach((e=>{switch(e){case"ds-panel-tools":if(!customElements.get(i(e))){customElements.define(i(e),m)}break;case"ds-badge":if(!customElements.get(i(e))){l()}break;case"ds-button-unfilled-icon":if(!customElements.get(i(e))){r()}break;case"ds-icon":if(!customElements.get(i(e))){d()}break}}))}b();const _=m;const v=b;export{_ as DsPanelTools,v as defineCustomElement};
|
|
2
2
|
//# sourceMappingURL=ds-panel-tools.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["PANEL_TOOLS_PRIMARY_TOOL_ID","PANEL_TOOLS_LABELS","search","messages","stacks","activity","agents","parsePanelToolsItems","items","itemsJson","parseJsonArrayProp","panelToolsDrawerResting","open","motion","panelToolsCss","PanelTools","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","activeTool","readyForMotion","rovingIndex","motionEnableGeneration","handleTransitionEnd","event","target","el","querySelector","propertyName","dsChromeTransitionEnd","emit","source","handleToolChange","id","selected","isRailSelected","dsToolChange","handleRailKeyDown","e","index","orderedRailItems","length","key","preventDefault","focusRailAt","railItems","headerItem","find","item","bodyItems","filter","disconnectedCallback","removeEventListener","deferMotionEnable","generation","requestAnimationFrame","connectedCallback","addEventListener","openChanged","isOpen","wasOpen","undefined","dsChromeTransitionStart","phase","activeToolChanged","componentDidLoad","itemsChanged","isDrawerPresent","isViewActive","headerLabel","bounded","actions","Array","from","querySelectorAll","focus","preventScroll","renderRailAction","h","class","icon","isActive","activeFill","dot","inactive","focusTabIndex","ariaLabel","pressed","onFocusin","onKeyDown","onDsClick","render","showDrawerChrome","drawerResting","Host","role","map","bodyIdx","inert","hidden","name"],"sources":["src/wc/components/PanelTools/panel-tools-types.ts","src/wc/components/PanelTools/panel-tools-utils.ts","src/wc/components/PanelTools/PanelTools.css?tag=ds-panel-tools&encapsulation=scoped","src/wc/components/PanelTools/PanelTools.tsx"],"sourcesContent":["/** Tool ids for the `ds-panel-tools` rail and drawer views. */\nexport type PanelToolsToolId = 'search' | 'agents' | 'messages' | 'stacks' | 'activity';\n\nexport const PANEL_TOOLS_TOOL_IDS: PanelToolsToolId[] = [\n 'search',\n 'agents',\n 'messages',\n 'stacks',\n 'activity',\n];\n\n/** Rail header slot — mirrors panel-nav M logo row. */\nexport const PANEL_TOOLS_PRIMARY_TOOL_ID: PanelToolsToolId = 'search';\n\nexport const PANEL_TOOLS_LABELS: Record<PanelToolsToolId, string> = {\n search: 'Search',\n messages: 'Messages',\n stacks: 'Stacks',\n activity: 'Activity',\n agents: 'Agents',\n};\n\nexport interface PanelToolsItem {\n id: PanelToolsToolId;\n /** Icon name for <ds-icon>. */\n icon: string;\n /** Whether this rail button is currently pressed/active. */\n selected?: boolean;\n /** Show a notification dot. */\n dot?: boolean;\n inactive?: boolean;\n ariaLabel?: string;\n}\n","import { parseJsonArrayProp } from '../BarNav/bar-nav-utils';\nimport type { PanelToolsItem } from './panel-tools-types';\n\nexport function parsePanelToolsItems(\n items: PanelToolsItem[],\n itemsJson: string,\n): PanelToolsItem[] {\n if (itemsJson) {\n return parseJsonArrayProp<PanelToolsItem>(itemsJson, []);\n }\n return items ?? [];\n}\n\nexport function shouldResyncPanelToolsItems(\n prev: PanelToolsItem[],\n next: PanelToolsItem[],\n): boolean {\n if (prev.length !== next.length) return true;\n return next.some((item, index) => {\n const prior = prev[index];\n if (!prior) return true;\n return (\n prior.id !== item.id ||\n prior.icon !== item.icon ||\n prior.selected !== item.selected ||\n prior.dot !== item.dot ||\n prior.inactive !== item.inactive ||\n prior.ariaLabel !== item.ariaLabel\n );\n });\n}\n\nexport type PanelToolsMotion = 'opening' | 'closing' | 'idle';\n\n/** True when the drawer clip is fully closed — safe to skip painting slot content. */\nexport function panelToolsDrawerResting(open: boolean, motion: PanelToolsMotion): boolean {\n return !open && motion === 'idle';\n}\n",":host {\n display: block;\n flex: 0 0 auto;\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n --_panel-tools-rail-width: var(--dimension-size-600);\n --_panel-tools-drawer-width: var(--dimension-panel-width-sm);\n --_panel-tools-border: var(--dimension-stroke-width-012, 1px) solid var(--color-border-tertiary);\n --_panel-tools-surface-bg: var(--color-background-secondary);\n /* Match panel-nav expand timing (medium-1); easing differs by direction. */\n --_panel-tools-expand-dur: var(--effect-animation-duration-medium-1, 300ms);\n}\n\n.panel-tools__layout {\n display: flex;\n flex-direction: row-reverse;\n align-items: stretch;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n/* Clip frame — only max-width animates (slide reveal, same as pre-rail :host). */\n.panel-tools__drawer {\n flex: 0 0 auto;\n max-width: 0;\n min-width: 0;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n box-sizing: border-box;\n transition: none;\n}\n\n:host(.panel-tools--ready.panel-tools--motion-opening) .panel-tools__drawer {\n transition: max-width var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-out, ease-out);\n}\n\n:host(.panel-tools--ready.panel-tools--motion-closing) .panel-tools__drawer {\n transition: max-width var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-in, ease-in);\n}\n\n:host(.panel-tools--open) .panel-tools__drawer {\n max-width: var(--_panel-tools-drawer-width);\n}\n\n.panel-tools__drawer--visible {\n border-left: var(--_panel-tools-border);\n}\n\n/* Fixed-width surface — stays 400px while the clip frame opens/closes. */\n.panel-tools__drawer-surface {\n display: flex;\n flex-direction: column;\n width: var(--_panel-tools-drawer-width);\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n background-color: var(--_panel-tools-surface-bg);\n}\n\n/* Shell-owned chrome (bg + wash +/or grid) — drawer + rail are transparent frames. */\n:host-context(ds-app-shell[gradient]) .panel-tools__drawer-surface,\n:host-context(ds-app-shell[grid]) .panel-tools__drawer-surface,\n:host-context(ds-app-shell[gradient]) .panel-tools__rail,\n:host-context(ds-app-shell[grid]) .panel-tools__rail {\n background-color: transparent;\n}\n\n/* Aligns with ds-bar-nav row — same height, inset, border, and title token. */\n.panel-tools__header {\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n border-bottom: var(--_panel-tools-border);\n color: var(--color-foreground-primary);\n box-sizing: border-box;\n -webkit-user-select: none;\n user-select: none;\n}\n\n.panel-tools__title {\n display: inline-flex;\n align-items: center;\n height: var(--dimension-size-400);\n padding-inline: var(--dimension-space-100);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.panel-tools__body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n position: relative;\n}\n\n/* Skip paint while fully closed; cleared during open/close motion for WYSIWYG slide. */\n:host(.panel-tools--drawer-resting) .panel-tools__body {\n content-visibility: auto;\n contain-intrinsic-size: auto 200px;\n}\n\n.panel-tools__view {\n display: none;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n padding: var(--dimension-space-200);\n color: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-md);\n line-height: var(--typography-lineheight-md);\n font-weight: var(--typography-weight-regular);\n letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\n.panel-tools__view ::slotted(*) {\n margin: 0;\n color: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-md);\n line-height: var(--typography-lineheight-md);\n font-weight: var(--typography-weight-regular);\n letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\n.panel-tools__view--active {\n display: block;\n}\n\n/* Rail — mirrors collapsed panel-nav width, padding, and item rhythm. */\n.panel-tools__rail {\n flex: 0 0 var(--_panel-tools-rail-width);\n width: var(--_panel-tools-rail-width);\n min-width: var(--_panel-tools-rail-width);\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n border-left: var(--_panel-tools-border);\n background-color: var(--_panel-tools-surface-bg);\n}\n\n.panel-tools__rail-header {\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n flex-shrink: 0;\n box-sizing: border-box;\n border-bottom: var(--_panel-tools-border);\n}\n\n.panel-tools__rail-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050);\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n scrollbar-width: none;\n}\n\n.panel-tools__rail-body::-webkit-scrollbar {\n display: none;\n}\n\n.panel-tools__rail-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: var(--dimension-size-400);\n flex-shrink: 0;\n}\n","import { Component, Prop, Event, EventEmitter, Element, State, Watch, h, Host } from '@stencil/core';\nimport type { ChromeTransitionDetail } from '../../nav/chrome-transition';\nimport {\n PANEL_TOOLS_LABELS,\n PANEL_TOOLS_PRIMARY_TOOL_ID,\n type PanelToolsItem,\n type PanelToolsToolId,\n} from './panel-tools-types';\nimport { parsePanelToolsItems, panelToolsDrawerResting } from './panel-tools-utils';\n\n@Component({\n tag: 'ds-panel-tools',\n styleUrl: 'PanelTools.css',\n scoped: true,\n})\nexport class PanelTools {\n @Element() el!: HTMLElement;\n\n /** When false, only the icon rail is shown. */\n @Prop({ mutable: true, reflect: true }) open: boolean = false;\n\n /** Active tool view — `search`, `agents`, `messages`, `stacks`, or `activity`. */\n @Prop({ mutable: true, attribute: 'active-tool', reflect: true })\n activeTool: PanelToolsToolId | '' = '';\n\n /**\n * Rail items rendered in the right column.\n * Set via JS property: `el.items = [...]`. Replace the array reference to update.\n */\n @Prop() items: PanelToolsItem[] = [];\n\n /** JSON fallback for `items` — useful when framework bindings don't propagate arrays. */\n @Prop({ attribute: 'items-json' }) itemsJson: string = '';\n\n /** Emitted when a rail button is toggled. Detail = { id, selected }. */\n @Event({ bubbles: true, composed: true }) dsToolChange!: EventEmitter<{\n id: PanelToolsToolId;\n selected: boolean;\n }>;\n\n /** Bubbling lifecycle — `ds-bar-nav` defers overflow checks during drawer motion. */\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionStart!: EventEmitter<ChromeTransitionDetail>;\n\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionEnd!: EventEmitter<ChromeTransitionDetail>;\n\n /** Arms open vs close easing for the in-flight width transition. */\n @State() private motion: 'opening' | 'closing' | 'idle' = 'idle';\n\n /** Suppresses width transition until the host has painted its initial open state. */\n @State() private readyForMotion = false;\n\n @State() private rovingIndex = 0;\n\n private motionEnableGeneration = 0;\n\n private get railItems(): PanelToolsItem[] {\n return parsePanelToolsItems(this.items, this.itemsJson);\n }\n\n private get orderedRailItems(): PanelToolsItem[] {\n const railItems = this.railItems;\n const headerItem = railItems.find(item => item.id === PANEL_TOOLS_PRIMARY_TOOL_ID);\n const bodyItems = railItems.filter(item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID);\n return headerItem ? [headerItem, ...bodyItems] : bodyItems;\n }\n\n disconnectedCallback() {\n this.el.removeEventListener('transitionend', this.handleTransitionEnd);\n this.motionEnableGeneration += 1;\n }\n\n private deferMotionEnable() {\n if (this.readyForMotion) return;\n const generation = ++this.motionEnableGeneration;\n requestAnimationFrame(() => {\n if (generation !== this.motionEnableGeneration) return;\n requestAnimationFrame(() => {\n if (generation !== this.motionEnableGeneration) return;\n this.readyForMotion = true;\n });\n });\n }\n\n connectedCallback() {\n this.el.addEventListener('transitionend', this.handleTransitionEnd);\n }\n\n @Watch('open')\n openChanged(isOpen: boolean, wasOpen?: boolean) {\n if (this.readyForMotion && wasOpen !== undefined && wasOpen !== isOpen) {\n this.motion = isOpen ? 'opening' : 'closing';\n this.dsChromeTransitionStart.emit({\n source: 'panel-tools',\n phase: isOpen ? 'opening' : 'closing',\n });\n }\n this.deferMotionEnable();\n }\n\n @Watch('activeTool')\n activeToolChanged() {\n this.deferMotionEnable();\n }\n\n componentDidLoad() {\n this.deferMotionEnable();\n }\n\n @Watch('items')\n @Watch('itemsJson')\n itemsChanged() {\n this.rovingIndex = 0;\n this.deferMotionEnable();\n }\n\n private handleTransitionEnd = (event: TransitionEvent) => {\n if (event.target !== this.el.querySelector('.panel-tools__drawer')) return;\n if (event.propertyName !== 'max-width') return;\n this.motion = 'idle';\n this.dsChromeTransitionEnd.emit({ source: 'panel-tools' });\n };\n\n /** Rail selection follows `open` immediately — independent of the slide animation. */\n private isRailSelected(id: PanelToolsToolId): boolean {\n return this.open && this.activeTool === id;\n }\n\n /** Drawer body stays mounted while the clip frame animates closed. */\n private isDrawerPresent(): boolean {\n return this.open || this.motion === 'closing';\n }\n\n private isViewActive(id: PanelToolsToolId): boolean {\n return this.isDrawerPresent() && this.activeTool === id;\n }\n\n private headerLabel(): string {\n if (!this.isDrawerPresent() || !this.activeTool) return '';\n return PANEL_TOOLS_LABELS[this.activeTool as PanelToolsToolId] ?? '';\n }\n\n private handleToolChange = (id: PanelToolsToolId) => {\n const selected = !this.isRailSelected(id);\n if (selected) {\n this.open = true;\n this.activeTool = id;\n } else {\n this.open = false;\n }\n this.dsToolChange.emit({ id, selected });\n };\n\n private focusRailAt(index: number) {\n const items = this.orderedRailItems;\n if (!items.length) return;\n const bounded = ((index % items.length) + items.length) % items.length;\n this.rovingIndex = bounded;\n const actions = Array.from(\n this.el.querySelectorAll<HTMLElement>('.panel-tools__rail-action .button-icon'),\n );\n actions[bounded]?.focus({ preventScroll: true });\n }\n\n private handleRailKeyDown = (e: KeyboardEvent, index: number) => {\n const items = this.orderedRailItems;\n if (!items.length) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.handleToolChange(items[index].id);\n return;\n }\n\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n this.focusRailAt(index + 1);\n return;\n }\n\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n this.focusRailAt(index - 1);\n }\n };\n\n private renderRailAction(item: PanelToolsItem, index: number) {\n return (\n <ds-button-unfilled-icon\n key={item.id}\n class=\"panel-tools__rail-action\"\n icon={item.icon}\n isActive={this.isRailSelected(item.id)}\n activeFill={false}\n dot={item.dot ?? false}\n inactive={item.inactive}\n focusTabIndex={index === this.rovingIndex ? 0 : -1}\n aria-label={item.ariaLabel ?? PANEL_TOOLS_LABELS[item.id]}\n pressed={this.isRailSelected(item.id)}\n onFocusin={() => { this.rovingIndex = index; }}\n onKeyDown={(e: KeyboardEvent) => this.handleRailKeyDown(e, index)}\n onDsClick={() => this.handleToolChange(item.id)}\n />\n );\n }\n\n render() {\n const headerLabel = this.headerLabel();\n const orderedRailItems = this.orderedRailItems;\n const headerItem = orderedRailItems.find(item => item.id === PANEL_TOOLS_PRIMARY_TOOL_ID);\n const bodyItems = orderedRailItems.filter(item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID);\n const showDrawerChrome = this.isDrawerPresent();\n const drawerResting = panelToolsDrawerResting(this.open, this.motion);\n\n return (\n <Host\n class={{\n 'panel-tools': true,\n 'panel-tools--open': this.open,\n 'panel-tools--ready': this.readyForMotion,\n 'panel-tools--motion-opening': this.motion === 'opening',\n 'panel-tools--motion-closing': this.motion === 'closing',\n 'panel-tools--drawer-resting': drawerResting,\n }}\n role=\"complementary\"\n aria-label=\"Tools\"\n >\n <div class=\"panel-tools__layout\">\n <nav class=\"panel-tools__rail\" aria-label=\"Tool shortcuts\">\n {headerItem ? (\n <div class=\"panel-tools__rail-header\">\n {this.renderRailAction(headerItem, 0)}\n </div>\n ) : null}\n <div class=\"panel-tools__rail-body\">\n {bodyItems.map((item, bodyIdx) =>\n this.renderRailAction(item, headerItem ? bodyIdx + 1 : bodyIdx),\n )}\n </div>\n </nav>\n\n <div\n class={{\n 'panel-tools__drawer': true,\n 'panel-tools__drawer--visible': showDrawerChrome,\n }}\n aria-hidden={showDrawerChrome ? null : 'true'}\n inert={showDrawerChrome ? undefined : true}\n >\n <div class=\"panel-tools__drawer-surface\">\n <header class=\"panel-tools__header\">\n <span class=\"panel-tools__title text-body-medium-emphasis\">{headerLabel}</span>\n </header>\n <div class=\"panel-tools__body\">\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('search'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('search')}\n >\n <slot name=\"search\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('messages'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('messages')}\n >\n <slot name=\"messages\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('stacks'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('stacks')}\n >\n <slot name=\"stacks\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('activity'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('activity')}\n >\n <slot name=\"activity\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('agents'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('agents')}\n >\n <slot name=\"agents\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n </Host>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["PANEL_TOOLS_PRIMARY_TOOL_ID","PANEL_TOOLS_LABELS","search","messages","stacks","activity","agents","parsePanelToolsItems","items","itemsJson","parseJsonArrayProp","panelToolsDrawerResting","open","motion","resolvePanelToolActivation","activeTool","id","selected","panelToolsCss","PanelTools","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","readyForMotion","rovingIndex","motionEnableGeneration","handleTransitionEnd","event","target","el","querySelector","propertyName","dsChromeTransitionEnd","emit","source","handleToolChange","next","dsToolChange","handleRailKeyDown","e","index","orderedRailItems","length","key","preventDefault","focusRailAt","railItems","headerItem","find","item","bodyItems","filter","disconnectedCallback","removeEventListener","deferMotionEnable","generation","requestAnimationFrame","connectedCallback","addEventListener","openChanged","isOpen","wasOpen","undefined","dsChromeTransitionStart","phase","activeToolChanged","componentDidLoad","itemsChanged","isRailSelected","isDrawerPresent","isViewActive","headerLabel","activateTool","entry","inactive","closeDrawer","bounded","Math","max","min","actions","Array","from","querySelectorAll","focus","preventScroll","renderRailAction","h","class","icon","isActive","activeFill","dot","focusTabIndex","ariaLabel","pressed","onFocusin","onKeyDown","onDsClick","render","showDrawerChrome","drawerResting","Host","role","map","bodyIdx","inert","hidden","name"],"sources":["src/wc/components/PanelTools/panel-tools-types.ts","src/wc/components/PanelTools/panel-tools-utils.ts","src/wc/components/PanelTools/PanelTools.css?tag=ds-panel-tools&encapsulation=scoped","src/wc/components/PanelTools/PanelTools.tsx"],"sourcesContent":["/** Tool ids for the `ds-panel-tools` rail and drawer views. */\nexport type PanelToolsToolId = 'search' | 'agents' | 'messages' | 'stacks' | 'activity';\n\nexport const PANEL_TOOLS_TOOL_IDS: PanelToolsToolId[] = [\n 'search',\n 'agents',\n 'messages',\n 'stacks',\n 'activity',\n];\n\n/** Rail header slot — mirrors panel-nav M logo row. */\nexport const PANEL_TOOLS_PRIMARY_TOOL_ID: PanelToolsToolId = 'search';\n\nexport const PANEL_TOOLS_LABELS: Record<PanelToolsToolId, string> = {\n search: 'Search',\n messages: 'Messages',\n stacks: 'Stacks',\n activity: 'Activity',\n agents: 'Agents',\n};\n\nexport interface PanelToolsItem {\n id: PanelToolsToolId;\n /** Icon name for <ds-icon>. */\n icon: string;\n /** Whether this rail button is currently pressed/active. */\n selected?: boolean;\n /** Show a notification dot. */\n dot?: boolean;\n inactive?: boolean;\n ariaLabel?: string;\n}\n","import { parseJsonArrayProp } from '../BarNav/bar-nav-utils';\nimport type { PanelToolsItem, PanelToolsToolId } from './panel-tools-types';\n\nexport function parsePanelToolsItems(\n items: PanelToolsItem[],\n itemsJson: string,\n): PanelToolsItem[] {\n if (itemsJson) {\n return parseJsonArrayProp<PanelToolsItem>(itemsJson, []);\n }\n return items ?? [];\n}\n\nexport function shouldResyncPanelToolsItems(\n prev: PanelToolsItem[],\n next: PanelToolsItem[],\n): boolean {\n if (prev.length !== next.length) return true;\n return next.some((item, index) => {\n const prior = prev[index];\n if (!prior) return true;\n return (\n prior.id !== item.id ||\n prior.icon !== item.icon ||\n prior.selected !== item.selected ||\n prior.dot !== item.dot ||\n prior.inactive !== item.inactive ||\n prior.ariaLabel !== item.ariaLabel\n );\n });\n}\n\nexport type PanelToolsMotion = 'opening' | 'closing' | 'idle';\n\n/** True when the drawer clip is fully closed — safe to skip painting slot content. */\nexport function panelToolsDrawerResting(open: boolean, motion: PanelToolsMotion): boolean {\n return !open && motion === 'idle';\n}\n\n/** Toggle or switch rail tool selection — repeat activation closes the active tool. */\nexport function resolvePanelToolActivation(\n open: boolean,\n activeTool: PanelToolsToolId | '',\n id: PanelToolsToolId,\n): { open: boolean; activeTool: PanelToolsToolId; selected: boolean } {\n if (open && activeTool === id) {\n return { open: false, activeTool: id, selected: false };\n }\n return { open: true, activeTool: id, selected: true };\n}\n",":host {\n display: block;\n flex: 0 0 auto;\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n --_panel-tools-rail-width: var(--dimension-size-600);\n --_panel-tools-drawer-width: var(--dimension-panel-width-sm);\n --_panel-tools-border: var(--dimension-stroke-width-012, 1px) solid var(--color-border-tertiary);\n --_panel-tools-surface-bg: var(--color-background-secondary);\n /* Match panel-nav expand timing (medium-1); easing differs by direction. */\n --_panel-tools-expand-dur: var(--effect-animation-duration-medium-1, 300ms);\n}\n\n.panel-tools__layout {\n display: flex;\n flex-direction: row-reverse;\n align-items: stretch;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n/* Clip frame — only max-width animates (slide reveal, same as pre-rail :host). */\n.panel-tools__drawer {\n flex: 0 0 auto;\n max-width: 0;\n min-width: 0;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n box-sizing: border-box;\n transition: none;\n}\n\n:host(.panel-tools--ready.panel-tools--motion-opening) .panel-tools__drawer {\n transition: max-width var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-out, ease-out);\n}\n\n:host(.panel-tools--ready.panel-tools--motion-closing) .panel-tools__drawer {\n transition: max-width var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-in, ease-in);\n}\n\n:host(.panel-tools--open) .panel-tools__drawer {\n max-width: var(--_panel-tools-drawer-width);\n}\n\n.panel-tools__drawer--visible {\n border-left: var(--_panel-tools-border);\n}\n\n/* Fixed-width surface — stays 400px while the clip frame opens/closes. */\n.panel-tools__drawer-surface {\n display: flex;\n flex-direction: column;\n width: var(--_panel-tools-drawer-width);\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n background-color: var(--_panel-tools-surface-bg);\n}\n\n/* Shell-owned chrome (bg + wash +/or grid) — drawer + rail are transparent frames. */\n:host-context(ds-app-shell[gradient]) .panel-tools__drawer-surface,\n:host-context(ds-app-shell[grid]) .panel-tools__drawer-surface,\n:host-context(ds-app-shell[gradient]) .panel-tools__rail,\n:host-context(ds-app-shell[grid]) .panel-tools__rail {\n background-color: transparent;\n}\n\n/* Aligns with ds-bar-nav row — same height, inset, border, and title token. */\n.panel-tools__header {\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n border-bottom: var(--_panel-tools-border);\n color: var(--color-foreground-primary);\n box-sizing: border-box;\n -webkit-user-select: none;\n user-select: none;\n}\n\n.panel-tools__title {\n display: inline-flex;\n align-items: center;\n height: var(--dimension-size-400);\n padding-inline: var(--dimension-space-100);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.panel-tools__body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n position: relative;\n}\n\n/* Skip paint while fully closed; cleared during open/close motion for WYSIWYG slide. */\n:host(.panel-tools--drawer-resting) .panel-tools__body {\n content-visibility: auto;\n contain-intrinsic-size: auto 200px;\n}\n\n.panel-tools__view {\n display: none;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n padding: var(--dimension-space-200);\n color: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-md);\n line-height: var(--typography-lineheight-md);\n font-weight: var(--typography-weight-regular);\n letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\n.panel-tools__view ::slotted(*) {\n margin: 0;\n color: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-md);\n line-height: var(--typography-lineheight-md);\n font-weight: var(--typography-weight-regular);\n letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\n.panel-tools__view--active {\n display: block;\n}\n\n/* Rail — mirrors collapsed panel-nav width, padding, and item rhythm. */\n.panel-tools__rail {\n flex: 0 0 var(--_panel-tools-rail-width);\n width: var(--_panel-tools-rail-width);\n min-width: var(--_panel-tools-rail-width);\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n border-left: var(--_panel-tools-border);\n background-color: var(--_panel-tools-surface-bg);\n}\n\n.panel-tools__rail-header {\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n flex-shrink: 0;\n box-sizing: border-box;\n border-bottom: var(--_panel-tools-border);\n}\n\n.panel-tools__rail-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050);\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n scrollbar-width: none;\n}\n\n.panel-tools__rail-body::-webkit-scrollbar {\n display: none;\n}\n\n.panel-tools__rail-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: var(--dimension-size-400);\n flex-shrink: 0;\n}\n","import { Component, Prop, Event, EventEmitter, Element, State, Watch, Method, h, Host } from '@stencil/core';\nimport type { ChromeTransitionDetail } from '../../nav/chrome-transition';\nimport {\n PANEL_TOOLS_LABELS,\n PANEL_TOOLS_PRIMARY_TOOL_ID,\n type PanelToolsItem,\n type PanelToolsToolId,\n} from './panel-tools-types';\nimport { parsePanelToolsItems, panelToolsDrawerResting, resolvePanelToolActivation } from './panel-tools-utils';\n\n@Component({\n tag: 'ds-panel-tools',\n styleUrl: 'PanelTools.css',\n scoped: true,\n})\nexport class PanelTools {\n @Element() el!: HTMLElement;\n\n /** When false, only the icon rail is shown. */\n @Prop({ mutable: true, reflect: true }) open: boolean = false;\n\n /** Active tool view — `search`, `agents`, `messages`, `stacks`, or `activity`. */\n @Prop({ mutable: true, attribute: 'active-tool', reflect: true })\n activeTool: PanelToolsToolId | '' = '';\n\n /**\n * Rail items rendered in the right column.\n * Set via JS property: `el.items = [...]`. Replace the array reference to update.\n */\n @Prop() items: PanelToolsItem[] = [];\n\n /** JSON fallback for `items` — useful when framework bindings don't propagate arrays. */\n @Prop({ attribute: 'items-json' }) itemsJson: string = '';\n\n /** Emitted when a rail button is toggled. Detail = { id, selected }. */\n @Event({ bubbles: true, composed: true }) dsToolChange!: EventEmitter<{\n id: PanelToolsToolId;\n selected: boolean;\n }>;\n\n /** Bubbling lifecycle — `ds-bar-nav` defers overflow checks during drawer motion. */\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionStart!: EventEmitter<ChromeTransitionDetail>;\n\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionEnd!: EventEmitter<ChromeTransitionDetail>;\n\n /** Arms open vs close easing for the in-flight width transition. */\n @State() private motion: 'opening' | 'closing' | 'idle' = 'idle';\n\n /** Suppresses width transition until the host has painted its initial open state. */\n @State() private readyForMotion = false;\n\n @State() private rovingIndex = 0;\n\n private motionEnableGeneration = 0;\n\n private get railItems(): PanelToolsItem[] {\n return parsePanelToolsItems(this.items, this.itemsJson);\n }\n\n private get orderedRailItems(): PanelToolsItem[] {\n const railItems = this.railItems;\n const headerItem = railItems.find(item => item.id === PANEL_TOOLS_PRIMARY_TOOL_ID);\n const bodyItems = railItems.filter(item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID);\n return headerItem ? [headerItem, ...bodyItems] : bodyItems;\n }\n\n disconnectedCallback() {\n this.el.removeEventListener('transitionend', this.handleTransitionEnd);\n this.motionEnableGeneration += 1;\n }\n\n private deferMotionEnable() {\n if (this.readyForMotion) return;\n const generation = ++this.motionEnableGeneration;\n requestAnimationFrame(() => {\n if (generation !== this.motionEnableGeneration) return;\n requestAnimationFrame(() => {\n if (generation !== this.motionEnableGeneration) return;\n this.readyForMotion = true;\n });\n });\n }\n\n connectedCallback() {\n this.el.addEventListener('transitionend', this.handleTransitionEnd);\n }\n\n @Watch('open')\n openChanged(isOpen: boolean, wasOpen?: boolean) {\n if (this.readyForMotion && wasOpen !== undefined && wasOpen !== isOpen) {\n this.motion = isOpen ? 'opening' : 'closing';\n this.dsChromeTransitionStart.emit({\n source: 'panel-tools',\n phase: isOpen ? 'opening' : 'closing',\n });\n }\n this.deferMotionEnable();\n }\n\n @Watch('activeTool')\n activeToolChanged() {\n this.deferMotionEnable();\n }\n\n componentDidLoad() {\n this.deferMotionEnable();\n }\n\n @Watch('items')\n @Watch('itemsJson')\n itemsChanged() {\n this.rovingIndex = 0;\n this.deferMotionEnable();\n }\n\n private handleTransitionEnd = (event: TransitionEvent) => {\n if (event.target !== this.el.querySelector('.panel-tools__drawer')) return;\n if (event.propertyName !== 'max-width') return;\n this.motion = 'idle';\n this.dsChromeTransitionEnd.emit({ source: 'panel-tools' });\n };\n\n /** Rail selection follows `open` immediately — independent of the slide animation. */\n private isRailSelected(id: PanelToolsToolId): boolean {\n return this.open && this.activeTool === id;\n }\n\n /** Drawer body stays mounted while the clip frame animates closed. */\n private isDrawerPresent(): boolean {\n return this.open || this.motion === 'closing';\n }\n\n private isViewActive(id: PanelToolsToolId): boolean {\n return this.isDrawerPresent() && this.activeTool === id;\n }\n\n private headerLabel(): string {\n if (!this.isDrawerPresent() || !this.activeTool) return '';\n return PANEL_TOOLS_LABELS[this.activeTool as PanelToolsToolId] ?? '';\n }\n\n private handleToolChange = (id: PanelToolsToolId) => {\n const next = resolvePanelToolActivation(this.open, this.activeTool, id);\n this.open = next.open;\n this.activeTool = next.activeTool;\n this.dsToolChange.emit({ id, selected: next.selected });\n };\n\n /** Toggle any rail tool open/closed — shell shortcuts K/A/S/M/N call this. */\n @Method()\n async activateTool(id: PanelToolsToolId) {\n const item = this.railItems.find(entry => entry.id === id);\n if (!item || item.inactive) return;\n this.handleToolChange(id);\n }\n\n /** Close the tools drawer when open — used by shell keyboard shortcuts. */\n @Method()\n async closeDrawer() {\n if (!this.open) return;\n const id = this.activeTool;\n this.open = false;\n if (id) {\n this.dsToolChange.emit({ id, selected: false });\n }\n }\n\n private focusRailAt(index: number) {\n const items = this.orderedRailItems;\n if (!items.length) return;\n const bounded = Math.max(0, Math.min(index, items.length - 1));\n if (bounded === this.rovingIndex) return;\n this.rovingIndex = bounded;\n const actions = Array.from(\n this.el.querySelectorAll<HTMLElement>('.panel-tools__rail-action .button-icon'),\n );\n actions[bounded]?.focus({ preventScroll: true });\n }\n\n private handleRailKeyDown = (e: KeyboardEvent, index: number) => {\n const items = this.orderedRailItems;\n if (!items.length) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.handleToolChange(items[index].id);\n return;\n }\n\n if (e.key === 'ArrowDown') {\n if (index >= items.length - 1) return;\n e.preventDefault();\n this.focusRailAt(index + 1);\n return;\n }\n\n if (e.key === 'ArrowUp') {\n if (index <= 0) return;\n e.preventDefault();\n this.focusRailAt(index - 1);\n }\n };\n\n private renderRailAction(item: PanelToolsItem, index: number) {\n return (\n <ds-button-unfilled-icon\n key={item.id}\n class=\"panel-tools__rail-action\"\n icon={item.icon}\n isActive={this.isRailSelected(item.id)}\n activeFill={false}\n dot={item.dot ?? false}\n inactive={item.inactive}\n focusTabIndex={index === this.rovingIndex ? 0 : -1}\n aria-label={item.ariaLabel ?? PANEL_TOOLS_LABELS[item.id]}\n pressed={this.isRailSelected(item.id)}\n onFocusin={() => { this.rovingIndex = index; }}\n onKeyDown={(e: KeyboardEvent) => this.handleRailKeyDown(e, index)}\n onDsClick={() => this.handleToolChange(item.id)}\n />\n );\n }\n\n render() {\n const headerLabel = this.headerLabel();\n const orderedRailItems = this.orderedRailItems;\n const headerItem = orderedRailItems.find(item => item.id === PANEL_TOOLS_PRIMARY_TOOL_ID);\n const bodyItems = orderedRailItems.filter(item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID);\n const showDrawerChrome = this.isDrawerPresent();\n const drawerResting = panelToolsDrawerResting(this.open, this.motion);\n\n return (\n <Host\n class={{\n 'panel-tools': true,\n 'panel-tools--open': this.open,\n 'panel-tools--ready': this.readyForMotion,\n 'panel-tools--motion-opening': this.motion === 'opening',\n 'panel-tools--motion-closing': this.motion === 'closing',\n 'panel-tools--drawer-resting': drawerResting,\n }}\n role=\"complementary\"\n aria-label=\"Tools\"\n >\n <div class=\"panel-tools__layout\">\n <nav class=\"panel-tools__rail\" aria-label=\"Tool shortcuts\">\n {headerItem ? (\n <div class=\"panel-tools__rail-header\">\n {this.renderRailAction(headerItem, 0)}\n </div>\n ) : null}\n <div class=\"panel-tools__rail-body\">\n {bodyItems.map((item, bodyIdx) =>\n this.renderRailAction(item, headerItem ? bodyIdx + 1 : bodyIdx),\n )}\n </div>\n </nav>\n\n <div\n class={{\n 'panel-tools__drawer': true,\n 'panel-tools__drawer--visible': showDrawerChrome,\n }}\n aria-hidden={showDrawerChrome ? null : 'true'}\n inert={showDrawerChrome ? undefined : true}\n >\n <div class=\"panel-tools__drawer-surface\">\n <header class=\"panel-tools__header\">\n <span class=\"panel-tools__title text-body-medium-emphasis\">{headerLabel}</span>\n </header>\n <div class=\"panel-tools__body\">\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('search'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('search')}\n >\n <slot name=\"search\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('messages'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('messages')}\n >\n <slot name=\"messages\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('stacks'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('stacks')}\n >\n <slot name=\"stacks\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('activity'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('activity')}\n >\n <slot name=\"activity\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('agents'),\n 'text-body-medium': true,\n }}\n hidden={!this.isViewActive('agents')}\n >\n <slot name=\"agents\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n </Host>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
|