@ds-mo/ui 1.4.0 → 1.6.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.
Files changed (92) hide show
  1. package/README.md +1 -1
  2. package/dist/.build-stamp +1 -0
  3. package/dist/components/{ds-sidebar.d.ts → ds-app-shell.d.ts} +4 -4
  4. package/dist/components/ds-app-shell.js +2 -0
  5. package/dist/components/ds-app-shell.js.map +1 -0
  6. package/dist/components/ds-banner.js +1 -1
  7. package/dist/components/ds-banner.js.map +1 -1
  8. package/dist/components/ds-bar-nav.js +1 -1
  9. package/dist/components/ds-bar-nav.js.map +1 -1
  10. package/dist/components/ds-button-group.js +1 -1
  11. package/dist/components/ds-button.js +1 -1
  12. package/dist/components/ds-checkbox.js +1 -1
  13. package/dist/components/ds-field.js +1 -1
  14. package/dist/components/ds-loader.js +1 -1
  15. package/dist/components/ds-menu.js +1 -1
  16. package/dist/components/ds-modal.js +1 -1
  17. package/dist/components/ds-modal.js.map +1 -1
  18. package/dist/components/ds-panel-nav.js +1 -1
  19. package/dist/components/ds-panel-nav.js.map +1 -1
  20. package/dist/components/ds-select.js +1 -1
  21. package/dist/components/ds-slider.js +1 -1
  22. package/dist/components/ds-toast-provider.js +1 -1
  23. package/dist/components/ds-toast-provider.js.map +1 -1
  24. package/dist/components/ds-toggle-button-group.js +1 -1
  25. package/dist/components/ds-toggle-button.js +1 -1
  26. package/dist/components/ds-toggle.js +1 -1
  27. package/dist/components/ds-tooltip.js +1 -1
  28. package/dist/components/ds-tooltip.js.map +1 -1
  29. package/dist/components/p-BRju0sEC.js +2 -0
  30. package/dist/components/p-BRju0sEC.js.map +1 -0
  31. package/dist/components/p-BvmooLHV.js +2 -0
  32. package/dist/components/p-BvmooLHV.js.map +1 -0
  33. package/dist/components/p-C4WbCXBj.js +2 -0
  34. package/dist/components/p-C4WbCXBj.js.map +1 -0
  35. package/dist/components/p-CYJ-de0u.js +2 -0
  36. package/dist/components/p-CYJ-de0u.js.map +1 -0
  37. package/dist/components/{p--YDw8Q4o.js → p-CsO880L-.js} +2 -2
  38. package/dist/components/p-DTjpgYJV.js +2 -0
  39. package/dist/components/p-DTjpgYJV.js.map +1 -0
  40. package/dist/components/p-DfL2MOso.js +2 -0
  41. package/dist/components/p-DfL2MOso.js.map +1 -0
  42. package/dist/components/p-DiWQFROF.js +2 -0
  43. package/dist/components/p-DiWQFROF.js.map +1 -0
  44. package/dist/types/components/AppShell/AppShell.d.ts +25 -0
  45. package/dist/types/components/Banner/Banner.d.ts +2 -0
  46. package/dist/types/components/Loader/Loader.d.ts +3 -2
  47. package/dist/types/components/Menu/Menu.d.ts +11 -2
  48. package/dist/types/components/Modal/Modal.d.ts +1 -0
  49. package/dist/types/components/PanelNav/PanelNav.d.ts +3 -6
  50. package/dist/types/components/Toast/Toast.d.ts +1 -0
  51. package/dist/types/components/Tooltip/Tooltip.d.ts +14 -3
  52. package/dist/types/components.d.ts +92 -105
  53. package/dist/types/nav/index.d.ts +2 -0
  54. package/dist/types/nav/shell-gradient.d.ts +25 -0
  55. package/dist/types/nav/shell-view-transition.d.ts +2 -2
  56. package/dist/types/utils/index.d.ts +5 -0
  57. package/dist/types/utils/resolve-css-length-px.d.ts +8 -0
  58. package/dist/types/utils/resolve-css-time-ms.d.ts +8 -0
  59. package/dist/types/utils/token-defaults.d.ts +27 -0
  60. package/package.json +4 -4
  61. package/src/angular/index.ts +1 -1
  62. package/src/angular/proxies.ts +23 -33
  63. package/src/react/components.ts +1 -1
  64. package/src/react/ds-app-shell.ts +26 -0
  65. package/src/wc/components/AppShell/AppShell.tsx +180 -0
  66. package/src/wc/components/Banner/Banner.tsx +11 -5
  67. package/src/wc/components/Loader/Loader.tsx +8 -3
  68. package/src/wc/components/Menu/Menu.tsx +61 -26
  69. package/src/wc/components/Modal/Modal.tsx +10 -7
  70. package/src/wc/components/PanelNav/PanelNav.tsx +5 -8
  71. package/src/wc/components/Toast/Toast.tsx +7 -2
  72. package/src/wc/components/Toast/toast-service.ts +8 -1
  73. package/src/wc/components/ToggleButton/ToggleButton.tsx +7 -3
  74. package/src/wc/components/Tooltip/Tooltip.tsx +70 -31
  75. package/src/wc/components.d.ts +92 -105
  76. package/src/wc/nav/index.ts +14 -0
  77. package/src/wc/nav/shell-gradient.ts +44 -0
  78. package/src/wc/nav/shell-view-transition.ts +4 -10
  79. package/dist/components/ds-sidebar.js +0 -2
  80. package/dist/components/ds-sidebar.js.map +0 -1
  81. package/dist/components/p-BcuUR5Ao.js +0 -2
  82. package/dist/components/p-BcuUR5Ao.js.map +0 -1
  83. package/dist/components/p-CpbnmEu1.js +0 -2
  84. package/dist/components/p-CpbnmEu1.js.map +0 -1
  85. package/dist/components/p-DznbYg1m.js +0 -2
  86. package/dist/components/p-DznbYg1m.js.map +0 -1
  87. package/dist/components/p-uMN1Ppw2.js +0 -2
  88. package/dist/components/p-uMN1Ppw2.js.map +0 -1
  89. package/dist/types/components/Sidebar/Sidebar.d.ts +0 -29
  90. package/src/react/ds-sidebar.ts +0 -33
  91. package/src/wc/components/Sidebar/Sidebar.tsx +0 -245
  92. /package/dist/components/{p--YDw8Q4o.js.map → p-CsO880L-.js.map} +0 -0
@@ -0,0 +1,44 @@
1
+ import type { NavChromeStyle } from './nav-chrome';
2
+
3
+ /** CSS var names consumed by `ds-panel-nav` / `ds-bar-nav` inside `ds-app-shell`. */
4
+ export const SHELL_GRADIENT_IMAGE_VAR = '--ds-shell-gradient-image';
5
+ export const SHELL_GRADIENT_SIZE_VAR = '--ds-shell-gradient-size';
6
+ export const SHELL_GRADIENT_POSITION_PANEL_VAR = '--ds-shell-gradient-position-panel';
7
+ export const SHELL_GRADIENT_POSITION_BAR_VAR = '--ds-shell-gradient-position-bar';
8
+ export const SHELL_GRADIENT_OPACITY_VAR = '--ds-shell-gradient-opacity';
9
+
10
+ /** Layer opacity for the nav gradient wash. */
11
+ export const SHELL_GRADIENT_OPACITY = '0.1';
12
+
13
+ const GRADIENT_GEOMETRY = '128.57% 141.42% at 0% 0%';
14
+
15
+ /**
16
+ * Unified shell radial — same wash for all nav chrome styles.
17
+ * Tokens follow `data-theme` (light/dark blue intent).
18
+ */
19
+ export function buildShellRadialGradient(): string {
20
+ return `radial-gradient(${GRADIENT_GEOMETRY}, var(--color-background-transparent) 0%, var(--color-color-intent-blue-medium-background) 50%, var(--color-color-intent-blue-strong-background) 100%)`;
21
+ }
22
+
23
+ /** Built-in radial image (optional `gradientSrc` on shell overrides). */
24
+ export function shellGradientImageForStyle(_style: NavChromeStyle): string {
25
+ return buildShellRadialGradient();
26
+ }
27
+
28
+ export interface ShellGradientLayout {
29
+ width: number;
30
+ height: number;
31
+ panelWidth: number;
32
+ }
33
+
34
+ export function shellGradientSize(layout: ShellGradientLayout): string {
35
+ return `${Math.round(layout.width)}px ${Math.round(layout.height)}px`;
36
+ }
37
+
38
+ export function shellGradientPositionPanel(): string {
39
+ return '0 0';
40
+ }
41
+
42
+ export function shellGradientPositionBar(panelWidth: number): string {
43
+ return `${-Math.round(panelWidth)}px 0`;
44
+ }
@@ -1,17 +1,11 @@
1
+ import { parseCssTimeMs } from '../utils/resolve-css-time-ms';
2
+
1
3
  /** `view-transition-name` on `ds-bar-nav` — pairs with root reveal in shell apps. */
2
4
  export const SHELL_BAR_NAV_VT_NAME = 'ds-shell-bar-nav';
3
5
 
4
- const VT_STYLE_ID = 'ds-shell-nav-vt-style';
6
+ export { parseCssTimeMs };
5
7
 
6
- /** Parse a CSS <time> value to milliseconds. */
7
- export function parseCssTimeMs(value: string, fallback: number): number {
8
- const v = value.trim();
9
- const num = parseFloat(v);
10
- if (Number.isNaN(num)) return fallback;
11
- if (/ms\s*$/.test(v)) return num;
12
- if (/s\s*$/.test(v)) return num * 1000;
13
- return num;
14
- }
8
+ const VT_STYLE_ID = 'ds-shell-nav-vt-style';
15
9
 
16
10
  /** Suppress default cross-fade and pin new snapshots to a 0px circle for WAAPI reveal. */
