@ds-mo/ui 3.2.1 → 3.3.0

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 CHANGED
@@ -1 +1 @@
1
- 1783825797406
1
+ 1783827628207
package/dist/agent.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
3
  "package": "@ds-mo/ui",
4
- "packageVersion": "3.2.1",
4
+ "packageVersion": "3.3.0",
5
5
  "kind": "components",
6
6
  "entries": [
7
7
  {
@@ -1930,9 +1930,106 @@
1930
1930
  "tag": "ds-panel-tools",
1931
1931
  "name": "panel-tools",
1932
1932
  "title": "PanelTools",
1933
- "summary": "PanelTools component from @ds-mo/ui.",
1934
- "intentStatus": "migration-pending",
1935
- "intent": null,
1933
+ "summary": "Required AppShell utility rail and persistent drawer host for the fixed set of global Search, Agents, Messages, Stacks, Activity, and Help products.",
1934
+ "intentStatus": "complete",
1935
+ "intent": {
1936
+ "audience": "specialized",
1937
+ "status": "stable",
1938
+ "summary": "Required AppShell utility rail and persistent drawer host for the fixed set of global Search, Agents, Messages, Stacks, Activity, and Help products.",
1939
+ "useWhen": [
1940
+ "Composing the required global tools region inside the application's single AppShell.",
1941
+ "Users need to move between application-wide utilities without losing each tool's in-progress state.",
1942
+ "Search, AI conversations, user messages, review stacks, notifications, or help content must remain available alongside route content."
1943
+ ],
1944
+ "avoidWhen": [
1945
+ "The action is specific to the current page or selected content rather than globally available across the application.",
1946
+ "The item navigates to a primary or secondary route; use PanelNav or BarNav instead.",
1947
+ "A consumer wants to add arbitrary tools, reorder fixed tools, or repurpose a semantic tool id.",
1948
+ "Building the mobile tools experience; future mobile AppShell composition uses a different bottom-bar and panel pattern.",
1949
+ "PanelTools would be mounted outside the application's single AppShell."
1950
+ ],
1951
+ "alternatives": [
1952
+ {
1953
+ "when": "The action navigates to a top-level application destination.",
1954
+ "component": "component:ds-panel-nav",
1955
+ "reason": "PanelNav exclusively owns primary application navigation."
1956
+ },
1957
+ {
1958
+ "when": "The action navigates between route sections of the active destination.",
1959
+ "component": "component:ds-bar-nav",
1960
+ "reason": "BarNav exclusively owns secondary route navigation."
1961
+ },
1962
+ {
1963
+ "when": "Temporary contextual actions or options are needed.",
1964
+ "component": "component:ds-menu",
1965
+ "reason": "Menu owns transient contextual choices rather than persistent global products."
1966
+ }
1967
+ ],
1968
+ "commonlyComposedWith": [
1969
+ "component:ds-app-shell",
1970
+ "component:ds-panel-nav",
1971
+ "component:ds-bar-nav"
1972
+ ],
1973
+ "patterns": [
1974
+ "pattern:application-shell"
1975
+ ],
1976
+ "accessibility": [
1977
+ "Provide localized accessible labels for the rail, shortcut group, and every rendered tool.",
1978
+ "Keep Search first in the rail header and Help last in the rail footer so keyboard and visual order remain predictable.",
1979
+ "Keep focus on the selected rail action when opening a drawer and allow normal Tab navigation into its content.",
1980
+ "Do not trigger global shortcuts while focus is in an editable control.",
1981
+ "Use notification dots only as supplemental unread or new-content status and never as the sole status indication.",
1982
+ "Explain temporarily inactive tools through an accessible label or adjacent product guidance; omit unauthorized tools entirely."
1983
+ ],
1984
+ "states": [
1985
+ "Search and Help are required; optional Agents, Messages, Stacks, and Activity tools are filtered by the application for authorization and entitlement.",
1986
+ "Use only the fixed semantic tool ids and canonical order: Search, Agents, Messages, Stacks, Activity, Help; do not reorder, duplicate, or repurpose them.",
1987
+ "Search is application-wide; Agents is user-to-AI chat; Messages is user-to-user chat; Stacks is a specialized inbox of grouped application events for review; Activity is the notification center; Help is drawer content that may link to external resources.",
1988
+ "Only one drawer is open at a time; selecting another tool switches directly and selecting the active tool closes to rail-only mode.",
1989
+ "The drawer starts closed, remains open across ordinary route changes, and retains every mounted tool's independent conversation, query, scroll, and work state.",
1990
+ "When storageKey is set, persist only the last active tool in this browser and still restore the drawer closed after reload.",
1991
+ "The application owns unread state; opening Messages, Agents, Stacks, or Activity does not automatically clear its notification dot.",
1992
+ "If an active optional tool becomes unavailable, PanelTools closes the drawer, clears activeTool, and emits its deselection.",
1993
+ "Use isInactive only for a temporarily unavailable visible tool; omit tools the user is not authorized to access.",
1994
+ "The application owns slotted tool products and data while PanelTools owns rail ordering, drawer selection, open state, motion, and shell events."
1995
+ ],
1996
+ "responsiveBehavior": [
1997
+ "On desktop at 1200px and wider, the open drawer reduces main-content width and uses --dimension-panel-width-sm (400px).",
1998
+ "On tablet from 768px through 1199px, the open drawer also reduces main-content width and uses --dimension-panel-width-xs (300px).",
1999
+ "AppShell owns the responsive drawer-width variable and fixed breakpoint policy; consumers must not hardcode alternate drawer widths.",
2000
+ "Below 768px, do not reuse desktop PanelTools: future AppShell mobile composition uses a bottom bar for Search, Agents, Notifications, and Stacks, while Help moves into mobile primary navigation.",
2001
+ "Keep named-slot content mounted while tools switch or the drawer closes so users can return to in-progress global work.",
2002
+ "Use fixed drawer widths for now; do not add user resizing or width persistence."
2003
+ ],
2004
+ "frameworkCaveats": {
2005
+ "customElements": [
2006
+ "Assign items as a JavaScript property for structured data; items-json is the string fallback.",
2007
+ "Keep PanelTools mounted at AppShell scope across route changes and provide each product through its matching named slot."
2008
+ ],
2009
+ "react": [
2010
+ "Pass the fixed item collection through the generated React wrapper and keep named-slot product content mounted at AppShell scope.",
2011
+ "Use storageKey only for same-browser last-tool continuity; do not persist the open drawer."
2012
+ ],
2013
+ "angular": [
2014
+ "Import DsPanelTools from @ds-mo/ui/angular/ds-panel-tools and bind items as a property.",
2015
+ "Keep the component in the persistent shell layout rather than recreating it in routed page components."
2016
+ ]
2017
+ },
2018
+ "references": [
2019
+ {
2020
+ "label": "Executable Storybook examples",
2021
+ "path": "src/wc/components/PanelTools/PanelTools.stories.ts"
2022
+ },
2023
+ {
2024
+ "label": "Framework and shell integration",
2025
+ "path": "docs/framework-integration.md"
2026
+ },
2027
+ {
2028
+ "label": "Application shell composition",
2029
+ "path": "agent/patterns/application-shell/pattern.agent.json"
2030
+ }
2031
+ ]
2032
+ },
1936
2033
  "api": {
1937
2034
  "props": {
1938
2035
  "activeTool": {
@@ -1951,6 +2048,10 @@
1951
2048
  "type": "boolean",
1952
2049
  "required": false
1953
2050
  },
2051
+ "storageKey": {
2052
+ "type": "string",
2053
+ "required": false
2054
+ },
1954
2055
  "toolShortcutsLabel": {
1955
2056
  "type": "string",
1956
2057
  "required": false
@@ -15,7 +15,7 @@ export declare class DsPanelTools {
15
15
  dsChromeTransitionEnd: EventEmitter<DsPanelToolsCustomEvent<IDsPanelToolsChromeTransitionDetail>>;
16
16
  constructor(c: ChangeDetectorRef, r: ElementRef, z: NgZone);
17
17
  static ɵfac: i0.ɵɵFactoryDeclaration<DsPanelTools, never>;
18
- static ɵcmp: i0.ɵɵComponentDeclaration<DsPanelTools, "ds-panel-tools", never, { "activeTool": { "alias": "activeTool"; "required": false; }; "items": { "alias": "items"; "required": false; }; "itemsJson": { "alias": "itemsJson"; "required": false; }; "open": { "alias": "open"; "required": false; }; "toolShortcutsLabel": { "alias": "toolShortcutsLabel"; "required": false; }; "toolsLabel": { "alias": "toolsLabel"; "required": false; }; }, { "dsToolChange": "dsToolChange"; "dsChromeTransitionStart": "dsChromeTransitionStart"; "dsChromeTransitionEnd": "dsChromeTransitionEnd"; }, never, ["*"], true, never>;
18
+ static ɵcmp: i0.ɵɵComponentDeclaration<DsPanelTools, "ds-panel-tools", never, { "activeTool": { "alias": "activeTool"; "required": false; }; "items": { "alias": "items"; "required": false; }; "itemsJson": { "alias": "itemsJson"; "required": false; }; "open": { "alias": "open"; "required": false; }; "storageKey": { "alias": "storageKey"; "required": false; }; "toolShortcutsLabel": { "alias": "toolShortcutsLabel"; "required": false; }; "toolsLabel": { "alias": "toolsLabel"; "required": false; }; }, { "dsToolChange": "dsToolChange"; "dsChromeTransitionStart": "dsChromeTransitionStart"; "dsChromeTransitionEnd": "dsChromeTransitionEnd"; }, never, ["*"], true, never>;
19
19
  }
20
20
  export declare interface DsPanelTools extends Components.DsPanelTools {
21
21
  /**
@@ -20,12 +20,12 @@ let DsPanelTools = class DsPanelTools {
20
20
  this.el = r.nativeElement;
21
21
  }
22
22
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: DsPanelTools, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
23
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: DsPanelTools, isStandalone: true, selector: "ds-panel-tools", inputs: { activeTool: "activeTool", items: "items", itemsJson: "itemsJson", open: "open", toolShortcutsLabel: "toolShortcutsLabel", toolsLabel: "toolsLabel" }, outputs: { dsToolChange: "dsToolChange", dsChromeTransitionStart: "dsChromeTransitionStart", dsChromeTransitionEnd: "dsChromeTransitionEnd" }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: DsPanelTools, isStandalone: true, selector: "ds-panel-tools", inputs: { activeTool: "activeTool", items: "items", itemsJson: "itemsJson", open: "open", storageKey: "storageKey", toolShortcutsLabel: "toolShortcutsLabel", toolsLabel: "toolsLabel" }, outputs: { dsToolChange: "dsToolChange", dsChromeTransitionStart: "dsChromeTransitionStart", dsChromeTransitionEnd: "dsChromeTransitionEnd" }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24
24
  };
25
25
  DsPanelTools = __decorate([
26
26
  ProxyCmp({
27
27
  defineCustomElementFn: defineDsPanelTools,
28
- inputs: ['activeTool', 'items', 'itemsJson', 'open', 'toolShortcutsLabel', 'toolsLabel'],
28
+ inputs: ['activeTool', 'items', 'itemsJson', 'open', 'storageKey', 'toolShortcutsLabel', 'toolsLabel'],
29
29
  methods: ['activateTool', 'closeDrawer']
30
30
  })
31
31
  ], DsPanelTools);
@@ -37,7 +37,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
37
37
  changeDetection: ChangeDetectionStrategy.OnPush,
38
38
  template: '<ng-content></ng-content>',
39
39
  // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
40
- inputs: ['activeTool', 'items', 'itemsJson', 'open', 'toolShortcutsLabel', 'toolsLabel'],
40
+ inputs: ['activeTool', 'items', 'itemsJson', 'open', 'storageKey', 'toolShortcutsLabel', 'toolsLabel'],
41
41
  outputs: ['dsToolChange', 'dsChromeTransitionStart', 'dsChromeTransitionEnd'],
42
42
  }]
43
43
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { dsToolChange: [{
@@ -1,2 +1,2 @@
1
- import{p as e,t as s,H as t,h as n,a as i}from"./index.js";import{D as a,r as l,d as o,e as r,f as h,g as c,h as p,s as d,i as f,j as u,b,k as g}from"./p-Bz3jyrDV.js";import{C as v,c as m,r as y,a as _,b as x}from"./p-NkAPA-Dz.js";const w={k:"search",a:"agents",s:"stacks",m:"messages",n:"activity"};function k(e){return!e.metaKey&&!e.ctrlKey&&!e.altKey&&!e.shiftKey}function P(e){if(!e||typeof e!=="object")return false;if(!("closest"in e)||typeof e.closest!=="function")return false;const s=e;const t=s.closest('input, textarea, select, [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]');if(t)return true;const n=s.getAttribute("role");if(n==="textbox"||n==="combobox"||n==="searchbox")return true;return Boolean(s.isContentEditable)}function S(e){if(e.key==="["||e.code==="BracketLeft")return"[";if(e.key==="]"||e.code==="BracketRight")return"]";return e.key.length===1?e.key.toLowerCase():e.key.toLowerCase()}function z(e){if(!k(e))return null;const s=S(e);if(s==="[")return"toggle-panel-nav";if(s==="]")return"close-panel-tools";const t=w[s];if(t)return`open-tool:${t}`;return null}function C(e,s){if(typeof document==="undefined")return 0;const t=document.createElement("div");t.style.cssText="position:absolute;visibility:hidden;pointer-events:none;height:0;width:var("+s+");";e.appendChild(t);const n=t.getBoundingClientRect().width;e.removeChild(t);return n}function j(e){return{expandedPx:C(e,"--_nav-width"),collapsedPx:C(e,"--_nav-width-collapsed")}}function D(e,s){if(s?.classList.contains("panel-nav--collapsed"))return true;const t=e?.collapsed;return t===true}function V(e,s){return s?e.collapsedPx:e.expandedPx}const L=()=>`.sc-ds-app-shell-h{display:block;height:100%;min-height:0;box-sizing:border-box}.app-shell.sc-ds-app-shell{display:flex;flex-direction:column;height:100%;min-height:0;box-sizing:border-box;font-family:var(--typography-font-family, system-ui)}.app-shell--gradient.sc-ds-app-shell-h{--_shell-chrome-bg:var(--color-background-secondary)}.app-shell__row.sc-ds-app-shell{display:flex;flex:1 1 auto;min-height:0;height:100%;position:relative}.app-shell__chrome.sc-ds-app-shell{position:absolute;inset:0;pointer-events:none;z-index:0}.app-shell--gradient.sc-ds-app-shell-h .app-shell__chrome.sc-ds-app-shell{background-color:var(--_shell-chrome-bg)}.app-shell--gradient.sc-ds-app-shell-h .app-shell__chrome.sc-ds-app-shell::before{content:'';position:absolute;inset:0;pointer-events:none;background-position:0 0;background-attachment:fixed;z-index:1;opacity:var(--ds-shell-gradient-opacity, 1);background-image:var(--ds-shell-gradient-image, none);background-size:var(--ds-shell-gradient-size, auto);background-repeat:no-repeat}.app-shell__panel.sc-ds-app-shell{flex:0 0 auto;min-height:0;height:100%;position:relative;z-index:2}.app-shell__panel.sc-ds-app-shell-s>ds-panel-nav,.app-shell__panel .sc-ds-app-shell-s>ds-panel-nav{display:block;height:100%}.app-shell__main.sc-ds-app-shell{flex:1 1 auto;min-width:0;min-height:0;display:grid;grid-template-columns:minmax(0, 1fr) auto;grid-template-rows:auto minmax(0, 1fr);grid-template-areas:'bar tools' 'content tools';position:relative;z-index:1}.app-shell__bar.sc-ds-app-shell{grid-area:bar;flex:0 0 auto;min-width:0}.app-shell__bar.sc-ds-app-shell-s>ds-bar-nav,.app-shell__bar .sc-ds-app-shell-s>ds-bar-nav{display:block}.app-shell__content.sc-ds-app-shell{grid-area:content;flex:1 1 auto;min-width:0;min-height:0;overflow:auto;contain:layout}.app-shell--gradient.sc-ds-app-shell-h .app-shell__content.sc-ds-app-shell{position:relative;z-index:1;background-color:var(--color-background-primary)}.app-shell__tools.sc-ds-app-shell{grid-area:tools;flex:0 0 auto;min-width:0;min-height:0;height:100%;display:flex;position:relative;z-index:0;overflow:hidden}.app-shell__tools.sc-ds-app-shell-s>ds-panel-tools,.app-shell__tools .sc-ds-app-shell-s>ds-panel-tools{display:block;height:100%;min-height:0}`;const A=e(class e extends t{constructor(e){super();if(e!==false){this.__registerHost()}this.navStyle="dashboard";this.gradient=false;this.gradientSrc="";this.gradientPreset=a;this.shortcutsEnabled=true;this.resizeObserver=null;this.panelNavTransition=new v;this.chromeSyncCoalescer=m((()=>this.syncChrome()));this.panelWidthTokens={expandedPx:0,collapsedPx:0};this.cachedViewportWidth=0;this.cachedViewportHeight=0;this.onWindowResize=()=>{if(this.panelNavTransition.isActive)return;this.scheduleChromeSync()};this.onVisualViewportChange=()=>{if(this.panelNavTransition.isActive)return;this.scheduleChromeSync()};this.onChromeTransitionStart=e=>{if(y(e)!=="panel-nav")return;this.panelNavTransition.enter();const s=l();this.cachedViewportWidth=s.width;this.cachedViewportHeight=s.height;this.syncChrome()};this.onChromeTransitionEnd=e=>{if(y(e)!=="panel-nav")return;this.panelNavTransition.exit();if(!this.panelNavTransition.isActive){this.scheduleChromeSync()}}}componentDidLoad(){this.syncSlottedNavStyle();this.connectMetricsObserver();this.connectViewportListeners();this.el.addEventListener(_,this.onChromeTransitionStart);this.el.addEventListener(x,this.onChromeTransitionEnd);requestAnimationFrame((()=>{this.cachePanelWidthTokens();this.scheduleChromeSync()}))}disconnectedCallback(){this.resizeObserver?.disconnect();this.resizeObserver=null;this.disconnectViewportListeners();this.chromeSyncCoalescer.cancel();this.el.removeEventListener(_,this.onChromeTransitionStart);this.el.removeEventListener(x,this.onChromeTransitionEnd)}onShellPropsChange(){this.syncSlottedNavStyle();this.scheduleChromeSync()}scheduleChromeSync(){this.chromeSyncCoalescer.schedule()}syncSlottedNavStyle(){const e=this.el.querySelector("ds-panel-nav");const s=this.el.querySelector("ds-bar-nav");if(e){e.setAttribute("nav-style",this.navStyle);e.navStyle=this.navStyle}if(s){s.setAttribute("nav-style",this.navStyle);s.navStyle=this.navStyle}}connectMetricsObserver(){this.resizeObserver=new ResizeObserver((()=>{if(this.panelNavTransition.isActive)return;this.scheduleChromeSync()}));this.resizeObserver.observe(this.el);const e=this.el.querySelector(".app-shell__panel");if(e)this.resizeObserver.observe(e)}connectViewportListeners(){if(typeof window==="undefined")return;window.addEventListener("resize",this.onWindowResize,{passive:true});const e=window.visualViewport;if(e){e.addEventListener("resize",this.onVisualViewportChange,{passive:true});e.addEventListener("scroll",this.onVisualViewportChange,{passive:true})}}disconnectViewportListeners(){if(typeof window==="undefined")return;window.removeEventListener("resize",this.onWindowResize);const e=window.visualViewport;if(e){e.removeEventListener("resize",this.onVisualViewportChange);e.removeEventListener("scroll",this.onVisualViewportChange)}}cachePanelWidthTokens(){const e=this.el.querySelector("ds-panel-nav .panel-nav");if(!e)return;this.panelWidthTokens=j(e)}applyGradientVars(e,s){const t=e.style;for(const[e,n]of Object.entries(s)){if(n===null)t.removeProperty(e);else t.setProperty(e,n)}}clearGradientPaintVars(e){const s=[o,r,h];for(const t of e){for(const e of s)t.style.removeProperty(e)}}syncChromeLayoutVars(e,s,t,n){if(e){e.style.setProperty(c,t)}if(s){s.style.setProperty(p,n)}}resolvePanelWidthPx(e){const s=e?.querySelector(".panel-nav");if(this.panelNavTransition.isActive&&this.panelWidthTokens.expandedPx>0){const t=D(e,s);return V(this.panelWidthTokens,t)}const t=this.el.querySelector(".app-shell__panel");const n=t?.getBoundingClientRect().width??0;if(n>0)return n;if(this.panelWidthTokens.expandedPx>0){const t=D(e,s);return V(this.panelWidthTokens,t)}return 0}resolveViewportDimensions(){if(this.panelNavTransition.isActive&&this.cachedViewportWidth>0){return{width:this.cachedViewportWidth,height:this.cachedViewportHeight}}return l()}chromeLayerActive(){return this.gradient}handleWindowKeyDown(e){if(!this.shortcutsEnabled)return;if(P(e.target))return;const s=z(e);if(!s)return;e.preventDefault();const t=this.el.querySelector("ds-panel-nav");const n=this.el.querySelector("ds-panel-tools");if(s==="toggle-panel-nav"){void t?.toggleCollapsed();return}if(s==="close-panel-tools"){void n?.closeDrawer();return}if(s.startsWith("open-tool:")&&n){const e=s.slice("open-tool:".length);void n.activateTool(e)}}syncChrome(){const e=this.el.querySelector("ds-panel-nav");const s=this.el.querySelector("ds-bar-nav");const t=[this.el,e,s].filter((e=>e!==null));const n=()=>{if(e)e.style.removeProperty(c);if(s)s.style.removeProperty(p)};if(!this.gradient){this.clearGradientPaintVars(t);n();return}const i=this.resolveViewportDimensions();const a=this.resolvePanelWidthPx(e);const l=d();const v=f(a);this.syncChromeLayoutVars(e,s,l,v);const m=this.gradientSrc.trim()?`url(${this.gradientSrc.trim()})`:u(this.gradientPreset);const y=g({width:i.width,height:i.height});const _=b;for(const e of t){if(e===this.el){this.applyGradientVars(e,{[o]:m,[r]:y,[c]:l,[p]:v,[h]:_});continue}const s=e.tagName.toLowerCase()==="ds-bar-nav";this.applyGradientVars(e,{[o]:m,[r]:y,[h]:_,[c]:s?null:l,[p]:s?v:null})}}render(){const e=this.chromeLayerActive();const s={"app-shell":true,"app-shell--gradient":this.gradient,[`app-shell--${this.navStyle}`]:true};return n(i,{key:"4a9f8692893bba62a2fe4e4f4ee6338ea959935e",class:s},n("div",{key:"9bcd7c59ea5f653bae21eba71de38c7d9fae2196",class:"app-shell__row"},e?n("div",{class:"app-shell__chrome","aria-hidden":"true"}):null,n("div",{key:"5185e2dce7fe4d7a0a82b6a6fac10d5650833322",class:"app-shell__panel"},n("slot",{key:"fb23f25d5cf398da4f7ab11ab57017e68bfb10fb",name:"panel"})),n("div",{key:"8012f718181a697b5c625f50b7d7db2bd67e636d",class:"app-shell__main"},n("div",{key:"002b8ec32d1ef64d188cc062b0fb42490dbc9aec",class:"app-shell__bar"},n("slot",{key:"50cd0f20fed82ac80cbd40bed601a14ee5973dc1",name:"bar"})),n("div",{key:"0c6ab0369cd0849f729541fc3f479facb7d887ee",class:"app-shell__tools"},n("slot",{key:"d394ad6979da4c72edc18c3205facec77613ea6f",name:"tools"})),n("div",{key:"aea438b830aeb4e00e8bcdabaeba4e5caf75640d",class:"app-shell__content"},n("slot",{key:"f95130528bb58fc956a582cba908d9ff9c7c7bea"})))))}get el(){return this}static get watchers(){return{navStyle:[{onShellPropsChange:0}],gradient:[{onShellPropsChange:0}],gradientSrc:[{onShellPropsChange:0}],gradientPreset:[{onShellPropsChange:0}]}}static get style(){return L()}},[262,"ds-app-shell",{navStyle:[513,"nav-style"],gradient:[516],gradientSrc:[1,"gradient-src"],gradientPreset:[513,"gradient-preset"],shortcutsEnabled:[4,"shortcuts-enabled"]},[[10,"keydown","handleWindowKeyDown"]],{navStyle:[{onShellPropsChange:0}],gradient:[{onShellPropsChange:0}],gradientSrc:[{onShellPropsChange:0}],gradientPreset:[{onShellPropsChange:0}]}]);function B(){if(typeof customElements==="undefined"){return}const e=["ds-app-shell"];e.forEach((e=>{switch(e){case"ds-app-shell":if(!customElements.get(s(e))){customElements.define(s(e),A)}break}}))}B();const E=A;const W=B;export{E as DsAppShell,W as defineCustomElement};
1
+ import{p as e,t as s,H as t,h as n,a as i}from"./index.js";import{D as a,r as l,d as o,e as r,f as h,g as p,h as c,s as d,i as f,j as u,b,k as g}from"./p-Bz3jyrDV.js";import{C as m,c as v,r as y,a as _,b as w}from"./p-NkAPA-Dz.js";const x={k:"search",a:"agents",s:"stacks",m:"messages",n:"activity"};function k(e){return!e.metaKey&&!e.ctrlKey&&!e.altKey&&!e.shiftKey}function P(e){if(!e||typeof e!=="object")return false;if(!("closest"in e)||typeof e.closest!=="function")return false;const s=e;const t=s.closest('input, textarea, select, [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]');if(t)return true;const n=s.getAttribute("role");if(n==="textbox"||n==="combobox"||n==="searchbox")return true;return Boolean(s.isContentEditable)}function S(e){if(e.key==="["||e.code==="BracketLeft")return"[";if(e.key==="]"||e.code==="BracketRight")return"]";return e.key.length===1?e.key.toLowerCase():e.key.toLowerCase()}function z(e){if((e.key==="?"||e.code==="Slash"&&e.shiftKey)&&!e.metaKey&&!e.ctrlKey&&!e.altKey){return"open-tool:help"}if(!k(e))return null;const s=S(e);if(s==="[")return"toggle-panel-nav";if(s==="]")return"close-panel-tools";const t=x[s];if(t)return`open-tool:${t}`;return null}function C(e,s){if(typeof document==="undefined")return 0;const t=document.createElement("div");t.style.cssText="position:absolute;visibility:hidden;pointer-events:none;height:0;width:var("+s+");";e.appendChild(t);const n=t.getBoundingClientRect().width;e.removeChild(t);return n}function j(e){return{expandedPx:C(e,"--_nav-width"),collapsedPx:C(e,"--_nav-width-collapsed")}}function D(e,s){if(s?.classList.contains("panel-nav--collapsed"))return true;const t=e?.collapsed;return t===true}function V(e,s){return s?e.collapsedPx:e.expandedPx}const L=()=>`.sc-ds-app-shell-h{display:block;height:100%;min-height:0;box-sizing:border-box;--ds-shell-panel-tools-width:var(--dimension-panel-width-sm)}@media (min-width: 768px) and (max-width: 1199px){.sc-ds-app-shell-h{--ds-shell-panel-tools-width:var(--dimension-panel-width-xs)}}.app-shell.sc-ds-app-shell{display:flex;flex-direction:column;height:100%;min-height:0;box-sizing:border-box;font-family:var(--typography-font-family, system-ui)}.app-shell--gradient.sc-ds-app-shell-h{--_shell-chrome-bg:var(--color-background-secondary)}.app-shell__row.sc-ds-app-shell{display:flex;flex:1 1 auto;min-height:0;height:100%;position:relative}.app-shell__chrome.sc-ds-app-shell{position:absolute;inset:0;pointer-events:none;z-index:0}.app-shell--gradient.sc-ds-app-shell-h .app-shell__chrome.sc-ds-app-shell{background-color:var(--_shell-chrome-bg)}.app-shell--gradient.sc-ds-app-shell-h .app-shell__chrome.sc-ds-app-shell::before{content:'';position:absolute;inset:0;pointer-events:none;background-position:0 0;background-attachment:fixed;z-index:1;opacity:var(--ds-shell-gradient-opacity, 1);background-image:var(--ds-shell-gradient-image, none);background-size:var(--ds-shell-gradient-size, auto);background-repeat:no-repeat}.app-shell__panel.sc-ds-app-shell{flex:0 0 auto;min-height:0;height:100%;position:relative;z-index:2}.app-shell__panel.sc-ds-app-shell-s>ds-panel-nav,.app-shell__panel .sc-ds-app-shell-s>ds-panel-nav{display:block;height:100%}.app-shell__main.sc-ds-app-shell{flex:1 1 auto;min-width:0;min-height:0;display:grid;grid-template-columns:minmax(0, 1fr) auto;grid-template-rows:auto minmax(0, 1fr);grid-template-areas:'bar tools' 'content tools';position:relative;z-index:1}.app-shell__bar.sc-ds-app-shell{grid-area:bar;flex:0 0 auto;min-width:0}.app-shell__bar.sc-ds-app-shell-s>ds-bar-nav,.app-shell__bar .sc-ds-app-shell-s>ds-bar-nav{display:block}.app-shell__content.sc-ds-app-shell{grid-area:content;flex:1 1 auto;min-width:0;min-height:0;overflow:auto;contain:layout}.app-shell--gradient.sc-ds-app-shell-h .app-shell__content.sc-ds-app-shell{position:relative;z-index:1;background-color:var(--color-background-primary)}.app-shell__tools.sc-ds-app-shell{grid-area:tools;flex:0 0 auto;min-width:0;min-height:0;height:100%;display:flex;position:relative;z-index:0;overflow:hidden}.app-shell__tools.sc-ds-app-shell-s>ds-panel-tools,.app-shell__tools .sc-ds-app-shell-s>ds-panel-tools{display:block;height:100%;min-height:0}`;const A=e(class e extends t{constructor(e){super();if(e!==false){this.__registerHost()}this.navStyle="dashboard";this.gradient=false;this.gradientSrc="";this.gradientPreset=a;this.shortcutsEnabled=true;this.resizeObserver=null;this.panelNavTransition=new m;this.chromeSyncCoalescer=v((()=>this.syncChrome()));this.panelWidthTokens={expandedPx:0,collapsedPx:0};this.cachedViewportWidth=0;this.cachedViewportHeight=0;this.onWindowResize=()=>{if(this.panelNavTransition.isActive)return;this.scheduleChromeSync()};this.onVisualViewportChange=()=>{if(this.panelNavTransition.isActive)return;this.scheduleChromeSync()};this.onChromeTransitionStart=e=>{if(y(e)!=="panel-nav")return;this.panelNavTransition.enter();const s=l();this.cachedViewportWidth=s.width;this.cachedViewportHeight=s.height;this.syncChrome()};this.onChromeTransitionEnd=e=>{if(y(e)!=="panel-nav")return;this.panelNavTransition.exit();if(!this.panelNavTransition.isActive){this.scheduleChromeSync()}}}componentDidLoad(){this.syncSlottedNavStyle();this.connectMetricsObserver();this.connectViewportListeners();this.el.addEventListener(_,this.onChromeTransitionStart);this.el.addEventListener(w,this.onChromeTransitionEnd);requestAnimationFrame((()=>{this.cachePanelWidthTokens();this.scheduleChromeSync()}))}disconnectedCallback(){this.resizeObserver?.disconnect();this.resizeObserver=null;this.disconnectViewportListeners();this.chromeSyncCoalescer.cancel();this.el.removeEventListener(_,this.onChromeTransitionStart);this.el.removeEventListener(w,this.onChromeTransitionEnd)}onShellPropsChange(){this.syncSlottedNavStyle();this.scheduleChromeSync()}scheduleChromeSync(){this.chromeSyncCoalescer.schedule()}syncSlottedNavStyle(){const e=this.el.querySelector("ds-panel-nav");const s=this.el.querySelector("ds-bar-nav");if(e){e.setAttribute("nav-style",this.navStyle);e.navStyle=this.navStyle}if(s){s.setAttribute("nav-style",this.navStyle);s.navStyle=this.navStyle}}connectMetricsObserver(){this.resizeObserver=new ResizeObserver((()=>{if(this.panelNavTransition.isActive)return;this.scheduleChromeSync()}));this.resizeObserver.observe(this.el);const e=this.el.querySelector(".app-shell__panel");if(e)this.resizeObserver.observe(e)}connectViewportListeners(){if(typeof window==="undefined")return;window.addEventListener("resize",this.onWindowResize,{passive:true});const e=window.visualViewport;if(e){e.addEventListener("resize",this.onVisualViewportChange,{passive:true});e.addEventListener("scroll",this.onVisualViewportChange,{passive:true})}}disconnectViewportListeners(){if(typeof window==="undefined")return;window.removeEventListener("resize",this.onWindowResize);const e=window.visualViewport;if(e){e.removeEventListener("resize",this.onVisualViewportChange);e.removeEventListener("scroll",this.onVisualViewportChange)}}cachePanelWidthTokens(){const e=this.el.querySelector("ds-panel-nav .panel-nav");if(!e)return;this.panelWidthTokens=j(e)}applyGradientVars(e,s){const t=e.style;for(const[e,n]of Object.entries(s)){if(n===null)t.removeProperty(e);else t.setProperty(e,n)}}clearGradientPaintVars(e){const s=[o,r,h];for(const t of e){for(const e of s)t.style.removeProperty(e)}}syncChromeLayoutVars(e,s,t,n){if(e){e.style.setProperty(p,t)}if(s){s.style.setProperty(c,n)}}resolvePanelWidthPx(e){const s=e?.querySelector(".panel-nav");if(this.panelNavTransition.isActive&&this.panelWidthTokens.expandedPx>0){const t=D(e,s);return V(this.panelWidthTokens,t)}const t=this.el.querySelector(".app-shell__panel");const n=t?.getBoundingClientRect().width??0;if(n>0)return n;if(this.panelWidthTokens.expandedPx>0){const t=D(e,s);return V(this.panelWidthTokens,t)}return 0}resolveViewportDimensions(){if(this.panelNavTransition.isActive&&this.cachedViewportWidth>0){return{width:this.cachedViewportWidth,height:this.cachedViewportHeight}}return l()}chromeLayerActive(){return this.gradient}handleWindowKeyDown(e){if(!this.shortcutsEnabled)return;if(P(e.target))return;const s=z(e);if(!s)return;e.preventDefault();const t=this.el.querySelector("ds-panel-nav");const n=this.el.querySelector("ds-panel-tools");if(s==="toggle-panel-nav"){void t?.toggleCollapsed();return}if(s==="close-panel-tools"){void n?.closeDrawer();return}if(s.startsWith("open-tool:")&&n){const e=s.slice("open-tool:".length);void n.activateTool(e)}}syncChrome(){const e=this.el.querySelector("ds-panel-nav");const s=this.el.querySelector("ds-bar-nav");const t=[this.el,e,s].filter((e=>e!==null));const n=()=>{if(e)e.style.removeProperty(p);if(s)s.style.removeProperty(c)};if(!this.gradient){this.clearGradientPaintVars(t);n();return}const i=this.resolveViewportDimensions();const a=this.resolvePanelWidthPx(e);const l=d();const m=f(a);this.syncChromeLayoutVars(e,s,l,m);const v=this.gradientSrc.trim()?`url(${this.gradientSrc.trim()})`:u(this.gradientPreset);const y=g({width:i.width,height:i.height});const _=b;for(const e of t){if(e===this.el){this.applyGradientVars(e,{[o]:v,[r]:y,[p]:l,[c]:m,[h]:_});continue}const s=e.tagName.toLowerCase()==="ds-bar-nav";this.applyGradientVars(e,{[o]:v,[r]:y,[h]:_,[p]:s?null:l,[c]:s?m:null})}}render(){const e=this.chromeLayerActive();const s={"app-shell":true,"app-shell--gradient":this.gradient,[`app-shell--${this.navStyle}`]:true};return n(i,{key:"3cf3ce7a0734dc306a0b9f9cabb673e6fb595997",class:s},n("div",{key:"4380458fd195d5c30e193fc0312a0a3d28eddf85",class:"app-shell__row"},e?n("div",{class:"app-shell__chrome","aria-hidden":"true"}):null,n("div",{key:"6dc576da09150417d910a42a6f8175645b08730b",class:"app-shell__panel"},n("slot",{key:"95cc29120a740652a5b9506d3ff69d55f6e7ef64",name:"panel"})),n("div",{key:"9f428a7cec7c0f0264da5ef76b97e9ba3bd181aa",class:"app-shell__main"},n("div",{key:"1a3c198ea2c53eaff484e68a55627c739cf2a855",class:"app-shell__bar"},n("slot",{key:"d8b9da78e26972b803d9f0cd2f30d5fa8860c8bf",name:"bar"})),n("div",{key:"0180a1aba6490951656c1abf6ee90e7892a024d5",class:"app-shell__tools"},n("slot",{key:"a2622cc91fec5c9617fdfdad139dbcf4df899881",name:"tools"})),n("div",{key:"445b03b5898baa4e85416e933459b4e03d4f8cd6",class:"app-shell__content"},n("slot",{key:"bba92b0bc4e41e7501d76ed59c672b612b99f216"})))))}get el(){return this}static get watchers(){return{navStyle:[{onShellPropsChange:0}],gradient:[{onShellPropsChange:0}],gradientSrc:[{onShellPropsChange:0}],gradientPreset:[{onShellPropsChange:0}]}}static get style(){return L()}},[262,"ds-app-shell",{navStyle:[513,"nav-style"],gradient:[516],gradientSrc:[1,"gradient-src"],gradientPreset:[513,"gradient-preset"],shortcutsEnabled:[4,"shortcuts-enabled"]},[[10,"keydown","handleWindowKeyDown"]],{navStyle:[{onShellPropsChange:0}],gradient:[{onShellPropsChange:0}],gradientSrc:[{onShellPropsChange:0}],gradientPreset:[{onShellPropsChange:0}]}]);function B(){if(typeof customElements==="undefined"){return}const e=["ds-app-shell"];e.forEach((e=>{switch(e){case"ds-app-shell":if(!customElements.get(s(e))){customElements.define(s(e),A)}break}}))}B();const E=A;const W=B;export{E as DsAppShell,W as defineCustomElement};
2
2
  //# sourceMappingURL=ds-app-shell.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["TOOL_SHORTCUT_KEYS","k","a","s","m","n","isBareShellShortcutKey","e","metaKey","ctrlKey","altKey","shiftKey","isEditableShortcutTarget","target","closest","el","editable","role","getAttribute","Boolean","isContentEditable","normalizedShortcutKey","key","code","length","toLowerCase","resolveShellShortcut","toolId","readCssVarWidthPx","context","cssVarName","document","probe","createElement","style","cssText","appendChild","width","getBoundingClientRect","removeChild","readPanelNavWidthTokens","navRoot","expandedPx","collapsedPx","isPanelNavCollapsed","panelNavHost","classList","contains","collapsedProp","collapsed","panelWidthPxFromTokens","tokens","appShellCss","AppShell","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","navStyle","gradient","gradientSrc","gradientPreset","DEFAULT_SHELL_GRADIENT_PRESET","shortcutsEnabled","resizeObserver","panelNavTransition","ChromeTransitionDepth","chromeSyncCoalescer","createRafCoalescer","syncChrome","panelWidthTokens","cachedViewportWidth","cachedViewportHeight","onWindowResize","isActive","scheduleChromeSync","onVisualViewportChange","onChromeTransitionStart","event","readChromeTransitionSource","enter","viewport","readShellViewportDimensions","height","onChromeTransitionEnd","exit","componentDidLoad","syncSlottedNavStyle","connectMetricsObserver","connectViewportListeners","addEventListener","CHROME_TRANSITION_START","CHROME_TRANSITION_END","requestAnimationFrame","cachePanelWidthTokens","disconnectedCallback","disconnect","disconnectViewportListeners","cancel","removeEventListener","onShellPropsChange","schedule","panel","querySelector","bar","setAttribute","ResizeObserver","observe","panelWrap","window","passive","visual","visualViewport","applyGradientVars","vars","name","value","Object","entries","removeProperty","setProperty","clearGradientPaintVars","targets","keys","SHELL_GRADIENT_IMAGE_VAR","SHELL_GRADIENT_SIZE_VAR","SHELL_GRADIENT_OPACITY_VAR","syncChromeLayoutVars","panelPosition","barPosition","SHELL_GRADIENT_POSITION_PANEL_VAR","SHELL_GRADIENT_POSITION_BAR_VAR","resolvePanelWidthPx","panelNav","measured","resolveViewportDimensions","chromeLayerActive","handleWindowKeyDown","action","preventDefault","tools","toggleCollapsed","closeDrawer","startsWith","slice","activateTool","filter","clearLayoutVars","panelWidth","shellGradientPositionPanel","shellGradientPositionBar","image","trim","buildShellRadialGradient","size","shellGradientSize","opacity","SHELL_GRADIENT_OPACITY","isBar","tagName","render","chromeActive","shellCls","h","Host","class"],"sources":["src/wc/nav/shell-shortcuts.ts","src/wc/nav/shell-chrome-metrics.ts","src/wc/components/AppShell/AppShell.css?tag=ds-app-shell&encapsulation=scoped","src/wc/components/AppShell/AppShell.tsx"],"sourcesContent":["import type { PanelToolsToolId } from '../components/PanelTools/panel-tools-types';\n\nexport type ShellShortcutAction =\n | 'toggle-panel-nav'\n | 'close-panel-tools'\n | `open-tool:${PanelToolsToolId}`;\n\nconst TOOL_SHORTCUT_KEYS: Record<string, PanelToolsToolId> = {\n k: 'search',\n a: 'agents',\n s: 'stacks',\n m: 'messages',\n n: 'activity',\n};\n\n/** Tool shortcut keys (K/A/S/M/N) toggle open/closed via `ds-panel-tools.activateTool`. */\n\n/** True when no modifier keys are held — avoids browser/app chords like ⌘N. */\nexport function isBareShellShortcutKey(\n e: Pick<KeyboardEvent, 'metaKey' | 'ctrlKey' | 'altKey' | 'shiftKey'>,\n): boolean {\n return !e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey;\n}\n\n/** Skip shell shortcuts while typing in an editable control. */\nexport function isEditableShortcutTarget(target: EventTarget | null): boolean {\n if (!target || typeof target !== 'object') return false;\n if (!('closest' in target) || typeof target.closest !== 'function') return false;\n\n const el = target as Element & { isContentEditable?: boolean };\n\n const editable = el.closest(\n 'input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"], [contenteditable=\"plaintext-only\"]',\n );\n if (editable) return true;\n\n const role = el.getAttribute('role');\n if (role === 'textbox' || role === 'combobox' || role === 'searchbox') return true;\n\n return Boolean(el.isContentEditable);\n}\n\nfunction normalizedShortcutKey(e: Pick<KeyboardEvent, 'key' | 'code'>): string {\n if (e.key === '[' || e.code === 'BracketLeft') return '[';\n if (e.key === ']' || e.code === 'BracketRight') return ']';\n return e.key.length === 1 ? e.key.toLowerCase() : e.key.toLowerCase();\n}\n\n/** Resolve a shell chrome shortcut, or `null` when the key is not handled. */\nexport function resolveShellShortcut(\n e: Pick<KeyboardEvent, 'key' | 'code' | 'metaKey' | 'ctrlKey' | 'altKey' | 'shiftKey'>,\n): ShellShortcutAction | null {\n if (!isBareShellShortcutKey(e)) return null;\n\n const key = normalizedShortcutKey(e);\n if (key === '[') return 'toggle-panel-nav';\n if (key === ']') return 'close-panel-tools';\n\n const toolId = TOOL_SHORTCUT_KEYS[key];\n if (toolId) return `open-tool:${toolId}`;\n\n return null;\n}\n","import { shellGradientPositionBar } from './shell-gradient';\n\n/** Read a `var(--token)` width in px using a hidden probe (works with calc() tokens). */\nexport function readCssVarWidthPx(context: HTMLElement, cssVarName: string): number {\n if (typeof document === 'undefined') return 0;\n\n const probe = document.createElement('div');\n probe.style.cssText =\n 'position:absolute;visibility:hidden;pointer-events:none;height:0;width:var(' +\n cssVarName +\n ');';\n context.appendChild(probe);\n const width = probe.getBoundingClientRect().width;\n context.removeChild(probe);\n return width;\n}\n\nexport interface PanelNavWidthTokens {\n expandedPx: number;\n collapsedPx: number;\n}\n\n/** Resolve panel-nav expanded/collapsed widths from scoped CSS vars on `.panel-nav`. */\nexport function readPanelNavWidthTokens(navRoot: HTMLElement): PanelNavWidthTokens {\n return {\n expandedPx: readCssVarWidthPx(navRoot, '--_nav-width'),\n collapsedPx: readCssVarWidthPx(navRoot, '--_nav-width-collapsed'),\n };\n}\n\nexport function isPanelNavCollapsed(\n panelNavHost: HTMLElement | null,\n navRoot: HTMLElement | null,\n): boolean {\n if (navRoot?.classList.contains('panel-nav--collapsed')) return true;\n const collapsedProp = (panelNavHost as (HTMLElement & { collapsed?: boolean }) | null)?.collapsed;\n return collapsedProp === true;\n}\n\nexport function panelWidthPxFromTokens(\n tokens: PanelNavWidthTokens,\n collapsed: boolean,\n): number {\n return collapsed ? tokens.collapsedPx : tokens.expandedPx;\n}\n\nexport function barGradientPositionFromPanelWidth(panelWidthPx: number): string {\n return shellGradientPositionBar(panelWidthPx);\n}\n",":host {\n display: block;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n.app-shell {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n font-family: var(--typography-font-family, system-ui);\n}\n\n:host(.app-shell--gradient) {\n --_shell-chrome-bg: var(--color-background-secondary);\n}\n\n.app-shell__row {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n position: relative;\n}\n\n/*\n * One chrome layer behind the shell row. Wash uses background-attachment: fixed\n * so the pattern is locked to the viewport — panel/tools collapse only changes the\n * transparent window, not the pattern phase. JS sets wash background-size from\n * readShellViewportDimensions(), not the shell element box.\n */\n.app-shell__chrome {\n position: absolute;\n inset: 0;\n pointer-events: none;\n z-index: 0;\n}\n\n:host(.app-shell--gradient) .app-shell__chrome {\n background-color: var(--_shell-chrome-bg);\n}\n\n:host(.app-shell--gradient) .app-shell__chrome::before {\n content: '';\n position: absolute;\n inset: 0;\n pointer-events: none;\n background-position: 0 0;\n background-attachment: fixed;\n z-index: 1;\n opacity: var(--ds-shell-gradient-opacity, 1);\n background-image: var(--ds-shell-gradient-image, none);\n background-size: var(--ds-shell-gradient-size, auto);\n background-repeat: no-repeat;\n}\n\n.app-shell__panel {\n flex: 0 0 auto;\n min-height: 0;\n height: 100%;\n position: relative;\n /* Above main so resize handle line can paint over the workspace edge */\n z-index: 2;\n}\n\n.app-shell__panel ::slotted(ds-panel-nav) {\n display: block;\n height: 100%;\n}\n\n.app-shell__main {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n grid-template-rows: auto minmax(0, 1fr);\n grid-template-areas:\n 'bar tools'\n 'content tools';\n position: relative;\n z-index: 1;\n}\n\n.app-shell__bar {\n grid-area: bar;\n flex: 0 0 auto;\n min-width: 0;\n}\n\n.app-shell__bar ::slotted(ds-bar-nav) {\n display: block;\n}\n\n.app-shell__content {\n grid-area: content;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n overflow: auto;\n /* Limit reflow to the page column — not on __main (breaks tools flex shrink). */\n contain: layout;\n}\n\n/* Opaque page surface — masks the fixed chrome layer in the content column. */\n:host(.app-shell--gradient) .app-shell__content {\n position: relative;\n z-index: 1;\n background-color: var(--color-background-primary);\n}\n\n.app-shell__tools {\n grid-area: tools;\n flex: 0 0 auto;\n min-width: 0;\n min-height: 0;\n height: 100%;\n display: flex;\n position: relative;\n z-index: 0;\n overflow: hidden;\n}\n\n.app-shell__tools ::slotted(ds-panel-tools) {\n display: block;\n height: 100%;\n min-height: 0;\n}\n","import { Component, Prop, Element, Watch, Listen, h, Host } from '@stencil/core';\nimport type { NavChromeStyle } from '../../nav/nav-chrome';\nimport {\n isEditableShortcutTarget,\n resolveShellShortcut,\n} from '../../nav/shell-shortcuts';\nimport type { PanelToolsToolId } from '../PanelTools/panel-tools-types';\nimport {\n DEFAULT_SHELL_GRADIENT_PRESET,\n type ShellGradientPreset,\n} from '../../nav/shell-gradient-presets';\nimport {\n CHROME_TRANSITION_END,\n CHROME_TRANSITION_START,\n ChromeTransitionDepth,\n createRafCoalescer,\n readChromeTransitionSource,\n} from '../../nav/chrome-transition';\nimport {\n isPanelNavCollapsed,\n panelWidthPxFromTokens,\n readPanelNavWidthTokens,\n type PanelNavWidthTokens,\n} from '../../nav/shell-chrome-metrics';\nimport {\n SHELL_GRADIENT_IMAGE_VAR,\n SHELL_GRADIENT_OPACITY,\n SHELL_GRADIENT_OPACITY_VAR,\n SHELL_GRADIENT_POSITION_BAR_VAR,\n SHELL_GRADIENT_POSITION_PANEL_VAR,\n SHELL_GRADIENT_SIZE_VAR,\n buildShellRadialGradient,\n readShellViewportDimensions,\n shellGradientPositionBar,\n shellGradientPositionPanel,\n shellGradientSize,\n} from '../../nav/shell-gradient';\n\n@Component({\n tag: 'ds-app-shell',\n styleUrl: 'AppShell.css',\n scoped: true,\n})\nexport class AppShell {\n /** Chrome style propagated to slotted `ds-panel-nav` and `ds-bar-nav`. */\n @Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'dashboard';\n\n /** When `true`, paints the radial wash behind panel, bar, and tools (synced to shell layout). */\n @Prop({ reflect: true }) gradient: boolean = false;\n\n /**\n * Optional custom gradient for `background-image` (e.g. SVG URL).\n * When set, overrides the built-in radial wash.\n */\n @Prop() gradientSrc: string = '';\n\n /**\n * Built-in shell wash preset when `gradient` is true.\n * `none` (solid secondary), `cool` (blue), `neutral` (grey), `warm` (yellow). `gradientSrc` overrides when set.\n */\n @Prop({ attribute: 'gradient-preset', reflect: true }) gradientPreset: ShellGradientPreset =\n DEFAULT_SHELL_GRADIENT_PRESET;\n\n /** When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native. */\n @Prop({ attribute: 'shortcuts-enabled' }) shortcutsEnabled: boolean = true;\n\n @Element() el!: HTMLElement;\n\n private resizeObserver: ResizeObserver | null = null;\n private readonly panelNavTransition = new ChromeTransitionDepth();\n private readonly chromeSyncCoalescer = createRafCoalescer(() => this.syncChrome());\n private panelWidthTokens: PanelNavWidthTokens = { expandedPx: 0, collapsedPx: 0 };\n private cachedViewportWidth = 0;\n private cachedViewportHeight = 0;\n private onWindowResize = () => {\n if (this.panelNavTransition.isActive) return;\n this.scheduleChromeSync();\n };\n private onVisualViewportChange = () => {\n if (this.panelNavTransition.isActive) return;\n this.scheduleChromeSync();\n };\n\n componentDidLoad() {\n this.syncSlottedNavStyle();\n this.connectMetricsObserver();\n this.connectViewportListeners();\n this.el.addEventListener(CHROME_TRANSITION_START, this.onChromeTransitionStart);\n this.el.addEventListener(CHROME_TRANSITION_END, this.onChromeTransitionEnd);\n requestAnimationFrame(() => {\n this.cachePanelWidthTokens();\n this.scheduleChromeSync();\n });\n }\n\n disconnectedCallback() {\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.disconnectViewportListeners();\n this.chromeSyncCoalescer.cancel();\n this.el.removeEventListener(CHROME_TRANSITION_START, this.onChromeTransitionStart);\n this.el.removeEventListener(CHROME_TRANSITION_END, this.onChromeTransitionEnd);\n }\n\n @Watch('navStyle')\n @Watch('gradient')\n @Watch('gradientSrc')\n @Watch('gradientPreset')\n onShellPropsChange() {\n this.syncSlottedNavStyle();\n this.scheduleChromeSync();\n }\n\n private onChromeTransitionStart = (event: Event) => {\n if (readChromeTransitionSource(event) !== 'panel-nav') return;\n\n this.panelNavTransition.enter();\n const viewport = readShellViewportDimensions();\n this.cachedViewportWidth = viewport.width;\n this.cachedViewportHeight = viewport.height;\n this.syncChrome();\n };\n\n private onChromeTransitionEnd = (event: Event) => {\n if (readChromeTransitionSource(event) !== 'panel-nav') return;\n\n this.panelNavTransition.exit();\n if (!this.panelNavTransition.isActive) {\n this.scheduleChromeSync();\n }\n };\n\n /** Coalesce ResizeObserver bursts to one layout read per frame. */\n private scheduleChromeSync() {\n this.chromeSyncCoalescer.schedule();\n }\n\n private syncSlottedNavStyle() {\n const panel = this.el.querySelector('ds-panel-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;\n const bar = this.el.querySelector('ds-bar-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;\n if (panel) {\n panel.setAttribute('nav-style', this.navStyle);\n panel.navStyle = this.navStyle;\n }\n if (bar) {\n bar.setAttribute('nav-style', this.navStyle);\n bar.navStyle = this.navStyle;\n }\n }\n\n private connectMetricsObserver() {\n this.resizeObserver = new ResizeObserver(() => {\n if (this.panelNavTransition.isActive) return;\n this.scheduleChromeSync();\n });\n this.resizeObserver.observe(this.el);\n const panelWrap = this.el.querySelector('.app-shell__panel');\n if (panelWrap) this.resizeObserver.observe(panelWrap);\n }\n\n private connectViewportListeners() {\n if (typeof window === 'undefined') return;\n\n window.addEventListener('resize', this.onWindowResize, { passive: true });\n\n const visual = window.visualViewport;\n if (visual) {\n visual.addEventListener('resize', this.onVisualViewportChange, { passive: true });\n visual.addEventListener('scroll', this.onVisualViewportChange, { passive: true });\n }\n }\n\n private disconnectViewportListeners() {\n if (typeof window === 'undefined') return;\n\n window.removeEventListener('resize', this.onWindowResize);\n\n const visual = window.visualViewport;\n if (visual) {\n visual.removeEventListener('resize', this.onVisualViewportChange);\n visual.removeEventListener('scroll', this.onVisualViewportChange);\n }\n }\n\n private cachePanelWidthTokens() {\n const navRoot = this.el.querySelector('ds-panel-nav .panel-nav') as HTMLElement | null;\n if (!navRoot) return;\n this.panelWidthTokens = readPanelNavWidthTokens(navRoot);\n }\n\n private applyGradientVars(target: HTMLElement, vars: Record<string, string | null>) {\n const style = target.style;\n for (const [name, value] of Object.entries(vars)) {\n if (value === null) style.removeProperty(name);\n else style.setProperty(name, value);\n }\n }\n\n private clearGradientPaintVars(targets: HTMLElement[]) {\n const keys = [\n SHELL_GRADIENT_IMAGE_VAR,\n SHELL_GRADIENT_SIZE_VAR,\n SHELL_GRADIENT_OPACITY_VAR,\n ];\n for (const target of targets) {\n for (const key of keys) target.style.removeProperty(key);\n }\n }\n\n /** Panel/bar wash offsets for scroll fades and badge rings. */\n private syncChromeLayoutVars(\n panel: HTMLElement | null,\n bar: HTMLElement | null,\n panelPosition: string,\n barPosition: string,\n ) {\n if (panel) {\n panel.style.setProperty(SHELL_GRADIENT_POSITION_PANEL_VAR, panelPosition);\n }\n if (bar) {\n bar.style.setProperty(SHELL_GRADIENT_POSITION_BAR_VAR, barPosition);\n }\n }\n\n private resolvePanelWidthPx(panelNav: HTMLElement | null): number {\n const navRoot = panelNav?.querySelector('.panel-nav') as HTMLElement | null;\n\n if (this.panelNavTransition.isActive && this.panelWidthTokens.expandedPx > 0) {\n const collapsed = isPanelNavCollapsed(panelNav, navRoot);\n return panelWidthPxFromTokens(this.panelWidthTokens, collapsed);\n }\n\n const panelWrap = this.el.querySelector('.app-shell__panel') as HTMLElement | null;\n const measured = panelWrap?.getBoundingClientRect().width ?? 0;\n if (measured > 0) return measured;\n\n if (this.panelWidthTokens.expandedPx > 0) {\n const collapsed = isPanelNavCollapsed(panelNav, navRoot);\n return panelWidthPxFromTokens(this.panelWidthTokens, collapsed);\n }\n\n return 0;\n }\n\n /** Fixed-attachment wash/grid size — always the viewport, never the shell element box. */\n private resolveViewportDimensions(): { width: number; height: number } {\n if (this.panelNavTransition.isActive && this.cachedViewportWidth > 0) {\n return {\n width: this.cachedViewportWidth,\n height: this.cachedViewportHeight,\n };\n }\n\n return readShellViewportDimensions();\n }\n\n private chromeLayerActive(): boolean {\n return this.gradient;\n }\n\n @Listen('keydown', { target: 'window', capture: true })\n handleWindowKeyDown(e: KeyboardEvent) {\n if (!this.shortcutsEnabled) return;\n if (isEditableShortcutTarget(e.target)) return;\n\n const action = resolveShellShortcut(e);\n if (!action) return;\n\n e.preventDefault();\n\n const panel = this.el.querySelector('ds-panel-nav') as HTMLDsPanelNavElement | null;\n const tools = this.el.querySelector('ds-panel-tools') as HTMLDsPanelToolsElement | null;\n\n if (action === 'toggle-panel-nav') {\n void panel?.toggleCollapsed();\n return;\n }\n\n if (action === 'close-panel-tools') {\n void tools?.closeDrawer();\n return;\n }\n\n if (action.startsWith('open-tool:') && tools) {\n const toolId = action.slice('open-tool:'.length) as PanelToolsToolId;\n void tools.activateTool(toolId);\n }\n }\n\n private syncChrome() {\n const panelNav = this.el.querySelector('ds-panel-nav') as HTMLElement | null;\n const bar = this.el.querySelector('ds-bar-nav') as HTMLElement | null;\n const targets = [this.el, panelNav, bar].filter((el): el is HTMLElement => el !== null);\n\n const clearLayoutVars = () => {\n if (panelNav) panelNav.style.removeProperty(SHELL_GRADIENT_POSITION_PANEL_VAR);\n if (bar) bar.style.removeProperty(SHELL_GRADIENT_POSITION_BAR_VAR);\n };\n\n if (!this.gradient) {\n this.clearGradientPaintVars(targets);\n clearLayoutVars();\n return;\n }\n\n const viewport = this.resolveViewportDimensions();\n const panelWidth = this.resolvePanelWidthPx(panelNav);\n\n const panelPosition = shellGradientPositionPanel();\n const barPosition = shellGradientPositionBar(panelWidth);\n\n this.syncChromeLayoutVars(panelNav, bar, panelPosition, barPosition);\n\n const image = this.gradientSrc.trim()\n ? `url(${this.gradientSrc.trim()})`\n : buildShellRadialGradient(this.gradientPreset);\n\n const size = shellGradientSize({\n width: viewport.width,\n height: viewport.height,\n });\n const opacity = SHELL_GRADIENT_OPACITY;\n\n for (const target of targets) {\n if (target === this.el) {\n this.applyGradientVars(target, {\n [SHELL_GRADIENT_IMAGE_VAR]: image,\n [SHELL_GRADIENT_SIZE_VAR]: size,\n [SHELL_GRADIENT_POSITION_PANEL_VAR]: panelPosition,\n [SHELL_GRADIENT_POSITION_BAR_VAR]: barPosition,\n [SHELL_GRADIENT_OPACITY_VAR]: opacity,\n });\n continue;\n }\n\n const isBar = target.tagName.toLowerCase() === 'ds-bar-nav';\n this.applyGradientVars(target, {\n [SHELL_GRADIENT_IMAGE_VAR]: image,\n [SHELL_GRADIENT_SIZE_VAR]: size,\n [SHELL_GRADIENT_OPACITY_VAR]: opacity,\n [SHELL_GRADIENT_POSITION_PANEL_VAR]: isBar ? null : panelPosition,\n [SHELL_GRADIENT_POSITION_BAR_VAR]: isBar ? barPosition : null,\n });\n }\n }\n\n render() {\n const chromeActive = this.chromeLayerActive();\n const shellCls: Record<string, boolean> = {\n 'app-shell': true,\n 'app-shell--gradient': this.gradient,\n [`app-shell--${this.navStyle}`]: true,\n };\n\n return (\n <Host class={shellCls}>\n <div class=\"app-shell__row\">\n {chromeActive ? <div class=\"app-shell__chrome\" aria-hidden=\"true\" /> : null}\n <div class=\"app-shell__panel\">\n <slot name=\"panel\" />\n </div>\n <div class=\"app-shell__main\">\n <div class=\"app-shell__bar\">\n <slot name=\"bar\" />\n </div>\n <div class=\"app-shell__tools\">\n <slot name=\"tools\" />\n </div>\n <div class=\"app-shell__content\">\n <slot />\n </div>\n </div>\n </div>\n </Host>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["TOOL_SHORTCUT_KEYS","k","a","s","m","n","isBareShellShortcutKey","e","metaKey","ctrlKey","altKey","shiftKey","isEditableShortcutTarget","target","closest","el","editable","role","getAttribute","Boolean","isContentEditable","normalizedShortcutKey","key","code","length","toLowerCase","resolveShellShortcut","toolId","readCssVarWidthPx","context","cssVarName","document","probe","createElement","style","cssText","appendChild","width","getBoundingClientRect","removeChild","readPanelNavWidthTokens","navRoot","expandedPx","collapsedPx","isPanelNavCollapsed","panelNavHost","classList","contains","collapsedProp","collapsed","panelWidthPxFromTokens","tokens","appShellCss","AppShell","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","navStyle","gradient","gradientSrc","gradientPreset","DEFAULT_SHELL_GRADIENT_PRESET","shortcutsEnabled","resizeObserver","panelNavTransition","ChromeTransitionDepth","chromeSyncCoalescer","createRafCoalescer","syncChrome","panelWidthTokens","cachedViewportWidth","cachedViewportHeight","onWindowResize","isActive","scheduleChromeSync","onVisualViewportChange","onChromeTransitionStart","event","readChromeTransitionSource","enter","viewport","readShellViewportDimensions","height","onChromeTransitionEnd","exit","componentDidLoad","syncSlottedNavStyle","connectMetricsObserver","connectViewportListeners","addEventListener","CHROME_TRANSITION_START","CHROME_TRANSITION_END","requestAnimationFrame","cachePanelWidthTokens","disconnectedCallback","disconnect","disconnectViewportListeners","cancel","removeEventListener","onShellPropsChange","schedule","panel","querySelector","bar","setAttribute","ResizeObserver","observe","panelWrap","window","passive","visual","visualViewport","applyGradientVars","vars","name","value","Object","entries","removeProperty","setProperty","clearGradientPaintVars","targets","keys","SHELL_GRADIENT_IMAGE_VAR","SHELL_GRADIENT_SIZE_VAR","SHELL_GRADIENT_OPACITY_VAR","syncChromeLayoutVars","panelPosition","barPosition","SHELL_GRADIENT_POSITION_PANEL_VAR","SHELL_GRADIENT_POSITION_BAR_VAR","resolvePanelWidthPx","panelNav","measured","resolveViewportDimensions","chromeLayerActive","handleWindowKeyDown","action","preventDefault","tools","toggleCollapsed","closeDrawer","startsWith","slice","activateTool","filter","clearLayoutVars","panelWidth","shellGradientPositionPanel","shellGradientPositionBar","image","trim","buildShellRadialGradient","size","shellGradientSize","opacity","SHELL_GRADIENT_OPACITY","isBar","tagName","render","chromeActive","shellCls","h","Host","class"],"sources":["src/wc/nav/shell-shortcuts.ts","src/wc/nav/shell-chrome-metrics.ts","src/wc/components/AppShell/AppShell.css?tag=ds-app-shell&encapsulation=scoped","src/wc/components/AppShell/AppShell.tsx"],"sourcesContent":["import type { PanelToolsToolId } from '../components/PanelTools/panel-tools-types';\n\nexport type ShellShortcutAction =\n | 'toggle-panel-nav'\n | 'close-panel-tools'\n | `open-tool:${PanelToolsToolId}`;\n\nconst TOOL_SHORTCUT_KEYS: Record<string, PanelToolsToolId> = {\n k: 'search',\n a: 'agents',\n s: 'stacks',\n m: 'messages',\n n: 'activity',\n};\n\n/** Tool shortcut keys (K/A/S/M/N/?) toggle open/closed via `ds-panel-tools.activateTool`. */\n\n/** True when no modifier keys are held — avoids browser/app chords like ⌘N. */\nexport function isBareShellShortcutKey(\n e: Pick<KeyboardEvent, 'metaKey' | 'ctrlKey' | 'altKey' | 'shiftKey'>,\n): boolean {\n return !e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey;\n}\n\n/** Skip shell shortcuts while typing in an editable control. */\nexport function isEditableShortcutTarget(target: EventTarget | null): boolean {\n if (!target || typeof target !== 'object') return false;\n if (!('closest' in target) || typeof target.closest !== 'function') return false;\n\n const el = target as Element & { isContentEditable?: boolean };\n\n const editable = el.closest(\n 'input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"], [contenteditable=\"plaintext-only\"]',\n );\n if (editable) return true;\n\n const role = el.getAttribute('role');\n if (role === 'textbox' || role === 'combobox' || role === 'searchbox') return true;\n\n return Boolean(el.isContentEditable);\n}\n\nfunction normalizedShortcutKey(e: Pick<KeyboardEvent, 'key' | 'code'>): string {\n if (e.key === '[' || e.code === 'BracketLeft') return '[';\n if (e.key === ']' || e.code === 'BracketRight') return ']';\n return e.key.length === 1 ? e.key.toLowerCase() : e.key.toLowerCase();\n}\n\n/** Resolve a shell chrome shortcut, or `null` when the key is not handled. */\nexport function resolveShellShortcut(\n e: Pick<KeyboardEvent, 'key' | 'code' | 'metaKey' | 'ctrlKey' | 'altKey' | 'shiftKey'>,\n): ShellShortcutAction | null {\n if (\n (e.key === '?' || (e.code === 'Slash' && e.shiftKey)) &&\n !e.metaKey && !e.ctrlKey && !e.altKey\n ) {\n return 'open-tool:help';\n }\n if (!isBareShellShortcutKey(e)) return null;\n\n const key = normalizedShortcutKey(e);\n if (key === '[') return 'toggle-panel-nav';\n if (key === ']') return 'close-panel-tools';\n\n const toolId = TOOL_SHORTCUT_KEYS[key];\n if (toolId) return `open-tool:${toolId}`;\n\n return null;\n}\n","import { shellGradientPositionBar } from './shell-gradient';\n\n/** Read a `var(--token)` width in px using a hidden probe (works with calc() tokens). */\nexport function readCssVarWidthPx(context: HTMLElement, cssVarName: string): number {\n if (typeof document === 'undefined') return 0;\n\n const probe = document.createElement('div');\n probe.style.cssText =\n 'position:absolute;visibility:hidden;pointer-events:none;height:0;width:var(' +\n cssVarName +\n ');';\n context.appendChild(probe);\n const width = probe.getBoundingClientRect().width;\n context.removeChild(probe);\n return width;\n}\n\nexport interface PanelNavWidthTokens {\n expandedPx: number;\n collapsedPx: number;\n}\n\n/** Resolve panel-nav expanded/collapsed widths from scoped CSS vars on `.panel-nav`. */\nexport function readPanelNavWidthTokens(navRoot: HTMLElement): PanelNavWidthTokens {\n return {\n expandedPx: readCssVarWidthPx(navRoot, '--_nav-width'),\n collapsedPx: readCssVarWidthPx(navRoot, '--_nav-width-collapsed'),\n };\n}\n\nexport function isPanelNavCollapsed(\n panelNavHost: HTMLElement | null,\n navRoot: HTMLElement | null,\n): boolean {\n if (navRoot?.classList.contains('panel-nav--collapsed')) return true;\n const collapsedProp = (panelNavHost as (HTMLElement & { collapsed?: boolean }) | null)?.collapsed;\n return collapsedProp === true;\n}\n\nexport function panelWidthPxFromTokens(\n tokens: PanelNavWidthTokens,\n collapsed: boolean,\n): number {\n return collapsed ? tokens.collapsedPx : tokens.expandedPx;\n}\n\nexport function barGradientPositionFromPanelWidth(panelWidthPx: number): string {\n return shellGradientPositionBar(panelWidthPx);\n}\n",":host {\n display: block;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n --ds-shell-panel-tools-width: var(--dimension-panel-width-sm);\n}\n\n@media (min-width: 768px) and (max-width: 1199px) {\n :host {\n --ds-shell-panel-tools-width: var(--dimension-panel-width-xs);\n }\n}\n\n.app-shell {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n font-family: var(--typography-font-family, system-ui);\n}\n\n:host(.app-shell--gradient) {\n --_shell-chrome-bg: var(--color-background-secondary);\n}\n\n.app-shell__row {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n position: relative;\n}\n\n/*\n * One chrome layer behind the shell row. Wash uses background-attachment: fixed\n * so the pattern is locked to the viewport — panel/tools collapse only changes the\n * transparent window, not the pattern phase. JS sets wash background-size from\n * readShellViewportDimensions(), not the shell element box.\n */\n.app-shell__chrome {\n position: absolute;\n inset: 0;\n pointer-events: none;\n z-index: 0;\n}\n\n:host(.app-shell--gradient) .app-shell__chrome {\n background-color: var(--_shell-chrome-bg);\n}\n\n:host(.app-shell--gradient) .app-shell__chrome::before {\n content: '';\n position: absolute;\n inset: 0;\n pointer-events: none;\n background-position: 0 0;\n background-attachment: fixed;\n z-index: 1;\n opacity: var(--ds-shell-gradient-opacity, 1);\n background-image: var(--ds-shell-gradient-image, none);\n background-size: var(--ds-shell-gradient-size, auto);\n background-repeat: no-repeat;\n}\n\n.app-shell__panel {\n flex: 0 0 auto;\n min-height: 0;\n height: 100%;\n position: relative;\n /* Above main so resize handle line can paint over the workspace edge */\n z-index: 2;\n}\n\n.app-shell__panel ::slotted(ds-panel-nav) {\n display: block;\n height: 100%;\n}\n\n.app-shell__main {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n grid-template-rows: auto minmax(0, 1fr);\n grid-template-areas:\n 'bar tools'\n 'content tools';\n position: relative;\n z-index: 1;\n}\n\n.app-shell__bar {\n grid-area: bar;\n flex: 0 0 auto;\n min-width: 0;\n}\n\n.app-shell__bar ::slotted(ds-bar-nav) {\n display: block;\n}\n\n.app-shell__content {\n grid-area: content;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n overflow: auto;\n /* Limit reflow to the page column — not on __main (breaks tools flex shrink). */\n contain: layout;\n}\n\n/* Opaque page surface — masks the fixed chrome layer in the content column. */\n:host(.app-shell--gradient) .app-shell__content {\n position: relative;\n z-index: 1;\n background-color: var(--color-background-primary);\n}\n\n.app-shell__tools {\n grid-area: tools;\n flex: 0 0 auto;\n min-width: 0;\n min-height: 0;\n height: 100%;\n display: flex;\n position: relative;\n z-index: 0;\n overflow: hidden;\n}\n\n.app-shell__tools ::slotted(ds-panel-tools) {\n display: block;\n height: 100%;\n min-height: 0;\n}\n","import { Component, Prop, Element, Watch, Listen, h, Host } from '@stencil/core';\nimport type { NavChromeStyle } from '../../nav/nav-chrome';\nimport {\n isEditableShortcutTarget,\n resolveShellShortcut,\n} from '../../nav/shell-shortcuts';\nimport type { PanelToolsToolId } from '../PanelTools/panel-tools-types';\nimport {\n DEFAULT_SHELL_GRADIENT_PRESET,\n type ShellGradientPreset,\n} from '../../nav/shell-gradient-presets';\nimport {\n CHROME_TRANSITION_END,\n CHROME_TRANSITION_START,\n ChromeTransitionDepth,\n createRafCoalescer,\n readChromeTransitionSource,\n} from '../../nav/chrome-transition';\nimport {\n isPanelNavCollapsed,\n panelWidthPxFromTokens,\n readPanelNavWidthTokens,\n type PanelNavWidthTokens,\n} from '../../nav/shell-chrome-metrics';\nimport {\n SHELL_GRADIENT_IMAGE_VAR,\n SHELL_GRADIENT_OPACITY,\n SHELL_GRADIENT_OPACITY_VAR,\n SHELL_GRADIENT_POSITION_BAR_VAR,\n SHELL_GRADIENT_POSITION_PANEL_VAR,\n SHELL_GRADIENT_SIZE_VAR,\n buildShellRadialGradient,\n readShellViewportDimensions,\n shellGradientPositionBar,\n shellGradientPositionPanel,\n shellGradientSize,\n} from '../../nav/shell-gradient';\n\n@Component({\n tag: 'ds-app-shell',\n styleUrl: 'AppShell.css',\n scoped: true,\n})\nexport class AppShell {\n /** Chrome style propagated to slotted `ds-panel-nav` and `ds-bar-nav`. */\n @Prop({ attribute: 'nav-style', reflect: true }) navStyle: NavChromeStyle = 'dashboard';\n\n /** When `true`, paints the radial wash behind panel, bar, and tools (synced to shell layout). */\n @Prop({ reflect: true }) gradient: boolean = false;\n\n /**\n * Optional custom gradient for `background-image` (e.g. SVG URL).\n * When set, overrides the built-in radial wash.\n */\n @Prop() gradientSrc: string = '';\n\n /**\n * Built-in shell wash preset when `gradient` is true.\n * `none` (solid secondary), `cool` (blue), `neutral` (grey), `warm` (yellow). `gradientSrc` overrides when set.\n */\n @Prop({ attribute: 'gradient-preset', reflect: true }) gradientPreset: ShellGradientPreset =\n DEFAULT_SHELL_GRADIENT_PRESET;\n\n /** When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N/? toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native. */\n @Prop({ attribute: 'shortcuts-enabled' }) shortcutsEnabled: boolean = true;\n\n @Element() el!: HTMLElement;\n\n private resizeObserver: ResizeObserver | null = null;\n private readonly panelNavTransition = new ChromeTransitionDepth();\n private readonly chromeSyncCoalescer = createRafCoalescer(() => this.syncChrome());\n private panelWidthTokens: PanelNavWidthTokens = { expandedPx: 0, collapsedPx: 0 };\n private cachedViewportWidth = 0;\n private cachedViewportHeight = 0;\n private onWindowResize = () => {\n if (this.panelNavTransition.isActive) return;\n this.scheduleChromeSync();\n };\n private onVisualViewportChange = () => {\n if (this.panelNavTransition.isActive) return;\n this.scheduleChromeSync();\n };\n\n componentDidLoad() {\n this.syncSlottedNavStyle();\n this.connectMetricsObserver();\n this.connectViewportListeners();\n this.el.addEventListener(CHROME_TRANSITION_START, this.onChromeTransitionStart);\n this.el.addEventListener(CHROME_TRANSITION_END, this.onChromeTransitionEnd);\n requestAnimationFrame(() => {\n this.cachePanelWidthTokens();\n this.scheduleChromeSync();\n });\n }\n\n disconnectedCallback() {\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.disconnectViewportListeners();\n this.chromeSyncCoalescer.cancel();\n this.el.removeEventListener(CHROME_TRANSITION_START, this.onChromeTransitionStart);\n this.el.removeEventListener(CHROME_TRANSITION_END, this.onChromeTransitionEnd);\n }\n\n @Watch('navStyle')\n @Watch('gradient')\n @Watch('gradientSrc')\n @Watch('gradientPreset')\n onShellPropsChange() {\n this.syncSlottedNavStyle();\n this.scheduleChromeSync();\n }\n\n private onChromeTransitionStart = (event: Event) => {\n if (readChromeTransitionSource(event) !== 'panel-nav') return;\n\n this.panelNavTransition.enter();\n const viewport = readShellViewportDimensions();\n this.cachedViewportWidth = viewport.width;\n this.cachedViewportHeight = viewport.height;\n this.syncChrome();\n };\n\n private onChromeTransitionEnd = (event: Event) => {\n if (readChromeTransitionSource(event) !== 'panel-nav') return;\n\n this.panelNavTransition.exit();\n if (!this.panelNavTransition.isActive) {\n this.scheduleChromeSync();\n }\n };\n\n /** Coalesce ResizeObserver bursts to one layout read per frame. */\n private scheduleChromeSync() {\n this.chromeSyncCoalescer.schedule();\n }\n\n private syncSlottedNavStyle() {\n const panel = this.el.querySelector('ds-panel-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;\n const bar = this.el.querySelector('ds-bar-nav') as (HTMLElement & { navStyle: NavChromeStyle }) | null;\n if (panel) {\n panel.setAttribute('nav-style', this.navStyle);\n panel.navStyle = this.navStyle;\n }\n if (bar) {\n bar.setAttribute('nav-style', this.navStyle);\n bar.navStyle = this.navStyle;\n }\n }\n\n private connectMetricsObserver() {\n this.resizeObserver = new ResizeObserver(() => {\n if (this.panelNavTransition.isActive) return;\n this.scheduleChromeSync();\n });\n this.resizeObserver.observe(this.el);\n const panelWrap = this.el.querySelector('.app-shell__panel');\n if (panelWrap) this.resizeObserver.observe(panelWrap);\n }\n\n private connectViewportListeners() {\n if (typeof window === 'undefined') return;\n\n window.addEventListener('resize', this.onWindowResize, { passive: true });\n\n const visual = window.visualViewport;\n if (visual) {\n visual.addEventListener('resize', this.onVisualViewportChange, { passive: true });\n visual.addEventListener('scroll', this.onVisualViewportChange, { passive: true });\n }\n }\n\n private disconnectViewportListeners() {\n if (typeof window === 'undefined') return;\n\n window.removeEventListener('resize', this.onWindowResize);\n\n const visual = window.visualViewport;\n if (visual) {\n visual.removeEventListener('resize', this.onVisualViewportChange);\n visual.removeEventListener('scroll', this.onVisualViewportChange);\n }\n }\n\n private cachePanelWidthTokens() {\n const navRoot = this.el.querySelector('ds-panel-nav .panel-nav') as HTMLElement | null;\n if (!navRoot) return;\n this.panelWidthTokens = readPanelNavWidthTokens(navRoot);\n }\n\n private applyGradientVars(target: HTMLElement, vars: Record<string, string | null>) {\n const style = target.style;\n for (const [name, value] of Object.entries(vars)) {\n if (value === null) style.removeProperty(name);\n else style.setProperty(name, value);\n }\n }\n\n private clearGradientPaintVars(targets: HTMLElement[]) {\n const keys = [\n SHELL_GRADIENT_IMAGE_VAR,\n SHELL_GRADIENT_SIZE_VAR,\n SHELL_GRADIENT_OPACITY_VAR,\n ];\n for (const target of targets) {\n for (const key of keys) target.style.removeProperty(key);\n }\n }\n\n /** Panel/bar wash offsets for scroll fades and badge rings. */\n private syncChromeLayoutVars(\n panel: HTMLElement | null,\n bar: HTMLElement | null,\n panelPosition: string,\n barPosition: string,\n ) {\n if (panel) {\n panel.style.setProperty(SHELL_GRADIENT_POSITION_PANEL_VAR, panelPosition);\n }\n if (bar) {\n bar.style.setProperty(SHELL_GRADIENT_POSITION_BAR_VAR, barPosition);\n }\n }\n\n private resolvePanelWidthPx(panelNav: HTMLElement | null): number {\n const navRoot = panelNav?.querySelector('.panel-nav') as HTMLElement | null;\n\n if (this.panelNavTransition.isActive && this.panelWidthTokens.expandedPx > 0) {\n const collapsed = isPanelNavCollapsed(panelNav, navRoot);\n return panelWidthPxFromTokens(this.panelWidthTokens, collapsed);\n }\n\n const panelWrap = this.el.querySelector('.app-shell__panel') as HTMLElement | null;\n const measured = panelWrap?.getBoundingClientRect().width ?? 0;\n if (measured > 0) return measured;\n\n if (this.panelWidthTokens.expandedPx > 0) {\n const collapsed = isPanelNavCollapsed(panelNav, navRoot);\n return panelWidthPxFromTokens(this.panelWidthTokens, collapsed);\n }\n\n return 0;\n }\n\n /** Fixed-attachment wash/grid size — always the viewport, never the shell element box. */\n private resolveViewportDimensions(): { width: number; height: number } {\n if (this.panelNavTransition.isActive && this.cachedViewportWidth > 0) {\n return {\n width: this.cachedViewportWidth,\n height: this.cachedViewportHeight,\n };\n }\n\n return readShellViewportDimensions();\n }\n\n private chromeLayerActive(): boolean {\n return this.gradient;\n }\n\n @Listen('keydown', { target: 'window', capture: true })\n handleWindowKeyDown(e: KeyboardEvent) {\n if (!this.shortcutsEnabled) return;\n if (isEditableShortcutTarget(e.target)) return;\n\n const action = resolveShellShortcut(e);\n if (!action) return;\n\n e.preventDefault();\n\n const panel = this.el.querySelector('ds-panel-nav') as HTMLDsPanelNavElement | null;\n const tools = this.el.querySelector('ds-panel-tools') as HTMLDsPanelToolsElement | null;\n\n if (action === 'toggle-panel-nav') {\n void panel?.toggleCollapsed();\n return;\n }\n\n if (action === 'close-panel-tools') {\n void tools?.closeDrawer();\n return;\n }\n\n if (action.startsWith('open-tool:') && tools) {\n const toolId = action.slice('open-tool:'.length) as PanelToolsToolId;\n void tools.activateTool(toolId);\n }\n }\n\n private syncChrome() {\n const panelNav = this.el.querySelector('ds-panel-nav') as HTMLElement | null;\n const bar = this.el.querySelector('ds-bar-nav') as HTMLElement | null;\n const targets = [this.el, panelNav, bar].filter((el): el is HTMLElement => el !== null);\n\n const clearLayoutVars = () => {\n if (panelNav) panelNav.style.removeProperty(SHELL_GRADIENT_POSITION_PANEL_VAR);\n if (bar) bar.style.removeProperty(SHELL_GRADIENT_POSITION_BAR_VAR);\n };\n\n if (!this.gradient) {\n this.clearGradientPaintVars(targets);\n clearLayoutVars();\n return;\n }\n\n const viewport = this.resolveViewportDimensions();\n const panelWidth = this.resolvePanelWidthPx(panelNav);\n\n const panelPosition = shellGradientPositionPanel();\n const barPosition = shellGradientPositionBar(panelWidth);\n\n this.syncChromeLayoutVars(panelNav, bar, panelPosition, barPosition);\n\n const image = this.gradientSrc.trim()\n ? `url(${this.gradientSrc.trim()})`\n : buildShellRadialGradient(this.gradientPreset);\n\n const size = shellGradientSize({\n width: viewport.width,\n height: viewport.height,\n });\n const opacity = SHELL_GRADIENT_OPACITY;\n\n for (const target of targets) {\n if (target === this.el) {\n this.applyGradientVars(target, {\n [SHELL_GRADIENT_IMAGE_VAR]: image,\n [SHELL_GRADIENT_SIZE_VAR]: size,\n [SHELL_GRADIENT_POSITION_PANEL_VAR]: panelPosition,\n [SHELL_GRADIENT_POSITION_BAR_VAR]: barPosition,\n [SHELL_GRADIENT_OPACITY_VAR]: opacity,\n });\n continue;\n }\n\n const isBar = target.tagName.toLowerCase() === 'ds-bar-nav';\n this.applyGradientVars(target, {\n [SHELL_GRADIENT_IMAGE_VAR]: image,\n [SHELL_GRADIENT_SIZE_VAR]: size,\n [SHELL_GRADIENT_OPACITY_VAR]: opacity,\n [SHELL_GRADIENT_POSITION_PANEL_VAR]: isBar ? null : panelPosition,\n [SHELL_GRADIENT_POSITION_BAR_VAR]: isBar ? barPosition : null,\n });\n }\n }\n\n render() {\n const chromeActive = this.chromeLayerActive();\n const shellCls: Record<string, boolean> = {\n 'app-shell': true,\n 'app-shell--gradient': this.gradient,\n [`app-shell--${this.navStyle}`]: true,\n };\n\n return (\n <Host class={shellCls}>\n <div class=\"app-shell__row\">\n {chromeActive ? <div class=\"app-shell__chrome\" aria-hidden=\"true\" /> : null}\n <div class=\"app-shell__panel\">\n <slot name=\"panel\" />\n </div>\n <div class=\"app-shell__main\">\n <div class=\"app-shell__bar\">\n <slot name=\"bar\" />\n </div>\n <div class=\"app-shell__tools\">\n <slot name=\"tools\" />\n </div>\n <div class=\"app-shell__content\">\n <slot />\n </div>\n </div>\n </div>\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-DEgY_Lnb.js";import{d as r}from"./p-DHjjwgku.js";import{d}from"./p-9Qu1ls2y.js";import{d as c}from"./p-BOQRM49Q.js";import{d as p}from"./p-DI8rHm9u.js";const h="search";const f="help";const b={search:"Search",messages:"Messages",stacks:"Stacks",activity:"Activity",agents:"Agents",help:"Help & Support"};function _(e,s){if(s){return n(s,[])}return e??[]}function m(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[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{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}ds-text.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}ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools__body.sc-ds-panel-tools{opacity:0;transition:none}.panel-tools--ready.panel-tools--motion-opening.sc-ds-panel-tools-h ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools--ready.panel-tools--motion-opening.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{transition:opacity 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 ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools--ready.panel-tools--motion-closing.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{transition:opacity var(--_panel-tools-expand-dur) var(--effect-animation-easing-ease-in, ease-in)}.panel-tools--open.sc-ds-panel-tools-h ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools--open.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{opacity:1}.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-footer.sc-ds-panel-tools{display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:auto;padding:var(--dimension-space-100);box-sizing:border-box}.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 v=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.toolsLabel="Tools";this.toolShortcutsLabel="Tool shortcuts";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 _(this.items,this.itemsJson)}get orderedRailItems(){const e=this.railItems;const s=e.find((e=>e.id===h));const t=e.find((e=>e.id===f));const o=e.filter((e=>e.id!==h&&e.id!==f));const a=[];if(s)a.push(s);a.push(...o);if(t)a.push(t);return a}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 b[this.activeTool]??""}async activateTool(e){const s=this.railItems.find((s=>s.id===e));if(!s||s.isInactive)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){const t=e.ariaLabel??b[e.id];return o("ds-tooltip",{key:e.id,label:t,side:"left",size:"sm"},o("ds-button-unfilled",{variant:"icon",class:"panel-tools__rail-action",icon:e.icon,isActive:this.isRailSelected(e.id),activeFill:false,hasBorder:false,dot:e.dot??false,isInactive:e.isInactive,focusTabIndex:s===this.rovingIndex?0:-1,"aria-label":t,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===h));const i=s.find((e=>e.id===f));const n=s.filter((e=>e.id!==h&&e.id!==f));const l=i?(t?1:0)+n.length:-1;const r=this.isDrawerPresent();const d=m(this.open,this.motion);return o(a,{key:"83179a0808edb9a4e07b34658c5df26e3918d3c8",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":d},role:"complementary","aria-label":this.toolsLabel},o("div",{key:"b7022d442ad0be533c70661387adbd7f86d57ce1",class:"panel-tools__layout"},o("nav",{key:"2e10040aa5e6c8aefe9e2a5ca0882567c7487c8e",class:"panel-tools__rail","aria-label":this.toolShortcutsLabel},t?o("div",{class:"panel-tools__rail-header"},this.renderRailAction(t,0)):null,o("div",{key:"8f1428e3bd22836ae93f24df2547bc0c424eb1be",class:"panel-tools__rail-body"},n.map(((e,s)=>this.renderRailAction(e,t?s+1:s)))),i?o("div",{class:"panel-tools__rail-footer"},this.renderRailAction(i,l)):null),o("div",{key:"9b829e06ee080645259ef12c749f36638ebb3eca",class:{"panel-tools__drawer":true,"panel-tools__drawer--visible":r},"aria-hidden":r?null:"true",inert:r?undefined:true},o("div",{key:"6f459b50ddb1939b06c8795e034d75e8c235f5cf",class:"panel-tools__drawer-surface"},o("header",{key:"502ba015e4e3d3a6b89c3f2fe550a2f4d6ad3b69",class:"panel-tools__header"},o("ds-text",{key:"6196b1037b26e73e73e017c9a869b02e3e3ef9cb",class:"panel-tools__title",as:"span",variant:"text-body-medium",emphasis:true,color:"primary",wrap:"nowrap"},e)),o("div",{key:"187800a17b603f873d900dbaeeab8ebac929aeb5",class:"panel-tools__body"},o("div",{key:"466b9a2fb083735873166dd645c554923679e102",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("search")},hidden:!this.isViewActive("search")},o("slot",{key:"19bd70688d531759080ca4bc0b0e83f814e929a9",name:"search"})),o("div",{key:"19e871e2d0a04de920ede597ca947c3c149e8923",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("messages")},hidden:!this.isViewActive("messages")},o("slot",{key:"cf25286ad2f283f398859c3ccf2a9c8dbb10efbd",name:"messages"})),o("div",{key:"0bf1d648e4ee4605234c7963a99e1e1ec96926ae",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("stacks")},hidden:!this.isViewActive("stacks")},o("slot",{key:"1dcb6306f65b52a5f47e177294e5078531f4e56a",name:"stacks"})),o("div",{key:"93e28563b442bf44eca3da3591abef27f26c1ed5",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("activity")},hidden:!this.isViewActive("activity")},o("slot",{key:"d7527ac08e4db33e93528bbf3b2959e4920389c2",name:"activity"})),o("div",{key:"d66e8921d5500114f1c176e82dc7282d6fefe9e4",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("agents")},hidden:!this.isViewActive("agents")},o("slot",{key:"3ede0bd37b887fea8c4d23e65969938f2293695c",name:"agents"})),o("div",{key:"3d2782b711935dc8c6df988e74e13f20f887f83c",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("help")},hidden:!this.isViewActive("help")},o("slot",{key:"7653355346a5b6b5cc83ef457bac882fa81a658f",name:"help"})))))))}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"],toolsLabel:[1,"tools-label"],toolShortcutsLabel:[1,"tool-shortcuts-label"],motion:[32],readyForMotion:[32],rovingIndex:[32],activateTool:[64],closeDrawer:[64]},undefined,{open:[{openChanged:0}],activeTool:[{activeToolChanged:0}],items:[{itemsChanged:0}],itemsJson:[{itemsChanged:0}]}]);function y(){if(typeof customElements==="undefined"){return}const e=["ds-panel-tools","ds-badge","ds-button-unfilled","ds-icon","ds-text","ds-tooltip"];e.forEach((e=>{switch(e){case"ds-panel-tools":if(!customElements.get(i(e))){customElements.define(i(e),v)}break;case"ds-badge":if(!customElements.get(i(e))){l()}break;case"ds-button-unfilled":if(!customElements.get(i(e))){r()}break;case"ds-icon":if(!customElements.get(i(e))){d()}break;case"ds-text":if(!customElements.get(i(e))){c()}break;case"ds-tooltip":if(!customElements.get(i(e))){p()}break}}))}y();const w=v;const x=y;export{w as DsPanelTools,x 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-DEgY_Lnb.js";import{d as r}from"./p-DHjjwgku.js";import{d}from"./p-9Qu1ls2y.js";import{d as c}from"./p-BOQRM49Q.js";import{d as p}from"./p-DI8rHm9u.js";const h=["search","agents","messages","stacks","activity","help"];const f="search";const g="help";const u={search:"Search",messages:"Messages",stacks:"Stacks",activity:"Activity",agents:"Agents",help:"Help & Support"};const b={search:"K",agents:"A",messages:"M",stacks:"S",activity:"N",help:"?"};function m(e,s){if(s){return n(s,[])}return e??[]}function _(e){const s=new Map;for(const t of e){if(!s.has(t.id))s.set(t.id,t)}return h.flatMap((e=>{const t=s.get(e);return t?[t]:[]}))}function v(e){return e!==null&&h.includes(e)}function y(e,s,t){if(!t||e.some((e=>e.id===t))){return{open:s,activeTool:t,removedTool:""}}return{open:false,activeTool:"",removedTool:t}}function w(e,s){return!e&&s==="idle"}function x(e,s,t){if(e&&s===t){return{open:false,activeTool:t,selected:false}}return{open:true,activeTool:t,selected:true}}const k=()=>`.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( --ds-shell-panel-tools-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[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{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}ds-text.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}ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools__body.sc-ds-panel-tools{opacity:0;transition:none}.panel-tools--ready.panel-tools--motion-opening.sc-ds-panel-tools-h ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools--ready.panel-tools--motion-opening.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{transition:opacity 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 ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools--ready.panel-tools--motion-closing.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{transition:opacity var(--_panel-tools-expand-dur) var(--effect-animation-easing-ease-in, ease-in)}.panel-tools--open.sc-ds-panel-tools-h ds-text.panel-tools__title.sc-ds-panel-tools,.panel-tools--open.sc-ds-panel-tools-h .panel-tools__body.sc-ds-panel-tools{opacity:1}.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-footer.sc-ds-panel-tools{display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:auto;padding:var(--dimension-space-100);box-sizing:border-box}.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 T=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.toolsLabel="Tools";this.toolShortcutsLabel="Tool shortcuts";this.storageKey="";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=x(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 m(this.items,this.itemsJson)}get orderedRailItems(){const e=_(this.railItems);const s=e.find((e=>e.id===f));const t=e.find((e=>e.id===g));const o=e.filter((e=>e.id!==f&&e.id!==g));const a=[];if(s)a.push(s);a.push(...o);if(t)a.push(t);return a}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)}componentWillLoad(){this.restoreLastActiveTool()}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.persistLastActiveTool();this.deferMotionEnable()}storageKeyChanged(){this.restoreLastActiveTool()}componentDidLoad(){this.deferMotionEnable()}itemsChanged(){this.rovingIndex=0;this.reconcileActiveTool();this.deferMotionEnable()}restoreLastActiveTool(){if(!this.storageKey||this.activeTool)return;try{const e=localStorage.getItem(this.storageKey);if(v(e))this.activeTool=e}catch{}}persistLastActiveTool(){if(!this.storageKey||!this.activeTool)return;try{localStorage.setItem(this.storageKey,this.activeTool)}catch{}}clearPersistedTool(){if(!this.storageKey)return;try{localStorage.removeItem(this.storageKey)}catch{}}reconcileActiveTool(){const e=y(this.railItems,this.open,this.activeTool);if(!e.removedTool)return;this.clearPersistedTool();this.open=e.open;this.activeTool=e.activeTool;this.dsToolChange.emit({id:e.removedTool,selected:false})}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 u[this.activeTool]??""}async activateTool(e){const s=this.railItems.find((s=>s.id===e));if(!s||s.isInactive)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){const t=e.ariaLabel??u[e.id];return o("ds-tooltip",{key:e.id,label:t,shortcutKey:b[e.id],side:"left",size:"sm"},o("ds-button-unfilled",{variant:"icon",class:"panel-tools__rail-action",icon:e.icon,isActive:this.isRailSelected(e.id),activeFill:false,hasBorder:false,dot:e.dot??false,isInactive:e.isInactive,focusTabIndex:s===this.rovingIndex?0:-1,"aria-label":t,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===f));const i=s.find((e=>e.id===g));const n=s.filter((e=>e.id!==f&&e.id!==g));const l=i?(t?1:0)+n.length:-1;const r=this.isDrawerPresent();const d=w(this.open,this.motion);return o(a,{key:"bc622c7d1a89640492a2a0b8af6a36cdd317bd6f",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":d},role:"complementary","aria-label":this.toolsLabel},o("div",{key:"3d8998d4092f3d7afd0f18e2ce7fb7f9a543ba24",class:"panel-tools__layout"},o("nav",{key:"14e8f172c024794110b3121b39463dad18f7f3ff",class:"panel-tools__rail","aria-label":this.toolShortcutsLabel},t?o("div",{class:"panel-tools__rail-header"},this.renderRailAction(t,0)):null,o("div",{key:"d2fb3f4861d4e0dce409445321d3454782a1fefb",class:"panel-tools__rail-body"},n.map(((e,s)=>this.renderRailAction(e,t?s+1:s)))),i?o("div",{class:"panel-tools__rail-footer"},this.renderRailAction(i,l)):null),o("div",{key:"78791330056be1bbd85a0e7982e70dccfe1c2b84",class:{"panel-tools__drawer":true,"panel-tools__drawer--visible":r},"aria-hidden":r?null:"true",inert:r?undefined:true},o("div",{key:"c43059deb82ef2d5a47ae6af561e8f8b045462d3",class:"panel-tools__drawer-surface"},o("header",{key:"9ef751e7aa6a5dc960acede5d95a44b333b893f7",class:"panel-tools__header"},o("ds-text",{key:"429adbc38ffe20bf5574f398de845f6f53a65782",class:"panel-tools__title",as:"span",variant:"text-body-medium",emphasis:true,color:"primary",wrap:"nowrap"},e)),o("div",{key:"9a08e03155dc34c27e3029467491ff6884c8a749",class:"panel-tools__body"},o("div",{key:"832ce9f7ba05a9392a8efdef0f23e1ddd617ca20",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("search")},hidden:!this.isViewActive("search")},o("slot",{key:"3044318c7efbc364bab85b5fe8142fa6e1801821",name:"search"})),o("div",{key:"5f37c7018619a268baf80c0b779c9a0dbb54ec61",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("messages")},hidden:!this.isViewActive("messages")},o("slot",{key:"91d8ef3c24d06b17805289aba4343ef85bd89644",name:"messages"})),o("div",{key:"f6eb9f300e92bdc577ba5c881e255825574969be",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("stacks")},hidden:!this.isViewActive("stacks")},o("slot",{key:"1cd01901a4a168edb4ebd29afc99dcc2d16dc7ab",name:"stacks"})),o("div",{key:"c52cb74f160e3d52808e4ce02f07898016303fc3",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("activity")},hidden:!this.isViewActive("activity")},o("slot",{key:"2c196413b27bd9d46575527f3a2a11dc3801ded4",name:"activity"})),o("div",{key:"d508248557e9b1988138208206b0edf62258b2af",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("agents")},hidden:!this.isViewActive("agents")},o("slot",{key:"dcce07a3efe83c6e75bc1d430dfec10135318dee",name:"agents"})),o("div",{key:"709a131c1e6f61c0f5b07dc4b835bd6dbc03310f",class:{"panel-tools__view":true,"panel-tools__view--active":this.isViewActive("help")},hidden:!this.isViewActive("help")},o("slot",{key:"163db81e6ba14dae41c5a8a2ada3977e0d4c6327",name:"help"})))))))}get el(){return this}static get watchers(){return{open:[{openChanged:0}],activeTool:[{activeToolChanged:0}],storageKey:[{storageKeyChanged:0}],items:[{itemsChanged:0}],itemsJson:[{itemsChanged:0}]}}static get style(){return k()}},[262,"ds-panel-tools",{open:[1540],activeTool:[1537,"active-tool"],items:[16],itemsJson:[1,"items-json"],toolsLabel:[1,"tools-label"],toolShortcutsLabel:[1,"tool-shortcuts-label"],storageKey:[1,"storage-key"],motion:[32],readyForMotion:[32],rovingIndex:[32],activateTool:[64],closeDrawer:[64]},undefined,{open:[{openChanged:0}],activeTool:[{activeToolChanged:0}],storageKey:[{storageKeyChanged:0}],items:[{itemsChanged:0}],itemsJson:[{itemsChanged:0}]}]);function z(){if(typeof customElements==="undefined"){return}const e=["ds-panel-tools","ds-badge","ds-button-unfilled","ds-icon","ds-text","ds-tooltip"];e.forEach((e=>{switch(e){case"ds-panel-tools":if(!customElements.get(i(e))){customElements.define(i(e),T)}break;case"ds-badge":if(!customElements.get(i(e))){l()}break;case"ds-button-unfilled":if(!customElements.get(i(e))){r()}break;case"ds-icon":if(!customElements.get(i(e))){d()}break;case"ds-text":if(!customElements.get(i(e))){c()}break;case"ds-tooltip":if(!customElements.get(i(e))){p()}break}}))}z();const C=T;const A=z;export{C as DsPanelTools,A as defineCustomElement};
2
2
  //# sourceMappingURL=ds-panel-tools.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["PANEL_TOOLS_PRIMARY_TOOL_ID","PANEL_TOOLS_FOOTER_TOOL_ID","PANEL_TOOLS_LABELS","search","messages","stacks","activity","agents","help","parsePanelToolsItems","items","itemsJson","parseJsonArrayProp","panelToolsDrawerResting","open","motion","resolvePanelToolActivation","activeTool","id","selected","panelToolsCss","PanelTools","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","toolsLabel","toolShortcutsLabel","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","footerItem","bodyItems","filter","ordered","push","disconnectedCallback","removeEventListener","deferMotionEnable","generation","requestAnimationFrame","connectedCallback","addEventListener","openChanged","isOpen","wasOpen","undefined","dsChromeTransitionStart","phase","activeToolChanged","componentDidLoad","itemsChanged","isRailSelected","isDrawerPresent","isViewActive","headerLabel","activateTool","entry","isInactive","closeDrawer","bounded","Math","max","min","actions","Array","from","querySelectorAll","focus","preventScroll","renderRailAction","label","ariaLabel","h","side","size","variant","class","icon","isActive","activeFill","hasBorder","dot","focusTabIndex","pressed","onFocusin","onKeyDown","onDsClick","render","footerIndex","showDrawerChrome","drawerResting","Host","role","map","bodyIdx","inert","as","emphasis","color","wrap","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 =\n | 'search'\n | 'agents'\n | 'messages'\n | 'stacks'\n | 'activity'\n | 'help';\n\nexport const PANEL_TOOLS_TOOL_IDS: PanelToolsToolId[] = [\n 'search',\n 'agents',\n 'messages',\n 'stacks',\n 'activity',\n 'help',\n];\n\n/** Rail header slot — mirrors panel-nav M logo row. */\nexport const PANEL_TOOLS_PRIMARY_TOOL_ID: PanelToolsToolId = 'search';\n\n/** Rail footer slot — flush to the bottom of the tools column. */\nexport const PANEL_TOOLS_FOOTER_TOOL_ID: PanelToolsToolId = 'help';\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 help: 'Help & Support',\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 isInactive?: 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.isInactive !== item.isInactive ||\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) — drawer + rail are transparent frames. */\n:host-context(ds-app-shell[gradient]) .panel-tools__drawer-surface,\n:host-context(ds-app-shell[gradient]) .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/*\n * Drawer title — match rail action height (size-400) and BarNav heading inset.\n * Use `ds-text.` so scoped specificity beats Text's `:host(.ds-text--inline-box)`\n * (class-only `.panel-tools__title` ties and loses when Text CSS loads later).\n */\nds-text.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/*\n * Fade title + slot body with the drawer slide (same dur/easing).\n * Header border stays opaque — only inner content opacity animates.\n */\nds-text.panel-tools__title,\n.panel-tools__body {\n opacity: 0;\n transition: none;\n}\n\n:host(.panel-tools--ready.panel-tools--motion-opening) ds-text.panel-tools__title,\n:host(.panel-tools--ready.panel-tools--motion-opening) .panel-tools__body {\n transition: opacity 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) ds-text.panel-tools__title,\n:host(.panel-tools--ready.panel-tools--motion-closing) .panel-tools__body {\n transition: opacity var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-in, ease-in);\n}\n\n:host(.panel-tools--open) ds-text.panel-tools__title,\n:host(.panel-tools--open) .panel-tools__body {\n opacity: 1;\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/* Flush to the bottom of the rail — mirrors Search header pin. */\n.panel-tools__rail-footer {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-top: auto;\n padding: var(--dimension-space-100);\n box-sizing: border-box;\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_FOOTER_TOOL_ID,\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`, `activity`, or `help`. */\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 @Prop() toolsLabel: string = 'Tools';\n @Prop() toolShortcutsLabel: string = 'Tool shortcuts';\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 footerItem = railItems.find(item => item.id === PANEL_TOOLS_FOOTER_TOOL_ID);\n const bodyItems = railItems.filter(\n item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID && item.id !== PANEL_TOOLS_FOOTER_TOOL_ID,\n );\n const ordered: PanelToolsItem[] = [];\n if (headerItem) ordered.push(headerItem);\n ordered.push(...bodyItems);\n if (footerItem) ordered.push(footerItem);\n return ordered;\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.isInactive) 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 const label = item.ariaLabel ?? PANEL_TOOLS_LABELS[item.id];\n return (\n <ds-tooltip key={item.id} label={label} side=\"left\" size=\"sm\">\n <ds-button-unfilled variant=\"icon\"\n class=\"panel-tools__rail-action\"\n icon={item.icon}\n isActive={this.isRailSelected(item.id)}\n activeFill={false}\n hasBorder={false}\n dot={item.dot ?? false}\n isInactive={item.isInactive}\n focusTabIndex={index === this.rovingIndex ? 0 : -1}\n aria-label={label}\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 </ds-tooltip>\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 footerItem = orderedRailItems.find(item => item.id === PANEL_TOOLS_FOOTER_TOOL_ID);\n const bodyItems = orderedRailItems.filter(\n item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID && item.id !== PANEL_TOOLS_FOOTER_TOOL_ID,\n );\n const footerIndex = footerItem\n ? (headerItem ? 1 : 0) + bodyItems.length\n : -1;\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={this.toolsLabel}\n >\n <div class=\"panel-tools__layout\">\n <nav class=\"panel-tools__rail\" aria-label={this.toolShortcutsLabel}>\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 {footerItem ? (\n <div class=\"panel-tools__rail-footer\">\n {this.renderRailAction(footerItem, footerIndex)}\n </div>\n ) : null}\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 <ds-text\n class=\"panel-tools__title\"\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color=\"primary\"\n wrap=\"nowrap\"\n >\n {headerLabel}\n </ds-text>\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 }}\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 }}\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 }}\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 }}\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 }}\n hidden={!this.isViewActive('agents')}\n >\n <slot name=\"agents\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('help'),\n }}\n hidden={!this.isViewActive('help')}\n >\n <slot name=\"help\" />\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_TOOL_IDS","PANEL_TOOLS_PRIMARY_TOOL_ID","PANEL_TOOLS_FOOTER_TOOL_ID","PANEL_TOOLS_LABELS","search","messages","stacks","activity","agents","help","PANEL_TOOLS_SHORTCUTS","parsePanelToolsItems","items","itemsJson","parseJsonArrayProp","orderPanelToolsItems","firstById","Map","item","has","id","set","flatMap","get","isPanelToolsToolId","value","includes","reconcilePanelToolsAvailability","open","activeTool","some","removedTool","panelToolsDrawerResting","motion","resolvePanelToolActivation","selected","panelToolsCss","PanelTools","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","toolsLabel","toolShortcutsLabel","storageKey","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","footerItem","bodyItems","filter","ordered","push","disconnectedCallback","removeEventListener","deferMotionEnable","generation","requestAnimationFrame","connectedCallback","addEventListener","componentWillLoad","restoreLastActiveTool","openChanged","isOpen","wasOpen","undefined","dsChromeTransitionStart","phase","activeToolChanged","persistLastActiveTool","storageKeyChanged","componentDidLoad","itemsChanged","reconcileActiveTool","stored","localStorage","getItem","setItem","clearPersistedTool","removeItem","isRailSelected","isDrawerPresent","isViewActive","headerLabel","activateTool","entry","isInactive","closeDrawer","bounded","Math","max","min","actions","Array","from","querySelectorAll","focus","preventScroll","renderRailAction","label","ariaLabel","h","shortcutKey","side","size","variant","class","icon","isActive","activeFill","hasBorder","dot","focusTabIndex","pressed","onFocusin","onKeyDown","onDsClick","render","footerIndex","showDrawerChrome","drawerResting","Host","role","map","bodyIdx","inert","as","emphasis","color","wrap","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 =\n | 'search'\n | 'agents'\n | 'messages'\n | 'stacks'\n | 'activity'\n | 'help';\n\nexport const PANEL_TOOLS_TOOL_IDS: PanelToolsToolId[] = [\n 'search',\n 'agents',\n 'messages',\n 'stacks',\n 'activity',\n 'help',\n];\n\n/** Rail header slot — mirrors panel-nav M logo row. */\nexport const PANEL_TOOLS_PRIMARY_TOOL_ID: PanelToolsToolId = 'search';\n\n/** Rail footer slot — flush to the bottom of the tools column. */\nexport const PANEL_TOOLS_FOOTER_TOOL_ID: PanelToolsToolId = 'help';\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 help: 'Help & Support',\n};\n\nexport const PANEL_TOOLS_SHORTCUTS: Partial<Record<PanelToolsToolId, string>> = {\n search: 'K',\n agents: 'A',\n messages: 'M',\n stacks: 'S',\n activity: 'N',\n help: '?',\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 isInactive?: boolean;\n ariaLabel?: string;\n}\n","import { parseJsonArrayProp } from '../BarNav/bar-nav-utils';\nimport {\n PANEL_TOOLS_TOOL_IDS,\n type PanelToolsItem,\n type PanelToolsToolId,\n} 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 orderPanelToolsItems(items: PanelToolsItem[]): PanelToolsItem[] {\n const firstById = new Map<PanelToolsToolId, PanelToolsItem>();\n for (const item of items) {\n if (!firstById.has(item.id)) firstById.set(item.id, item);\n }\n return PANEL_TOOLS_TOOL_IDS.flatMap(id => {\n const item = firstById.get(id);\n return item ? [item] : [];\n });\n}\n\nexport function isPanelToolsToolId(value: string | null): value is PanelToolsToolId {\n return value !== null && PANEL_TOOLS_TOOL_IDS.includes(value as PanelToolsToolId);\n}\n\nexport function reconcilePanelToolsAvailability(\n items: PanelToolsItem[],\n open: boolean,\n activeTool: PanelToolsToolId | '',\n): { open: boolean; activeTool: PanelToolsToolId | ''; removedTool: PanelToolsToolId | '' } {\n if (!activeTool || items.some(item => item.id === activeTool)) {\n return { open, activeTool, removedTool: '' };\n }\n return { open: false, activeTool: '', removedTool: activeTool };\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.isInactive !== item.isInactive ||\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(\n --ds-shell-panel-tools-width,\n var(--dimension-panel-width-sm)\n );\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 — AppShell supplies 400px desktop / 300px tablet tokens. */\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) — drawer + rail are transparent frames. */\n:host-context(ds-app-shell[gradient]) .panel-tools__drawer-surface,\n:host-context(ds-app-shell[gradient]) .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/*\n * Drawer title — match rail action height (size-400) and BarNav heading inset.\n * Use `ds-text.` so scoped specificity beats Text's `:host(.ds-text--inline-box)`\n * (class-only `.panel-tools__title` ties and loses when Text CSS loads later).\n */\nds-text.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/*\n * Fade title + slot body with the drawer slide (same dur/easing).\n * Header border stays opaque — only inner content opacity animates.\n */\nds-text.panel-tools__title,\n.panel-tools__body {\n opacity: 0;\n transition: none;\n}\n\n:host(.panel-tools--ready.panel-tools--motion-opening) ds-text.panel-tools__title,\n:host(.panel-tools--ready.panel-tools--motion-opening) .panel-tools__body {\n transition: opacity 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) ds-text.panel-tools__title,\n:host(.panel-tools--ready.panel-tools--motion-closing) .panel-tools__body {\n transition: opacity var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-in, ease-in);\n}\n\n:host(.panel-tools--open) ds-text.panel-tools__title,\n:host(.panel-tools--open) .panel-tools__body {\n opacity: 1;\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/* Flush to the bottom of the rail — mirrors Search header pin. */\n.panel-tools__rail-footer {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-top: auto;\n padding: var(--dimension-space-100);\n box-sizing: border-box;\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_FOOTER_TOOL_ID,\n PANEL_TOOLS_LABELS,\n PANEL_TOOLS_PRIMARY_TOOL_ID,\n PANEL_TOOLS_SHORTCUTS,\n type PanelToolsItem,\n type PanelToolsToolId,\n} from './panel-tools-types';\nimport {\n isPanelToolsToolId,\n orderPanelToolsItems,\n parsePanelToolsItems,\n panelToolsDrawerResting,\n reconcilePanelToolsAvailability,\n resolvePanelToolActivation,\n} 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`, `activity`, or `help`. */\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 @Prop() toolsLabel: string = 'Tools';\n @Prop() toolShortcutsLabel: string = 'Tool shortcuts';\n\n /**\n * Optional localStorage key for the last active tool. The drawer always starts\n * closed; only the tool identity is restored for continuity within this browser.\n */\n @Prop({ attribute: 'storage-key' }) storageKey: 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 = orderPanelToolsItems(this.railItems);\n const headerItem = railItems.find(item => item.id === PANEL_TOOLS_PRIMARY_TOOL_ID);\n const footerItem = railItems.find(item => item.id === PANEL_TOOLS_FOOTER_TOOL_ID);\n const bodyItems = railItems.filter(\n item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID && item.id !== PANEL_TOOLS_FOOTER_TOOL_ID,\n );\n const ordered: PanelToolsItem[] = [];\n if (headerItem) ordered.push(headerItem);\n ordered.push(...bodyItems);\n if (footerItem) ordered.push(footerItem);\n return ordered;\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 componentWillLoad() {\n this.restoreLastActiveTool();\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.persistLastActiveTool();\n this.deferMotionEnable();\n }\n\n @Watch('storageKey')\n storageKeyChanged() {\n this.restoreLastActiveTool();\n }\n\n componentDidLoad() {\n this.deferMotionEnable();\n }\n\n @Watch('items')\n @Watch('itemsJson')\n itemsChanged() {\n this.rovingIndex = 0;\n this.reconcileActiveTool();\n this.deferMotionEnable();\n }\n\n private restoreLastActiveTool() {\n if (!this.storageKey || this.activeTool) return;\n try {\n const stored = localStorage.getItem(this.storageKey);\n if (isPanelToolsToolId(stored)) this.activeTool = stored;\n } catch { /* localStorage unavailable */ }\n }\n\n private persistLastActiveTool() {\n if (!this.storageKey || !this.activeTool) return;\n try { localStorage.setItem(this.storageKey, this.activeTool); } catch { /* unavailable */ }\n }\n\n private clearPersistedTool() {\n if (!this.storageKey) return;\n try { localStorage.removeItem(this.storageKey); } catch { /* unavailable */ }\n }\n\n private reconcileActiveTool() {\n const next = reconcilePanelToolsAvailability(this.railItems, this.open, this.activeTool);\n if (!next.removedTool) return;\n this.clearPersistedTool();\n this.open = next.open;\n this.activeTool = next.activeTool;\n this.dsToolChange.emit({ id: next.removedTool, selected: false });\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.isInactive) 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 const label = item.ariaLabel ?? PANEL_TOOLS_LABELS[item.id];\n return (\n <ds-tooltip\n key={item.id}\n label={label}\n shortcutKey={PANEL_TOOLS_SHORTCUTS[item.id]}\n side=\"left\"\n size=\"sm\"\n >\n <ds-button-unfilled variant=\"icon\"\n class=\"panel-tools__rail-action\"\n icon={item.icon}\n isActive={this.isRailSelected(item.id)}\n activeFill={false}\n hasBorder={false}\n dot={item.dot ?? false}\n isInactive={item.isInactive}\n focusTabIndex={index === this.rovingIndex ? 0 : -1}\n aria-label={label}\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 </ds-tooltip>\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 footerItem = orderedRailItems.find(item => item.id === PANEL_TOOLS_FOOTER_TOOL_ID);\n const bodyItems = orderedRailItems.filter(\n item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID && item.id !== PANEL_TOOLS_FOOTER_TOOL_ID,\n );\n const footerIndex = footerItem\n ? (headerItem ? 1 : 0) + bodyItems.length\n : -1;\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={this.toolsLabel}\n >\n <div class=\"panel-tools__layout\">\n <nav class=\"panel-tools__rail\" aria-label={this.toolShortcutsLabel}>\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 {footerItem ? (\n <div class=\"panel-tools__rail-footer\">\n {this.renderRailAction(footerItem, footerIndex)}\n </div>\n ) : null}\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 <ds-text\n class=\"panel-tools__title\"\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color=\"primary\"\n wrap=\"nowrap\"\n >\n {headerLabel}\n </ds-text>\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 }}\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 }}\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 }}\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 }}\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 }}\n hidden={!this.isViewActive('agents')}\n >\n <slot name=\"agents\" />\n </div>\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': this.isViewActive('help'),\n }}\n hidden={!this.isViewActive('help')}\n >\n <slot name=\"help\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n </Host>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-07-12T03:09:48",
2
+ "timestamp": "2026-07-12T03:40:19",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
@@ -173,7 +173,7 @@
173
173
  "mutable": false,
174
174
  "attr": "shortcuts-enabled",
175
175
  "reflectToAttr": false,
176
- "docs": "When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native.",
176
+ "docs": "When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N/? toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native.",
177
177
  "docsTags": [
178
178
  {
179
179
  "name": "default",
@@ -7975,6 +7975,35 @@
7975
7975
  "getter": false,
7976
7976
  "setter": false
7977
7977
  },
7978
+ {
7979
+ "name": "storageKey",
7980
+ "type": "string",
7981
+ "complexType": {
7982
+ "original": "string",
7983
+ "resolved": "string",
7984
+ "references": {}
7985
+ },
7986
+ "mutable": false,
7987
+ "attr": "storage-key",
7988
+ "reflectToAttr": false,
7989
+ "docs": "Optional localStorage key for the last active tool. The drawer always starts\nclosed; only the tool identity is restored for continuity within this browser.",
7990
+ "docsTags": [
7991
+ {
7992
+ "name": "default",
7993
+ "text": "''"
7994
+ }
7995
+ ],
7996
+ "default": "''",
7997
+ "values": [
7998
+ {
7999
+ "type": "string"
8000
+ }
8001
+ ],
8002
+ "optional": false,
8003
+ "required": false,
8004
+ "getter": false,
8005
+ "setter": false
8006
+ },
7978
8007
  {
7979
8008
  "name": "toolShortcutsLabel",
7980
8009
  "type": "string",
@@ -15,7 +15,7 @@ export declare class AppShell {
15
15
  * `none` (solid secondary), `cool` (blue), `neutral` (grey), `warm` (yellow). `gradientSrc` overrides when set.
16
16
  */
17
17
  gradientPreset: ShellGradientPreset;
18
- /** When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native. */
18
+ /** When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N/? toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native. */
19
19
  shortcutsEnabled: boolean;
20
20
  el: HTMLElement;
21
21
  private resizeObserver;
@@ -16,6 +16,11 @@ export declare class PanelTools {
16
16
  itemsJson: string;
17
17
  toolsLabel: string;
18
18
  toolShortcutsLabel: string;
19
+ /**
20
+ * Optional localStorage key for the last active tool. The drawer always starts
21
+ * closed; only the tool identity is restored for continuity within this browser.
22
+ */
23
+ storageKey: string;
19
24
  /** Emitted when a rail button is toggled. Detail = { id, selected }. */
20
25
  dsToolChange: EventEmitter<{
21
26
  id: PanelToolsToolId;
@@ -35,10 +40,16 @@ export declare class PanelTools {
35
40
  disconnectedCallback(): void;
36
41
  private deferMotionEnable;
37
42
  connectedCallback(): void;
43
+ componentWillLoad(): void;
38
44
  openChanged(isOpen: boolean, wasOpen?: boolean): void;
39
45
  activeToolChanged(): void;
46
+ storageKeyChanged(): void;
40
47
  componentDidLoad(): void;
41
48
  itemsChanged(): void;
49
+ private restoreLastActiveTool;
50
+ private persistLastActiveTool;
51
+ private clearPersistedTool;
52
+ private reconcileActiveTool;
42
53
  private handleTransitionEnd;
43
54
  /** Rail selection follows `open` immediately — independent of the slide animation. */
44
55
  private isRailSelected;
@@ -1,3 +1,3 @@
1
1
  export type { PanelToolsItem, PanelToolsToolId } from './panel-tools-types';
2
- export { PANEL_TOOLS_FOOTER_TOOL_ID, PANEL_TOOLS_LABELS, PANEL_TOOLS_PRIMARY_TOOL_ID, PANEL_TOOLS_TOOL_IDS, } from './panel-tools-types';
2
+ export { PANEL_TOOLS_FOOTER_TOOL_ID, PANEL_TOOLS_LABELS, PANEL_TOOLS_PRIMARY_TOOL_ID, PANEL_TOOLS_SHORTCUTS, PANEL_TOOLS_TOOL_IDS, } from './panel-tools-types';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -6,6 +6,7 @@ export declare const PANEL_TOOLS_PRIMARY_TOOL_ID: PanelToolsToolId;
6
6
  /** Rail footer slot — flush to the bottom of the tools column. */
7
7
  export declare const PANEL_TOOLS_FOOTER_TOOL_ID: PanelToolsToolId;
8
8
  export declare const PANEL_TOOLS_LABELS: Record<PanelToolsToolId, string>;
9
+ export declare const PANEL_TOOLS_SHORTCUTS: Partial<Record<PanelToolsToolId, string>>;
9
10
  export interface PanelToolsItem {
10
11
  id: PanelToolsToolId;
11
12
  /** Icon name for <ds-icon>. */
@@ -1,5 +1,12 @@
1
- import type { PanelToolsItem, PanelToolsToolId } from './panel-tools-types';
1
+ import { type PanelToolsItem, type PanelToolsToolId } from './panel-tools-types';
2
2
  export declare function parsePanelToolsItems(items: PanelToolsItem[], itemsJson: string): PanelToolsItem[];
3
+ export declare function orderPanelToolsItems(items: PanelToolsItem[]): PanelToolsItem[];
4
+ export declare function isPanelToolsToolId(value: string | null): value is PanelToolsToolId;
5
+ export declare function reconcilePanelToolsAvailability(items: PanelToolsItem[], open: boolean, activeTool: PanelToolsToolId | ''): {
6
+ open: boolean;
7
+ activeTool: PanelToolsToolId | '';
8
+ removedTool: PanelToolsToolId | '';
9
+ };
3
10
  export declare function shouldResyncPanelToolsItems(prev: PanelToolsItem[], next: PanelToolsItem[]): boolean;
4
11
  export type PanelToolsMotion = 'opening' | 'closing' | 'idle';
5
12
  /** True when the drawer clip is fully closed — safe to skip painting slot content. */
@@ -98,7 +98,7 @@ export namespace Components {
98
98
  */
99
99
  "navStyle": NavChromeStyle;
100
100
  /**
101
- * When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native.
101
+ * When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N/? toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native.
102
102
  * @default true
103
103
  */
104
104
  "shortcutsEnabled": boolean;
@@ -946,6 +946,11 @@ export namespace Components {
946
946
  * @default false
947
947
  */
948
948
  "open": boolean;
949
+ /**
950
+ * Optional localStorage key for the last active tool. The drawer always starts closed; only the tool identity is restored for continuity within this browser.
951
+ * @default ''
952
+ */
953
+ "storageKey": string;
949
954
  /**
950
955
  * @default 'Tool shortcuts'
951
956
  */
@@ -2156,7 +2161,7 @@ declare namespace LocalJSX {
2156
2161
  */
2157
2162
  "navStyle"?: NavChromeStyle;
2158
2163
  /**
2159
- * When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native.
2164
+ * When `true` (default), registers global shell keyboard shortcuts. `[` toggles panel nav; `]` closes tools; K/A/S/M/N/? toggle tool drawers. Modifiers are ignored so browser chords like ⌘N stay native.
2160
2165
  * @default true
2161
2166
  */
2162
2167
  "shortcutsEnabled"?: boolean;
@@ -3073,6 +3078,11 @@ declare namespace LocalJSX {
3073
3078
  * @default false
3074
3079
  */
3075
3080
  "open"?: boolean;
3081
+ /**
3082
+ * Optional localStorage key for the last active tool. The drawer always starts closed; only the tool identity is restored for continuity within this browser.
3083
+ * @default ''
3084
+ */
3085
+ "storageKey"?: string;
3076
3086
  /**
3077
3087
  * @default 'Tool shortcuts'
3078
3088
  */
@@ -3797,6 +3807,7 @@ declare namespace LocalJSX {
3797
3807
  "itemsJson": string;
3798
3808
  "toolsLabel": string;
3799
3809
  "toolShortcutsLabel": string;
3810
+ "storageKey": string;
3800
3811
  }
3801
3812
  interface DsRadioGroupAttributes {
3802
3813
  "value": string;
@@ -1,6 +1,6 @@
1
1
  import type { PanelToolsToolId } from '../components/PanelTools/panel-tools-types';
2
2
  export type ShellShortcutAction = 'toggle-panel-nav' | 'close-panel-tools' | `open-tool:${PanelToolsToolId}`;
3
- /** Tool shortcut keys (K/A/S/M/N) toggle open/closed via `ds-panel-tools.activateTool`. */
3
+ /** Tool shortcut keys (K/A/S/M/N/?) toggle open/closed via `ds-panel-tools.activateTool`. */
4
4
  /** True when no modifier keys are held — avoids browser/app chords like ⌘N. */
5
5
  export declare function isBareShellShortcutKey(e: Pick<KeyboardEvent, 'metaKey' | 'ctrlKey' | 'altKey' | 'shiftKey'>): boolean;
6
6
  /** Skip shell shortcuts while typing in an editable control. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ds-mo/ui",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "CompoMo — composable web components styled with TokoMo design tokens",
5
5
  "keywords": [
6
6
  "web-components",