@ds-mo/ui 3.2.0 → 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
- 1783823343161
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.0",
4
+ "packageVersion": "3.3.0",
5
5
  "kind": "components",
6
6
  "entries": [
7
7
  {
@@ -9,31 +9,21 @@
9
9
  "tag": "ds-app-shell",
10
10
  "name": "app-shell",
11
11
  "title": "AppShell",
12
- "summary": "Workspace layout primitive coordinating panel navigation, top navigation, tools, content, shared chrome, and shell shortcuts.",
12
+ "summary": "The single required workspace root for standard authenticated application pages, coordinating primary and secondary navigation, tools chrome, responsive composition, content geometry, shared styling, and shell behavior.",
13
13
  "intentStatus": "complete",
14
14
  "intent": {
15
15
  "audience": "specialized",
16
16
  "status": "stable",
17
- "summary": "Workspace layout primitive coordinating panel navigation, top navigation, tools, content, shared chrome, and shell shortcuts.",
17
+ "summary": "The single required workspace root for standard authenticated application pages, coordinating primary and secondary navigation, tools chrome, responsive composition, content geometry, shared styling, and shell behavior.",
18
18
  "useWhen": [
19
- "Building a dashboard-style workspace with coordinated left navigation, top navigation, tools, and content.",
20
- "Navigation chrome needs shared styling, gradient alignment, collapse behavior, and keyboard shortcuts."
19
+ "Building any standard authenticated product or workspace page with CompoMo.",
20
+ "PanelNav, BarNav, PanelTools, page content, shared chrome, responsive behavior, and shell shortcuts must be composed as one application frame.",
21
+ "Future application templates need the supported base-page composition boundary."
21
22
  ],
22
23
  "avoidWhen": [
23
- "The page is a standalone marketing, authentication, or single-purpose layout.",
24
- "The interface does not use the coordinated CompoMo navigation surfaces."
25
- ],
26
- "alternatives": [
27
- {
28
- "when": "Only a top-level section tab row is needed.",
29
- "component": "component:ds-bar-nav",
30
- "reason": "BarNav can be used without the complete workspace shell."
31
- },
32
- {
33
- "when": "Only persistent left-side destination navigation is needed.",
34
- "component": "component:ds-panel-nav",
35
- "reason": "PanelNav owns left navigation without requiring the full shell composition."
36
- }
24
+ "Building authentication, onboarding, public, marketing, print, error, or intentionally focused full-screen experiences that require a different layout.",
25
+ "Another AppShell already exists in the page; applications must render exactly one and must never nest AppShells.",
26
+ "Building content inside an existing AppShell; render the page content rather than another shell."
37
27
  ],
38
28
  "commonlyComposedWith": [
39
29
  "component:ds-panel-nav",
@@ -44,27 +34,44 @@
44
34
  "pattern:application-shell"
45
35
  ],
46
36
  "accessibility": [
47
- "Keep destination navigation in PanelNav and section navigation in BarNav.",
37
+ "Keep primary destinations in PanelNav and secondary route sections in BarNav.",
38
+ "Ensure the default content region contains the page's single main landmark.",
39
+ "Keep PanelNav, BarNav, and PanelTools chrome available in the shell's supported desktop and tablet compositions.",
48
40
  "Do not override browser keyboard chords when enabling shell shortcuts.",
49
- "Ensure the default slot contains the page main-content landmark."
41
+ "Require Search and Help as the minimum PanelTools actions and provide accessible labels for every tool.",
42
+ "Preserve focus and accessible names across navigation, collapse, overflow, and responsive presentation changes."
50
43
  ],
51
44
  "states": [
52
- "The shell coordinates chrome but the host application owns active destinations, active tools, and route state.",
53
- "Use one AppShell as the workspace root rather than nesting shells."
45
+ "Render exactly one AppShell as the workspace root and never nest it.",
46
+ "PanelNav, BarNav, and PanelTools are required shell regions; PanelTools contains at least Search and Help even when no additional product tools apply.",
47
+ "The application router owns the current route, authorization filtering, Dashboard or Settings context, destination collections, section collections, and localized content labels.",
48
+ "AppShell propagates navStyle and coordinates layout, gradient alignment, transitions, metrics, shortcuts, and responsive composition.",
49
+ "Dashboard represents day-to-day operational work while Settings represents administrative and configuration work; route state selects the context.",
50
+ "Update PanelNav groups, BarNav tabs and heading, navStyle, basePath, and currentUrl atomically from one resolved route state.",
51
+ "BarNav remains present: it shows route-section tabs when available and the active PanelNav destination label as heading otherwise.",
52
+ "The application filters unauthorized destinations, sections, and tools before passing them into shell components."
54
53
  ],
55
54
  "responsiveBehavior": [
56
- "The host and shell must fill the viewport for chrome clipping and synchronized gradient sizing.",
57
- "Panel collapse and tool-drawer behavior should preserve the main content region rather than introducing a second page shell."
55
+ "AppShell owns the fixed system breakpoints and resolves desktop at 1200px and wider, tablet from 768px through 1199px, and mobile below 768px.",
56
+ "On desktop, PanelNav defaults expanded, permits user collapse or expansion, and respects the locally persisted desktop preference.",
57
+ "On tablet, AppShell keeps PanelNav permanently collapsed and prevents user expansion without overwriting the desktop preference.",
58
+ "On mobile, AppShell remains the page root but replaces PanelNav and desktop navigation composition with a future dedicated mobile navigation design.",
59
+ "Keep PanelNav width, BarNav height, PanelTools chrome, and main-content origin stable except during intentional responsive or collapse transitions.",
60
+ "The current runtime does not yet implement the complete desktop, tablet, and mobile composition contract; consuming applications must enforce missing breakpoint behavior until AppShell provides it."
58
61
  ],
59
62
  "frameworkCaveats": {
60
63
  "customElements": [
61
- "Assign complex navigation item collections as element properties."
64
+ "Assign complex navigation and tool collections as JavaScript properties on the slotted components.",
65
+ "Stamp route-derived nav-style before components connect when deterministic first paint is required."
62
66
  ],
63
67
  "react": [
64
- "Use generated wrappers but preserve native slot names on slotted navigation children."
68
+ "Use generated wrappers and preserve native slot names for PanelNav, BarNav, PanelTools, and main content.",
69
+ "Resolve all shell inputs from one router state before rendering the composition."
65
70
  ],
66
71
  "angular": [
67
- "Bind complex inputs after the generated custom elements are registered and preserve slot attributes in templates."
72
+ "Use generated standalone adapters and preserve slot attributes in templates.",
73
+ "Bind complex inputs as properties and update navigation inputs atomically from one resolved router state.",
74
+ "Bind both nav-style attributes and properties when deterministic first paint is required."
68
75
  ]
69
76
  },
70
77
  "references": [
@@ -79,6 +86,10 @@
79
86
  {
80
87
  "label": "Framework integration",
81
88
  "path": "docs/framework-integration.md"
89
+ },
90
+ {
91
+ "label": "Application shell contract",
92
+ "path": "agent/patterns/application-shell/pattern.agent.json"
82
93
  }
83
94
  ]
84
95
  },
@@ -243,9 +254,101 @@
243
254
  "tag": "ds-bar-nav",
244
255
  "name": "bar-nav",
245
256
  "title": "BarNav",
246
- "summary": "BarNav component from @ds-mo/ui.",
247
- "intentStatus": "migration-pending",
248
- "intent": null,
257
+ "summary": "Required secondary route navigation within AppShell, showing peer sections of the active PanelNav destination or its destination label when no section tabs apply.",
258
+ "intentStatus": "complete",
259
+ "intent": {
260
+ "audience": "specialized",
261
+ "status": "stable",
262
+ "summary": "Required secondary route navigation within AppShell, showing peer sections of the active PanelNav destination or its destination label when no section tabs apply.",
263
+ "useWhen": [
264
+ "Rendering the required secondary navigation region inside AppShell.",
265
+ "The active primary destination has peer route sections that users can navigate between.",
266
+ "The active primary destination has no route sections or is showing a detail route and its destination label must preserve the BarNav region."
267
+ ],
268
+ "avoidWhen": [
269
+ "Primary application destinations are being rendered; use PanelNav instead.",
270
+ "A third navigation level is needed; BarNav is never tertiary navigation.",
271
+ "The choices switch local content without navigating routes; use TabGroup instead.",
272
+ "Document-style tabs need reordering, pinning, closing, or user customization.",
273
+ "BarNav would be mounted outside the application's single AppShell."
274
+ ],
275
+ "alternatives": [
276
+ {
277
+ "when": "The choices are the application's top-level destinations.",
278
+ "component": "component:ds-panel-nav",
279
+ "reason": "PanelNav exclusively owns primary application navigation."
280
+ },
281
+ {
282
+ "when": "The choices switch local content without changing routes.",
283
+ "component": "component:ds-tab-group",
284
+ "reason": "TabGroup owns local view selection and tab semantics."
285
+ },
286
+ {
287
+ "when": "The choices are temporary commands or contextual options.",
288
+ "component": "component:ds-menu",
289
+ "reason": "Menu owns transient action and option collections."
290
+ }
291
+ ],
292
+ "commonlyComposedWith": [
293
+ "component:ds-app-shell",
294
+ "component:ds-panel-nav",
295
+ "component:ds-panel-tools"
296
+ ],
297
+ "patterns": [
298
+ "pattern:application-shell"
299
+ ],
300
+ "accessibility": [
301
+ "Use concise localized labels for every route section.",
302
+ "Keep section navigation keyboard accessible through the generated TabGroupNav behavior and overflow menu.",
303
+ "Preserve the selected route state when sections move between the visible row and overflow menu.",
304
+ "Use notification dots only as supplemental status and not as the sole indication of important information.",
305
+ "Pass the active PanelNav destination label through heading whenever section tabs are absent or hidden."
306
+ ],
307
+ "states": [
308
+ "BarNav is the second and final application navigation level; it never replaces PanelNav and never becomes tertiary navigation.",
309
+ "The host router owns the current route; prefer currentUrl with basePath so BarNav derives the selected section.",
310
+ "Use value only when URL-derived selection is unavailable.",
311
+ "The consuming application supplies heading from the active PanelNav destination; BarNav does not inspect PanelNav to derive it.",
312
+ "When no sections apply, retain the BarNav region and show heading rather than shifting the main content upward.",
313
+ "On non-tab detail routes, show the parent PanelNav destination label in BarNav while the detail-page title remains in page content.",
314
+ "Dividers and groups visually organize peer route sections only and do not create hierarchy.",
315
+ "The application filters unauthorized sections before passing tabs to BarNav.",
316
+ "Dashboard and Settings route state updates PanelNav groups, BarNav tabs, heading, basePath, currentUrl, and navStyle as one coordinated change."
317
+ ],
318
+ "responsiveBehavior": [
319
+ "Keep the BarNav region present so shell height and main-content origin remain stable across routes.",
320
+ "Allow the built-in overflow behavior to move trailing sections into Menu when the available width is insufficient.",
321
+ "The active section does not need to remain visible in the tab row when it moves into overflow because page content supplies the page title.",
322
+ "Do not infer mobile navigation behavior from desktop BarNav; future AppShell mobile composition may use a different navigation design."
323
+ ],
324
+ "frameworkCaveats": {
325
+ "customElements": [
326
+ "Assign tabs as a JavaScript property for structured data; tabs-json is the string fallback.",
327
+ "Update tabs, heading, basePath, currentUrl, and navStyle from the same resolved route state."
328
+ ],
329
+ "react": [
330
+ "Pass tabs as an array through the generated React wrapper and synchronize currentUrl and basePath with the host router."
331
+ ],
332
+ "angular": [
333
+ "Import DsBarNav from @ds-mo/ui/angular/ds-bar-nav and bind tabs as a property.",
334
+ "Bind heading to the active PanelNav destination label and update route inputs atomically."
335
+ ]
336
+ },
337
+ "references": [
338
+ {
339
+ "label": "Executable Storybook examples",
340
+ "path": "src/wc/components/BarNav/BarNav.stories.ts"
341
+ },
342
+ {
343
+ "label": "Framework and routing integration",
344
+ "path": "docs/framework-integration.md"
345
+ },
346
+ {
347
+ "label": "Application shell composition",
348
+ "path": "agent/patterns/application-shell/pattern.agent.json"
349
+ }
350
+ ]
351
+ },
249
352
  "api": {
250
353
  "props": {
251
354
  "basePath": {
@@ -1602,9 +1705,105 @@
1602
1705
  "tag": "ds-panel-nav",
1603
1706
  "name": "panel-nav",
1604
1707
  "title": "PanelNav",
1605
- "summary": "PanelNav component from @ds-mo/ui.",
1606
- "intentStatus": "migration-pending",
1607
- "intent": null,
1708
+ "summary": "The single persistent primary navigation for an application, providing grouped top-level destinations, active-route state, standard dashboard/settings switching, user access, and collapsible desktop and tablet presentation.",
1709
+ "intentStatus": "complete",
1710
+ "intent": {
1711
+ "audience": "specialized",
1712
+ "status": "stable",
1713
+ "summary": "The single persistent primary navigation for an application, providing grouped top-level destinations, active-route state, standard dashboard/settings switching, user access, and collapsible desktop and tablet presentation.",
1714
+ "useWhen": [
1715
+ "Building the one primary navigation surface for an application that uses the CompoMo system.",
1716
+ "Top-level destinations must remain consistently available while the application's page content changes.",
1717
+ "Primary destinations need visual grouping, icons, notification indicators, active-route state, and expanded or collapsed presentation."
1718
+ ],
1719
+ "avoidWhen": [
1720
+ "A second navigation surface is needed within the same application; an application must have only one PanelNav.",
1721
+ "The choices represent sections within the active primary destination; use BarNav instead.",
1722
+ "The choices switch local content without changing the application's primary destination; use TabGroup instead.",
1723
+ "The interaction performs a command or presents temporary contextual choices; use a button or Menu instead.",
1724
+ "Building navigation below the mobile breakpoint; use the application's dedicated mobile navigation component instead."
1725
+ ],
1726
+ "alternatives": [
1727
+ {
1728
+ "when": "The choices represent route sections within the active primary destination.",
1729
+ "component": "component:ds-bar-nav",
1730
+ "reason": "BarNav owns secondary section navigation within the destination selected by PanelNav."
1731
+ },
1732
+ {
1733
+ "when": "The choices switch local content without changing the application's primary destination.",
1734
+ "component": "component:ds-tab-group",
1735
+ "reason": "TabGroup owns local view selection and tab semantics."
1736
+ },
1737
+ {
1738
+ "when": "The choices are commands or temporary contextual actions.",
1739
+ "component": "component:ds-menu",
1740
+ "reason": "Menu owns transient action and option collections rather than persistent destinations."
1741
+ }
1742
+ ],
1743
+ "commonlyComposedWith": [
1744
+ "component:ds-app-shell",
1745
+ "component:ds-bar-nav",
1746
+ "component:ds-panel-tools",
1747
+ "component:ds-menu"
1748
+ ],
1749
+ "patterns": [
1750
+ "pattern:application-shell"
1751
+ ],
1752
+ "accessibility": [
1753
+ "Give every primary destination a concise visible label and an icon that supports rather than replaces that label.",
1754
+ "Provide localized dashboard, settings, account, navigation, collapse, and expand labels.",
1755
+ "Preserve accessible destination names when the panel is collapsed to icon-only presentation.",
1756
+ "Use notification dots as supplemental status and never as the only indication of important information.",
1757
+ "Keep the standard dashboard/settings switch and user/account entry available in the footer."
1758
+ ],
1759
+ "states": [
1760
+ "Render exactly one PanelNav per application; it owns primary application destinations and no other navigation role.",
1761
+ "The host router owns the current route; prefer currentUrl for active destination matching and use activeId only when route matching is unavailable.",
1762
+ "Use anchor mode for native links or routers that intercept anchors; use event mode when the host performs navigation from dsNavSelect.",
1763
+ "Groups visually organize top-level destinations only and must not be interpreted as nested or expandable navigation.",
1764
+ "Dashboard presents day-to-day operational destinations; Settings presents administrative and configuration destinations.",
1765
+ "The standard footer switches the entire destination collection and navStyle between Dashboard and Settings and exposes the user/account entry.",
1766
+ "The host owns the external user menu opened from dsNavUserAction.",
1767
+ "On desktop, allow user-controlled expand and collapse and persist the preference with storageKey when cross-session persistence is appropriate."
1768
+ ],
1769
+ "responsiveBehavior": [
1770
+ "At 1200px and wider, default to expanded, allow the user to expand or collapse, and restore the locally persisted desktop preference when available.",
1771
+ "From 768px through 1199px, present PanelNav permanently collapsed and do not allow user expansion.",
1772
+ "Below 768px, the consuming application replaces PanelNav with a dedicated mobile navigation component; PanelNav does not own mobile navigation.",
1773
+ "AppShell permanently owns responsive composition: it determines shell mode, enforces tablet collapse, and replaces PanelNav with future mobile navigation below 768px.",
1774
+ "The current breakpoint prop can auto-collapse PanelNav but does not enforce the complete tablet lock; AppShell or the consuming application must currently enforce that lock.",
1775
+ "Collapsed presentation must preserve destination ordering, active state, notification status, and accessible names."
1776
+ ],
1777
+ "frameworkCaveats": {
1778
+ "customElements": [
1779
+ "Assign groups as a JavaScript property for structured data; a JSON string attribute is also supported.",
1780
+ "Set nav-style before the element connects when first-paint style must match the current route."
1781
+ ],
1782
+ "react": [
1783
+ "Pass groups as an array through the generated React wrapper and synchronize currentUrl with the host router.",
1784
+ "AppShell owns mobile replacement and currently enforces the tablet expansion lock."
1785
+ ],
1786
+ "angular": [
1787
+ "Import DsPanelNav from @ds-mo/ui/angular/ds-panel-nav and bind groups as a property.",
1788
+ "Bind both the nav-style attribute and navStyle property when first-paint route styling must be deterministic.",
1789
+ "AppShell owns mobile replacement and currently enforces the tablet expansion lock."
1790
+ ]
1791
+ },
1792
+ "references": [
1793
+ {
1794
+ "label": "Executable Storybook examples",
1795
+ "path": "src/wc/components/PanelNav/PanelNav.stories.ts"
1796
+ },
1797
+ {
1798
+ "label": "Framework and routing integration",
1799
+ "path": "docs/framework-integration.md"
1800
+ },
1801
+ {
1802
+ "label": "Application shell composition",
1803
+ "path": "agent/patterns/application-shell/pattern.agent.json"
1804
+ }
1805
+ ]
1806
+ },
1608
1807
  "api": {
1609
1808
  "props": {
1610
1809
  "accountLabel": {
@@ -1731,9 +1930,106 @@
1731
1930
  "tag": "ds-panel-tools",
1732
1931
  "name": "panel-tools",
1733
1932
  "title": "PanelTools",
1734
- "summary": "PanelTools component from @ds-mo/ui.",
1735
- "intentStatus": "migration-pending",
1736
- "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
+ },
1737
2033
  "api": {
1738
2034
  "props": {
1739
2035
  "activeTool": {
@@ -1752,6 +2048,10 @@
1752
2048
  "type": "boolean",
1753
2049
  "required": false
1754
2050
  },
2051
+ "storageKey": {
2052
+ "type": "string",
2053
+ "required": false
2054
+ },
1755
2055
  "toolShortcutsLabel": {
1756
2056
  "type": "string",
1757
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":"uOAOA,MAAMA,EAAuD,CAC3DC,EAAG,SACHC,EAAG,SACHC,EAAG,SACHC,EAAG,WACHC,EAAG,YAMC,SAAUC,EACdC,GAEA,OAAQA,EAAEC,UAAYD,EAAEE,UAAYF,EAAEG,SAAWH,EAAEI,QACrD,CAGM,SAAUC,EAAyBC,GACvC,IAAKA,UAAiBA,IAAW,SAAU,OAAO,MAClD,KAAM,YAAaA,WAAkBA,EAAOC,UAAY,WAAY,OAAO,MAE3E,MAAMC,EAAKF,EAEX,MAAMG,EAAWD,EAAGD,QAClB,+GAEF,GAAIE,EAAU,OAAO,KAErB,MAAMC,EAAOF,EAAGG,aAAa,QAC7B,GAAID,IAAS,WAAaA,IAAS,YAAcA,IAAS,YAAa,OAAO,KAE9E,OAAOE,QAAQJ,EAAGK,kBACpB,CAEA,SAASC,EAAsBd,GAC7B,GAAIA,EAAEe,MAAQ,KAAOf,EAAEgB,OAAS,cAAe,MAAO,IACtD,GAAIhB,EAAEe,MAAQ,KAAOf,EAAEgB,OAAS,eAAgB,MAAO,IACvD,OAAOhB,EAAEe,IAAIE,SAAW,EAAIjB,EAAEe,IAAIG,cAAgBlB,EAAEe,IAAIG,aAC1D,CAGM,SAAUC,EACdnB,GAEA,IAAKD,EAAuBC,GAAI,OAAO,KAEvC,MAAMe,EAAMD,EAAsBd,GAClC,GAAIe,IAAQ,IAAK,MAAO,mBACxB,GAAIA,IAAQ,IAAK,MAAO,oBAExB,MAAMK,EAAS3B,EAAmBsB,GAClC,GAAIK,EAAQ,MAAO,aAAaA,IAEhC,OAAO,IACT,CC3DM,SAAUC,EAAkBC,EAAsBC,GACtD,UAAWC,WAAa,YAAa,OAAO,EAE5C,MAAMC,EAAQD,SAASE,cAAc,OACrCD,EAAME,MAAMC,QACV,8EACAL,EACA,KACFD,EAAQO,YAAYJ,GACpB,MAAMK,EAAQL,EAAMM,wBAAwBD,MAC5CR,EAAQU,YAAYP,GACpB,OAAOK,CACT,CAQM,SAAUG,EAAwBC,GACtC,MAAO,CACLC,WAAYd,EAAkBa,EAAS,gBACvCE,YAAaf,EAAkBa,EAAS,0BAE5C,CAEM,SAAUG,EACdC,EACAJ,GAEA,GAAIA,GAASK,UAAUC,SAAS,wBAAyB,OAAO,KAChE,MAAMC,EAAiBH,GAAiEI,UACxF,OAAOD,IAAkB,IAC3B,CAEM,SAAUE,EACdC,EACAF,GAEA,OAAOA,EAAYE,EAAOR,YAAcQ,EAAOT,UACjD,CC5CA,MAAMU,EAAc,IAAM,usE,MC2CbC,EAAQC,EAAA,MAAAD,UAAAE,EALrB,WAAAC,CAAAC,G,4CAOmDC,KAAAC,SAA2B,YAGnDD,KAAAE,SAAoB,MAMrCF,KAAAG,YAAsB,GAMyBH,KAAAI,eACrDC,EAGwCL,KAAAM,iBAA4B,KAI9DN,KAAAO,eAAwC,KAC/BP,KAAAQ,mBAAqB,IAAIC,EACzBT,KAAAU,oBAAsBC,GAAmB,IAAMX,KAAKY,eAC7DZ,KAAAa,iBAAwC,CAAE7B,WAAY,EAAGC,YAAa,GACtEe,KAAAc,oBAAsB,EACtBd,KAAAe,qBAAuB,EACvBf,KAAAgB,eAAiB,KACvB,GAAIhB,KAAKQ,mBAAmBS,SAAU,OACtCjB,KAAKkB,oBAAoB,EAEnBlB,KAAAmB,uBAAyB,KAC/B,GAAInB,KAAKQ,mBAAmBS,SAAU,OACtCjB,KAAKkB,oBAAoB,EAiCnBlB,KAAAoB,wBAA2BC,IACjC,GAAIC,EAA2BD,KAAW,YAAa,OAEvDrB,KAAKQ,mBAAmBe,QACxB,MAAMC,EAAWC,IACjBzB,KAAKc,oBAAsBU,EAAS7C,MACpCqB,KAAKe,qBAAuBS,EAASE,OACrC1B,KAAKY,YAAY,EAGXZ,KAAA2B,sBAAyBN,IAC/B,GAAIC,EAA2BD,KAAW,YAAa,OAEvDrB,KAAKQ,mBAAmBoB,OACxB,IAAK5B,KAAKQ,mBAAmBS,SAAU,CACrCjB,KAAKkB,oB,EAwPV,CArSC,gBAAAW,GACE7B,KAAK8B,sBACL9B,KAAK+B,yBACL/B,KAAKgC,2BACLhC,KAAK3C,GAAG4E,iBAAiBC,EAAyBlC,KAAKoB,yBACvDpB,KAAK3C,GAAG4E,iBAAiBE,EAAuBnC,KAAK2B,uBACrDS,uBAAsB,KACpBpC,KAAKqC,wBACLrC,KAAKkB,oBAAoB,G,CAI7B,oBAAAoB,GACEtC,KAAKO,gBAAgBgC,aACrBvC,KAAKO,eAAiB,KACtBP,KAAKwC,8BACLxC,KAAKU,oBAAoB+B,SACzBzC,KAAK3C,GAAGqF,oBAAoBR,EAAyBlC,KAAKoB,yBAC1DpB,KAAK3C,GAAGqF,oBAAoBP,EAAuBnC,KAAK2B,sB,CAO1D,kBAAAgB,GACE3C,KAAK8B,sBACL9B,KAAKkB,oB,CAuBC,kBAAAA,GACNlB,KAAKU,oBAAoBkC,U,CAGnB,mBAAAd,GACN,MAAMe,EAAQ7C,KAAK3C,GAAGyF,cAAc,gBACpC,MAAMC,EAAM/C,KAAK3C,GAAGyF,cAAc,cAClC,GAAID,EAAO,CACTA,EAAMG,aAAa,YAAahD,KAAKC,UACrC4C,EAAM5C,SAAWD,KAAKC,Q,CAExB,GAAI8C,EAAK,CACPA,EAAIC,aAAa,YAAahD,KAAKC,UACnC8C,EAAI9C,SAAWD,KAAKC,Q,EAIhB,sBAAA8B,GACN/B,KAAKO,eAAiB,IAAI0C,gBAAe,KACvC,GAAIjD,KAAKQ,mBAAmBS,SAAU,OACtCjB,KAAKkB,oBAAoB,IAE3BlB,KAAKO,eAAe2C,QAAQlD,KAAK3C,IACjC,MAAM8F,EAAYnD,KAAK3C,GAAGyF,cAAc,qBACxC,GAAIK,EAAWnD,KAAKO,eAAe2C,QAAQC,E,CAGrC,wBAAAnB,GACN,UAAWoB,SAAW,YAAa,OAEnCA,OAAOnB,iBAAiB,SAAUjC,KAAKgB,eAAgB,CAAEqC,QAAS,OAElE,MAAMC,EAASF,OAAOG,eACtB,GAAID,EAAQ,CACVA,EAAOrB,iBAAiB,SAAUjC,KAAKmB,uBAAwB,CAAEkC,QAAS,OAC1EC,EAAOrB,iBAAiB,SAAUjC,KAAKmB,uBAAwB,CAAEkC,QAAS,M,EAItE,2BAAAb,GACN,UAAWY,SAAW,YAAa,OAEnCA,OAAOV,oBAAoB,SAAU1C,KAAKgB,gBAE1C,MAAMsC,EAASF,OAAOG,eACtB,GAAID,EAAQ,CACVA,EAAOZ,oBAAoB,SAAU1C,KAAKmB,wBAC1CmC,EAAOZ,oBAAoB,SAAU1C,KAAKmB,uB,EAItC,qBAAAkB,GACN,MAAMtD,EAAUiB,KAAK3C,GAAGyF,cAAc,2BACtC,IAAK/D,EAAS,OACdiB,KAAKa,iBAAmB/B,EAAwBC,E,CAG1C,iBAAAyE,CAAkBrG,EAAqBsG,GAC7C,MAAMjF,EAAQrB,EAAOqB,MACrB,IAAK,MAAOkF,EAAMC,KAAUC,OAAOC,QAAQJ,GAAO,CAChD,GAAIE,IAAU,KAAMnF,EAAMsF,eAAeJ,QACpClF,EAAMuF,YAAYL,EAAMC,E,EAIzB,sBAAAK,CAAuBC,GAC7B,MAAMC,EAAO,CACXC,EACAC,EACAC,GAEF,IAAK,MAAMlH,KAAU8G,EAAS,CAC5B,IAAK,MAAMrG,KAAOsG,EAAM/G,EAAOqB,MAAMsF,eAAelG,E,EAKhD,oBAAA0G,CACNzB,EACAE,EACAwB,EACAC,GAEA,GAAI3B,EAAO,CACTA,EAAMrE,MAAMuF,YAAYU,EAAmCF,E,CAE7D,GAAIxB,EAAK,CACPA,EAAIvE,MAAMuF,YAAYW,EAAiCF,E,EAInD,mBAAAG,CAAoBC,GAC1B,MAAM7F,EAAU6F,GAAU9B,cAAc,cAExC,GAAI9C,KAAKQ,mBAAmBS,UAAYjB,KAAKa,iBAAiB7B,WAAa,EAAG,CAC5E,MAAMO,EAAYL,EAAoB0F,EAAU7F,GAChD,OAAOS,EAAuBQ,KAAKa,iBAAkBtB,E,CAGvD,MAAM4D,EAAYnD,KAAK3C,GAAGyF,cAAc,qBACxC,MAAM+B,EAAW1B,GAAWvE,wBAAwBD,OAAS,EAC7D,GAAIkG,EAAW,EAAG,OAAOA,EAEzB,GAAI7E,KAAKa,iBAAiB7B,WAAa,EAAG,CACxC,MAAMO,EAAYL,EAAoB0F,EAAU7F,GAChD,OAAOS,EAAuBQ,KAAKa,iBAAkBtB,E,CAGvD,OAAO,C,CAID,yBAAAuF,GACN,GAAI9E,KAAKQ,mBAAmBS,UAAYjB,KAAKc,oBAAsB,EAAG,CACpE,MAAO,CACLnC,MAAOqB,KAAKc,oBACZY,OAAQ1B,KAAKe,qB,CAIjB,OAAOU,G,CAGD,iBAAAsD,GACN,OAAO/E,KAAKE,Q,CAId,mBAAA8E,CAAoBnI,GAClB,IAAKmD,KAAKM,iBAAkB,OAC5B,GAAIpD,EAAyBL,EAAEM,QAAS,OAExC,MAAM8H,EAASjH,EAAqBnB,GACpC,IAAKoI,EAAQ,OAEbpI,EAAEqI,iBAEF,MAAMrC,EAAQ7C,KAAK3C,GAAGyF,cAAc,gBACpC,MAAMqC,EAAQnF,KAAK3C,GAAGyF,cAAc,kBAEpC,GAAImC,IAAW,mBAAoB,MAC5BpC,GAAOuC,kBACZ,M,CAGF,GAAIH,IAAW,oBAAqB,MAC7BE,GAAOE,cACZ,M,CAGF,GAAIJ,EAAOK,WAAW,eAAiBH,EAAO,CAC5C,MAAMlH,EAASgH,EAAOM,MAAM,aAAazH,aACpCqH,EAAMK,aAAavH,E,EAIpB,UAAA2C,GACN,MAAMgE,EAAW5E,KAAK3C,GAAGyF,cAAc,gBACvC,MAAMC,EAAM/C,KAAK3C,GAAGyF,cAAc,cAClC,MAAMmB,EAAU,CAACjE,KAAK3C,GAAIuH,EAAU7B,GAAK0C,QAAQpI,GAA0BA,IAAO,OAElF,MAAMqI,EAAkB,KACtB,GAAId,EAAUA,EAASpG,MAAMsF,eAAeW,GAC5C,GAAI1B,EAAKA,EAAIvE,MAAMsF,eAAeY,EAAgC,EAGpE,IAAK1E,KAAKE,SAAU,CAClBF,KAAKgE,uBAAuBC,GAC5ByB,IACA,M,CAGF,MAAMlE,EAAWxB,KAAK8E,4BACtB,MAAMa,EAAa3F,KAAK2E,oBAAoBC,GAE5C,MAAML,EAAgBqB,IACtB,MAAMpB,EAAcqB,EAAyBF,GAE7C3F,KAAKsE,qBAAqBM,EAAU7B,EAAKwB,EAAeC,GAExD,MAAMsB,EAAQ9F,KAAKG,YAAY4F,OAC3B,OAAO/F,KAAKG,YAAY4F,UACxBC,EAAyBhG,KAAKI,gBAElC,MAAM6F,EAAOC,EAAkB,CAC7BvH,MAAO6C,EAAS7C,MAChB+C,OAAQF,EAASE,SAEnB,MAAMyE,EAAUC,EAEhB,IAAK,MAAMjJ,KAAU8G,EAAS,CAC5B,GAAI9G,IAAW6C,KAAK3C,GAAI,CACtB2C,KAAKwD,kBAAkBrG,EAAQ,CAC7BgH,CAACA,GAA2B2B,EAC5B1B,CAACA,GAA0B6B,EAC3BxB,CAACA,GAAoCF,EACrCG,CAACA,GAAkCF,EACnCH,CAACA,GAA6B8B,IAEhC,Q,CAGF,MAAME,EAAQlJ,EAAOmJ,QAAQvI,gBAAkB,aAC/CiC,KAAKwD,kBAAkBrG,EAAQ,CAC7BgH,CAACA,GAA2B2B,EAC5B1B,CAACA,GAA0B6B,EAC3B5B,CAACA,GAA6B8B,EAC9B1B,CAACA,GAAoC4B,EAAQ,KAAO9B,EACpDG,CAACA,GAAkC2B,EAAQ7B,EAAc,M,EAK/D,MAAA+B,GACE,MAAMC,EAAexG,KAAK+E,oBAC1B,MAAM0B,EAAoC,CACxC,YAAa,KACb,sBAAuBzG,KAAKE,SAC5B,CAAC,cAAcF,KAAKC,YAAa,MAGnC,OACEyG,EAACC,EAAI,CAAA/I,IAAA,2CAACgJ,MAAOH,GACXC,EAAA,OAAA9I,IAAA,2CAAKgJ,MAAM,kBACRJ,EAAeE,EAAA,OAAKE,MAAM,oBAAmB,cAAa,SAAY,KACvEF,EAAA,OAAA9I,IAAA,2CAAKgJ,MAAM,oBACTF,EAAA,QAAA9I,IAAA,2CAAM8F,KAAK,WAEbgD,EAAA,OAAA9I,IAAA,2CAAKgJ,MAAM,mBACTF,EAAA,OAAA9I,IAAA,2CAAKgJ,MAAM,kBACTF,EAAA,QAAA9I,IAAA,2CAAM8F,KAAK,SAEbgD,EAAA,OAAA9I,IAAA,2CAAKgJ,MAAM,oBACTF,EAAA,QAAA9I,IAAA,2CAAM8F,KAAK,WAEbgD,EAAA,OAAA9I,IAAA,2CAAKgJ,MAAM,sBACTF,EAAA,QAAA9I,IAAA,gD","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-12T02:28:54",
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.0",
3
+ "version": "3.3.0",
4
4
  "description": "CompoMo — composable web components styled with TokoMo design tokens",
5
5
  "keywords": [
6
6
  "web-components",