@countermeasure-platform/web-components 1.3.3-dev.33.1 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/component-D5sRm1fq.js +389 -0
- package/dist/component-D5sRm1fq.js.map +1 -0
- package/dist/components/index.js +27 -27
- package/dist/icons/index.d.ts +12 -0
- package/dist/icons/index.d.ts.map +1 -1
- package/dist/icons/index.js +12 -0
- package/dist/icons/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +127 -126
- package/dist/layout/app-shell.d.ts +50 -3
- package/dist/layout/app-shell.d.ts.map +1 -1
- package/dist/layout/app-shell.js +142 -13
- package/dist/layout/app-shell.js.map +1 -1
- package/dist/layout/core-app-chrome.d.ts +81 -0
- package/dist/layout/core-app-chrome.d.ts.map +1 -0
- package/dist/layout/core-app-chrome.js +349 -0
- package/dist/layout/core-app-chrome.js.map +1 -0
- package/dist/layout/index.d.ts +4 -2
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +88 -87
- package/dist/layout/index.js.map +1 -1
- package/dist/react/primitives/badge.d.ts +1 -1
- package/dist/react/primitives/button.d.ts +2 -2
- package/dist/react/primitives/copy-button.d.ts +1 -1
- package/dist/react/primitives/stat-card.d.ts +1 -1
- package/dist/react/primitives/toggle.d.ts +1 -1
- package/dist/react/sidebar.d.ts +4 -4
- package/dist/react/sidebar.d.ts.map +1 -1
- package/dist/react/sidebar.js +18 -16
- package/dist/react/sidebar.js.map +1 -1
- package/dist/sidebar/component.d.ts +24 -2
- package/dist/sidebar/component.d.ts.map +1 -1
- package/dist/sidebar/enhance.d.ts +8 -0
- package/dist/sidebar/enhance.d.ts.map +1 -1
- package/dist/sidebar/index.d.ts +3 -0
- package/dist/sidebar/index.d.ts.map +1 -1
- package/dist/sidebar/index.js +81 -28
- package/dist/sidebar/index.js.map +1 -1
- package/dist/sidebar/types.d.ts +126 -4
- package/dist/sidebar/types.d.ts.map +1 -1
- package/dist/styles/layout.css +252 -0
- package/dist/styles/sidebar.css +313 -5
- package/package.json +6 -1
- package/src/icons/icons.test.ts +9 -0
- package/src/icons/index.ts +12 -0
- package/src/index.ts +11 -0
- package/src/layout/app-shell.test.ts +204 -0
- package/src/layout/app-shell.ts +362 -3
- package/src/layout/core-app-chrome.test.ts +507 -0
- package/src/layout/core-app-chrome.ts +662 -0
- package/src/layout/index.ts +36 -2
- package/src/react/sidebar.test.tsx +104 -3
- package/src/react/sidebar.tsx +26 -4
- package/src/sidebar/component.test.ts +395 -1
- package/src/sidebar/component.ts +661 -86
- package/src/sidebar/enhance.ts +118 -0
- package/src/sidebar/index.ts +144 -0
- package/src/sidebar/types.ts +143 -4
- package/src/styles/layout.css +252 -0
- package/src/styles/sidebar.css +313 -5
- package/dist/component-Bxhxf21c.js +0 -167
- package/dist/component-Bxhxf21c.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.js","names":[],"sources":["../../src/react/sidebar.tsx"],"sourcesContent":["/**\n * Sidebar React wrapper — Lane A imperative wrap over src/sidebar/component.ts\n *\n * Import from the dedicated subpath:\n * import { Sidebar } from '@countermeasure-platform/web-components/react/sidebar'\n *\n * The wrapper renders a host div then mounts `SidebarComponent` into it on\n * mount. Prop changes to `activeItemId` and controlled `open
|
|
1
|
+
{"version":3,"file":"sidebar.js","names":[],"sources":["../../src/react/sidebar.tsx"],"sourcesContent":["/**\n * Sidebar React wrapper — Lane A imperative wrap over src/sidebar/component.ts\n *\n * Import from the dedicated subpath:\n * import { Sidebar } from '@countermeasure-platform/web-components/react/sidebar'\n *\n * The wrapper renders a host div then mounts `SidebarComponent` into it on\n * mount. Prop changes to `activeItemId`, `pathname`, and controlled `open`\n * are synced via the class's public API.\n */\n\nimport * as React from 'react'\nimport { cn } from './primitives/utils'\nimport { SidebarComponent } from '../sidebar/component'\nimport type {\n SidebarComponentConfig,\n SidebarBadgeConfig,\n SidebarBadgeTone,\n SidebarNavItem,\n SidebarScopeConfig,\n SidebarScopeOption,\n SidebarSection,\n SidebarUser,\n SidebarFooterAction,\n} from '../sidebar/types'\n\nexport interface SidebarProps extends Omit<\n SidebarComponentConfig,\n 'container' | 'onNavigate' | 'onCollapse'\n> {\n /** Currently active nav item ID. Synced via `setActive` on changes. */\n activeItemId?: string\n /** Called when the user clicks a nav item. */\n onNavigate?: (item: SidebarNavItem) => void\n /** Called when the sidebar is collapsed/expanded. */\n onCollapse?: (collapsed: boolean) => void\n className?: string\n}\n\nexport type {\n SidebarBadgeConfig,\n SidebarBadgeTone,\n SidebarFooterAction,\n SidebarNavItem,\n SidebarScopeConfig,\n SidebarScopeOption,\n SidebarSection,\n SidebarUser,\n}\n\nexport interface SidebarCollapseButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n collapsed?: boolean\n edge?: boolean\n visible?: boolean\n label?: string\n}\n\nconst Sidebar = (props: SidebarProps) => {\n const { activeItemId, pathname, onNavigate, onCollapse, className, open, ...config } = props\n const containerRef = React.useRef<HTMLDivElement>(null)\n const sidebarRef = React.useRef<SidebarComponent | null>(null)\n const onNavigateRef = React.useRef(onNavigate)\n const onCollapseRef = React.useRef(onCollapse)\n onNavigateRef.current = onNavigate\n onCollapseRef.current = onCollapse\n\n // Construct once on mount — SSR-safe\n React.useEffect(() => {\n if (typeof document === 'undefined' || !containerRef.current) return\n const sidebarConfig: SidebarComponentConfig = {\n ...config,\n container: containerRef.current,\n onNavigate: (item: SidebarNavItem) => {\n onNavigateRef.current?.(item)\n },\n onCollapse: (collapsed: boolean) => {\n onCollapseRef.current?.(collapsed)\n },\n }\n if (open !== undefined) {\n sidebarConfig.open = open\n }\n if (pathname !== undefined) {\n sidebarConfig.pathname = pathname\n }\n sidebarRef.current = new SidebarComponent(sidebarConfig)\n return () => {\n sidebarRef.current?.destroy()\n sidebarRef.current = null\n }\n }, [])\n\n // Sync mobile open state to the component default when the prop is removed.\n React.useEffect(() => {\n if (!sidebarRef.current) return\n sidebarRef.current.setOpen(open === true)\n }, [open])\n\n // Sync active item when prop changes\n React.useEffect(() => {\n if (!sidebarRef.current || activeItemId === undefined) return\n sidebarRef.current.setActive(activeItemId)\n }, [activeItemId])\n\n // Sync route-derived active state when no explicit active item controls it.\n React.useEffect(() => {\n if (!sidebarRef.current || activeItemId !== undefined) return\n sidebarRef.current.setPathname(pathname)\n }, [activeItemId, pathname])\n\n return <div ref={containerRef} data-slot=\"sidebar\" className={cn(className)} />\n}\n\nSidebar.displayName = 'Sidebar'\n\nconst collapseDefaultLabel = (collapsed: boolean): string =>\n collapsed ? 'Expand sidebar' : 'Collapse sidebar'\n\nconst collapseIconPath = (collapsed: boolean): string =>\n collapsed ? 'm9 18 6-6-6-6' : 'm15 18-6-6 6-6'\n\nconst CollapseChevron = ({ collapsed }: { collapsed: boolean }) => (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d={collapseIconPath(collapsed)} />\n </svg>\n)\n\nconst SidebarCollapseButton = (componentProps: SidebarCollapseButtonProps) => {\n const {\n collapsed = false,\n edge = false,\n visible = false,\n label,\n className,\n type = 'button',\n children,\n ...props\n } = componentProps\n const resolvedLabel = label ?? collapseDefaultLabel(collapsed)\n\n return (\n <button\n type={type}\n className={cn('sidebar__collapse-btn', edge && 'sidebar__collapse-btn--edge', className)}\n aria-label={resolvedLabel}\n aria-expanded={!collapsed}\n title={resolvedLabel}\n data-collapsed={collapsed ? 'true' : 'false'}\n data-visible={visible ? 'true' : undefined}\n {...props}\n >\n {children ?? <CollapseChevron collapsed={collapsed} />}\n </button>\n )\n}\n\nSidebarCollapseButton.displayName = 'SidebarCollapseButton'\n\nexport { Sidebar, SidebarCollapseButton }\n"],"mappings":";;;;;AAyDA,IAAM,KAAW,MAAwB;CACvC,IAAM,EAAE,iBAAc,aAAU,eAAY,eAAY,cAAW,SAAM,GAAG,MAAW,GACjF,IAAe,EAAM,OAAuB,IAAI,GAChD,IAAa,EAAM,OAAgC,IAAI,GACvD,IAAgB,EAAM,OAAO,CAAU,GACvC,IAAgB,EAAM,OAAO,CAAU;CAgD7C,OA/CA,EAAc,UAAU,GACxB,EAAc,UAAU,GAGxB,EAAM,gBAAgB;EACpB,IAAI,OAAO,WAAa,OAAe,CAAC,EAAa,SAAS;EAC9D,IAAM,IAAwC;GAC5C,GAAG;GACH,WAAW,EAAa;GACxB,aAAa,MAAyB;IACpC,EAAc,UAAU,CAAI;GAC9B;GACA,aAAa,MAAuB;IAClC,EAAc,UAAU,CAAS;GACnC;EACF;EAQA,OAPI,MAAS,KAAA,MACX,EAAc,OAAO,IAEnB,MAAa,KAAA,MACf,EAAc,WAAW,IAE3B,EAAW,UAAU,IAAI,EAAiB,CAAa,SAC1C;GAEX,AADA,EAAW,SAAS,QAAQ,GAC5B,EAAW,UAAU;EACvB;CACF,GAAG,CAAC,CAAC,GAGL,EAAM,gBAAgB;EACf,EAAW,WAChB,EAAW,QAAQ,QAAQ,MAAS,EAAI;CAC1C,GAAG,CAAC,CAAI,CAAC,GAGT,EAAM,gBAAgB;EAChB,CAAC,EAAW,WAAW,MAAiB,KAAA,KAC5C,EAAW,QAAQ,UAAU,CAAY;CAC3C,GAAG,CAAC,CAAY,CAAC,GAGjB,EAAM,gBAAgB;EAChB,CAAC,EAAW,WAAW,MAAiB,KAAA,KAC5C,EAAW,QAAQ,YAAY,CAAQ;CACzC,GAAG,CAAC,GAAc,CAAQ,CAAC,GAEpB,kBAAC,OAAD;EAAK,KAAK;EAAc,aAAU;EAAU,WAAW,EAAG,CAAS;CAAI,CAAA;AAChF;AAEA,EAAQ,cAAc;AAEtB,IAAM,KAAwB,MAC5B,IAAY,mBAAmB,oBAE3B,KAAoB,MACxB,IAAY,kBAAkB,kBAE1B,KAAmB,EAAE,mBACzB,kBAAC,OAAD;CACE,eAAY;CACZ,SAAQ;CACR,MAAK;CACL,QAAO;CACP,aAAY;CACZ,eAAc;CACd,gBAAe;WAEf,kBAAC,QAAD,EAAM,GAAG,EAAiB,CAAS,EAAI,CAAA;AACpC,CAAA,GAGD,KAAyB,MAA+C;CAC5E,IAAM,EACJ,eAAY,IACZ,UAAO,IACP,aAAU,IACV,UACA,cACA,UAAO,UACP,aACA,GAAG,MACD,GACE,IAAgB,KAAS,EAAqB,CAAS;CAE7D,OACE,kBAAC,UAAD;EACQ;EACN,WAAW,EAAG,yBAAyB,KAAQ,+BAA+B,CAAS;EACvF,cAAY;EACZ,iBAAe,CAAC;EAChB,OAAO;EACP,kBAAgB,IAAY,SAAS;EACrC,gBAAc,IAAU,SAAS,KAAA;EACjC,GAAI;YAEH,KAAY,kBAAC,GAAD,EAA4B,aAAY,CAAA;CAC/C,CAAA;AAEZ;AAEA,EAAsB,cAAc"}
|
|
@@ -1,20 +1,31 @@
|
|
|
1
|
-
import { SidebarComponentConfig } from './types';
|
|
1
|
+
import { SidebarBadgeTone, SidebarComponentConfig } from './types';
|
|
2
2
|
export declare class SidebarComponent {
|
|
3
3
|
private readonly container;
|
|
4
4
|
private readonly aside;
|
|
5
5
|
private readonly config;
|
|
6
6
|
private readonly iconSet;
|
|
7
|
+
private readonly variant;
|
|
8
|
+
private readonly cleanupFns;
|
|
7
9
|
private collapseButton;
|
|
10
|
+
private backdrop;
|
|
8
11
|
constructor(config: SidebarComponentConfig);
|
|
9
12
|
private render;
|
|
10
13
|
private buildSection;
|
|
14
|
+
private buildItem;
|
|
11
15
|
private renderHeader;
|
|
16
|
+
private renderScope;
|
|
12
17
|
private renderCollapseButton;
|
|
13
18
|
private renderFooter;
|
|
19
|
+
private renderBackdrop;
|
|
20
|
+
private setupBehavior;
|
|
21
|
+
private setupKeyboardNavigation;
|
|
22
|
+
private setupMobileToggles;
|
|
14
23
|
/** Mark a nav item as active, removing active state from all others. */
|
|
15
24
|
setActive(itemId: string): void;
|
|
25
|
+
/** Recompute active route state from a supplied pathname or the current location. */
|
|
26
|
+
setPathname(pathname: string | undefined): void;
|
|
16
27
|
/** Update the badge count for a nav item (empty string when count is 0). */
|
|
17
|
-
updateBadge(itemId: string, count: number): void;
|
|
28
|
+
updateBadge(itemId: string, count: number, tone?: SidebarBadgeTone): void;
|
|
18
29
|
/** Toggle the sidebar between collapsed and expanded states. */
|
|
19
30
|
toggleCollapse(): void;
|
|
20
31
|
/** Collapse the sidebar. */
|
|
@@ -25,6 +36,17 @@ export declare class SidebarComponent {
|
|
|
25
36
|
setOpen(open: boolean): void;
|
|
26
37
|
/** Remove the sidebar from the DOM. */
|
|
27
38
|
destroy(): void;
|
|
39
|
+
private applyBadge;
|
|
40
|
+
private setCollapsed;
|
|
41
|
+
private isCollapsed;
|
|
42
|
+
private isOpen;
|
|
43
|
+
private getMobileBreakpoint;
|
|
44
|
+
private resolveInitialCollapsed;
|
|
45
|
+
private persistCollapsed;
|
|
46
|
+
private getCurrentPathname;
|
|
47
|
+
private isItemActive;
|
|
48
|
+
private syncActiveRouteState;
|
|
49
|
+
private closeScopeMenus;
|
|
28
50
|
private updateCollapseButton;
|
|
29
51
|
}
|
|
30
52
|
//# sourceMappingURL=component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/sidebar/component.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/sidebar/component.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAG5B,MAAM,SAAS,CAAA;AA4HhB,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,cAAc,CAAiC;IACvD,OAAO,CAAC,QAAQ,CAA2B;gBAE/B,MAAM,EAAE,sBAAsB;IA6B1C,OAAO,CAAC,MAAM;IA4Bd,OAAO,CAAC,YAAY;IAoEpB,OAAO,CAAC,SAAS;IA6EjB,OAAO,CAAC,YAAY;IAiDpB,OAAO,CAAC,WAAW;IAgHnB,OAAO,CAAC,oBAAoB;IAgC5B,OAAO,CAAC,YAAY;IAuGpB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,aAAa;IA4BrB,OAAO,CAAC,uBAAuB;IA2B/B,OAAO,CAAC,kBAAkB;IAmB1B,wEAAwE;IACxE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAgB/B,qFAAqF;IACrF,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAU/C,4EAA4E;IAC5E,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI;IAmBzE,gEAAgE;IAChE,cAAc,IAAI,IAAI;IAItB,4BAA4B;IAC5B,QAAQ,IAAI,IAAI;IAIhB,0BAA0B;IAC1B,MAAM,IAAI,IAAI;IAId,sEAAsE;IACtE,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAU5B,uCAAuC;IACvC,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,YAAY;IAwCpB,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,oBAAoB;CAe7B"}
|
|
@@ -21,6 +21,12 @@ export interface EnhanceOptions {
|
|
|
21
21
|
skeletonTimeoutMs?: number;
|
|
22
22
|
/** CSS class for collapsed state (default: 'sidebar--collapsed') */
|
|
23
23
|
collapsedClass?: string;
|
|
24
|
+
/** Variants that should opt into product sidebar visuals. */
|
|
25
|
+
productVariants?: string[];
|
|
26
|
+
/** Derive the active nav item from window.location on enhancement. */
|
|
27
|
+
activeFromLocation?: boolean;
|
|
28
|
+
/** Close an open mobile sidebar after clicking a route link. */
|
|
29
|
+
closeOnNavigate?: boolean;
|
|
24
30
|
}
|
|
25
31
|
export declare class Sidebar {
|
|
26
32
|
readonly element: HTMLElement;
|
|
@@ -30,6 +36,8 @@ export declare class Sidebar {
|
|
|
30
36
|
private skeletonTimer;
|
|
31
37
|
constructor(element: HTMLElement, options?: EnhanceOptions);
|
|
32
38
|
private init;
|
|
39
|
+
private setupProductChrome;
|
|
40
|
+
private setupRouteState;
|
|
33
41
|
/**
|
|
34
42
|
* Collapse/expand toggle with localStorage persistence.
|
|
35
43
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enhance.d.ts","sourceRoot":"","sources":["../../src/sidebar/enhance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"enhance.d.ts","sourceRoot":"","sources":["../../src/sidebar/enhance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,gEAAgE;IAChE,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAqCD,qBAAa,OAAO;IAClB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,aAAa,CAA6C;gBAEtD,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,cAAc;IAO1D,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,eAAe;IA2CvB;;OAEG;IACH,OAAO,CAAC,aAAa;IAwGrB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA6BxB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4B5B;;OAEG;IACH,qBAAqB,IAAI,IAAI;IAO7B;;OAEG;IACH,OAAO,IAAI,IAAI;CAQhB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,SAA0B,GAAG,IAAI,CAexF;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,GAAG,IAAI,CAalF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,IAAI,CAgB/D"}
|
package/dist/sidebar/index.d.ts
CHANGED
|
@@ -16,6 +16,9 @@ export interface SidebarConfig {
|
|
|
16
16
|
storageKey?: string;
|
|
17
17
|
mobileBreakpoint?: number;
|
|
18
18
|
collapsedClass?: string;
|
|
19
|
+
productVariants?: string[];
|
|
20
|
+
activeFromLocation?: boolean;
|
|
21
|
+
closeOnNavigate?: boolean;
|
|
19
22
|
}
|
|
20
23
|
export interface LegacySidebarConfig {
|
|
21
24
|
sidebar: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sidebar/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,WAAW,EACX,mBAAmB,GACpB,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sidebar/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,WAAW,EACX,mBAAmB,GACpB,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;CACvB;AAcD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAE5D;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAE/D;AA2QD;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,EA6BrD,CAAA;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,MAAM,CAAC,EAAE,aAAa,EACtB,aAAa,GAAE,mBAAmB,EAAyB,GAC1D,IAAI,CAUN"}
|
package/dist/sidebar/index.js
CHANGED
|
@@ -1,61 +1,114 @@
|
|
|
1
|
-
import { t as e } from "../component-
|
|
1
|
+
import { t as e } from "../component-D5sRm1fq.js";
|
|
2
2
|
//#region src/sidebar/index.ts
|
|
3
3
|
var t = {
|
|
4
4
|
storageKey: "sidebar-collapsed",
|
|
5
5
|
mobileBreakpoint: 900,
|
|
6
|
-
collapsedClass: "sidebar--collapsed"
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
collapsedClass: "sidebar--collapsed",
|
|
7
|
+
productVariants: [
|
|
8
|
+
"app",
|
|
9
|
+
"cm",
|
|
10
|
+
"threat-library"
|
|
11
|
+
],
|
|
12
|
+
activeFromLocation: !0,
|
|
13
|
+
closeOnNavigate: !0
|
|
14
|
+
}, n = { ...t }, r = "data-sidebar-initialized";
|
|
15
|
+
function i(e) {
|
|
9
16
|
n = {
|
|
10
17
|
...t,
|
|
11
18
|
...e
|
|
12
19
|
};
|
|
13
20
|
}
|
|
14
|
-
function
|
|
21
|
+
function a() {
|
|
15
22
|
return window.innerWidth <= n.mobileBreakpoint;
|
|
16
23
|
}
|
|
17
|
-
function
|
|
24
|
+
function o(e) {
|
|
18
25
|
return localStorage.getItem(`${n.storageKey}-${e}`) === "true";
|
|
19
26
|
}
|
|
20
|
-
function
|
|
27
|
+
function s(e, t) {
|
|
21
28
|
localStorage.setItem(`${n.storageKey}-${e}`, String(t));
|
|
22
29
|
}
|
|
23
|
-
function
|
|
30
|
+
function c(e, t) {
|
|
24
31
|
e.setAttribute("data-open", "false"), t && t.setAttribute("data-visible", "false");
|
|
25
32
|
}
|
|
26
|
-
function
|
|
33
|
+
function l(e, t) {
|
|
27
34
|
let n = e.getAttribute("data-open") === "true";
|
|
28
35
|
e.setAttribute("data-open", String(!n)), t && t.setAttribute("data-visible", String(!n));
|
|
29
36
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
function u(e) {
|
|
38
|
+
return e === "/" ? e : e.replace(/\/+$/, "");
|
|
39
|
+
}
|
|
40
|
+
function d(e, t) {
|
|
41
|
+
try {
|
|
42
|
+
let n = u(new URL(t, window.location.href).pathname), r = u(e);
|
|
43
|
+
return n === "/" ? r === "/" : r === n || r.startsWith(`${n}/`);
|
|
44
|
+
} catch {
|
|
45
|
+
return !1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function f(e) {
|
|
49
|
+
let t = Array.from(e.querySelectorAll("a.sidebar__item[href], a.sidebar__nav-link[href], a[data-nav-item][href]")), n = null, r = -1;
|
|
50
|
+
for (let e of t) {
|
|
51
|
+
let t = e.getAttribute("href");
|
|
52
|
+
if (!(t === null || !d(window.location.pathname, t))) try {
|
|
53
|
+
let i = u(new URL(t, window.location.href).pathname);
|
|
54
|
+
i.length > r && (n = e, r = i.length);
|
|
55
|
+
} catch {}
|
|
56
|
+
}
|
|
57
|
+
return n;
|
|
58
|
+
}
|
|
59
|
+
function p(e) {
|
|
60
|
+
if (n.activeFromLocation !== !0 || typeof window > "u") return;
|
|
61
|
+
let t = f(e);
|
|
62
|
+
t !== null && (e.querySelectorAll(".sidebar__item--active").forEach((e) => {
|
|
63
|
+
e.classList.remove("sidebar__item--active"), e.removeAttribute("aria-current");
|
|
64
|
+
}), t.classList.add("sidebar__item--active"), t.setAttribute("aria-current", "page"));
|
|
65
|
+
}
|
|
66
|
+
function m(e, t) {
|
|
67
|
+
(e.hasAttribute("data-sidebar-product") || e.classList.contains("sidebar--cm") || n.productVariants.includes(t)) && e.classList.add("sidebar--product"), e.querySelectorAll(".sidebar__item, .sidebar__nav-link").forEach((e) => {
|
|
68
|
+
e.hasAttribute("data-nav-item") || e.setAttribute("data-nav-item", "");
|
|
69
|
+
}), p(e);
|
|
70
|
+
}
|
|
71
|
+
function h(e) {
|
|
72
|
+
e.addEventListener("keydown", (t) => {
|
|
73
|
+
if (t.key !== "ArrowDown" && t.key !== "ArrowUp") return;
|
|
74
|
+
let n = Array.from(e.querySelectorAll("[data-nav-item]:not([aria-disabled=\"true\"])")).filter((e) => !e.hidden && e.offsetParent !== null);
|
|
75
|
+
if (n.length === 0) return;
|
|
76
|
+
let r = n.indexOf(document.activeElement);
|
|
77
|
+
r !== -1 && (t.preventDefault(), n[t.key === "ArrowDown" ? (r + 1) % n.length : (r - 1 + n.length) % n.length]?.focus());
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function g({ sidebar: e, toggle: t, mobileToggles: i, backdrop: u, collapsedClass: d, key: f }) {
|
|
81
|
+
!a() && o(f) && e.classList.add(d), t && t.addEventListener("click", () => {
|
|
82
|
+
s(f, e.classList.toggle(d));
|
|
83
|
+
}), i.forEach((t) => {
|
|
34
84
|
t.addEventListener("click", () => {
|
|
35
|
-
|
|
85
|
+
l(e, u);
|
|
36
86
|
});
|
|
37
|
-
}),
|
|
38
|
-
|
|
87
|
+
}), u && u.addEventListener("click", () => {
|
|
88
|
+
c(e, u);
|
|
89
|
+
}), n.closeOnNavigate === !0 && e.addEventListener("click", (t) => {
|
|
90
|
+
let n = t.target;
|
|
91
|
+
(n instanceof Element ? n.closest("a.sidebar__item[href], a.sidebar__nav-link[href], a[data-nav-item][href]") : null) !== null && e.getAttribute("data-open") === "true" && c(e, u);
|
|
39
92
|
}), window.addEventListener("resize", () => {
|
|
40
|
-
|
|
93
|
+
a() && c(e, u);
|
|
41
94
|
}), document.addEventListener("keydown", (t) => {
|
|
42
|
-
t.key === "Escape" && e.getAttribute("data-open") === "true" &&
|
|
43
|
-
});
|
|
95
|
+
t.key === "Escape" && e.getAttribute("data-open") === "true" && c(e, u);
|
|
96
|
+
}), h(e), e.setAttribute(r, "true");
|
|
44
97
|
}
|
|
45
|
-
function
|
|
98
|
+
function _(e) {
|
|
46
99
|
let t = e.getAttribute("data-sidebar");
|
|
47
|
-
t === null || t === "" ||
|
|
100
|
+
t === null || t === "" || (m(e, t), e.getAttribute(r) !== "true" && g({
|
|
48
101
|
sidebar: e,
|
|
49
102
|
toggle: e.querySelector("[data-sidebar-toggle]"),
|
|
50
103
|
mobileToggles: Array.from(document.querySelectorAll("[data-sidebar-mobile-toggle]")),
|
|
51
104
|
backdrop: document.querySelector(`[data-sidebar-backdrop="${t}"]`),
|
|
52
105
|
collapsedClass: n.collapsedClass,
|
|
53
106
|
key: t
|
|
54
|
-
});
|
|
107
|
+
}));
|
|
55
108
|
}
|
|
56
|
-
function
|
|
109
|
+
function v(e) {
|
|
57
110
|
let t = document.querySelector(e.sidebar);
|
|
58
|
-
t && (t.hasAttribute("data-sidebar") ||
|
|
111
|
+
t && (t.hasAttribute("data-sidebar") || g({
|
|
59
112
|
sidebar: t,
|
|
60
113
|
toggle: document.querySelector(e.toggle),
|
|
61
114
|
mobileToggles: Array.from(document.querySelectorAll(e.mobileToggle)),
|
|
@@ -64,7 +117,7 @@ function d(e) {
|
|
|
64
117
|
key: e.sidebar.replace(/[^a-z]/g, "")
|
|
65
118
|
}));
|
|
66
119
|
}
|
|
67
|
-
var
|
|
120
|
+
var y = [
|
|
68
121
|
{
|
|
69
122
|
sidebar: ".page__sidebar",
|
|
70
123
|
toggle: "[data-page-sidebar-toggle]",
|
|
@@ -94,10 +147,10 @@ var f = [
|
|
|
94
147
|
collapsedClass: "storage-sidebar--collapsed"
|
|
95
148
|
}
|
|
96
149
|
];
|
|
97
|
-
function
|
|
98
|
-
e &&
|
|
150
|
+
function b(e, t = y) {
|
|
151
|
+
e && i(e), document.querySelectorAll("[data-sidebar]").forEach(_), t.forEach(v);
|
|
99
152
|
}
|
|
100
153
|
//#endregion
|
|
101
|
-
export { e as SidebarComponent,
|
|
154
|
+
export { e as SidebarComponent, i as configureSidebar, y as defaultLegacyConfigs, o as getStoredState, b as initSidebar, a as isMobile, s as saveState };
|
|
102
155
|
|
|
103
156
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/sidebar/index.ts"],"sourcesContent":["/**\n * Sidebar Module\n *\n * Unified sidebar toggle functionality for CounterMeasure applications.\n * Handles collapsible sidebar for desktop and mobile with localStorage persistence.\n *\n * Usage:\n * - Add data-sidebar=\"{variant}\" to your sidebar element (e.g., data-sidebar=\"admin\")\n * - Add data-sidebar-toggle to the toggle button\n * - Add data-sidebar-mobile-toggle to the mobile toggle button\n * - Add data-sidebar-backdrop=\"{variant}\" to the backdrop element\n */\n\n// Re-export programmatic sidebar component\nexport { SidebarComponent } from './component'\nexport type {\n SidebarComponentConfig,\n SidebarBrandConfig,\n SidebarNavItem,\n SidebarSection,\n SidebarUser,\n SidebarFooterAction,\n} from './types'\n\nexport interface SidebarConfig {\n storageKey?: string\n mobileBreakpoint?: number\n collapsedClass?: string\n}\n\nexport interface LegacySidebarConfig {\n sidebar: string\n toggle: string\n mobileToggle: string\n backdrop: string\n collapsedClass: string\n}\n\nconst DEFAULT_CONFIG: Required<SidebarConfig> = {\n storageKey: 'sidebar-collapsed',\n mobileBreakpoint: 900,\n collapsedClass: 'sidebar--collapsed',\n}\n\nlet currentConfig: Required<SidebarConfig> = { ...DEFAULT_CONFIG }\n\n/**\n * Configure sidebar settings.\n */\nexport function configureSidebar(config: SidebarConfig): void {\n currentConfig = { ...DEFAULT_CONFIG, ...config }\n}\n\n/**\n * Check if we're on mobile viewport.\n */\nexport function isMobile(): boolean {\n return window.innerWidth <= currentConfig.mobileBreakpoint\n}\n\n/**\n * Get stored collapsed state for a sidebar.\n */\nexport function getStoredState(key: string): boolean {\n const stored = localStorage.getItem(`${currentConfig.storageKey}-${key}`)\n return stored === 'true'\n}\n\n/**\n * Save collapsed state for a sidebar.\n */\nexport function saveState(key: string, collapsed: boolean): void {\n localStorage.setItem(`${currentConfig.storageKey}-${key}`, String(collapsed))\n}\n\n/**\n * Close a sidebar (mobile).\n */\nfunction closeSidebar(sidebar: HTMLElement, backdrop: HTMLElement | null): void {\n sidebar.setAttribute('data-open', 'false')\n if (backdrop) {\n backdrop.setAttribute('data-visible', 'false')\n }\n}\n\n/**\n * Toggle sidebar open state (mobile).\n */\nfunction toggleSidebarOpen(sidebar: HTMLElement, backdrop: HTMLElement | null): void {\n const isOpen = sidebar.getAttribute('data-open') === 'true'\n sidebar.setAttribute('data-open', String(!isOpen))\n if (backdrop) {\n backdrop.setAttribute('data-visible', String(!isOpen))\n }\n}\n\ninterface SidebarHandlerParams {\n sidebar: HTMLElement\n toggle: HTMLButtonElement | null\n mobileToggles: HTMLButtonElement[]\n backdrop: HTMLElement | null\n collapsedClass: string\n key: string\n}\n\n/**\n * Attach all sidebar event handlers (shared between unified and legacy init).\n */\nfunction attachSidebarHandlers({\n sidebar,\n toggle,\n mobileToggles,\n backdrop,\n collapsedClass,\n key,\n}: SidebarHandlerParams): void {\n // Apply stored collapsed state on desktop\n if (!isMobile() && getStoredState(key)) {\n sidebar.classList.add(collapsedClass)\n }\n\n // Desktop toggle handler\n if (toggle) {\n toggle.addEventListener('click', () => {\n const isCollapsed = sidebar.classList.toggle(collapsedClass)\n saveState(key, isCollapsed)\n })\n }\n\n // Mobile toggle handler\n mobileToggles.forEach(mobileToggle => {\n mobileToggle.addEventListener('click', () => {\n toggleSidebarOpen(sidebar, backdrop)\n })\n })\n\n // Backdrop click handler\n if (backdrop) {\n backdrop.addEventListener('click', () => {\n closeSidebar(sidebar, backdrop)\n })\n }\n\n // Handle window resize\n window.addEventListener('resize', () => {\n if (isMobile()) {\n closeSidebar(sidebar, backdrop)\n }\n })\n\n // Close sidebar on escape key\n document.addEventListener('keydown', e => {\n if (e.key === 'Escape' && sidebar.getAttribute('data-open') === 'true') {\n closeSidebar(sidebar, backdrop)\n }\n })\n}\n\n/**\n * Initialize a single sidebar using the unified data-sidebar attribute.\n */\nfunction initUnifiedSidebar(sidebar: HTMLElement): void {\n const variant = sidebar.getAttribute('data-sidebar')\n if (variant === null || variant === '') {\n return\n }\n\n attachSidebarHandlers({\n sidebar,\n toggle: sidebar.querySelector<HTMLButtonElement>('[data-sidebar-toggle]'),\n mobileToggles: Array.from(\n document.querySelectorAll<HTMLButtonElement>('[data-sidebar-mobile-toggle]')\n ),\n backdrop: document.querySelector<HTMLElement>(`[data-sidebar-backdrop=\"${variant}\"]`),\n collapsedClass: currentConfig.collapsedClass,\n key: variant,\n })\n}\n\n/**\n * Initialize a legacy sidebar (backwards compatibility).\n */\nfunction initLegacySidebar(config: LegacySidebarConfig): void {\n const sidebar = document.querySelector<HTMLElement>(config.sidebar)\n if (!sidebar) {\n return\n }\n\n // Skip if this sidebar uses the new unified approach\n if (sidebar.hasAttribute('data-sidebar')) {\n return\n }\n\n attachSidebarHandlers({\n sidebar,\n toggle: document.querySelector<HTMLButtonElement>(config.toggle),\n mobileToggles: Array.from(document.querySelectorAll<HTMLButtonElement>(config.mobileToggle)),\n backdrop: document.querySelector<HTMLElement>(config.backdrop),\n collapsedClass: config.collapsedClass,\n key: config.sidebar.replace(/[^a-z]/g, ''),\n })\n}\n\n/**\n * Default legacy sidebar configurations for CounterMeasure apps.\n */\nexport const defaultLegacyConfigs: LegacySidebarConfig[] = [\n {\n sidebar: '.page__sidebar',\n toggle: '[data-page-sidebar-toggle]',\n mobileToggle: '[data-page-mobile-toggle]',\n backdrop: '.sidebar-backdrop',\n collapsedClass: 'page__sidebar--collapsed',\n },\n {\n sidebar: '.chat-sidebar',\n toggle: '[data-chat-sidebar-toggle]',\n mobileToggle: '.chat-header__menu-toggle',\n backdrop: '.chat-sidebar-backdrop',\n collapsedClass: 'chat-sidebar--collapsed',\n },\n {\n sidebar: '.files-sidebar',\n toggle: '[data-files-sidebar-toggle]',\n mobileToggle: '[data-files-mobile-toggle]',\n backdrop: '.files-sidebar-backdrop',\n collapsedClass: 'files-sidebar--collapsed',\n },\n {\n sidebar: '.storage-sidebar',\n toggle: '[data-storage-sidebar-toggle]',\n mobileToggle: '[data-storage-mobile-toggle]',\n backdrop: '.storage-sidebar-backdrop',\n collapsedClass: 'storage-sidebar--collapsed',\n },\n]\n\n/**\n * Initialize all sidebars (both new unified and legacy).\n */\nexport function initSidebar(\n config?: SidebarConfig,\n legacyConfigs: LegacySidebarConfig[] = defaultLegacyConfigs\n): void {\n if (config) {\n configureSidebar(config)\n }\n\n // Initialize new unified sidebars\n document.querySelectorAll<HTMLElement>('[data-sidebar]').forEach(initUnifiedSidebar)\n\n // Initialize legacy sidebars for backwards compatibility\n legacyConfigs.forEach(initLegacySidebar)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/sidebar/index.ts"],"sourcesContent":["/**\n * Sidebar Module\n *\n * Unified sidebar toggle functionality for CounterMeasure applications.\n * Handles collapsible sidebar for desktop and mobile with localStorage persistence.\n *\n * Usage:\n * - Add data-sidebar=\"{variant}\" to your sidebar element (e.g., data-sidebar=\"admin\")\n * - Add data-sidebar-toggle to the toggle button\n * - Add data-sidebar-mobile-toggle to the mobile toggle button\n * - Add data-sidebar-backdrop=\"{variant}\" to the backdrop element\n */\n\n// Re-export programmatic sidebar component\nexport { SidebarComponent } from './component'\nexport type {\n SidebarComponentConfig,\n SidebarBrandConfig,\n SidebarNavItem,\n SidebarSection,\n SidebarUser,\n SidebarFooterAction,\n} from './types'\n\nexport interface SidebarConfig {\n storageKey?: string\n mobileBreakpoint?: number\n collapsedClass?: string\n productVariants?: string[]\n activeFromLocation?: boolean\n closeOnNavigate?: boolean\n}\n\nexport interface LegacySidebarConfig {\n sidebar: string\n toggle: string\n mobileToggle: string\n backdrop: string\n collapsedClass: string\n}\n\nconst DEFAULT_CONFIG: Required<SidebarConfig> = {\n storageKey: 'sidebar-collapsed',\n mobileBreakpoint: 900,\n collapsedClass: 'sidebar--collapsed',\n productVariants: ['app', 'cm', 'threat-library'],\n activeFromLocation: true,\n closeOnNavigate: true,\n}\n\nlet currentConfig: Required<SidebarConfig> = { ...DEFAULT_CONFIG }\nconst INITIALIZED_ATTR = 'data-sidebar-initialized'\n\n/**\n * Configure sidebar settings.\n */\nexport function configureSidebar(config: SidebarConfig): void {\n currentConfig = { ...DEFAULT_CONFIG, ...config }\n}\n\n/**\n * Check if we're on mobile viewport.\n */\nexport function isMobile(): boolean {\n return window.innerWidth <= currentConfig.mobileBreakpoint\n}\n\n/**\n * Get stored collapsed state for a sidebar.\n */\nexport function getStoredState(key: string): boolean {\n const stored = localStorage.getItem(`${currentConfig.storageKey}-${key}`)\n return stored === 'true'\n}\n\n/**\n * Save collapsed state for a sidebar.\n */\nexport function saveState(key: string, collapsed: boolean): void {\n localStorage.setItem(`${currentConfig.storageKey}-${key}`, String(collapsed))\n}\n\n/**\n * Close a sidebar (mobile).\n */\nfunction closeSidebar(sidebar: HTMLElement, backdrop: HTMLElement | null): void {\n sidebar.setAttribute('data-open', 'false')\n if (backdrop) {\n backdrop.setAttribute('data-visible', 'false')\n }\n}\n\n/**\n * Toggle sidebar open state (mobile).\n */\nfunction toggleSidebarOpen(sidebar: HTMLElement, backdrop: HTMLElement | null): void {\n const isOpen = sidebar.getAttribute('data-open') === 'true'\n sidebar.setAttribute('data-open', String(!isOpen))\n if (backdrop) {\n backdrop.setAttribute('data-visible', String(!isOpen))\n }\n}\n\ninterface SidebarHandlerParams {\n sidebar: HTMLElement\n toggle: HTMLButtonElement | null\n mobileToggles: HTMLButtonElement[]\n backdrop: HTMLElement | null\n collapsedClass: string\n key: string\n}\n\nfunction normalizePathname(pathname: string): string {\n if (pathname === '/') {\n return pathname\n }\n\n return pathname.replace(/\\/+$/, '')\n}\n\nfunction routeMatches(pathname: string, href: string): boolean {\n try {\n const hrefPathname = normalizePathname(new URL(href, window.location.href).pathname)\n const currentPathname = normalizePathname(pathname)\n\n if (hrefPathname === '/') {\n return currentPathname === '/'\n }\n\n return currentPathname === hrefPathname || currentPathname.startsWith(`${hrefPathname}/`)\n } catch {\n return false\n }\n}\n\nfunction resolveActiveRouteItem(sidebar: HTMLElement): HTMLElement | null {\n const items = Array.from(\n sidebar.querySelectorAll<HTMLElement>(\n 'a.sidebar__item[href], a.sidebar__nav-link[href], a[data-nav-item][href]'\n )\n )\n\n let active: HTMLElement | null = null\n let activeLength = -1\n\n for (const item of items) {\n const href = item.getAttribute('href')\n if (href === null || !routeMatches(window.location.pathname, href)) {\n continue\n }\n\n try {\n const pathname = normalizePathname(new URL(href, window.location.href).pathname)\n if (pathname.length > activeLength) {\n active = item\n activeLength = pathname.length\n }\n } catch {\n // Ignore malformed href values; they cannot represent the current route.\n }\n }\n\n return active\n}\n\nfunction syncRouteActiveState(sidebar: HTMLElement): void {\n if (currentConfig.activeFromLocation !== true || typeof window === 'undefined') {\n return\n }\n\n const active = resolveActiveRouteItem(sidebar)\n if (active === null) {\n return\n }\n\n sidebar.querySelectorAll<HTMLElement>('.sidebar__item--active').forEach(item => {\n item.classList.remove('sidebar__item--active')\n item.removeAttribute('aria-current')\n })\n active.classList.add('sidebar__item--active')\n active.setAttribute('aria-current', 'page')\n}\n\nfunction prepareUnifiedSidebar(sidebar: HTMLElement, variant: string): void {\n const shouldUseProductStyle =\n sidebar.hasAttribute('data-sidebar-product') ||\n sidebar.classList.contains('sidebar--cm') ||\n currentConfig.productVariants.includes(variant)\n\n if (shouldUseProductStyle) {\n sidebar.classList.add('sidebar--product')\n }\n\n sidebar.querySelectorAll<HTMLElement>('.sidebar__item, .sidebar__nav-link').forEach(item => {\n if (!item.hasAttribute('data-nav-item')) {\n item.setAttribute('data-nav-item', '')\n }\n })\n\n syncRouteActiveState(sidebar)\n}\n\nfunction setupKeyboardNavigation(sidebar: HTMLElement): void {\n sidebar.addEventListener('keydown', event => {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n\n const items = Array.from(\n sidebar.querySelectorAll<HTMLElement>('[data-nav-item]:not([aria-disabled=\"true\"])')\n ).filter(item => !item.hidden && item.offsetParent !== null)\n\n if (items.length === 0) return\n\n const currentIndex = items.indexOf(document.activeElement as HTMLElement)\n if (currentIndex === -1) return\n\n event.preventDefault()\n const nextIndex =\n event.key === 'ArrowDown'\n ? (currentIndex + 1) % items.length\n : (currentIndex - 1 + items.length) % items.length\n\n items[nextIndex]?.focus()\n })\n}\n\n/**\n * Attach all sidebar event handlers (shared between unified and legacy init).\n */\nfunction attachSidebarHandlers({\n sidebar,\n toggle,\n mobileToggles,\n backdrop,\n collapsedClass,\n key,\n}: SidebarHandlerParams): void {\n // Apply stored collapsed state on desktop\n if (!isMobile() && getStoredState(key)) {\n sidebar.classList.add(collapsedClass)\n }\n\n // Desktop toggle handler\n if (toggle) {\n toggle.addEventListener('click', () => {\n const isCollapsed = sidebar.classList.toggle(collapsedClass)\n saveState(key, isCollapsed)\n })\n }\n\n // Mobile toggle handler\n mobileToggles.forEach(mobileToggle => {\n mobileToggle.addEventListener('click', () => {\n toggleSidebarOpen(sidebar, backdrop)\n })\n })\n\n // Backdrop click handler\n if (backdrop) {\n backdrop.addEventListener('click', () => {\n closeSidebar(sidebar, backdrop)\n })\n }\n\n if (currentConfig.closeOnNavigate === true) {\n sidebar.addEventListener('click', event => {\n const target = event.target\n const navItem =\n target instanceof Element\n ? target.closest<HTMLElement>(\n 'a.sidebar__item[href], a.sidebar__nav-link[href], a[data-nav-item][href]'\n )\n : null\n if (navItem !== null && sidebar.getAttribute('data-open') === 'true') {\n closeSidebar(sidebar, backdrop)\n }\n })\n }\n\n // Handle window resize\n window.addEventListener('resize', () => {\n if (isMobile()) {\n closeSidebar(sidebar, backdrop)\n }\n })\n\n // Close sidebar on escape key\n document.addEventListener('keydown', e => {\n if (e.key === 'Escape' && sidebar.getAttribute('data-open') === 'true') {\n closeSidebar(sidebar, backdrop)\n }\n })\n\n setupKeyboardNavigation(sidebar)\n sidebar.setAttribute(INITIALIZED_ATTR, 'true')\n}\n\n/**\n * Initialize a single sidebar using the unified data-sidebar attribute.\n */\nfunction initUnifiedSidebar(sidebar: HTMLElement): void {\n const variant = sidebar.getAttribute('data-sidebar')\n if (variant === null || variant === '') {\n return\n }\n\n prepareUnifiedSidebar(sidebar, variant)\n\n if (sidebar.getAttribute(INITIALIZED_ATTR) === 'true') {\n return\n }\n\n attachSidebarHandlers({\n sidebar,\n toggle: sidebar.querySelector<HTMLButtonElement>('[data-sidebar-toggle]'),\n mobileToggles: Array.from(\n document.querySelectorAll<HTMLButtonElement>('[data-sidebar-mobile-toggle]')\n ),\n backdrop: document.querySelector<HTMLElement>(`[data-sidebar-backdrop=\"${variant}\"]`),\n collapsedClass: currentConfig.collapsedClass,\n key: variant,\n })\n}\n\n/**\n * Initialize a legacy sidebar (backwards compatibility).\n */\nfunction initLegacySidebar(config: LegacySidebarConfig): void {\n const sidebar = document.querySelector<HTMLElement>(config.sidebar)\n if (!sidebar) {\n return\n }\n\n // Skip if this sidebar uses the new unified approach\n if (sidebar.hasAttribute('data-sidebar')) {\n return\n }\n\n attachSidebarHandlers({\n sidebar,\n toggle: document.querySelector<HTMLButtonElement>(config.toggle),\n mobileToggles: Array.from(document.querySelectorAll<HTMLButtonElement>(config.mobileToggle)),\n backdrop: document.querySelector<HTMLElement>(config.backdrop),\n collapsedClass: config.collapsedClass,\n key: config.sidebar.replace(/[^a-z]/g, ''),\n })\n}\n\n/**\n * Default legacy sidebar configurations for CounterMeasure apps.\n */\nexport const defaultLegacyConfigs: LegacySidebarConfig[] = [\n {\n sidebar: '.page__sidebar',\n toggle: '[data-page-sidebar-toggle]',\n mobileToggle: '[data-page-mobile-toggle]',\n backdrop: '.sidebar-backdrop',\n collapsedClass: 'page__sidebar--collapsed',\n },\n {\n sidebar: '.chat-sidebar',\n toggle: '[data-chat-sidebar-toggle]',\n mobileToggle: '.chat-header__menu-toggle',\n backdrop: '.chat-sidebar-backdrop',\n collapsedClass: 'chat-sidebar--collapsed',\n },\n {\n sidebar: '.files-sidebar',\n toggle: '[data-files-sidebar-toggle]',\n mobileToggle: '[data-files-mobile-toggle]',\n backdrop: '.files-sidebar-backdrop',\n collapsedClass: 'files-sidebar--collapsed',\n },\n {\n sidebar: '.storage-sidebar',\n toggle: '[data-storage-sidebar-toggle]',\n mobileToggle: '[data-storage-mobile-toggle]',\n backdrop: '.storage-sidebar-backdrop',\n collapsedClass: 'storage-sidebar--collapsed',\n },\n]\n\n/**\n * Initialize all sidebars (both new unified and legacy).\n */\nexport function initSidebar(\n config?: SidebarConfig,\n legacyConfigs: LegacySidebarConfig[] = defaultLegacyConfigs\n): void {\n if (config) {\n configureSidebar(config)\n }\n\n // Initialize new unified sidebars\n document.querySelectorAll<HTMLElement>('[data-sidebar]').forEach(initUnifiedSidebar)\n\n // Initialize legacy sidebars for backwards compatibility\n legacyConfigs.forEach(initLegacySidebar)\n}\n"],"mappings":"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"}
|
package/dist/sidebar/types.d.ts
CHANGED
|
@@ -1,21 +1,68 @@
|
|
|
1
1
|
import { BrandSize } from '../components/brand';
|
|
2
2
|
import { IconSet } from '../icons/index';
|
|
3
|
+
export type SidebarBadgeTone = 'default' | 'primary' | 'amber' | 'cyan' | 'rose' | 'warning' | 'error';
|
|
4
|
+
export type SidebarActiveMatcher = 'exact' | 'prefix' | string | RegExp | ((pathname: string, item: SidebarNavItem) => boolean);
|
|
5
|
+
export interface SidebarBadgeConfig {
|
|
6
|
+
/** Visible badge text. Use short labels such as "9", "99+", or "Soon". */
|
|
7
|
+
label: string;
|
|
8
|
+
/** Optional accessible title used in collapsed tooltips and native titles. */
|
|
9
|
+
title?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Visual tone for the badge.
|
|
12
|
+
* @default 'primary'
|
|
13
|
+
*/
|
|
14
|
+
tone?: SidebarBadgeTone;
|
|
15
|
+
/**
|
|
16
|
+
* Keep the collapsed rail dot visible even when label is empty.
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
dot?: boolean;
|
|
20
|
+
}
|
|
3
21
|
export interface SidebarNavItem {
|
|
4
22
|
/** Stable identifier used for selection and badge updates. */
|
|
5
23
|
id: string;
|
|
6
24
|
/** Visible label rendered alongside the icon. */
|
|
7
25
|
label: string;
|
|
26
|
+
/** Optional navigation target. When omitted, the item renders as a button. */
|
|
27
|
+
href?: string;
|
|
28
|
+
/** Optional target for link navigation. */
|
|
29
|
+
target?: string;
|
|
30
|
+
/** Optional rel for external links. */
|
|
31
|
+
rel?: string;
|
|
32
|
+
/** Accessible label override. */
|
|
33
|
+
ariaLabel?: string;
|
|
8
34
|
/** Icon name resolved through the active icon set. */
|
|
9
35
|
icon?: string;
|
|
10
|
-
/** Numeric badge displayed at the trailing edge of the row. */
|
|
11
|
-
badge?: number;
|
|
36
|
+
/** Numeric or rich badge displayed at the trailing edge of the row. */
|
|
37
|
+
badge?: number | SidebarBadgeConfig;
|
|
12
38
|
/**
|
|
13
39
|
* Visual tone for the badge.
|
|
14
40
|
* @default 'primary'
|
|
15
41
|
*/
|
|
16
|
-
badgeTone?:
|
|
42
|
+
badgeTone?: SidebarBadgeTone;
|
|
43
|
+
/** Static pill label such as "Admin" or "Soon". */
|
|
44
|
+
tag?: string;
|
|
45
|
+
/** Tooltip/title shown when the sidebar is collapsed. */
|
|
46
|
+
tooltip?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Whether this item is the current page. If omitted, active state can be
|
|
49
|
+
* derived from `activeItemId`, `href`, or `activeMatch`.
|
|
50
|
+
*/
|
|
51
|
+
active?: boolean;
|
|
52
|
+
/** Route matching rule used against the current configured/browser pathname. */
|
|
53
|
+
activeMatch?: SidebarActiveMatcher;
|
|
54
|
+
/**
|
|
55
|
+
* Treat href matching as exact instead of prefix matching.
|
|
56
|
+
* @default false
|
|
57
|
+
*/
|
|
58
|
+
end?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Render the item as unavailable while preserving its position.
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
disabled?: boolean;
|
|
17
64
|
/** Called when the item is activated. */
|
|
18
|
-
onClick?: () => void;
|
|
65
|
+
onClick?: (event: MouseEvent) => void;
|
|
19
66
|
}
|
|
20
67
|
export interface SidebarSection {
|
|
21
68
|
/** Stable section identifier. */
|
|
@@ -42,6 +89,18 @@ export interface SidebarSection {
|
|
|
42
89
|
export interface SidebarUser {
|
|
43
90
|
/** Display name shown in the footer. */
|
|
44
91
|
name: string;
|
|
92
|
+
/** Secondary user metadata such as email or role. */
|
|
93
|
+
detail?: string;
|
|
94
|
+
/** Avatar image URL. */
|
|
95
|
+
avatarUrl?: string;
|
|
96
|
+
/** Initials fallback when no avatar URL is provided. */
|
|
97
|
+
initials?: string;
|
|
98
|
+
/** Presence dot tone shown on the avatar. */
|
|
99
|
+
presence?: 'online' | 'away' | 'busy' | 'dnd' | 'offline';
|
|
100
|
+
/** Accessible label for the user trigger. */
|
|
101
|
+
label?: string;
|
|
102
|
+
/** Called when the user surface is activated. */
|
|
103
|
+
onClick?: () => void;
|
|
45
104
|
}
|
|
46
105
|
export interface SidebarFooterAction {
|
|
47
106
|
/** Stable identifier for the action. */
|
|
@@ -78,6 +137,26 @@ export interface SidebarBrandConfig {
|
|
|
78
137
|
*/
|
|
79
138
|
decorative?: boolean;
|
|
80
139
|
}
|
|
140
|
+
export interface SidebarScopeOption {
|
|
141
|
+
id: string;
|
|
142
|
+
label: string;
|
|
143
|
+
status?: 'active' | 'suspended' | 'archived' | 'warning' | 'error' | 'neutral';
|
|
144
|
+
disabled?: boolean;
|
|
145
|
+
}
|
|
146
|
+
export interface SidebarScopeConfig {
|
|
147
|
+
/** Label shown above/inside the selector. */
|
|
148
|
+
label?: string;
|
|
149
|
+
/** Icon name resolved through the active icon set. */
|
|
150
|
+
icon?: string;
|
|
151
|
+
/** Current selected option id. */
|
|
152
|
+
value?: string;
|
|
153
|
+
/** Fallback label when `value` does not match an option. */
|
|
154
|
+
placeholder?: string;
|
|
155
|
+
/** Options rendered in the selector menu. */
|
|
156
|
+
options: SidebarScopeOption[];
|
|
157
|
+
/** Called when the selected option changes. */
|
|
158
|
+
onChange?: (option: SidebarScopeOption) => void;
|
|
159
|
+
}
|
|
81
160
|
export interface SidebarComponentConfig {
|
|
82
161
|
/** Container element (or selector) the sidebar is mounted into. */
|
|
83
162
|
container: HTMLElement | string;
|
|
@@ -87,6 +166,12 @@ export interface SidebarComponentConfig {
|
|
|
87
166
|
sections: SidebarSection[];
|
|
88
167
|
/** Optional brand header rendered above the navigation. */
|
|
89
168
|
brand?: SidebarBrandConfig;
|
|
169
|
+
/** Optional scope/tenant selector rendered below the brand. */
|
|
170
|
+
scope?: SidebarScopeConfig;
|
|
171
|
+
/** Optional element inserted between the header/scope area and navigation. */
|
|
172
|
+
beforeNav?: HTMLElement | HTMLElement[];
|
|
173
|
+
/** Optional element inserted after navigation and before footer. */
|
|
174
|
+
afterNav?: HTMLElement | HTMLElement[];
|
|
90
175
|
/**
|
|
91
176
|
* Render the shared edge-docked collapse control.
|
|
92
177
|
* @default false
|
|
@@ -113,6 +198,41 @@ export interface SidebarComponentConfig {
|
|
|
113
198
|
* @default false
|
|
114
199
|
*/
|
|
115
200
|
collapsed?: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Current active nav item ID. Applied during initial render and when React
|
|
203
|
+
* wrappers call `setActive`.
|
|
204
|
+
*/
|
|
205
|
+
activeItemId?: string;
|
|
206
|
+
/**
|
|
207
|
+
* Current route path used to derive active link state. When omitted, browser
|
|
208
|
+
* consumers fall back to `window.location.pathname`.
|
|
209
|
+
*/
|
|
210
|
+
pathname?: string;
|
|
211
|
+
/**
|
|
212
|
+
* Persist collapsed state under this localStorage key.
|
|
213
|
+
* When omitted, collapsed state remains in memory only.
|
|
214
|
+
*/
|
|
215
|
+
storageKey?: string;
|
|
216
|
+
/**
|
|
217
|
+
* Persist collapsed state when `storageKey` is supplied.
|
|
218
|
+
* @default true
|
|
219
|
+
*/
|
|
220
|
+
persistCollapsed?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Viewport width below which the sidebar behaves as a mobile drawer.
|
|
223
|
+
* @default 900
|
|
224
|
+
*/
|
|
225
|
+
mobileBreakpoint?: number;
|
|
226
|
+
/**
|
|
227
|
+
* Render and control a mobile backdrop alongside the sidebar.
|
|
228
|
+
* @default false
|
|
229
|
+
*/
|
|
230
|
+
mobileBackdrop?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* Close the mobile drawer after a nav item activates.
|
|
233
|
+
* @default true
|
|
234
|
+
*/
|
|
235
|
+
closeOnNavigate?: boolean;
|
|
116
236
|
/**
|
|
117
237
|
* Controlled mobile open state. Reflected to `data-open` for the mobile
|
|
118
238
|
* sidebar visibility contract.
|
|
@@ -123,5 +243,7 @@ export interface SidebarComponentConfig {
|
|
|
123
243
|
onNavigate?: (item: SidebarNavItem) => void;
|
|
124
244
|
/** Called when the sidebar's collapsed state changes. */
|
|
125
245
|
onCollapse?: (collapsed: boolean) => void;
|
|
246
|
+
/** Called when the mobile open state changes. */
|
|
247
|
+
onOpenChange?: (open: boolean) => void;
|
|
126
248
|
}
|
|
127
249
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sidebar/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAA;IACV,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sidebar/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,GACT,OAAO,CAAA;AAEX,MAAM,MAAM,oBAAoB,GAC5B,OAAO,GACP,QAAQ,GACR,MAAM,GACN,MAAM,GACN,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC,CAAA;AAEzD,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAA;IACvB;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAA;IACV,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAAA;IACnC;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,gFAAgF;IAChF,WAAW,CAAC,EAAE,oBAAoB,CAAA;IAClC;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IACb;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,yCAAyC;IACzC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8CAA8C;IAC9C,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAA;IACzD,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAA;IACV,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uBAAuB;IACvB,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6CAA6C;IAC7C,OAAO,EAAE,kBAAkB,EAAE,CAAA;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;CAChD;AAED,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,SAAS,EAAE,WAAW,GAAG,MAAM,CAAA;IAC/B,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,2DAA2D;IAC3D,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,8EAA8E;IAC9E,SAAS,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAA;IACvC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,CAAA;IACtC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,oDAAoD;IACpD,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,2CAA2C;IAC3C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;IAC3C,yDAAyD;IACzD,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;IACzC,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CACvC"}
|