17
11
  export function ensureShellNavVtStyle(): void {
@@ -1,2 +0,0 @@
1
- import{p as s,H as i,c as e,h as t,a as o,t as r}from"./index.js";const a=()=>`.sc-ds-sidebar-h{display:contents}.backdrop.sc-ds-sidebar{position:fixed;inset:0;background-color:var(--color-background-shade);z-index:9996}.sidebar.sc-ds-sidebar{display:flex;flex-direction:column;height:100%;background-color:var(--color-background-secondary);border-right:var(--dimension-stroke-width-015) solid var(--color-border-primary);position:relative;flex-shrink:0;overflow:hidden;transition:width var(--effect-motion-short-2);box-sizing:border-box}.sidebar--resizing.sc-ds-sidebar{transition:none}.sidebar--collapsed.sc-ds-sidebar{width:0 !important;border-right:none}.sidebar--mobile.sc-ds-sidebar{position:fixed;top:0;left:0;bottom:0;z-index:9997}.sidebar--mini.sc-ds-sidebar-s>[data-sidebar-label],.sidebar--mini .sc-ds-sidebar-s>[data-sidebar-label],.sidebar--mini.sc-ds-sidebar-s>[data-sidebar-badge],.sidebar--mini .sc-ds-sidebar-s>[data-sidebar-badge],.sidebar--mini.sc-ds-sidebar-s>[data-sidebar-section-header],.sidebar--mini .sc-ds-sidebar-s>[data-sidebar-section-header]{display:none}.sidebar__content.sc-ds-sidebar{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--dimension-space-050);scrollbar-width:none}.sidebar__content.sc-ds-sidebar::-webkit-scrollbar{display:none}.sidebar__footer.sc-ds-sidebar{flex-shrink:0;padding:var(--dimension-space-050);border-top:var(--dimension-stroke-width-015) solid var(--color-border-primary)}.sidebar__footer.sc-ds-sidebar:empty{display:none}.sidebar__resize-handle.sc-ds-sidebar{position:absolute;top:0;right:-3px;bottom:0;width:6px;cursor:col-resize;z-index:10}.sidebar__resize-handle.sc-ds-sidebar:hover{background-color:var(--color-border-bold-brand);opacity:0.5}.sidebar__resize-handle.sc-ds-sidebar:focus-visible{outline:var(--dimension-stroke-width-025) solid var(--color-border-bold-brand);outline-offset:var(--dimension-stroke-width-015);background-color:var(--color-border-bold-brand);opacity:0.5}`;const d=56;const n=240;const l=480;const c=180;const h=140;const b=16;const u=["a[href]","button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(",");const m=s(class s extends i{constructor(s){super();if(s!==false){this.__registerHost()}this.dsToggle=e(this,"dsToggle");this.dsWidthChange=e(this,"dsWidthChange");this.collapsed=false;this.width="default";this.resizable=true;this.mobile=false;this.isResizing=false;this.triggerEl=null;this.escapeHandler=null;this.tabHandler=null;this.mouseMoveHandler=null;this.mouseUpHandler=null}get resolvedWidth(){if(this.width==="mini")return d;if(this.width==="default")return n;return this.width}get isMobileOpen(){return this.mobile&&!this.collapsed}onCollapsedChange(){if(this.isMobileOpen){this.setupMobileFocusTrap()}else{this.teardownMobileFocusTrap()}}componentDidLoad(){if(this.isMobileOpen){this.setupMobileFocusTrap()}if(this.mobile){this.escapeHandler=s=>{if(s.key==="Escape"&&!this.collapsed){this.dsToggle.emit()}};document.addEventListener("keydown",this.escapeHandler)}}disconnectedCallback(){this.teardownMobileFocusTrap();if(this.escapeHandler){document.removeEventListener("keydown",this.escapeHandler);this.escapeHandler=null}this.cleanupMouseHandlers()}setupMobileFocusTrap(){this.triggerEl=document.activeElement;const s=()=>Array.from(this.el.querySelectorAll(u)).filter((s=>!s.hasAttribute("aria-hidden")&&s.offsetParent!==null));const i=s();(i[0]??this.el).focus();this.tabHandler=i=>{if(i.key!=="Tab")return;const e=s();if(!e.length){i.preventDefault();this.el.focus();return}const t=e[0];const o=e[e.length-1];const r=document.activeElement;if(i.shiftKey&&(r===t||!this.el.contains(r))){i.preventDefault();o.focus()}else if(!i.shiftKey&&(r===o||!this.el.contains(r))){i.preventDefault();t.focus()}};document.addEventListener("keydown",this.tabHandler)}teardownMobileFocusTrap(){if(this.tabHandler){document.removeEventListener("keydown",this.tabHandler);this.tabHandler=null}this.triggerEl?.focus?.();this.triggerEl=null}cleanupMouseHandlers(){if(this.mouseMoveHandler)document.removeEventListener("mousemove",this.mouseMoveHandler);if(this.mouseUpHandler)document.removeEventListener("mouseup",this.mouseUpHandler);this.mouseMoveHandler=null;this.mouseUpHandler=null;document.body.style.cursor="";document.body.style.userSelect=""}handleResizeMouseDown(s){if(!this.resizable)return;s.preventDefault();this.isResizing=true;this.mouseMoveHandler=s=>{const i=s.clientX;if(i<h){this.dsWidthChange.emit("mini")}else if(i<c){this.dsWidthChange.emit("default")}else{this.dsWidthChange.emit(i)}};this.mouseUpHandler=()=>{this.isResizing=false;this.cleanupMouseHandlers()};document.body.style.cursor="col-resize";document.body.style.userSelect="none";document.addEventListener("mousemove",this.mouseMoveHandler);document.addEventListener("mouseup",this.mouseUpHandler)}handleResizeKeyDown(s){if(!this.resizable)return;const i=this.width;const e=this.resolvedWidth;switch(s.key){case"ArrowLeft":{s.preventDefault();if(i==="mini")return;const t=e-b;this.dsWidthChange.emit(t<c?"mini":t);break}case"ArrowRight":{s.preventDefault();if(i==="mini"){this.dsWidthChange.emit("default");return}this.dsWidthChange.emit(Math.min(e+b,l));break}case"Home":s.preventDefault();this.dsWidthChange.emit("mini");break;case"End":s.preventDefault();this.dsWidthChange.emit(l);break}}render(){if(this.collapsed&&!this.mobile)return null;const s=this.width==="mini";const i=this.isMobileOpen;const e=this.collapsed?0:this.resolvedWidth;const r=i?{role:"dialog","aria-modal":"true",tabIndex:-1}:{role:"navigation"};return t(o,null,this.mobile&&!this.collapsed&&t("div",{class:"backdrop",onClick:()=>this.dsToggle.emit(),"aria-hidden":"true"}),t("aside",{class:{sidebar:true,"sidebar--mini":s,"sidebar--mobile":this.mobile,"sidebar--collapsed":this.collapsed,"sidebar--resizing":this.isResizing},style:{width:`${e}px`},"aria-label":"Sidebar",...r},t("div",{class:"sidebar__content"},t("slot",null)),t("div",{class:"sidebar__footer"},t("slot",{name:"footer"})),this.resizable&&!this.mobile&&t("div",{class:"sidebar__resize-handle",onMouseDown:s=>this.handleResizeMouseDown(s),onKeyDown:s=>this.handleResizeKeyDown(s),role:"separator","aria-orientation":"vertical","aria-label":"Resize sidebar","aria-valuenow":this.resolvedWidth,"aria-valuemin":d,"aria-valuemax":l,tabIndex:0})))}get el(){return this}static get watchers(){return{collapsed:[{onCollapsedChange:0}]}}static get style(){return a()}},[262,"ds-sidebar",{collapsed:[1028],width:[8],resizable:[4],mobile:[4],isResizing:[32]},undefined,{collapsed:[{onCollapsedChange:0}]}]);function f(){if(typeof customElements==="undefined"){return}const s=["ds-sidebar"];s.forEach((s=>{switch(s){case"ds-sidebar":if(!customElements.get(r(s))){customElements.define(r(s),m)}break}}))}f();const p=m;const g=f;export{p as DsSidebar,g as defineCustomElement};
2
- //# sourceMappingURL=ds-sidebar.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["sidebarCss","MINI_WIDTH","DEFAULT_WIDTH","MAX_WIDTH","MIN_DRAG_WIDTH","SNAP_THRESHOLD","KEYBOARD_STEP","FOCUSABLE_SEL","join","Sidebar","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","collapsed","width","resizable","mobile","isResizing","triggerEl","escapeHandler","tabHandler","mouseMoveHandler","mouseUpHandler","resolvedWidth","isMobileOpen","onCollapsedChange","setupMobileFocusTrap","teardownMobileFocusTrap","componentDidLoad","e","key","dsToggle","emit","document","addEventListener","disconnectedCallback","removeEventListener","cleanupMouseHandlers","activeElement","focusables","Array","from","el","querySelectorAll","filter","hasAttribute","offsetParent","initial","focus","items","length","preventDefault","first","last","active","shiftKey","contains","body","style","cursor","userSelect","handleResizeMouseDown","ev","newW","clientX","dsWidthChange","handleResizeKeyDown","w","resolved","next","Math","min","render","isMini","sidebarWidth","dialogProps","role","tabIndex","h","Host","class","onClick","sidebar","name","onMouseDown","onKeyDown"],"sources":["src/wc/components/Sidebar/Sidebar.css?tag=ds-sidebar&encapsulation=scoped","src/wc/components/Sidebar/Sidebar.tsx"],"sourcesContent":[":host {\n display: contents;\n}\n\n.backdrop {\n position: fixed;\n inset: 0;\n background-color: var(--color-background-shade);\n z-index: 9996;\n}\n\n.sidebar {\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--color-background-secondary);\n border-right: var(--dimension-stroke-width-015) solid var(--color-border-primary);\n position: relative;\n flex-shrink: 0;\n overflow: hidden;\n transition: width var(--effect-motion-short-2);\n box-sizing: border-box;\n}\n\n.sidebar--resizing { transition: none; }\n\n.sidebar--collapsed {\n width: 0 !important;\n border-right: none;\n}\n\n.sidebar--mobile {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n z-index: 9997;\n}\n\n/* Hide labels/badges/section headers when mini */\n.sidebar--mini ::slotted([data-sidebar-label]),\n.sidebar--mini ::slotted([data-sidebar-badge]),\n.sidebar--mini ::slotted([data-sidebar-section-header]) {\n display: none;\n}\n\n.sidebar__content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: var(--dimension-space-050);\n scrollbar-width: none;\n}\n\n.sidebar__content::-webkit-scrollbar { display: none; }\n\n.sidebar__footer {\n flex-shrink: 0;\n padding: var(--dimension-space-050);\n border-top: var(--dimension-stroke-width-015) solid var(--color-border-primary);\n}\n\n.sidebar__footer:empty { display: none; }\n\n.sidebar__resize-handle {\n position: absolute;\n top: 0;\n right: -3px;\n bottom: 0;\n width: 6px;\n cursor: col-resize;\n z-index: 10;\n}\n\n.sidebar__resize-handle:hover {\n background-color: var(--color-border-bold-brand);\n opacity: 0.5;\n}\n\n.sidebar__resize-handle:focus-visible {\n outline: var(--dimension-stroke-width-025) solid var(--color-border-bold-brand);\n outline-offset: var(--dimension-stroke-width-015);\n background-color: var(--color-border-bold-brand);\n opacity: 0.5;\n}\n","import { Component, Prop, State, Event, EventEmitter, Element, Watch, h, Host } from '@stencil/core';\n\nexport type SidebarWidth = 'mini' | 'default' | number;\n\nconst MINI_WIDTH = 56;\nconst DEFAULT_WIDTH = 240;\nconst MAX_WIDTH = 480;\nconst MIN_DRAG_WIDTH = 180;\nconst SNAP_THRESHOLD = 140;\nconst KEYBOARD_STEP = 16;\n\nconst FOCUSABLE_SEL = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\n@Component({\n tag: 'ds-sidebar',\n styleUrl: 'Sidebar.css',\n scoped: true,\n})\nexport class Sidebar {\n @Element() el!: HTMLElement;\n\n @Prop({ mutable: true }) collapsed: boolean = false;\n @Prop() width: SidebarWidth = 'default';\n @Prop() resizable: boolean = true;\n @Prop() mobile: boolean = false;\n\n @State() private isResizing: boolean = false;\n\n @Event() dsToggle!: EventEmitter<void>;\n @Event() dsWidthChange!: EventEmitter<SidebarWidth>;\n\n private triggerEl: HTMLElement | null = null;\n private escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n private tabHandler: ((e: KeyboardEvent) => void) | null = null;\n private mouseMoveHandler: ((e: MouseEvent) => void) | null = null;\n private mouseUpHandler: (() => void) | null = null;\n\n private get resolvedWidth(): number {\n if (this.width === 'mini') return MINI_WIDTH;\n if (this.width === 'default') return DEFAULT_WIDTH;\n return this.width as number;\n }\n\n private get isMobileOpen(): boolean {\n return this.mobile && !this.collapsed;\n }\n\n @Watch('collapsed')\n onCollapsedChange() {\n if (this.isMobileOpen) {\n this.setupMobileFocusTrap();\n } else {\n this.teardownMobileFocusTrap();\n }\n }\n\n componentDidLoad() {\n if (this.isMobileOpen) {\n this.setupMobileFocusTrap();\n }\n if (this.mobile) {\n this.escapeHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && !this.collapsed) {\n this.dsToggle.emit();\n }\n };\n document.addEventListener('keydown', this.escapeHandler);\n }\n }\n\n disconnectedCallback() {\n this.teardownMobileFocusTrap();\n if (this.escapeHandler) {\n document.removeEventListener('keydown', this.escapeHandler);\n this.escapeHandler = null;\n }\n this.cleanupMouseHandlers();\n }\n\n private setupMobileFocusTrap() {\n this.triggerEl = document.activeElement as HTMLElement | null;\n\n const focusables = () =>\n Array.from(this.el.querySelectorAll<HTMLElement>(FOCUSABLE_SEL)).filter(\n el => !el.hasAttribute('aria-hidden') && el.offsetParent !== null,\n );\n\n const initial = focusables();\n (initial[0] ?? this.el).focus();\n\n this.tabHandler = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n const items = focusables();\n if (!items.length) { e.preventDefault(); this.el.focus(); return; }\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement as HTMLElement | null;\n if (e.shiftKey && (active === first || !this.el.contains(active))) {\n e.preventDefault(); last.focus();\n } else if (!e.shiftKey && (active === last || !this.el.contains(active))) {\n e.preventDefault(); first.focus();\n }\n };\n document.addEventListener('keydown', this.tabHandler);\n }\n\n private teardownMobileFocusTrap() {\n if (this.tabHandler) {\n document.removeEventListener('keydown', this.tabHandler);\n this.tabHandler = null;\n }\n this.triggerEl?.focus?.();\n this.triggerEl = null;\n }\n\n private cleanupMouseHandlers() {\n if (this.mouseMoveHandler) document.removeEventListener('mousemove', this.mouseMoveHandler);\n if (this.mouseUpHandler) document.removeEventListener('mouseup', this.mouseUpHandler);\n this.mouseMoveHandler = null;\n this.mouseUpHandler = null;\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n }\n\n private handleResizeMouseDown(e: MouseEvent) {\n if (!this.resizable) return;\n e.preventDefault();\n this.isResizing = true;\n\n this.mouseMoveHandler = (ev: MouseEvent) => {\n const newW = ev.clientX;\n if (newW < SNAP_THRESHOLD) {\n this.dsWidthChange.emit('mini');\n } else if (newW < MIN_DRAG_WIDTH) {\n this.dsWidthChange.emit('default');\n } else {\n this.dsWidthChange.emit(newW);\n }\n };\n\n this.mouseUpHandler = () => {\n this.isResizing = false;\n this.cleanupMouseHandlers();\n };\n\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n document.addEventListener('mousemove', this.mouseMoveHandler);\n document.addEventListener('mouseup', this.mouseUpHandler);\n }\n\n private handleResizeKeyDown(e: KeyboardEvent) {\n if (!this.resizable) return;\n const w = this.width;\n const resolved = this.resolvedWidth;\n\n switch (e.key) {\n case 'ArrowLeft': {\n e.preventDefault();\n if (w === 'mini') return;\n const next = resolved - KEYBOARD_STEP;\n this.dsWidthChange.emit(next < MIN_DRAG_WIDTH ? 'mini' : next);\n break;\n }\n case 'ArrowRight': {\n e.preventDefault();\n if (w === 'mini') { this.dsWidthChange.emit('default'); return; }\n this.dsWidthChange.emit(Math.min(resolved + KEYBOARD_STEP, MAX_WIDTH));\n break;\n }\n case 'Home':\n e.preventDefault();\n this.dsWidthChange.emit('mini');\n break;\n case 'End':\n e.preventDefault();\n this.dsWidthChange.emit(MAX_WIDTH);\n break;\n }\n }\n\n render() {\n if (this.collapsed && !this.mobile) return null;\n\n const isMini = this.width === 'mini';\n const isMobileOpen = this.isMobileOpen;\n const sidebarWidth = this.collapsed ? 0 : this.resolvedWidth;\n\n const dialogProps = isMobileOpen\n ? { role: 'dialog', 'aria-modal': 'true', tabIndex: -1 }\n : { role: 'navigation' };\n\n return (\n <Host>\n {this.mobile && !this.collapsed && (\n <div\n class=\"backdrop\"\n onClick={() => this.dsToggle.emit()}\n aria-hidden=\"true\"\n />\n )}\n <aside\n class={{\n sidebar: true,\n 'sidebar--mini': isMini,\n 'sidebar--mobile': this.mobile,\n 'sidebar--collapsed': this.collapsed,\n 'sidebar--resizing': this.isResizing,\n }}\n style={{ width: `${sidebarWidth}px` }}\n aria-label=\"Sidebar\"\n {...dialogProps}\n >\n <div class=\"sidebar__content\">\n <slot />\n </div>\n <div class=\"sidebar__footer\">\n <slot name=\"footer\" />\n </div>\n {this.resizable && !this.mobile && (\n <div\n class=\"sidebar__resize-handle\"\n onMouseDown={(e: MouseEvent) => this.handleResizeMouseDown(e)}\n onKeyDown={(e: KeyboardEvent) => this.handleResizeKeyDown(e)}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label=\"Resize sidebar\"\n aria-valuenow={this.resolvedWidth}\n aria-valuemin={MINI_WIDTH}\n aria-valuemax={MAX_WIDTH}\n tabIndex={0}\n />\n )}\n </aside>\n </Host>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,2 +0,0 @@
1
- import{p as e,H as s,h as t,t as i}from"./index.js";const n=()=>`:host{display:inline-flex;align-items:center;flex-shrink:0}.spinner{flex-shrink:0;animation:spin 0.75s linear infinite}.status{display:inline-flex;align-items:center}.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}@keyframes spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}`;const r=e(class e extends s{constructor(e){super();if(e!==false){this.__registerHost()}this.__attachShadow();this.size=20}render(){const e=`${this.size}px`;const s=t("svg",{style:{width:e,height:e},viewBox:"0 0 16 16",fill:"none",class:"spinner","aria-hidden":"true"},t("circle",{cx:"8",cy:"8",r:"5",stroke:"currentColor","stroke-width":"1","stroke-linecap":"round","stroke-dasharray":"23.6 7.9"}));if(!this.label)return s;return t("span",{role:"status","aria-live":"polite",class:"status"},s,t("span",{class:"visually-hidden"},this.label))}static get style(){return n()}},[1,"ds-loader",{size:[2],label:[1]}]);function a(){if(typeof customElements==="undefined"){return}const e=["ds-loader"];e.forEach((e=>{switch(e){case"ds-loader":if(!customElements.get(i(e))){customElements.define(i(e),r)}break}}))}a();export{r as L,a as d};
2
- //# sourceMappingURL=p-BcuUR5Ao.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["loaderCss","Loader","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","size","render","px","svg","h","style","width","height","viewBox","fill","class","cx","cy","r","stroke","label","role"],"sources":["src/wc/components/Loader/Loader.css?tag=ds-loader&encapsulation=shadow","src/wc/components/Loader/Loader.tsx"],"sourcesContent":[":host {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n}\n\n.spinner {\n flex-shrink: 0;\n animation: spin 0.75s linear infinite;\n}\n\n.status {\n display: inline-flex;\n align-items: center;\n}\n\n.visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n@keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n","import { Component, Prop, h } from '@stencil/core';\n\n@Component({\n tag: 'ds-loader',\n styleUrl: 'Loader.css',\n shadow: true,\n})\nexport class Loader {\n /** Render size in px. Designed on a 16×16 viewBox; stroke scales proportionally. */\n @Prop() size: number = 20;\n /**\n * Accessible label for standalone usage. Wraps the spinner in a live region\n * and renders the label visually-hidden. Omit when the host element already\n * conveys busy state via aria-busy.\n */\n @Prop() label: string | undefined;\n\n render() {\n const px = `${this.size}px`;\n const svg = (\n <svg\n style={{ width: px, height: px }}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"spinner\"\n aria-hidden=\"true\"\n >\n <circle\n cx=\"8\" cy=\"8\" r=\"5\"\n stroke=\"currentColor\"\n stroke-width=\"1\"\n stroke-linecap=\"round\"\n stroke-dasharray=\"23.6 7.9\"\n />\n </svg>\n );\n\n if (!this.label) return svg;\n\n return (\n <span role=\"status\" aria-live=\"polite\" class=\"status\">\n {svg}\n <span class=\"visually-hidden\">{this.label}</span>\n </span>\n );\n }\n}\n"],"mappings":"oDAAA,MAAMA,EAAY,IAAM,kY,MCOXC,EAAMC,EAAA,MAAAD,UAAAE,EALnB,WAAAC,CAAAC,G,kEAOUC,KAAAC,KAAe,EAqCxB,CA7BC,MAAAC,GACE,MAAMC,EAAK,GAAGH,KAAKC,SACnB,MAAMG,EACJC,EAAA,OACEC,MAAO,CAAEC,MAAOJ,EAAIK,OAAQL,GAC5BM,QAAQ,YACRC,KAAK,OACLC,MAAM,UAAS,cACH,QAEZN,EAAA,UACEO,GAAG,IAAIC,GAAG,IAAIC,EAAE,IAChBC,OAAO,eAAc,eACR,IAAG,iBACD,QAAO,mBACL,cAKvB,IAAKf,KAAKgB,MAAO,OAAOZ,EAExB,OACEC,EAAA,QAAMY,KAAK,SAAQ,YAAW,SAASN,MAAM,UAC1CP,EACDC,EAAA,QAAMM,MAAM,mBAAmBX,KAAKgB,O","ignoreList":[]}
@@ -1,2 +0,0 @@
1
- import{p as e,H as t,c as s,h as i,a as n,t as o}from"./index.js";const r=()=>`.menu-popup.sc-ds-menu{box-sizing:border-box;display:flex;flex-direction:column;min-width:200px;max-width:600px;overflow:hidden;background-color:var(--color-background-primary);border-radius:var(--dimension-radius-075);box-shadow:var(--effect-shadow-elevated-floating);animation:menuFadeIn var(--effect-motion-short-2) forwards;backface-visibility:hidden;will-change:transform}.menu-popup.sc-ds-menu::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;box-shadow:var(--effect-highlight-elevated-floating)}.menu-popup--closing.sc-ds-menu{animation:menuFadeOut var(--effect-motion-short-3) forwards}@keyframes menuFadeIn{from{opacity:0;transform:inherit scale(0.97)}to{opacity:1}}@keyframes menuFadeOut{from{opacity:1}to{opacity:0}}.menu-section.sc-ds-menu{display:flex;flex-direction:column;gap:var(--dimension-space-050);padding:var(--dimension-space-050)}.menu-section--divided.sc-ds-menu{border-bottom:var(--dimension-stroke-width-015) solid var(--color-border-tertiary)}.section-header.sc-ds-menu{display:flex;align-items:center;height:var(--dimension-size-400);padding:var(--dimension-space-050) var(--dimension-space-075);-webkit-user-select:none;user-select:none}.section-label.sc-ds-menu{color:var(--color-foreground-secondary)}.menu-item.sc-ds-menu{display:flex;align-items:center;gap:var(--dimension-space-050);position:relative;width:100%;min-height:var(--dimension-size-400);padding:var(--dimension-space-075);box-sizing:border-box;border:none;border-radius:var(--dimension-radius-025);background:transparent;cursor:pointer;-webkit-user-select:none;user-select:none;text-align:left;color:inherit;--_hover-bg:var(--color-interaction-hover);--_pressed-bg:var(--color-interaction-pressed);--_selected-bg:var(--color-interaction-active)}.menu-item.sc-ds-menu:has(.menu-item__subtext){align-items:flex-start}.menu-item.sc-ds-menu::after{content:'';position:absolute;inset:0;border-radius:inherit;background:transparent;pointer-events:none;transition:none}.menu-item--selected.sc-ds-menu::after{background:var(--_selected-bg);transition:none}.menu-item.sc-ds-menu:hover:not(:disabled):not(.menu-item--selected)::after,.menu-item--focused.sc-ds-menu:not(:disabled):not(.menu-item--selected)::after{background:var(--_hover-bg);transition:none}.menu-item.sc-ds-menu:active:not(:disabled)::after{background:var(--_pressed-bg);transition:none}.menu-item.sc-ds-menu:focus-visible{outline:var(--dimension-stroke-width-025) solid var(--color-interaction-focus);outline-offset:var(--dimension-space-025)}.menu-item--inactive.sc-ds-menu{opacity:0.5;cursor:not-allowed;pointer-events:none}.menu-item--destructive.sc-ds-menu .menu-item__label.sc-ds-menu{color:var(--color-foreground-bold-negative) !important}.menu-item__content.sc-ds-menu{position:relative;z-index:1;display:flex;flex:1;flex-direction:column;gap:var(--dimension-space-025);min-width:0}.menu-item__label.sc-ds-menu{color:var(--color-foreground-secondary)}.menu-item.sc-ds-menu:has(.menu-item__subtext) .menu-item__label.sc-ds-menu,.menu-item--selected.sc-ds-menu .menu-item__label.sc-ds-menu{color:var(--color-foreground-primary)}.menu-item__subtext.sc-ds-menu{color:var(--color-foreground-secondary);line-height:1.4}.menu-item__toggle.sc-ds-menu{position:relative;z-index:1;flex-shrink:0;width:calc(var(--dimension-size-400) + var(--dimension-size-050));height:var(--dimension-size-250);border-radius:var(--dimension-radius-125);background-color:var(--color-background-translucent);transition:background-color var(--effect-motion-short-2)}.menu-item__toggle--on.sc-ds-menu{background-color:var(--color-background-medium-brand)}.menu-item__toggle-thumb.sc-ds-menu{position:absolute;top:var(--dimension-space-025);left:var(--dimension-space-025);width:var(--dimension-size-200);height:var(--dimension-size-200);border-radius:50%;background-color:var(--color-foreground-on-bold-background-primary);transition:transform var(--effect-motion-short-2)}.menu-item__toggle--on.sc-ds-menu .menu-item__toggle-thumb.sc-ds-menu{transform:translateX(var(--dimension-offset-200, 16px))}`;const a=220;const d=4;const c=e(class e extends t{constructor(e){super();if(e!==false){this.__registerHost()}this.dsClose=s(this,"dsClose");this.dsSelect=s(this,"dsSelect");this.open=false;this.items=[];this.sections=[];this.side="bottom";this.align="start";this.sideOffset=4;this.alignOffset=0;this.shouldRender=false;this.closing=false;this.pos={x:0,y:0};this.focusedIndex=0;this.positionReady=false;this.clickOutsideHandler=null;this.scrollResizeHandler=null;this.closeTimer=null;this.itemEls=[]}componentDidLoad(){if(this.open)this.onOpenChange(true)}disconnectedCallback(){this.teardownListeners()}onOpenChange(e){if(e){this.shouldRender=true;this.closing=false;this.positionReady=false;requestAnimationFrame((()=>{this.calculatePosition();this.positionReady=true;this.focusInitialItem();this.setupListeners()}))}else if(this.shouldRender){this.closing=true;this.teardownListeners();this.closeTimer=setTimeout((()=>{this.shouldRender=false;this.closing=false;this.closeTimer=null}),a)}}get resolvedAnchor(){if(this.anchor)return this.anchor;if(this.anchorId)return document.getElementById(this.anchorId);return null}get activeSections(){if(this.sections.length>0)return this.sections;if(this.items.length>0)return[{items:this.items}];return[]}get flatItems(){return this.activeSections.flatMap((e=>e.items))}calculatePosition(){const e=this.resolvedAnchor;if(!e)return;const t=this.el.querySelector(".menu-popup");if(!t)return;const s=e.getBoundingClientRect();const i=t.offsetWidth||200;const n=t.offsetHeight||160;let o=0,r=0;switch(this.side){case"top":r=s.top-n-this.sideOffset;o=this.align==="start"?s.left+this.alignOffset:this.align==="end"?s.right-i+this.alignOffset:s.left+s.width/2-i/2+this.alignOffset;break;case"bottom":r=s.bottom+this.sideOffset;o=this.align==="start"?s.left+this.alignOffset:this.align==="end"?s.right-i+this.alignOffset:s.left+s.width/2-i/2+this.alignOffset;break;case"left":o=s.left-i-this.sideOffset;r=this.align==="start"?s.top+this.alignOffset:this.align==="end"?s.bottom-n+this.alignOffset:s.top+s.height/2-n/2+this.alignOffset;break;case"right":o=s.right+this.sideOffset;r=this.align==="start"?s.top+this.alignOffset:this.align==="end"?s.bottom-n+this.alignOffset:s.top+s.height/2-n/2+this.alignOffset;break}this.pos={x:Math.min(Math.max(o,d),window.innerWidth-i-d),y:Math.min(Math.max(r,d),window.innerHeight-n-d)}}focusInitialItem(){const e=this.flatItems;const t=e.findIndex((e=>e.isSelected&&!e.isInactive));const s=e.findIndex((e=>!e.isInactive));this.focusedIndex=t>=0?t:s>=0?s:0;requestAnimationFrame((()=>{const e=this.el.querySelectorAll(".menu-item");e[this.focusedIndex]?.focus()}))}setupListeners(){this.clickOutsideHandler=e=>{const t=e.target;const s=this.el.querySelector(".menu-popup");const i=this.resolvedAnchor;if(s?.contains(t)||i?.contains(t))return;this.close()};this.scrollResizeHandler=()=>this.calculatePosition();document.addEventListener("mousedown",this.clickOutsideHandler,true);window.addEventListener("scroll",this.scrollResizeHandler,true);window.addEventListener("resize",this.scrollResizeHandler)}teardownListeners(){if(this.clickOutsideHandler){document.removeEventListener("mousedown",this.clickOutsideHandler,true);this.clickOutsideHandler=null}if(this.scrollResizeHandler){window.removeEventListener("scroll",this.scrollResizeHandler,true);window.removeEventListener("resize",this.scrollResizeHandler);this.scrollResizeHandler=null}if(this.closeTimer){clearTimeout(this.closeTimer);this.closeTimer=null}}close(){this.resolvedAnchor?.focus();this.dsClose.emit();this.open=false}handleKeyDown(e){if(!this.open)return;const t=this.flatItems;const s=t.map(((e,t)=>({it:e,i:t}))).filter((({it:e})=>!e.isInactive)).map((({i:e})=>e));if(!s.length)return;const i=s.indexOf(this.focusedIndex);const n=i<0?0:i;switch(e.key){case"ArrowDown":e.preventDefault();e.stopPropagation();this.focusedIndex=s[(n+1)%s.length];this.focusItem(this.focusedIndex);break;case"ArrowUp":e.preventDefault();e.stopPropagation();this.focusedIndex=s[(n-1+s.length)%s.length];this.focusItem(this.focusedIndex);break;case"Home":e.preventDefault();e.stopPropagation();this.focusedIndex=s[0];this.focusItem(this.focusedIndex);break;case"End":e.preventDefault();e.stopPropagation();this.focusedIndex=s[s.length-1];this.focusItem(this.focusedIndex);break;case"Escape":e.preventDefault();this.close();break;case"Tab":e.preventDefault();this.close();break}}focusItem(e){const t=this.el.querySelectorAll(".menu-item");t[e]?.focus()}handleItemClick(e){if(e.isInactive)return;this.dsSelect.emit(e);this.close()}render(){if(!this.shouldRender)return i(n,{style:{display:"contents"}});const e=this.activeSections;let t=0;const s={position:"fixed",left:"0",top:"0",transform:`translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,zIndex:"9998",visibility:this.positionReady?"visible":"hidden"};if(this.menuWidth)s["width"]=this.menuWidth;if(this.minWidth)s["min-width"]=this.minWidth;return i(n,{style:{display:"contents"}},i("div",{class:{"menu-popup":true,"menu-popup--closing":this.closing},style:s,role:"menu","aria-label":"Menu","aria-orientation":"vertical"},e.map(((s,n)=>i("div",{key:n,class:{"menu-section":true,"menu-section--divided":n<e.length-1},role:s.header?"group":undefined,"aria-label":s.header},s.header&&i("div",{class:"section-header","aria-hidden":"true"},i("span",{class:"text-body-small-emphasis section-label"},s.header)),s.items.map((e=>{const s=t++;const n=this.focusedIndex===s;return i("button",{key:s,type:"button",class:{"menu-item":true,"menu-item--selected":!!e.isSelected,"menu-item--inactive":!!e.isInactive,"menu-item--destructive":!!e.isDestructive,"menu-item--focused":n},role:"menuitem","aria-current":e.isSelected?"true":undefined,disabled:e.isInactive,tabIndex:n?0:-1,onClick:()=>this.handleItemClick(e),onFocus:()=>{this.focusedIndex=s}},i("div",{class:"menu-item__content"},i("span",{class:e.isSelected?"text-body-medium-emphasis menu-item__label":"text-body-medium menu-item__label"},e.label),e.subtext&&i("span",{class:"text-body-small menu-item__subtext"},e.subtext)),e.showToggle&&i("div",{class:{"menu-item__toggle":true,"menu-item__toggle--on":!!e.toggleValue},"aria-hidden":"true"},i("div",{class:"menu-item__toggle-thumb"})))})))))))}get el(){return this}static get watchers(){return{open:[{onOpenChange:0}]}}static get style(){return r()}},[2,"ds-menu",{open:[1028],items:[16],sections:[16],side:[1],align:[1],sideOffset:[2,"side-offset"],alignOffset:[2,"align-offset"],menuWidth:[1,"menu-width"],minWidth:[1,"min-width"],anchor:[16],anchorId:[1,"anchor-id"],shouldRender:[32],closing:[32],pos:[32],focusedIndex:[32],positionReady:[32]},[[0,"keydown","handleKeyDown"]],{open:[{onOpenChange:0}]}]);function u(){if(typeof customElements==="undefined"){return}const e=["ds-menu"];e.forEach((e=>{switch(e){case"ds-menu":if(!customElements.get(o(e))){customElements.define(o(e),c)}break}}))}u();export{c as M,u as d};
2
- //# sourceMappingURL=p-CpbnmEu1.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["menuCss","CLOSE_ANIMATION_MS","VP_PAD","Menu","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","open","items","sections","side","align","sideOffset","alignOffset","shouldRender","closing","pos","x","y","focusedIndex","positionReady","clickOutsideHandler","scrollResizeHandler","closeTimer","itemEls","componentDidLoad","onOpenChange","disconnectedCallback","teardownListeners","isOpen","requestAnimationFrame","calculatePosition","focusInitialItem","setupListeners","setTimeout","resolvedAnchor","anchor","anchorId","document","getElementById","activeSections","length","flatItems","flatMap","s","anchorEl","popup","el","querySelector","a","getBoundingClientRect","pw","offsetWidth","ph","offsetHeight","top","left","right","width","bottom","height","Math","min","max","window","innerWidth","innerHeight","flat","selectedIdx","findIndex","it","isSelected","isInactive","firstEnabledIdx","btns","querySelectorAll","focus","e","t","target","contains","close","addEventListener","removeEventListener","clearTimeout","dsClose","emit","handleKeyDown","enabled","map","i","filter","cur","indexOf","safe","key","preventDefault","stopPropagation","focusItem","idx","handleItemClick","item","dsSelect","render","h","Host","style","display","flatIdx","popupStyle","position","transform","round","zIndex","visibility","menuWidth","minWidth","class","role","section","si","header","undefined","isFocused","type","isDestructive","disabled","tabIndex","onClick","onFocus","label","subtext","showToggle","toggleValue"],"sources":["src/wc/components/Menu/Menu.css?tag=ds-menu&encapsulation=scoped","src/wc/components/Menu/Menu.tsx"],"sourcesContent":["/* ── Popup shell ─────────────────────────────────────────────────────────── */\n\n.menu-popup {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n min-width: 200px;\n max-width: 600px;\n overflow: hidden;\n background-color: var(--color-background-primary);\n border-radius: var(--dimension-radius-075);\n /* Split elevation: shadow on shell, inset highlight on ::after (combined token clips with overflow:hidden). */\n box-shadow: var(--effect-shadow-elevated-floating);\n animation: menuFadeIn var(--effect-motion-short-2) forwards;\n backface-visibility: hidden;\n will-change: transform;\n}\n\n.menu-popup::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n box-shadow: var(--effect-highlight-elevated-floating);\n}\n\n.menu-popup--closing {\n animation: menuFadeOut var(--effect-motion-short-3) forwards;\n}\n\n@keyframes menuFadeIn {\n from { opacity: 0; transform: inherit scale(0.97); }\n to { opacity: 1; }\n}\n\n@keyframes menuFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n}\n\n/* ── Sections ────────────────────────────────────────────────────────────── */\n\n.menu-section {\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050);\n padding: var(--dimension-space-050);\n}\n\n.menu-section--divided {\n border-bottom: var(--dimension-stroke-width-015) solid var(--color-border-tertiary);\n}\n\n.section-header {\n display: flex;\n align-items: center;\n height: var(--dimension-size-400);\n padding: var(--dimension-space-050) var(--dimension-space-075);\n -webkit-user-select: none;\n user-select: none;\n}\n\n.section-label {\n color: var(--color-foreground-secondary);\n}\n\n/* ── Items ───────────────────────────────────────────────────────────────── */\n\n.menu-item {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-050);\n position: relative;\n width: 100%;\n min-height: var(--dimension-size-400);\n padding: var(--dimension-space-075);\n box-sizing: border-box;\n border: none;\n border-radius: var(--dimension-radius-025);\n background: transparent;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n text-align: left;\n color: inherit;\n --_hover-bg: var(--color-interaction-hover);\n --_pressed-bg: var(--color-interaction-pressed);\n --_selected-bg: var(--color-interaction-active);\n}\n\n.menu-item:has(.menu-item__subtext) {\n align-items: flex-start;\n}\n\n/* Interaction layer — same ::after pattern as tabs / BarNav trigger */\n.menu-item::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: inherit;\n background: transparent;\n pointer-events: none;\n transition: none;\n}\n\n.menu-item--selected::after {\n background: var(--_selected-bg);\n transition: none;\n}\n\n.menu-item:hover:not(:disabled):not(.menu-item--selected)::after,\n.menu-item--focused:not(:disabled):not(.menu-item--selected)::after {\n background: var(--_hover-bg);\n transition: none;\n}\n\n.menu-item:active:not(:disabled)::after {\n background: var(--_pressed-bg);\n transition: none;\n}\n\n.menu-item:focus-visible {\n outline: var(--dimension-stroke-width-025) solid var(--color-interaction-focus);\n outline-offset: var(--dimension-space-025);\n}\n\n.menu-item--inactive {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.menu-item--destructive .menu-item__label {\n color: var(--color-foreground-bold-negative) !important;\n}\n\n.menu-item__content {\n position: relative;\n z-index: 1;\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--dimension-space-025);\n min-width: 0;\n}\n\n.menu-item__label {\n color: var(--color-foreground-secondary);\n}\n\n.menu-item:has(.menu-item__subtext) .menu-item__label,\n.menu-item--selected .menu-item__label {\n color: var(--color-foreground-primary);\n}\n\n.menu-item__subtext {\n color: var(--color-foreground-secondary);\n line-height: 1.4;\n}\n\n/* ── Toggle suffix ───────────────────────────────────────────────────────── */\n\n.menu-item__toggle {\n position: relative;\n z-index: 1;\n flex-shrink: 0;\n width: calc(var(--dimension-size-400) + var(--dimension-size-050));\n height: var(--dimension-size-250);\n border-radius: var(--dimension-radius-125);\n background-color: var(--color-background-translucent);\n transition: background-color var(--effect-motion-short-2);\n}\n\n.menu-item__toggle--on {\n background-color: var(--color-background-medium-brand);\n}\n\n.menu-item__toggle-thumb {\n position: absolute;\n top: var(--dimension-space-025);\n left: var(--dimension-space-025);\n width: var(--dimension-size-200);\n height: var(--dimension-size-200);\n border-radius: 50%;\n background-color: var(--color-foreground-on-bold-background-primary);\n transition: transform var(--effect-motion-short-2);\n}\n\n.menu-item__toggle--on .menu-item__toggle-thumb {\n transform: translateX(var(--dimension-offset-200, 16px));\n}\n","import { Component, Prop, State, Event, EventEmitter, Element, Watch, Listen, h, Host } from '@stencil/core';\n\nexport type MenuSide = 'top' | 'right' | 'bottom' | 'left';\nexport type MenuAlign = 'start' | 'center' | 'end';\n\nexport interface MenuItemData {\n label: string;\n value?: string;\n subtext?: string;\n isSelected?: boolean;\n isInactive?: boolean;\n isDestructive?: boolean;\n showToggle?: boolean;\n toggleValue?: boolean;\n}\n\nexport interface MenuSection {\n header?: string;\n items: MenuItemData[];\n}\n\nconst CLOSE_ANIMATION_MS = 220;\nconst VP_PAD = 4;\n\n@Component({\n tag: 'ds-menu',\n styleUrl: 'Menu.css',\n scoped: true,\n})\nexport class Menu {\n @Element() el!: HTMLElement;\n\n @Prop({ mutable: true }) open: boolean = false;\n @Prop() items: MenuItemData[] = [];\n @Prop() sections: MenuSection[] = [];\n @Prop() side: MenuSide = 'bottom';\n @Prop() align: MenuAlign = 'start';\n @Prop() sideOffset: number = 4;\n @Prop() alignOffset: number = 0;\n @Prop() menuWidth: string | undefined;\n @Prop() minWidth: string | undefined;\n /** External trigger element to position against. Set via JS: menuEl.anchor = buttonEl */\n @Prop() anchor: HTMLElement | undefined;\n /** ID of the external trigger element for positioning */\n @Prop() anchorId: string | undefined;\n\n @State() private shouldRender: boolean = false;\n @State() private closing: boolean = false;\n @State() private pos: { x: number; y: number } = { x: 0, y: 0 };\n @State() private focusedIndex: number = 0;\n @State() private positionReady: boolean = false;\n\n @Event() dsClose!: EventEmitter<void>;\n @Event() dsSelect!: EventEmitter<MenuItemData>;\n\n private clickOutsideHandler: ((e: MouseEvent) => void) | null = null;\n private scrollResizeHandler: (() => void) | null = null;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n private itemEls: HTMLElement[] = [];\n\n componentDidLoad() {\n if (this.open) this.onOpenChange(true);\n }\n\n disconnectedCallback() {\n this.teardownListeners();\n }\n\n @Watch('open')\n onOpenChange(isOpen: boolean) {\n if (isOpen) {\n this.shouldRender = true;\n this.closing = false;\n this.positionReady = false;\n requestAnimationFrame(() => {\n this.calculatePosition();\n this.positionReady = true;\n this.focusInitialItem();\n this.setupListeners();\n });\n } else if (this.shouldRender) {\n this.closing = true;\n this.teardownListeners();\n this.closeTimer = setTimeout(() => {\n this.shouldRender = false;\n this.closing = false;\n this.closeTimer = null;\n }, CLOSE_ANIMATION_MS);\n }\n }\n\n private get resolvedAnchor(): HTMLElement | null {\n if (this.anchor) return this.anchor;\n if (this.anchorId) return document.getElementById(this.anchorId);\n return null;\n }\n\n private get activeSections(): MenuSection[] {\n if (this.sections.length > 0) return this.sections;\n if (this.items.length > 0) return [{ items: this.items }];\n return [];\n }\n\n private get flatItems(): MenuItemData[] {\n return this.activeSections.flatMap(s => s.items);\n }\n\n private calculatePosition() {\n const anchorEl = this.resolvedAnchor;\n if (!anchorEl) return;\n const popup = this.el.querySelector('.menu-popup') as HTMLElement | null;\n if (!popup) return;\n\n const a = anchorEl.getBoundingClientRect();\n const pw = popup.offsetWidth || 200;\n const ph = popup.offsetHeight || 160;\n let x = 0, y = 0;\n\n switch (this.side) {\n case 'top':\n y = a.top - ph - this.sideOffset;\n x = this.align === 'start' ? a.left + this.alignOffset\n : this.align === 'end' ? a.right - pw + this.alignOffset\n : a.left + a.width / 2 - pw / 2 + this.alignOffset;\n break;\n case 'bottom':\n y = a.bottom + this.sideOffset;\n x = this.align === 'start' ? a.left + this.alignOffset\n : this.align === 'end' ? a.right - pw + this.alignOffset\n : a.left + a.width / 2 - pw / 2 + this.alignOffset;\n break;\n case 'left':\n x = a.left - pw - this.sideOffset;\n y = this.align === 'start' ? a.top + this.alignOffset\n : this.align === 'end' ? a.bottom - ph + this.alignOffset\n : a.top + a.height / 2 - ph / 2 + this.alignOffset;\n break;\n case 'right':\n x = a.right + this.sideOffset;\n y = this.align === 'start' ? a.top + this.alignOffset\n : this.align === 'end' ? a.bottom - ph + this.alignOffset\n : a.top + a.height / 2 - ph / 2 + this.alignOffset;\n break;\n }\n\n this.pos = {\n x: Math.min(Math.max(x, VP_PAD), window.innerWidth - pw - VP_PAD),\n y: Math.min(Math.max(y, VP_PAD), window.innerHeight - ph - VP_PAD),\n };\n }\n\n /** Focus the selected item when present, otherwise the first enabled item. */\n private focusInitialItem() {\n const flat = this.flatItems;\n const selectedIdx = flat.findIndex(it => it.isSelected && !it.isInactive);\n const firstEnabledIdx = flat.findIndex(it => !it.isInactive);\n this.focusedIndex = selectedIdx >= 0\n ? selectedIdx\n : (firstEnabledIdx >= 0 ? firstEnabledIdx : 0);\n\n requestAnimationFrame(() => {\n const btns = this.el.querySelectorAll<HTMLElement>('.menu-item');\n btns[this.focusedIndex]?.focus();\n });\n }\n\n private setupListeners() {\n this.clickOutsideHandler = (e: MouseEvent) => {\n const t = e.target as Node;\n const popup = this.el.querySelector('.menu-popup');\n const anchorEl = this.resolvedAnchor;\n if (popup?.contains(t) || anchorEl?.contains(t)) return;\n this.close();\n };\n\n this.scrollResizeHandler = () => this.calculatePosition();\n\n document.addEventListener('mousedown', this.clickOutsideHandler, true);\n window.addEventListener('scroll', this.scrollResizeHandler, true);\n window.addEventListener('resize', this.scrollResizeHandler);\n }\n\n private teardownListeners() {\n if (this.clickOutsideHandler) {\n document.removeEventListener('mousedown', this.clickOutsideHandler, true);\n this.clickOutsideHandler = null;\n }\n if (this.scrollResizeHandler) {\n window.removeEventListener('scroll', this.scrollResizeHandler, true);\n window.removeEventListener('resize', this.scrollResizeHandler);\n this.scrollResizeHandler = null;\n }\n if (this.closeTimer) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private close() {\n this.resolvedAnchor?.focus();\n this.dsClose.emit();\n this.open = false;\n }\n\n @Listen('keydown')\n handleKeyDown(e: KeyboardEvent) {\n if (!this.open) return;\n const flat = this.flatItems;\n const enabled = flat.map((it, i) => ({ it, i })).filter(({ it }) => !it.isInactive).map(({ i }) => i);\n if (!enabled.length) return;\n\n const cur = enabled.indexOf(this.focusedIndex);\n const safe = cur < 0 ? 0 : cur;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault(); e.stopPropagation();\n this.focusedIndex = enabled[(safe + 1) % enabled.length];\n this.focusItem(this.focusedIndex);\n break;\n case 'ArrowUp':\n e.preventDefault(); e.stopPropagation();\n this.focusedIndex = enabled[(safe - 1 + enabled.length) % enabled.length];\n this.focusItem(this.focusedIndex);\n break;\n case 'Home':\n e.preventDefault(); e.stopPropagation();\n this.focusedIndex = enabled[0];\n this.focusItem(this.focusedIndex);\n break;\n case 'End':\n e.preventDefault(); e.stopPropagation();\n this.focusedIndex = enabled[enabled.length - 1];\n this.focusItem(this.focusedIndex);\n break;\n case 'Escape':\n e.preventDefault();\n this.close();\n break;\n case 'Tab':\n e.preventDefault();\n this.close();\n break;\n }\n }\n\n private focusItem(idx: number) {\n const btns = this.el.querySelectorAll<HTMLElement>('.menu-item');\n btns[idx]?.focus();\n }\n\n private handleItemClick(item: MenuItemData) {\n if (item.isInactive) return;\n this.dsSelect.emit(item);\n this.close();\n }\n\n render() {\n if (!this.shouldRender) return <Host style={{ display: 'contents' }} />;\n\n const sections = this.activeSections;\n let flatIdx = 0;\n\n const popupStyle: Record<string, string> = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,\n zIndex: '9998',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n\n if (this.menuWidth) popupStyle['width'] = this.menuWidth;\n if (this.minWidth) popupStyle['min-width'] = this.minWidth;\n\n return (\n <Host style={{ display: 'contents' }}>\n <div\n class={{ 'menu-popup': true, 'menu-popup--closing': this.closing }}\n style={popupStyle}\n role=\"menu\"\n aria-label=\"Menu\"\n aria-orientation=\"vertical\"\n >\n {sections.map((section, si) => (\n <div\n key={si}\n class={{ 'menu-section': true, 'menu-section--divided': si < sections.length - 1 }}\n role={section.header ? 'group' : undefined}\n aria-label={section.header}\n >\n {section.header && (\n <div class=\"section-header\" aria-hidden=\"true\">\n <span class=\"text-body-small-emphasis section-label\">{section.header}</span>\n </div>\n )}\n {section.items.map(item => {\n const idx = flatIdx++;\n const isFocused = this.focusedIndex === idx;\n return (\n <button\n key={idx}\n type=\"button\"\n class={{\n 'menu-item': true,\n 'menu-item--selected': !!item.isSelected,\n 'menu-item--inactive': !!item.isInactive,\n 'menu-item--destructive': !!item.isDestructive,\n 'menu-item--focused': isFocused,\n }}\n role=\"menuitem\"\n aria-current={item.isSelected ? 'true' : undefined}\n disabled={item.isInactive}\n tabIndex={isFocused ? 0 : -1}\n onClick={() => this.handleItemClick(item)}\n onFocus={() => { this.focusedIndex = idx; }}\n >\n <div class=\"menu-item__content\">\n <span class={item.isSelected ? 'text-body-medium-emphasis menu-item__label' : 'text-body-medium menu-item__label'}>\n {item.label}\n </span>\n {item.subtext && (\n <span class=\"text-body-small menu-item__subtext\">{item.subtext}</span>\n )}\n </div>\n {item.showToggle && (\n <div class={{ 'menu-item__toggle': true, 'menu-item__toggle--on': !!item.toggleValue }} aria-hidden=\"true\">\n <div class=\"menu-item__toggle-thumb\" />\n </div>\n )}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n </Host>\n );\n }\n}\n"],"mappings":"kEAAA,MAAMA,EAAU,IAAM,q+HCqBtB,MAAMC,EAAqB,IAC3B,MAAMC,EAAS,E,MAOFC,EAAIC,EAAA,MAAAD,UAAAE,EALjB,WAAAC,CAAAC,G,4GAQ2BC,KAAAC,KAAgB,MACjCD,KAAAE,MAAwB,GACxBF,KAAAG,SAA0B,GAC1BH,KAAAI,KAAiB,SACjBJ,KAAAK,MAAmB,QACnBL,KAAAM,WAAqB,EACrBN,KAAAO,YAAsB,EAQbP,KAAAQ,aAAwB,MACxBR,KAAAS,QAAmB,MACnBT,KAAAU,IAAgC,CAAEC,EAAG,EAAGC,EAAG,GAC3CZ,KAAAa,aAAuB,EACvBb,KAAAc,cAAyB,MAKlCd,KAAAe,oBAAwD,KACxDf,KAAAgB,oBAA2C,KAC3ChB,KAAAiB,WAAmD,KACnDjB,KAAAkB,QAAyB,EAyRlC,CAvRC,gBAAAC,GACE,GAAInB,KAAKC,KAAMD,KAAKoB,aAAa,K,CAGnC,oBAAAC,GACErB,KAAKsB,mB,CAIP,YAAAF,CAAaG,GACX,GAAIA,EAAQ,CACVvB,KAAKQ,aAAe,KACpBR,KAAKS,QAAU,MACfT,KAAKc,cAAgB,MACrBU,uBAAsB,KACpBxB,KAAKyB,oBACLzB,KAAKc,cAAgB,KACrBd,KAAK0B,mBACL1B,KAAK2B,gBAAgB,G,MAElB,GAAI3B,KAAKQ,aAAc,CAC5BR,KAAKS,QAAU,KACfT,KAAKsB,oBACLtB,KAAKiB,WAAaW,YAAW,KAC3B5B,KAAKQ,aAAe,MACpBR,KAAKS,QAAU,MACfT,KAAKiB,WAAa,IAAI,GACrBxB,E,EAIP,kBAAYoC,GACV,GAAI7B,KAAK8B,OAAQ,OAAO9B,KAAK8B,OAC7B,GAAI9B,KAAK+B,SAAU,OAAOC,SAASC,eAAejC,KAAK+B,UACvD,OAAO,I,CAGT,kBAAYG,GACV,GAAIlC,KAAKG,SAASgC,OAAS,EAAG,OAAOnC,KAAKG,SAC1C,GAAIH,KAAKE,MAAMiC,OAAS,EAAG,MAAO,CAAC,CAAEjC,MAAOF,KAAKE,QACjD,MAAO,E,CAGT,aAAYkC,GACV,OAAOpC,KAAKkC,eAAeG,SAAQC,GAAKA,EAAEpC,O,CAGpC,iBAAAuB,GACN,MAAMc,EAAWvC,KAAK6B,eACtB,IAAKU,EAAU,OACf,MAAMC,EAAQxC,KAAKyC,GAAGC,cAAc,eACpC,IAAKF,EAAO,OAEZ,MAAMG,EAAIJ,EAASK,wBACnB,MAAMC,EAAKL,EAAMM,aAAe,IAChC,MAAMC,EAAKP,EAAMQ,cAAgB,IACjC,IAAIrC,EAAI,EAAGC,EAAI,EAEf,OAAQZ,KAAKI,MACX,IAAK,MACHQ,EAAI+B,EAAEM,IAAMF,EAAK/C,KAAKM,WACtBK,EAAIX,KAAKK,QAAU,QAAUsC,EAAEO,KAAOlD,KAAKO,YACvCP,KAAKK,QAAU,MAAQsC,EAAEQ,MAAQN,EAAK7C,KAAKO,YAC3CoC,EAAEO,KAAOP,EAAES,MAAQ,EAAIP,EAAK,EAAI7C,KAAKO,YACzC,MACF,IAAK,SACHK,EAAI+B,EAAEU,OAASrD,KAAKM,WACpBK,EAAIX,KAAKK,QAAU,QAAUsC,EAAEO,KAAOlD,KAAKO,YACvCP,KAAKK,QAAU,MAAQsC,EAAEQ,MAAQN,EAAK7C,KAAKO,YAC3CoC,EAAEO,KAAOP,EAAES,MAAQ,EAAIP,EAAK,EAAI7C,KAAKO,YACzC,MACF,IAAK,OACHI,EAAIgC,EAAEO,KAAOL,EAAK7C,KAAKM,WACvBM,EAAIZ,KAAKK,QAAU,QAAUsC,EAAEM,IAAMjD,KAAKO,YACtCP,KAAKK,QAAU,MAAQsC,EAAEU,OAASN,EAAK/C,KAAKO,YAC5CoC,EAAEM,IAAMN,EAAEW,OAAS,EAAIP,EAAK,EAAI/C,KAAKO,YACzC,MACF,IAAK,QACHI,EAAIgC,EAAEQ,MAAQnD,KAAKM,WACnBM,EAAIZ,KAAKK,QAAU,QAAUsC,EAAEM,IAAMjD,KAAKO,YACtCP,KAAKK,QAAU,MAAQsC,EAAEU,OAASN,EAAK/C,KAAKO,YAC5CoC,EAAEM,IAAMN,EAAEW,OAAS,EAAIP,EAAK,EAAI/C,KAAKO,YACzC,MAGJP,KAAKU,IAAM,CACTC,EAAG4C,KAAKC,IAAID,KAAKE,IAAI9C,EAAGjB,GAASgE,OAAOC,WAAad,EAAKnD,GAC1DkB,EAAG2C,KAAKC,IAAID,KAAKE,IAAI7C,EAAGlB,GAASgE,OAAOE,YAAcb,EAAKrD,G,CAKvD,gBAAAgC,GACN,MAAMmC,EAAO7D,KAAKoC,UAClB,MAAM0B,EAAcD,EAAKE,WAAUC,GAAMA,EAAGC,aAAeD,EAAGE,aAC9D,MAAMC,EAAkBN,EAAKE,WAAUC,IAAOA,EAAGE,aACjDlE,KAAKa,aAAeiD,GAAe,EAC/BA,EACCK,GAAmB,EAAIA,EAAkB,EAE9C3C,uBAAsB,KACpB,MAAM4C,EAAOpE,KAAKyC,GAAG4B,iBAA8B,cACnDD,EAAKpE,KAAKa,eAAeyD,OAAO,G,CAI5B,cAAA3C,GACN3B,KAAKe,oBAAuBwD,IAC1B,MAAMC,EAAID,EAAEE,OACZ,MAAMjC,EAAQxC,KAAKyC,GAAGC,cAAc,eACpC,MAAMH,EAAWvC,KAAK6B,eACtB,GAAIW,GAAOkC,SAASF,IAAMjC,GAAUmC,SAASF,GAAI,OACjDxE,KAAK2E,OAAO,EAGd3E,KAAKgB,oBAAsB,IAAMhB,KAAKyB,oBAEtCO,SAAS4C,iBAAiB,YAAa5E,KAAKe,oBAAqB,MACjE2C,OAAOkB,iBAAiB,SAAU5E,KAAKgB,oBAAqB,MAC5D0C,OAAOkB,iBAAiB,SAAU5E,KAAKgB,oB,CAGjC,iBAAAM,GACN,GAAItB,KAAKe,oBAAqB,CAC5BiB,SAAS6C,oBAAoB,YAAa7E,KAAKe,oBAAqB,MACpEf,KAAKe,oBAAsB,I,CAE7B,GAAIf,KAAKgB,oBAAqB,CAC5B0C,OAAOmB,oBAAoB,SAAU7E,KAAKgB,oBAAqB,MAC/D0C,OAAOmB,oBAAoB,SAAU7E,KAAKgB,qBAC1ChB,KAAKgB,oBAAsB,I,CAE7B,GAAIhB,KAAKiB,WAAY,CACnB6D,aAAa9E,KAAKiB,YAClBjB,KAAKiB,WAAa,I,EAId,KAAA0D,GACN3E,KAAK6B,gBAAgByC,QACrBtE,KAAK+E,QAAQC,OACbhF,KAAKC,KAAO,K,CAId,aAAAgF,CAAcV,GACZ,IAAKvE,KAAKC,KAAM,OAChB,MAAM4D,EAAO7D,KAAKoC,UAClB,MAAM8C,EAAUrB,EAAKsB,KAAI,CAACnB,EAAIoB,KAAC,CAAQpB,KAAIoB,QAAMC,QAAO,EAAGrB,SAAUA,EAAGE,aAAYiB,KAAI,EAAGC,OAAQA,IACnG,IAAKF,EAAQ/C,OAAQ,OAErB,MAAMmD,EAAMJ,EAAQK,QAAQvF,KAAKa,cACjC,MAAM2E,EAAOF,EAAM,EAAI,EAAIA,EAE3B,OAAQf,EAAEkB,KACR,IAAK,YACHlB,EAAEmB,iBAAkBnB,EAAEoB,kBACtB3F,KAAKa,aAAeqE,GAASM,EAAO,GAAKN,EAAQ/C,QACjDnC,KAAK4F,UAAU5F,KAAKa,cACpB,MACF,IAAK,UACH0D,EAAEmB,iBAAkBnB,EAAEoB,kBACtB3F,KAAKa,aAAeqE,GAASM,EAAO,EAAIN,EAAQ/C,QAAU+C,EAAQ/C,QAClEnC,KAAK4F,UAAU5F,KAAKa,cACpB,MACF,IAAK,OACH0D,EAAEmB,iBAAkBnB,EAAEoB,kBACtB3F,KAAKa,aAAeqE,EAAQ,GAC5BlF,KAAK4F,UAAU5F,KAAKa,cACpB,MACF,IAAK,MACH0D,EAAEmB,iBAAkBnB,EAAEoB,kBACtB3F,KAAKa,aAAeqE,EAAQA,EAAQ/C,OAAS,GAC7CnC,KAAK4F,UAAU5F,KAAKa,cACpB,MACF,IAAK,SACH0D,EAAEmB,iBACF1F,KAAK2E,QACL,MACF,IAAK,MACHJ,EAAEmB,iBACF1F,KAAK2E,QACL,M,CAIE,SAAAiB,CAAUC,GAChB,MAAMzB,EAAOpE,KAAKyC,GAAG4B,iBAA8B,cACnDD,EAAKyB,IAAMvB,O,CAGL,eAAAwB,CAAgBC,GACtB,GAAIA,EAAK7B,WAAY,OACrBlE,KAAKgG,SAAShB,KAAKe,GACnB/F,KAAK2E,O,CAGP,MAAAsB,GACE,IAAKjG,KAAKQ,aAAc,OAAO0F,EAACC,EAAI,CAACC,MAAO,CAAEC,QAAS,cAEvD,MAAMlG,EAAWH,KAAKkC,eACtB,IAAIoE,EAAU,EAEd,MAAMC,EAAqC,CACzCC,SAAU,QACVtD,KAAM,IACND,IAAK,IACLwD,UAAW,aAAalD,KAAKmD,MAAM1G,KAAKU,IAAIC,SAAS4C,KAAKmD,MAAM1G,KAAKU,IAAIE,QACzE+F,OAAQ,OACRC,WAAY5G,KAAKc,cAAgB,UAAY,UAG/C,GAAId,KAAK6G,UAAWN,EAAW,SAAWvG,KAAK6G,UAC/C,GAAI7G,KAAK8G,SAAUP,EAAW,aAAevG,KAAK8G,SAElD,OACEZ,EAACC,EAAI,CAACC,MAAO,CAAEC,QAAS,aACtBH,EAAA,OACEa,MAAO,CAAE,aAAc,KAAM,sBAAuB/G,KAAKS,SACzD2F,MAAOG,EACPS,KAAK,OAAM,aACA,OAAM,mBACA,YAEhB7G,EAASgF,KAAI,CAAC8B,EAASC,IACtBhB,EAAA,OACET,IAAKyB,EACLH,MAAO,CAAE,eAAgB,KAAM,wBAAyBG,EAAK/G,EAASgC,OAAS,GAC/E6E,KAAMC,EAAQE,OAAS,QAAUC,UAAS,aAC9BH,EAAQE,QAEnBF,EAAQE,QACPjB,EAAA,OAAKa,MAAM,iBAAgB,cAAa,QACtCb,EAAA,QAAMa,MAAM,0CAA0CE,EAAQE,SAGjEF,EAAQ/G,MAAMiF,KAAIY,IACjB,MAAMF,EAAMS,IACZ,MAAMe,EAAYrH,KAAKa,eAAiBgF,EACxC,OACEK,EAAA,UACET,IAAKI,EACLyB,KAAK,SACLP,MAAO,CACL,YAAa,KACb,wBAAyBhB,EAAK9B,WAC9B,wBAAyB8B,EAAK7B,WAC9B,2BAA4B6B,EAAKwB,cACjC,qBAAsBF,GAExBL,KAAK,WAAU,eACDjB,EAAK9B,WAAa,OAASmD,UACzCI,SAAUzB,EAAK7B,WACfuD,SAAUJ,EAAY,GAAI,EAC1BK,QAAS,IAAM1H,KAAK8F,gBAAgBC,GACpC4B,QAAS,KAAQ3H,KAAKa,aAAegF,CAAG,GAExCK,EAAA,OAAKa,MAAM,sBACTb,EAAA,QAAMa,MAAOhB,EAAK9B,WAAa,6CAA+C,qCAC3E8B,EAAK6B,OAEP7B,EAAK8B,SACJ3B,EAAA,QAAMa,MAAM,sCAAsChB,EAAK8B,UAG1D9B,EAAK+B,YACJ5B,EAAA,OAAKa,MAAO,CAAE,oBAAqB,KAAM,0BAA2BhB,EAAKgC,aAAa,cAAc,QAClG7B,EAAA,OAAKa,MAAM,6BAGR,Q","ignoreList":[]}
@@ -1,2 +0,0 @@
1
- const t="ds-shell-bar-nav";const n="ds-shell-nav-vt-style";function o(t,n){const o=t.trim();const e=parseFloat(o);if(Number.isNaN(e))return n;if(/ms\s*$/.test(o))return e;if(/s\s*$/.test(o))return e*1e3;return e}function e(){if(typeof document==="undefined")return;if(document.getElementById(n))return;const o=document.createElement("style");o.id=n;o.textContent=["::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}",`::view-transition-old(${t}),::view-transition-new(${t}){animation:none;mix-blend-mode:normal}`,"::view-transition-new(root){clip-path:circle(0px at var(--vt-x,50%) var(--vt-y,50%))}",`::view-transition-new(${t}){clip-path:circle(0px at var(--vt-x,50%) var(--vt-y,50%))}`].join("\n");document.head.appendChild(o)}function i(t){const n=t??document.querySelector(".panel-nav__footer-btn");const o=n?.getBoundingClientRect();const e=o?Math.round(o.left+o.width/2):Math.round(window.innerWidth/2);const i=o?Math.round(o.top+o.height/2):Math.round(window.innerHeight/2);const a=Math.ceil(Math.hypot(Math.max(e,window.innerWidth-e),Math.max(i,window.innerHeight-i)));return{x:e,y:i,maxRadius:a}}function a(t){document.documentElement.style.setProperty("--vt-x",`${t.x}px`);document.documentElement.style.setProperty("--vt-y",`${t.y}px`)}function r(n,e){const i=getComputedStyle(document.documentElement).getPropertyValue("--effect-animation-duration-long-1").trim();const a=o(i,750);const r={clipPath:[`circle(0px at ${n.x}px ${n.y}px)`,`circle(${n.maxRadius}px at ${n.x}px ${n.y}px)`]};const s={duration:a,easing:"ease-in-out",fill:"forwards"};document.documentElement.animate(r,{...s,pseudoElement:"::view-transition-new(root)"});document.documentElement.animate(r,{...s,pseudoElement:`::view-transition-new(${t})`})}export{t as S,r as a,e,i as r,a as s};
2
- //# sourceMappingURL=p-DznbYg1m.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["SHELL_BAR_NAV_VT_NAME","VT_STYLE_ID","parseCssTimeMs","value","fallback","v","trim","num","parseFloat","Number","isNaN","test","ensureShellNavVtStyle","document","getElementById","style","createElement","id","textContent","join","head","appendChild","resolveShellNavRevealOrigin","originEl","btn","querySelector","rect","getBoundingClientRect","x","Math","round","left","width","window","innerWidth","y","top","height","innerHeight","maxRadius","ceil","hypot","max","setShellNavRevealOriginVars","origin","documentElement","setProperty","animateShellNavRadialReveal","durationMs","durToken","getComputedStyle","getPropertyValue","duration","keyframes","clipPath","options","easing","fill","animate","pseudoElement"],"sources":["src/wc/nav/shell-view-transition.ts"],"sourcesContent":["/** `view-transition-name` on `ds-bar-nav` — pairs with root reveal in shell apps. */\nexport const SHELL_BAR_NAV_VT_NAME = 'ds-shell-bar-nav';\n\nconst VT_STYLE_ID = 'ds-shell-nav-vt-style';\n\n/** Parse a CSS <time> value to milliseconds. */\nexport function parseCssTimeMs(value: string, fallback: number): number {\n const v = value.trim();\n const num = parseFloat(v);\n if (Number.isNaN(num)) return fallback;\n if (/ms\\s*$/.test(v)) return num;\n if (/s\\s*$/.test(v)) return num * 1000;\n return num;\n}\n\n/** Suppress default cross-fade and pin new snapshots to a 0px circle for WAAPI reveal. */\nexport function ensureShellNavVtStyle(): void {\n if (typeof document === 'undefined') return;\n if (document.getElementById(VT_STYLE_ID)) return;\n\n const style = document.createElement('style');\n style.id = VT_STYLE_ID;\n style.textContent = [\n '::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}',\n `::view-transition-old(${SHELL_BAR_NAV_VT_NAME}),::view-transition-new(${SHELL_BAR_NAV_VT_NAME}){animation:none;mix-blend-mode:normal}`,\n '::view-transition-new(root){clip-path:circle(0px at var(--vt-x,50%) var(--vt-y,50%))}',\n `::view-transition-new(${SHELL_BAR_NAV_VT_NAME}){clip-path:circle(0px at var(--vt-x,50%) var(--vt-y,50%))}`,\n ].join('\\n');\n document.head.appendChild(style);\n}\n\nexport interface ShellNavRevealOrigin {\n x: number;\n y: number;\n maxRadius: number;\n}\n\n/** Origin for the radial reveal — defaults to panel-nav footer gear, then viewport center. */\nexport function resolveShellNavRevealOrigin(originEl?: HTMLElement | null): ShellNavRevealOrigin {\n const btn =\n originEl ??\n document.querySelector<HTMLElement>('.panel-nav__footer-btn');\n const rect = btn?.getBoundingClientRect();\n const x = rect ? Math.round(rect.left + rect.width / 2) : Math.round(window.innerWidth / 2);\n const y = rect ? Math.round(rect.top + rect.height / 2) : Math.round(window.innerHeight / 2);\n const maxRadius = Math.ceil(\n Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y)),\n );\n return { x, y, maxRadius };\n}\n\nexport function setShellNavRevealOriginVars(origin: ShellNavRevealOrigin): void {\n document.documentElement.style.setProperty('--vt-x', `${origin.x}px`);\n document.documentElement.style.setProperty('--vt-y', `${origin.y}px`);\n}\n\n/** Animate root + bar-nav snapshots with the same radial clip-path reveal. */\nexport function animateShellNavRadialReveal(\n origin: ShellNavRevealOrigin,\n durationMs?: number,\n): void {\n const durToken = getComputedStyle(document.documentElement)\n .getPropertyValue('--effect-animation-duration-long-1')\n .trim();\n const duration = durationMs ?? parseCssTimeMs(durToken, 750);\n const keyframes = {\n clipPath: [\n `circle(0px at ${origin.x}px ${origin.y}px)`,\n `circle(${origin.maxRadius}px at ${origin.x}px ${origin.y}px)`,\n ],\n };\n const options = {\n duration,\n easing: 'ease-in-out',\n fill: 'forwards' as const,\n };\n\n document.documentElement.animate(keyframes, {\n ...options,\n pseudoElement: '::view-transition-new(root)',\n });\n document.documentElement.animate(keyframes, {\n ...options,\n pseudoElement: `::view-transition-new(${SHELL_BAR_NAV_VT_NAME})`,\n });\n}\n\n/** Run radial reveal when a view transition's `ready` promise settles (app/router driver). */\nexport function runShellNavStyleRevealOnReady(\n transition: { ready: Promise<void> },\n originEl?: HTMLElement | null,\n): void {\n ensureShellNavVtStyle();\n const origin = resolveShellNavRevealOrigin(originEl);\n setShellNavRevealOriginVars(origin);\n\n transition.ready\n .then(() => animateShellNavRadialReveal(origin))\n .catch(() => {\n /* transition skipped or superseded */\n });\n}\n"],"mappings":"AACO,MAAMA,EAAwB,mBAErC,MAAMC,EAAc,wBAGd,SAAUC,EAAeC,EAAeC,GAC5C,MAAMC,EAAIF,EAAMG,OAChB,MAAMC,EAAMC,WAAWH,GACvB,GAAII,OAAOC,MAAMH,GAAM,OAAOH,EAC9B,GAAI,SAASO,KAAKN,GAAI,OAAOE,EAC7B,GAAI,QAAQI,KAAKN,GAAI,OAAOE,EAAM,IAClC,OAAOA,CACT,C,SAGgBK,IACd,UAAWC,WAAa,YAAa,OACrC,GAAIA,SAASC,eAAeb,GAAc,OAE1C,MAAMc,EAAQF,SAASG,cAAc,SACrCD,EAAME,GAAKhB,EACXc,EAAMG,YAAc,CAClB,gGACA,yBAAyBlB,4BAAgDA,2CACzE,wFACA,yBAAyBA,gEACzBmB,KAAK,MACPN,SAASO,KAAKC,YAAYN,EAC5B,CASM,SAAUO,EAA4BC,GAC1C,MAAMC,EACJD,GACAV,SAASY,cAA2B,0BACtC,MAAMC,EAAOF,GAAKG,wBAClB,MAAMC,EAAIF,EAAOG,KAAKC,MAAMJ,EAAKK,KAAOL,EAAKM,MAAQ,GAAKH,KAAKC,MAAMG,OAAOC,WAAa,GACzF,MAAMC,EAAIT,EAAOG,KAAKC,MAAMJ,EAAKU,IAAMV,EAAKW,OAAS,GAAKR,KAAKC,MAAMG,OAAOK,YAAc,GAC1F,MAAMC,EAAYV,KAAKW,KACrBX,KAAKY,MAAMZ,KAAKa,IAAId,EAAGK,OAAOC,WAAaN,GAAIC,KAAKa,IAAIP,EAAGF,OAAOK,YAAcH,KAElF,MAAO,CAAEP,IAAGO,IAAGI,YACjB,CAEM,SAAUI,EAA4BC,GAC1C/B,SAASgC,gBAAgB9B,MAAM+B,YAAY,SAAU,GAAGF,EAAOhB,OAC/Df,SAASgC,gBAAgB9B,MAAM+B,YAAY,SAAU,GAAGF,EAAOT,MACjE,CAGM,SAAUY,EACdH,EACAI,GAEA,MAAMC,EAAWC,iBAAiBrC,SAASgC,iBACxCM,iBAAiB,sCACjB7C,OACH,MAAM8C,EAAyBlD,EAAe+C,EAAU,KACxD,MAAMI,EAAY,CAChBC,SAAU,CACR,iBAAiBV,EAAOhB,OAAOgB,EAAOT,OACtC,UAAUS,EAAOL,kBAAkBK,EAAOhB,OAAOgB,EAAOT,SAG5D,MAAMoB,EAAU,CACdH,WACAI,OAAQ,cACRC,KAAM,YAGR5C,SAASgC,gBAAgBa,QAAQL,EAAW,IACvCE,EACHI,cAAe,gCAEjB9C,SAASgC,gBAAgBa,QAAQL,EAAW,IACvCE,EACHI,cAAe,yBAAyB3D,MAE5C,Q","ignoreList":[]}
@@ -1,2 +0,0 @@
1
- import{p as o,H as e,c as n,h as s,a as t,t as r}from"./index.js";import{d as i}from"./p-DqBCQRRd.js";const a=()=>`.toggle-btn.sc-ds-toggle-button{display:inline-flex;align-items:center;justify-content:center;border:none;border-radius:var(--dimension-radius-050);cursor:pointer;position:relative;transition:transform var(--effect-motion-short-2);height:var(--dimension-size-400);font-family:inherit;background:transparent;box-sizing:border-box;-webkit-user-select:none;user-select:none;--_hover-bg:var(--color-interaction-hover);--_pressed-bg:var(--color-interaction-pressed);--_border:var(--color-border-tertiary)}.toggle-btn.sc-ds-toggle-button:focus-visible{outline:var(--dimension-stroke-width-025) solid var(--color-interaction-focus);outline-offset:var(--dimension-space-025)}.toggle-btn.sc-ds-toggle-button:hover:not(.inactive){background-color:var(--_hover-bg)}.toggle-btn.sc-ds-toggle-button:active:not(.inactive){background-color:var(--_pressed-bg);transform:scale(var(--dimension-scale-subtle))}.onMedium.sc-ds-toggle-button{--_hover-bg:var(--color-interaction-on-medium-background-hover);--_pressed-bg:var(--color-interaction-on-medium-background-pressed);--_border:var(--color-border-on-medium-background-tertiary)}.onBold.sc-ds-toggle-button{--_hover-bg:var(--color-interaction-on-bold-background-hover);--_pressed-bg:var(--color-interaction-on-bold-background-pressed);--_border:var(--color-border-on-bold-background-tertiary)}.onStrong.sc-ds-toggle-button{--_hover-bg:var(--color-interaction-on-strong-background-hover);--_pressed-bg:var(--color-interaction-on-strong-background-pressed);--_border:var(--color-border-on-strong-background-tertiary)}.onAlwaysDark.sc-ds-toggle-button{--_hover-bg:var(--color-always-dark-interaction-hover);--_pressed-bg:var(--color-always-dark-interaction-pressed);--_border:var(--color-always-dark-border-tertiary)}.elevationElevated.sc-ds-toggle-button{background-color:var(--color-background-primary);box-shadow:var(--effect-elevation-elevated-sm);color:var(--color-foreground-secondary);--_hover-bg:color-mix(in oklch, var(--color-background-primary) 90%, var(--color-foreground-primary));--_pressed-bg:color-mix(in oklch, var(--color-background-primary) 85%, var(--color-foreground-primary))}.elevationFlat.sc-ds-toggle-button{box-shadow:inset 0 0 0 1px var(--_border);color:var(--color-foreground-secondary)}.elevationNone.sc-ds-toggle-button{color:var(--color-foreground-secondary)}.elevationFloating.sc-ds-toggle-button{background-color:var(--color-background-primary);box-shadow:var(--effect-elevation-elevated-floating);color:var(--color-foreground-secondary);--_hover-bg:color-mix(in oklch, var(--color-background-primary) 90%, var(--color-foreground-primary));--_pressed-bg:color-mix(in oklch, var(--color-background-primary) 85%, var(--color-foreground-primary))}.onBold.elevationNone.sc-ds-toggle-button,.onBold.elevationFlat.sc-ds-toggle-button,.onStrong.elevationNone.sc-ds-toggle-button,.onStrong.elevationFlat.sc-ds-toggle-button{color:var(--color-foreground-on-bold-background-secondary)}.onAlwaysDark.elevationNone.sc-ds-toggle-button,.onAlwaysDark.elevationFlat.sc-ds-toggle-button{color:var(--color-always-dark-foreground-secondary)}.pressed.sc-ds-toggle-button{background-color:var(--color-background-faint-brand);color:var(--color-foreground-bold-brand)}.iconOnly.sc-ds-toggle-button{padding:0;width:var(--dimension-size-400);min-width:var(--dimension-size-400)}.labelOnly.sc-ds-toggle-button{padding:0 var(--dimension-space-100)}.iconAndLabel.sc-ds-toggle-button{padding:0 var(--dimension-space-100) 0 var(--dimension-space-075);gap:var(--dimension-space-025)}.sizeSM.sc-ds-toggle-button{height:var(--dimension-size-300)}.sizeSM.iconOnly.sc-ds-toggle-button{width:var(--dimension-size-300);min-width:var(--dimension-size-300)}.sizeSM.labelOnly.sc-ds-toggle-button{padding:0 var(--dimension-space-075)}.sizeSM.iconAndLabel.sc-ds-toggle-button{padding:0 var(--dimension-space-075) 0 var(--dimension-space-050);gap:0}.sizeXS.sc-ds-toggle-button{height:var(--dimension-size-200)}.sizeXS.iconOnly.sc-ds-toggle-button{width:var(--dimension-size-200);min-width:var(--dimension-size-200)}.sizeXS.labelOnly.sc-ds-toggle-button,.sizeXS.iconAndLabel.sc-ds-toggle-button{padding:0 var(--dimension-space-025);gap:0}.rounded.sc-ds-toggle-button{border-radius:var(--dimension-radius-half)}.rounded.labelOnly.sc-ds-toggle-button{padding-left:calc(var(--dimension-space-100) + var(--dimension-space-050));padding-right:calc(var(--dimension-space-100) + var(--dimension-space-050))}.rounded.iconAndLabel.sc-ds-toggle-button{padding-left:calc(var(--dimension-space-075) + var(--dimension-space-050));padding-right:calc(var(--dimension-space-100) + var(--dimension-space-050))}.rounded.sizeSM.labelOnly.sc-ds-toggle-button{padding-left:calc(var(--dimension-space-075) + var(--dimension-space-050));padding-right:calc(var(--dimension-space-075) + var(--dimension-space-050))}.rounded.sizeSM.iconAndLabel.sc-ds-toggle-button{padding-left:calc(var(--dimension-space-050) + var(--dimension-space-050));padding-right:calc(var(--dimension-space-075) + var(--dimension-space-050))}.rounded.iconOnly.sc-ds-toggle-button{width:var(--dimension-size-400);min-width:var(--dimension-size-400);padding:0}.rounded.sizeSM.iconOnly.sc-ds-toggle-button{width:var(--dimension-size-300);min-width:var(--dimension-size-300)}.rounded.sizeXS.iconOnly.sc-ds-toggle-button{width:var(--dimension-size-200);min-width:var(--dimension-size-200)}.inactive.sc-ds-toggle-button{opacity:0.5;cursor:not-allowed;pointer-events:none}.toggle-btn__icon.sc-ds-toggle-button{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;line-height:0}.toggle-btn__label.sc-ds-toggle-button{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}`;const d={md:"md",sm:"sm",xs:"xs"};const c={md:20,sm:16,xs:12};const l={md:"text-body-medium-emphasis",sm:"text-body-small-emphasis",xs:"text-caption-emphasis"};const g=o(class o extends e{constructor(o){super();if(o!==false){this.__registerHost()}this.dsChange=n(this,"dsChange");this.elevation="elevated";this.size="md";this.rounded=false;this.pressed=false;this.inactive=false;this.handleClick=()=>{if(this.inactive)return;this.dsChange.emit(!this.pressed)}}render(){const o=this.size;const e=d[o];const n=c[o];const r=l[o];const i=!!this.icon;const a=!!this.label;const g=i&&!a;const b=a&&!i;const u=i&&a;const v=this.background;const m=this.elevation.charAt(0).toUpperCase()+this.elevation.slice(1);const p={"toggle-btn":true,[`elevation${m}`]:true,sizeSM:o==="sm",sizeXS:o==="xs",rounded:this.rounded,inactive:this.inactive,pressed:this.pressed,iconOnly:g,labelOnly:b,iconAndLabel:u,onMedium:v==="medium",onBold:v==="bold",onStrong:v==="strong",onAlwaysDark:v==="always-dark"};return s(t,{key:"9244d2daba16db780469f8e2b91ee4200a580bd1"},s("button",{key:"92fb4bf31f1fcf79f391630ff1ab8d1689fe5e86",type:"button",class:p,disabled:this.inactive,"aria-label":this.ariaLabel??this.label??"toggle","aria-pressed":this.pressed,onClick:this.handleClick},i&&s("span",{key:"115361d90ec5e1416c57b1939ae5cb3dfa6ecca2",class:"toggle-btn__icon",style:{fontSize:`${n}px`}},s("ds-icon",{key:"134fd161500b3d70a61416d68f663041db80dbe2",name:this.icon,size:e})),a&&s("span",{key:"cc3cea62d81535c119ab08ec40cd49810196514e",class:`toggle-btn__label ${r}`},this.label)))}static get style(){return a()}},[2,"ds-toggle-button",{elevation:[1],label:[1],icon:[1],size:[1],rounded:[4],background:[1],pressed:[1028],inactive:[4],ariaLabel:[1,"aria-label"]}]);function b(){if(typeof customElements==="undefined"){return}const o=["ds-toggle-button","ds-icon"];o.forEach((o=>{switch(o){case"ds-toggle-button":if(!customElements.get(r(o))){customElements.define(r(o),g)}break;case"ds-icon":if(!customElements.get(r(o))){i()}break}}))}b();export{g as T,b as d};
2
- //# sourceMappingURL=p-uMN1Ppw2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["toggleButtonCss","ICON_SIZE","md","sm","xs","ICON_PX","TEXT_CLASS","ToggleButton","__stencil_proxyCustomElement","HTMLElement","constructor","registerHost","this","elevation","size","rounded","pressed","inactive","handleClick","dsChange","emit","render","iconSize","iconPx","textClass","hasIcon","icon","hasLabel","label","isIconOnly","isLabelOnly","isIconAndLabel","bg","background","elevKey","charAt","toUpperCase","slice","cls","sizeSM","sizeXS","iconOnly","labelOnly","iconAndLabel","onMedium","onBold","onStrong","onAlwaysDark","h","Host","key","type","class","disabled","ariaLabel","onClick","style","fontSize","name"],"sources":["src/wc/components/ToggleButton/ToggleButton.css?tag=ds-toggle-button&encapsulation=scoped","src/wc/components/ToggleButton/ToggleButton.tsx"],"sourcesContent":["/* ==========================================================================\n ToggleButton — hover/pressed via direct background-color + color-mix().\n Elevation controls the chrome level:\n elevated — bg-primary + shadow (default)\n flat — border only\n none — ghost (transparent, no border, no shadow)\n floating — bg-primary + FAB-strength shadow\n ========================================================================== */\n\n.toggle-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--dimension-radius-050);\n cursor: pointer;\n position: relative;\n transition: transform var(--effect-motion-short-2);\n height: var(--dimension-size-400);\n font-family: inherit;\n background: transparent;\n box-sizing: border-box;\n -webkit-user-select: none;\n user-select: none;\n\n /* Interaction — ghost defaults */\n --_hover-bg: var(--color-interaction-hover);\n --_pressed-bg: var(--color-interaction-pressed);\n --_border: var(--color-border-tertiary);\n}\n\n.toggle-btn:focus-visible {\n outline: var(--dimension-stroke-width-025) solid var(--color-interaction-focus);\n outline-offset: var(--dimension-space-025);\n}\n\n.toggle-btn:hover:not(.inactive) {\n background-color: var(--_hover-bg);\n}\n\n.toggle-btn:active:not(.inactive) {\n background-color: var(--_pressed-bg);\n transform: scale(var(--dimension-scale-subtle));\n}\n\n/* ==========================================================================\n Background context — parent surface awareness\n ========================================================================== */\n\n.onMedium {\n --_hover-bg: var(--color-interaction-on-medium-background-hover);\n --_pressed-bg: var(--color-interaction-on-medium-background-pressed);\n --_border: var(--color-border-on-medium-background-tertiary);\n}\n\n.onBold {\n --_hover-bg: var(--color-interaction-on-bold-background-hover);\n --_pressed-bg: var(--color-interaction-on-bold-background-pressed);\n --_border: var(--color-border-on-bold-background-tertiary);\n}\n\n.onStrong {\n --_hover-bg: var(--color-interaction-on-strong-background-hover);\n --_pressed-bg: var(--color-interaction-on-strong-background-pressed);\n --_border: var(--color-border-on-strong-background-tertiary);\n}\n\n.onAlwaysDark {\n --_hover-bg: var(--color-always-dark-interaction-hover);\n --_pressed-bg: var(--color-always-dark-interaction-pressed);\n --_border: var(--color-always-dark-border-tertiary);\n}\n\n/* ==========================================================================\n Elevation levels\n ========================================================================== */\n\n/* ── Elevated (default): bg-primary + shadow ───────────────────────────── */\n\n.elevationElevated {\n background-color: var(--color-background-primary);\n box-shadow: var(--effect-elevation-elevated-sm);\n color: var(--color-foreground-secondary);\n --_hover-bg: color-mix(in oklch, var(--color-background-primary) 90%, var(--color-foreground-primary));\n --_pressed-bg: color-mix(in oklch, var(--color-background-primary) 85%, var(--color-foreground-primary));\n}\n\n/* ── Flat: border only, transparent bg ─────────────────────────────────── */\n\n.elevationFlat {\n box-shadow: inset 0 0 0 1px var(--_border);\n color: var(--color-foreground-secondary);\n}\n\n/* ── None: ghost — transparent, no border, no shadow ───────────────────── */\n\n.elevationNone {\n color: var(--color-foreground-secondary);\n}\n\n/* ── Floating: bg-primary + FAB-strength shadow ─────────────────────────── */\n\n.elevationFloating {\n background-color: var(--color-background-primary);\n box-shadow: var(--effect-elevation-elevated-floating);\n color: var(--color-foreground-secondary);\n --_hover-bg: color-mix(in oklch, var(--color-background-primary) 90%, var(--color-foreground-primary));\n --_pressed-bg: color-mix(in oklch, var(--color-background-primary) 85%, var(--color-foreground-primary));\n}\n\n/* ── Fg on bold / strong surface ────────────────────────────────────────── */\n\n.onBold.elevationNone, .onBold.elevationFlat,\n.onStrong.elevationNone, .onStrong.elevationFlat {\n color: var(--color-foreground-on-bold-background-secondary);\n}\n\n/* ── Fg on always-dark surface ─────────────────────────────────────────── */\n\n.onAlwaysDark.elevationNone, .onAlwaysDark.elevationFlat {\n color: var(--color-always-dark-foreground-secondary);\n}\n\n/* ==========================================================================\n Pressed state — shared across all elevation levels\n ========================================================================== */\n\n.pressed {\n background-color: var(--color-background-faint-brand);\n color: var(--color-foreground-bold-brand);\n}\n\n/* ==========================================================================\n Layout\n ========================================================================== */\n\n.iconOnly { padding: 0; width: var(--dimension-size-400); min-width: var(--dimension-size-400); }\n.labelOnly { padding: 0 var(--dimension-space-100); }\n.iconAndLabel { padding: 0 var(--dimension-space-100) 0 var(--dimension-space-075); gap: var(--dimension-space-025); }\n\n/* ==========================================================================\n Sizes\n ========================================================================== */\n\n.sizeSM { height: var(--dimension-size-300); }\n.sizeSM.iconOnly { width: var(--dimension-size-300); min-width: var(--dimension-size-300); }\n.sizeSM.labelOnly { padding: 0 var(--dimension-space-075); }\n.sizeSM.iconAndLabel { padding: 0 var(--dimension-space-075) 0 var(--dimension-space-050); gap: 0; }\n\n.sizeXS { height: var(--dimension-size-200); }\n.sizeXS.iconOnly { width: var(--dimension-size-200); min-width: var(--dimension-size-200); }\n.sizeXS.labelOnly, .sizeXS.iconAndLabel { padding: 0 var(--dimension-space-025); gap: 0; }\n\n/* ==========================================================================\n Rounded (pill shape)\n ========================================================================== */\n\n.rounded { border-radius: var(--dimension-radius-half); }\n.rounded.labelOnly { padding-left: calc(var(--dimension-space-100) + var(--dimension-space-050)); padding-right: calc(var(--dimension-space-100) + var(--dimension-space-050)); }\n.rounded.iconAndLabel { padding-left: calc(var(--dimension-space-075) + var(--dimension-space-050)); padding-right: calc(var(--dimension-space-100) + var(--dimension-space-050)); }\n.rounded.sizeSM.labelOnly { padding-left: calc(var(--dimension-space-075) + var(--dimension-space-050)); padding-right: calc(var(--dimension-space-075) + var(--dimension-space-050)); }\n.rounded.sizeSM.iconAndLabel { padding-left: calc(var(--dimension-space-050) + var(--dimension-space-050)); padding-right: calc(var(--dimension-space-075) + var(--dimension-space-050)); }\n.rounded.iconOnly { width: var(--dimension-size-400); min-width: var(--dimension-size-400); padding: 0; }\n.rounded.sizeSM.iconOnly { width: var(--dimension-size-300); min-width: var(--dimension-size-300); }\n.rounded.sizeXS.iconOnly { width: var(--dimension-size-200); min-width: var(--dimension-size-200); }\n\n/* ==========================================================================\n Disabled\n ========================================================================== */\n\n.inactive { opacity: 0.5; cursor: not-allowed; pointer-events: none; }\n\n/* ==========================================================================\n Inner slots\n ========================================================================== */\n\n.toggle-btn__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n line-height: 0;\n}\n\n.toggle-btn__label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n","import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';\nimport type { IconSize } from '../Icon/Icon';\n\nexport type ToggleButtonElevation = 'none' | 'flat' | 'elevated' | 'floating';\nexport type ToggleButtonSize = 'md' | 'sm' | 'xs';\nexport type ToggleButtonBackground = 'faint' | 'medium' | 'bold' | 'strong' | 'always-dark';\n\nconst ICON_SIZE: Record<ToggleButtonSize, IconSize> = { md: 'md', sm: 'sm', xs: 'xs' };\n\n// Pixel size reference for internal layout (icon span font-size)\nconst ICON_PX: Record<ToggleButtonSize, number> = { md: 20, sm: 16, xs: 12 };\n\nconst TEXT_CLASS: Record<ToggleButtonSize, string> = {\n md: 'text-body-medium-emphasis',\n sm: 'text-body-small-emphasis',\n xs: 'text-caption-emphasis',\n};\n\n@Component({\n tag: 'ds-toggle-button',\n styleUrl: 'ToggleButton.css',\n scoped: true,\n})\nexport class ToggleButton {\n /**\n * Chrome level.\n * none — ghost (transparent, no border, no shadow)\n * flat — border only, transparent bg\n * elevated — bg-primary + shadow [default]\n * floating — bg-primary + FAB-strength shadow\n */\n @Prop() elevation: ToggleButtonElevation = 'elevated';\n\n /** Label text. */\n @Prop() label: string | undefined;\n\n /**\n * Icon name for <ds-icon>. Set via JS property.\n * @example el.icon = 'GridView';\n */\n @Prop() icon: string | undefined;\n\n /** Size: md (32px), sm (24px), xs (16px). */\n @Prop() size: ToggleButtonSize = 'md';\n\n /** Pill shape. */\n @Prop() rounded: boolean = false;\n\n /** Parent surface context — adjusts hover tokens for colored backgrounds. */\n @Prop() background: ToggleButtonBackground | undefined;\n\n /** Controlled pressed state. */\n @Prop({ mutable: true }) pressed: boolean = false;\n\n /** Disables interaction. */\n @Prop() inactive: boolean = false;\n\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | undefined;\n\n /** Emits the new pressed value (!pressed) on click. */\n @Event() dsChange!: EventEmitter<boolean>;\n\n private handleClick = () => {\n if (this.inactive) return;\n this.dsChange.emit(!this.pressed);\n };\n\n render() {\n const size = this.size;\n const iconSize = ICON_SIZE[size];\n const iconPx = ICON_PX[size];\n const textClass = TEXT_CLASS[size];\n const hasIcon = !!this.icon;\n const hasLabel = !!this.label;\n const isIconOnly = hasIcon && !hasLabel;\n const isLabelOnly = hasLabel && !hasIcon;\n const isIconAndLabel = hasIcon && hasLabel;\n const bg = this.background;\n const elevKey = this.elevation.charAt(0).toUpperCase() + this.elevation.slice(1);\n\n const cls: Record<string, boolean> = {\n 'toggle-btn': true,\n [`elevation${elevKey}`]: true,\n sizeSM: size === 'sm',\n sizeXS: size === 'xs',\n rounded: this.rounded,\n inactive: this.inactive,\n pressed: this.pressed,\n iconOnly: isIconOnly,\n labelOnly: isLabelOnly,\n iconAndLabel: isIconAndLabel,\n onMedium: bg === 'medium',\n onBold: bg === 'bold',\n onStrong: bg === 'strong',\n onAlwaysDark: bg === 'always-dark',\n };\n\n return (\n <Host>\n <button\n type=\"button\"\n class={cls}\n disabled={this.inactive}\n aria-label={this.ariaLabel ?? this.label ?? 'toggle'}\n aria-pressed={this.pressed}\n onClick={this.handleClick}\n >\n {hasIcon && (\n <span class=\"toggle-btn__icon\" style={{ fontSize: `${iconPx}px` }}>\n <ds-icon name={this.icon} size={iconSize} />\n </span>\n )}\n {hasLabel && (\n <span class={`toggle-btn__label ${textClass}`}>{this.label}</span>\n )}\n </button>\n </Host>\n );\n }\n}\n"],"mappings":"sGAAA,MAAMA,EAAkB,IAAM,8hLCO9B,MAAMC,EAAgD,CAAEC,GAAI,KAAMC,GAAI,KAAMC,GAAI,MAGhF,MAAMC,EAA4C,CAAEH,GAAI,GAAIC,GAAI,GAAIC,GAAI,IAExE,MAAME,EAA+C,CACnDJ,GAAI,4BACJC,GAAI,2BACJC,GAAI,yB,MAQOG,EAAYC,EAAA,MAAAD,UAAAE,EALzB,WAAAC,CAAAC,G,6EAaUC,KAAAC,UAAmC,WAYnCD,KAAAE,KAAyB,KAGzBF,KAAAG,QAAmB,MAMFH,KAAAI,QAAmB,MAGpCJ,KAAAK,SAAoB,MAOpBL,KAAAM,YAAc,KACpB,GAAIN,KAAKK,SAAU,OACnBL,KAAKO,SAASC,MAAMR,KAAKI,QAAQ,CAuDpC,CApDC,MAAAK,GACE,MAAMP,EAAOF,KAAKE,KAClB,MAAMQ,EAAWrB,EAAUa,GAC3B,MAAMS,EAASlB,EAAQS,GACvB,MAAMU,EAAYlB,EAAWQ,GAC7B,MAAMW,IAAYb,KAAKc,KACvB,MAAMC,IAAaf,KAAKgB,MACxB,MAAMC,EAAaJ,IAAYE,EAC/B,MAAMG,EAAcH,IAAaF,EACjC,MAAMM,EAAiBN,GAAWE,EAClC,MAAMK,EAAKpB,KAAKqB,WAChB,MAAMC,EAAUtB,KAAKC,UAAUsB,OAAO,GAAGC,cAAgBxB,KAAKC,UAAUwB,MAAM,GAE9E,MAAMC,EAA+B,CACnC,aAAc,KACd,CAAC,YAAYJ,KAAY,KACzBK,OAAQzB,IAAS,KACjB0B,OAAQ1B,IAAS,KACjBC,QAASH,KAAKG,QACdE,SAAUL,KAAKK,SACfD,QAASJ,KAAKI,QACdyB,SAAUZ,EACVa,UAAWZ,EACXa,aAAcZ,EACda,SAAUZ,IAAO,SACjBa,OAAQb,IAAO,OACfc,SAAUd,IAAO,SACjBe,aAAcf,IAAO,eAGvB,OACEgB,EAACC,EAAI,CAAAC,IAAA,4CACHF,EAAA,UAAAE,IAAA,2CACEC,KAAK,SACLC,MAAOd,EACPe,SAAUzC,KAAKK,SAAQ,aACXL,KAAK0C,WAAa1C,KAAKgB,OAAS,SAAQ,eACtChB,KAAKI,QACnBuC,QAAS3C,KAAKM,aAEbO,GACCuB,EAAA,QAAAE,IAAA,2CAAME,MAAM,mBAAmBI,MAAO,CAAEC,SAAU,GAAGlC,QACnDyB,EAAA,WAAAE,IAAA,2CAASQ,KAAM9C,KAAKc,KAAMZ,KAAMQ,KAGnCK,GACCqB,EAAA,QAAAE,IAAA,2CAAME,MAAO,qBAAqB5B,KAAcZ,KAAKgB,Q","ignoreList":[]}
@@ -1,29 +0,0 @@
1
- import { EventEmitter } from '../../stencil-public-runtime';
2
- export type SidebarWidth = 'mini' | 'default' | number;
3
- export declare class Sidebar {
4
- el: HTMLElement;
5
- collapsed: boolean;
6
- width: SidebarWidth;
7
- resizable: boolean;
8
- mobile: boolean;
9
- private isResizing;
10
- dsToggle: EventEmitter<void>;
11
- dsWidthChange: EventEmitter<SidebarWidth>;
12
- private triggerEl;
13
- private escapeHandler;
14
- private tabHandler;
15
- private mouseMoveHandler;
16
- private mouseUpHandler;
17
- private get resolvedWidth();
18
- private get isMobileOpen();
19
- onCollapsedChange(): void;
20
- componentDidLoad(): void;
21
- disconnectedCallback(): void;
22
- private setupMobileFocusTrap;
23
- private teardownMobileFocusTrap;
24
- private cleanupMouseHandlers;
25
- private handleResizeMouseDown;
26
- private handleResizeKeyDown;
27
- render(): any;
28
- }
29
- //# sourceMappingURL=Sidebar.d.ts.map
@@ -1,33 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * This file was automatically generated by the Stencil React Output Target.
5
- * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
6
- */
7
-
8
- /* eslint-disable */
9
-
10
- import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
11
- import { createComponent } from '@stencil/react-output-target/runtime';
12
- import React from 'react';
13
-
14
- import { type DsSidebarCustomEvent, type SidebarWidth } from "@ds-mo/ui";
15
- import type { Components } from "@ds-mo/ui/dist/components";
16
- import { DsSidebar as DsSidebarElement, defineCustomElement as defineDsSidebar } from "@ds-mo/ui/dist/components/ds-sidebar.js";
17
-
18
- export type DsSidebarEvents = {
19
- onDsToggle: EventName<DsSidebarCustomEvent<void>>,
20
- onDsWidthChange: EventName<DsSidebarCustomEvent<SidebarWidth>>
21
- };
22
-
23
- export const DsSidebar: StencilReactComponent<DsSidebarElement, DsSidebarEvents, Components.DsSidebar> = /*@__PURE__*/ createComponent<DsSidebarElement, DsSidebarEvents, Components.DsSidebar>({
24
- tagName: 'ds-sidebar',
25
- elementClass: DsSidebarElement,
26
- // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
27
- react: React,
28
- events: {
29
- onDsToggle: 'dsToggle',
30
- onDsWidthChange: 'dsWidthChange'
31
- } as DsSidebarEvents,
32
- defineCustomElement: defineDsSidebar
33
- });
@@ -1,245 +0,0 @@
1
- import { Component, Prop, State, Event, EventEmitter, Element, Watch, h, Host } from '@stencil/core';
2
-
3
- export type SidebarWidth = 'mini' | 'default' | number;
4
-
5
- const MINI_WIDTH = 56;
6
- const DEFAULT_WIDTH = 240;
7
- const MAX_WIDTH = 480;
8
- const MIN_DRAG_WIDTH = 180;
9
- const SNAP_THRESHOLD = 140;
10
- const KEYBOARD_STEP = 16;
11
-
12
- const FOCUSABLE_SEL = [
13
- 'a[href]',
14
- 'button:not([disabled])',
15
- 'input:not([disabled])',
16
- 'select:not([disabled])',
17
- 'textarea:not([disabled])',
18
- '[tabindex]:not([tabindex="-1"])',
19
- ].join(',');
20
-
21
- @Component({
22
- tag: 'ds-sidebar',
23
- styleUrl: 'Sidebar.css',
24
- scoped: true,
25
- })
26
- export class Sidebar {
27
- @Element() el!: HTMLElement;
28
-
29
- @Prop({ mutable: true }) collapsed: boolean = false;
30
- @Prop() width: SidebarWidth = 'default';
31
- @Prop() resizable: boolean = true;
32
- @Prop() mobile: boolean = false;
33
-
34
- @State() private isResizing: boolean = false;
35
-
36
- @Event() dsToggle!: EventEmitter<void>;
37
- @Event() dsWidthChange!: EventEmitter<SidebarWidth>;
38
-
39
- private triggerEl: HTMLElement | null = null;
40
- private escapeHandler: ((e: KeyboardEvent) => void) | null = null;
41
- private tabHandler: ((e: KeyboardEvent) => void) | null = null;
42
- private mouseMoveHandler: ((e: MouseEvent) => void) | null = null;
43
- private mouseUpHandler: (() => void) | null = null;
44
-
45
- private get resolvedWidth(): number {
46
- if (this.width === 'mini') return MINI_WIDTH;
47
- if (this.width === 'default') return DEFAULT_WIDTH;
48
- return this.width as number;
49
- }
50
-
51
- private get isMobileOpen(): boolean {
52
- return this.mobile && !this.collapsed;
53
- }
54
-
55
- @Watch('collapsed')
56
- onCollapsedChange() {
57
- if (this.isMobileOpen) {
58
- this.setupMobileFocusTrap();
59
- } else {
60
- this.teardownMobileFocusTrap();
61
- }
62
- }
63
-
64
- componentDidLoad() {
65
- if (this.isMobileOpen) {
66
- this.setupMobileFocusTrap();
67
- }
68
- if (this.mobile) {
69
- this.escapeHandler = (e: KeyboardEvent) => {
70
- if (e.key === 'Escape' && !this.collapsed) {
71
- this.dsToggle.emit();
72
- }
73
- };
74
- document.addEventListener('keydown', this.escapeHandler);
75
- }
76
- }
77
-
78
- disconnectedCallback() {
79
- this.teardownMobileFocusTrap();
80
- if (this.escapeHandler) {
81
- document.removeEventListener('keydown', this.escapeHandler);
82
- this.escapeHandler = null;
83
- }
84
- this.cleanupMouseHandlers();
85
- }
86
-
87
- private setupMobileFocusTrap() {
88
- this.triggerEl = document.activeElement as HTMLElement | null;
89
-
90
- const focusables = () =>
91
- Array.from(this.el.querySelectorAll<HTMLElement>(FOCUSABLE_SEL)).filter(
92
- el => !el.hasAttribute('aria-hidden') && el.offsetParent !== null,
93
- );
94
-
95
- const initial = focusables();
96
- (initial[0] ?? this.el).focus();
97
-
98
- this.tabHandler = (e: KeyboardEvent) => {
99
- if (e.key !== 'Tab') return;
100
- const items = focusables();
101
- if (!items.length) { e.preventDefault(); this.el.focus(); return; }
102
- const first = items[0];
103
- const last = items[items.length - 1];
104
- const active = document.activeElement as HTMLElement | null;
105
- if (e.shiftKey && (active === first || !this.el.contains(active))) {
106
- e.preventDefault(); last.focus();
107
- } else if (!e.shiftKey && (active === last || !this.el.contains(active))) {
108
- e.preventDefault(); first.focus();
109
- }
110
- };
111
- document.addEventListener('keydown', this.tabHandler);
112
- }
113
-
114
- private teardownMobileFocusTrap() {
115
- if (this.tabHandler) {
116
- document.removeEventListener('keydown', this.tabHandler);
117
- this.tabHandler = null;
118
- }
119
- this.triggerEl?.focus?.();
120
- this.triggerEl = null;
121
- }
122
-
123
- private cleanupMouseHandlers() {
124
- if (this.mouseMoveHandler) document.removeEventListener('mousemove', this.mouseMoveHandler);
125
- if (this.mouseUpHandler) document.removeEventListener('mouseup', this.mouseUpHandler);
126
- this.mouseMoveHandler = null;
127
- this.mouseUpHandler = null;
128
- document.body.style.cursor = '';
129
- document.body.style.userSelect = '';
130
- }
131
-
132
- private handleResizeMouseDown(e: MouseEvent) {
133
- if (!this.resizable) return;
134
- e.preventDefault();
135
- this.isResizing = true;
136
-
137
- this.mouseMoveHandler = (ev: MouseEvent) => {
138
- const newW = ev.clientX;
139
- if (newW < SNAP_THRESHOLD) {
140
- this.dsWidthChange.emit('mini');
141
- } else if (newW < MIN_DRAG_WIDTH) {
142
- this.dsWidthChange.emit('default');
143
- } else {
144
- this.dsWidthChange.emit(newW);
145
- }
146
- };
147
-
148
- this.mouseUpHandler = () => {
149
- this.isResizing = false;
150
- this.cleanupMouseHandlers();
151
- };
152
-
153
- document.body.style.cursor = 'col-resize';
154
- document.body.style.userSelect = 'none';
155
- document.addEventListener('mousemove', this.mouseMoveHandler);
156
- document.addEventListener('mouseup', this.mouseUpHandler);
157
- }
158
-
159
- private handleResizeKeyDown(e: KeyboardEvent) {
160
- if (!this.resizable) return;
161
- const w = this.width;
162
- const resolved = this.resolvedWidth;
163
-
164
- switch (e.key) {
165
- case 'ArrowLeft': {
166
- e.preventDefault();
167
- if (w === 'mini') return;
168
- const next = resolved - KEYBOARD_STEP;
169
- this.dsWidthChange.emit(next < MIN_DRAG_WIDTH ? 'mini' : next);
170
- break;
171
- }
172
- case 'ArrowRight': {
173
- e.preventDefault();
174
- if (w === 'mini') { this.dsWidthChange.emit('default'); return; }
175
- this.dsWidthChange.emit(Math.min(resolved + KEYBOARD_STEP, MAX_WIDTH));
176
- break;
177
- }
178
- case 'Home':
179
- e.preventDefault();
180
- this.dsWidthChange.emit('mini');
181
- break;
182
- case 'End':
183
- e.preventDefault();
184
- this.dsWidthChange.emit(MAX_WIDTH);
185
- break;
186
- }
187
- }
188
-
189
- render() {
190
- if (this.collapsed && !this.mobile) return null;
191
-
192
- const isMini = this.width === 'mini';
193
- const isMobileOpen = this.isMobileOpen;
194
- const sidebarWidth = this.collapsed ? 0 : this.resolvedWidth;
195
-
196
- const dialogProps = isMobileOpen
197
- ? { role: 'dialog', 'aria-modal': 'true', tabIndex: -1 }
198
- : { role: 'navigation' };
199
-
200
- return (
201
- <Host>
202
- {this.mobile && !this.collapsed && (
203
- <div
204
- class="backdrop"
205
- onClick={() => this.dsToggle.emit()}
206
- aria-hidden="true"
207
- />
208
- )}
209
- <aside
210
- class={{
211
- sidebar: true,
212
- 'sidebar--mini': isMini,
213
- 'sidebar--mobile': this.mobile,
214
- 'sidebar--collapsed': this.collapsed,
215
- 'sidebar--resizing': this.isResizing,
216
- }}
217
- style={{ width: `${sidebarWidth}px` }}
218
- aria-label="Sidebar"
219
- {...dialogProps}
220
- >
221
- <div class="sidebar__content">
222
- <slot />
223
- </div>
224
- <div class="sidebar__footer">
225
- <slot name="footer" />
226
- </div>
227
- {this.resizable && !this.mobile && (
228
- <div
229
- class="sidebar__resize-handle"
230
- onMouseDown={(e: MouseEvent) => this.handleResizeMouseDown(e)}
231
- onKeyDown={(e: KeyboardEvent) => this.handleResizeKeyDown(e)}
232
- role="separator"
233
- aria-orientation="vertical"
234
- aria-label="Resize sidebar"
235
- aria-valuenow={this.resolvedWidth}
236
- aria-valuemin={MINI_WIDTH}
237
- aria-valuemax={MAX_WIDTH}
238
- tabIndex={0}
239
- />
240
- )}
241
- </aside>
242
- </Host>
243
- );
244
- }
245
- }