@tomny-dev/uzi 0.5.0 → 0.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 (277) hide show
  1. package/README.md +4 -1
  2. package/dist/components/card/Card.d.ts +7 -5
  3. package/dist/components/card/Card.d.ts.map +1 -1
  4. package/dist/components/surface/Surface.d.ts +16 -0
  5. package/dist/components/surface/Surface.d.ts.map +1 -0
  6. package/dist/components/toolbar/Toolbar.d.ts +13 -0
  7. package/dist/components/toolbar/Toolbar.d.ts.map +1 -0
  8. package/dist/index.cjs +36 -31
  9. package/dist/index.d.ts +4 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +34 -32
  12. package/dist/index10.cjs.map +1 -1
  13. package/dist/index10.js +19 -15
  14. package/dist/index10.js.map +1 -1
  15. package/dist/index11.cjs +21 -18
  16. package/dist/index11.cjs.map +1 -1
  17. package/dist/index11.js +8 -15
  18. package/dist/index11.js.map +1 -1
  19. package/dist/index12.cjs +7 -14
  20. package/dist/index12.cjs.map +1 -1
  21. package/dist/index12.js +15 -37
  22. package/dist/index12.js.map +1 -1
  23. package/dist/index13.cjs +18 -52
  24. package/dist/index13.cjs.map +1 -1
  25. package/dist/index13.js +15 -77
  26. package/dist/index13.js.map +1 -1
  27. package/dist/index14.cjs +15 -80
  28. package/dist/index14.cjs.map +1 -1
  29. package/dist/index14.js +37 -13
  30. package/dist/index14.js.map +1 -1
  31. package/dist/index15.cjs +52 -18
  32. package/dist/index15.cjs.map +1 -1
  33. package/dist/index15.js +77 -9
  34. package/dist/index15.js.map +1 -1
  35. package/dist/index16.cjs +79 -8
  36. package/dist/index16.cjs.map +1 -1
  37. package/dist/index16.js +13 -41
  38. package/dist/index16.js.map +1 -1
  39. package/dist/index17.cjs +18 -60
  40. package/dist/index17.cjs.map +1 -1
  41. package/dist/index17.js +9 -428
  42. package/dist/index17.js.map +1 -1
  43. package/dist/index18.cjs +8 -430
  44. package/dist/index18.cjs.map +1 -1
  45. package/dist/index18.js +42 -4
  46. package/dist/index18.js.map +1 -1
  47. package/dist/index19.cjs +61 -5
  48. package/dist/index19.cjs.map +1 -1
  49. package/dist/index19.js +430 -13
  50. package/dist/index19.js.map +1 -1
  51. package/dist/index20.cjs +430 -12
  52. package/dist/index20.cjs.map +1 -1
  53. package/dist/index20.js +4 -4
  54. package/dist/index20.js.map +1 -1
  55. package/dist/index21.cjs +5 -5
  56. package/dist/index21.cjs.map +1 -1
  57. package/dist/index21.js +12 -9
  58. package/dist/index21.js.map +1 -1
  59. package/dist/index22.cjs +12 -9
  60. package/dist/index22.cjs.map +1 -1
  61. package/dist/index22.js +4 -4
  62. package/dist/index22.js.map +1 -1
  63. package/dist/index23.cjs +5 -5
  64. package/dist/index23.cjs.map +1 -1
  65. package/dist/index23.js +9 -12
  66. package/dist/index23.js.map +1 -1
  67. package/dist/index24.cjs +9 -12
  68. package/dist/index24.cjs.map +1 -1
  69. package/dist/index24.js +4 -38
  70. package/dist/index24.js.map +1 -1
  71. package/dist/index25.cjs +5 -55
  72. package/dist/index25.cjs.map +1 -1
  73. package/dist/index25.js +11 -116
  74. package/dist/index25.js.map +1 -1
  75. package/dist/index26.cjs +10 -116
  76. package/dist/index26.cjs.map +1 -1
  77. package/dist/index26.js +31 -19
  78. package/dist/index26.js.map +1 -1
  79. package/dist/index27.cjs +42 -24
  80. package/dist/index27.cjs.map +1 -1
  81. package/dist/index27.js +106 -93
  82. package/dist/index27.js.map +1 -1
  83. package/dist/index28.cjs +106 -93
  84. package/dist/index28.cjs.map +1 -1
  85. package/dist/index28.js +26 -23
  86. package/dist/index28.js.map +1 -1
  87. package/dist/index29.cjs +37 -25
  88. package/dist/index29.cjs.map +1 -1
  89. package/dist/index29.js +107 -26
  90. package/dist/index29.js.map +1 -1
  91. package/dist/index30.cjs +110 -37
  92. package/dist/index30.cjs.map +1 -1
  93. package/dist/index30.js +21 -113
  94. package/dist/index30.js.map +1 -1
  95. package/dist/index31.cjs +19 -125
  96. package/dist/index31.cjs.map +1 -1
  97. package/dist/index31.js +26 -17
  98. package/dist/index31.js.map +1 -1
  99. package/dist/index32.cjs +37 -20
  100. package/dist/index32.cjs.map +1 -1
  101. package/dist/index32.js +108 -104
  102. package/dist/index32.js.map +1 -1
  103. package/dist/index33.cjs +122 -103
  104. package/dist/index33.cjs.map +1 -1
  105. package/dist/index33.js +17 -4
  106. package/dist/index33.js.map +1 -1
  107. package/dist/index34.cjs +20 -5
  108. package/dist/index34.cjs.map +1 -1
  109. package/dist/index34.js +106 -58
  110. package/dist/index34.js.map +1 -1
  111. package/dist/index35.cjs +106 -57
  112. package/dist/index35.cjs.map +1 -1
  113. package/dist/index35.js +4 -22
  114. package/dist/index35.js.map +1 -1
  115. package/dist/index36.cjs +5 -31
  116. package/dist/index36.cjs.map +1 -1
  117. package/dist/index36.js +55 -44
  118. package/dist/index36.js.map +1 -1
  119. package/dist/index37.cjs +55 -44
  120. package/dist/index37.cjs.map +1 -1
  121. package/dist/index37.js +21 -31
  122. package/dist/index37.js.map +1 -1
  123. package/dist/index38.cjs +30 -45
  124. package/dist/index38.cjs.map +1 -1
  125. package/dist/index38.js +46 -141
  126. package/dist/index38.js.map +1 -1
  127. package/dist/index39.cjs +46 -141
  128. package/dist/index39.cjs.map +1 -1
  129. package/dist/index39.js +31 -41
  130. package/dist/index39.js.map +1 -1
  131. package/dist/index40.cjs +45 -60
  132. package/dist/index40.cjs.map +1 -1
  133. package/dist/index40.js +139 -163
  134. package/dist/index40.js.map +1 -1
  135. package/dist/index41.cjs +137 -161
  136. package/dist/index41.cjs.map +1 -1
  137. package/dist/index41.js +41 -12
  138. package/dist/index41.js.map +1 -1
  139. package/dist/index42.cjs +60 -14
  140. package/dist/index42.cjs.map +1 -1
  141. package/dist/index42.js +167 -15
  142. package/dist/index42.js.map +1 -1
  143. package/dist/index43.cjs +166 -14
  144. package/dist/index43.cjs.map +1 -1
  145. package/dist/index43.js +12 -15
  146. package/dist/index43.js.map +1 -1
  147. package/dist/index44.cjs +14 -21
  148. package/dist/index44.cjs.map +1 -1
  149. package/dist/index44.js +15 -28
  150. package/dist/index44.js.map +1 -1
  151. package/dist/index45.cjs +14 -27
  152. package/dist/index45.cjs.map +1 -1
  153. package/dist/index45.js +10 -8
  154. package/dist/index45.js.map +1 -1
  155. package/dist/index46.cjs +11 -8
  156. package/dist/index46.cjs.map +1 -1
  157. package/dist/index46.js +22 -15
  158. package/dist/index46.js.map +1 -1
  159. package/dist/index47.cjs +22 -15
  160. package/dist/index47.cjs.map +1 -1
  161. package/dist/index47.js +9 -13
  162. package/dist/index47.js.map +1 -1
  163. package/dist/index48.cjs +10 -16
  164. package/dist/index48.cjs.map +1 -1
  165. package/dist/index48.js +18 -25
  166. package/dist/index48.js.map +1 -1
  167. package/dist/index49.cjs +18 -25
  168. package/dist/index49.cjs.map +1 -1
  169. package/dist/index49.js +17 -14
  170. package/dist/index49.js.map +1 -1
  171. package/dist/index50.cjs +24 -17
  172. package/dist/index50.cjs.map +1 -1
  173. package/dist/index50.js +28 -28
  174. package/dist/index50.js.map +1 -1
  175. package/dist/index51.cjs +27 -28
  176. package/dist/index51.cjs.map +1 -1
  177. package/dist/index51.js +14 -17
  178. package/dist/index51.js.map +1 -1
  179. package/dist/index52.cjs +17 -22
  180. package/dist/index52.cjs.map +1 -1
  181. package/dist/index52.js +23 -23
  182. package/dist/index52.js.map +1 -1
  183. package/dist/index53.cjs +23 -23
  184. package/dist/index53.cjs.map +1 -1
  185. package/dist/index53.js +17 -10
  186. package/dist/index53.js.map +1 -1
  187. package/dist/index54.cjs +22 -11
  188. package/dist/index54.cjs.map +1 -1
  189. package/dist/index54.js +28 -14
  190. package/dist/index54.js.map +1 -1
  191. package/dist/index55.cjs +28 -13
  192. package/dist/index55.cjs.map +1 -1
  193. package/dist/index55.js +17 -11
  194. package/dist/index55.js.map +1 -1
  195. package/dist/index56.cjs +23 -13
  196. package/dist/index56.cjs.map +1 -1
  197. package/dist/index56.js +24 -16
  198. package/dist/index56.js.map +1 -1
  199. package/dist/index57.cjs +24 -15
  200. package/dist/index57.cjs.map +1 -1
  201. package/dist/index57.js +10 -9
  202. package/dist/index57.js.map +1 -1
  203. package/dist/index58.cjs +11 -12
  204. package/dist/index58.cjs.map +1 -1
  205. package/dist/index58.js +12 -87
  206. package/dist/index58.js.map +1 -1
  207. package/dist/index59.cjs +12 -89
  208. package/dist/index59.cjs.map +1 -1
  209. package/dist/index59.js +11 -21
  210. package/dist/index59.js.map +1 -1
  211. package/dist/index60.cjs +13 -30
  212. package/dist/index60.cjs.map +1 -1
  213. package/dist/index60.js +17 -43
  214. package/dist/index60.js.map +1 -1
  215. package/dist/index61.cjs +16 -44
  216. package/dist/index61.cjs.map +1 -1
  217. package/dist/index61.js +9 -57
  218. package/dist/index61.js.map +1 -1
  219. package/dist/index62.cjs +11 -83
  220. package/dist/index62.cjs.map +1 -1
  221. package/dist/index62.js +83 -426
  222. package/dist/index62.js.map +1 -1
  223. package/dist/index63.cjs +82 -427
  224. package/dist/index63.cjs.map +1 -1
  225. package/dist/index63.js +21 -59
  226. package/dist/index63.js.map +1 -1
  227. package/dist/index64.cjs +30 -87
  228. package/dist/index64.cjs.map +1 -1
  229. package/dist/index64.js +44 -240
  230. package/dist/index64.js.map +1 -1
  231. package/dist/index65.cjs +43 -239
  232. package/dist/index65.cjs.map +1 -1
  233. package/dist/index65.js +57 -43
  234. package/dist/index65.js.map +1 -1
  235. package/dist/index66.cjs +84 -63
  236. package/dist/index66.cjs.map +1 -1
  237. package/dist/index66.js +426 -73
  238. package/dist/index66.js.map +1 -1
  239. package/dist/index67.cjs +426 -71
  240. package/dist/index67.cjs.map +1 -1
  241. package/dist/index67.js +59 -21
  242. package/dist/index67.js.map +1 -1
  243. package/dist/index68.cjs +87 -30
  244. package/dist/index68.cjs.map +1 -1
  245. package/dist/index68.js +233 -88
  246. package/dist/index68.js.map +1 -1
  247. package/dist/index69.cjs +232 -89
  248. package/dist/index69.cjs.map +1 -1
  249. package/dist/index69.js +40 -16
  250. package/dist/index69.js.map +1 -1
  251. package/dist/index70.cjs +56 -20
  252. package/dist/index70.cjs.map +1 -1
  253. package/dist/index70.js +72 -145
  254. package/dist/index70.js.map +1 -1
  255. package/dist/index71.cjs +72 -145
  256. package/dist/index71.cjs.map +1 -1
  257. package/dist/index71.js +25 -0
  258. package/dist/index71.js.map +1 -0
  259. package/dist/index72.cjs +34 -0
  260. package/dist/index72.cjs.map +1 -0
  261. package/dist/index72.js +101 -0
  262. package/dist/index72.js.map +1 -0
  263. package/dist/index73.cjs +105 -0
  264. package/dist/index73.cjs.map +1 -0
  265. package/dist/index73.js +23 -0
  266. package/dist/index73.js.map +1 -0
  267. package/dist/index74.cjs +31 -0
  268. package/dist/index74.cjs.map +1 -0
  269. package/dist/index74.js +159 -0
  270. package/dist/index74.js.map +1 -0
  271. package/dist/index75.cjs +161 -0
  272. package/dist/index75.cjs.map +1 -0
  273. package/dist/index8.js.map +1 -1
  274. package/dist/index9.cjs.map +1 -1
  275. package/dist/index9.js.map +1 -1
  276. package/dist/style.css +215 -45
  277. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"index40.js","names":[],"sources":["../src/components/sidebar-nav/SidebarNav.tsx"],"sourcesContent":["\"use client\";\n\nimport { type AnchorHTMLAttributes, type CSSProperties, type ReactNode, useMemo } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport styles from \"./sidebar-nav.module.css\";\n\nexport type SidebarNavItem = {\n label: string;\n href?: string;\n icon?: ReactNode;\n description?: ReactNode;\n badge?: ReactNode;\n active?: boolean;\n disabled?: boolean;\n /**\n * When `true`, this item uses exact matching (matches its own path and paths starting with `{href}/`)\n * instead of prefix matching. This flag takes precedence over the global `matchStrategy` prop on a\n * per-item basis — even when `matchStrategy=\"prefix\"`, an item with `exact: true` will use exact matching.\n * When `matchStrategy=\"most-specific\"`, exact-flagged items participate in the length-based tiebreaker\n * like all other candidates, provided they pass their own match check first.\n */\n exact?: boolean;\n title?: string;\n target?: AnchorHTMLAttributes<HTMLAnchorElement>[\"target\"];\n rel?: AnchorHTMLAttributes<HTMLAnchorElement>[\"rel\"];\n onClick?: () => void;\n};\n\nexport type SidebarNavSection = {\n id?: string;\n label?: ReactNode;\n items: SidebarNavItem[];\n};\n\nexport type SidebarNavProps = {\n items?: SidebarNavItem[];\n sections?: SidebarNavSection[];\n currentPath?: string;\n getIsActive?: (item: SidebarNavItem, currentPath?: string) => boolean;\n matchStrategy?: \"prefix\" | \"most-specific\";\n onItemClick?: (item: SidebarNavItem) => void;\n header?: ReactNode;\n footer?: ReactNode;\n ariaLabel?: string;\n collapsed?: boolean;\n iconSize?: number | string;\n className?: string;\n itemClassName?: string;\n sectionClassName?: string;\n};\n\nconst isActivePrefix = (item: SidebarNavItem, path?: string) => {\n if (item.active !== undefined) return item.active;\n if (!item.href) return false;\n if (!path) return false;\n if (item.href === \"/\") return path === \"/\";\n return path.startsWith(item.href);\n};\n\nconst isActiveExact = (item: SidebarNavItem, path?: string) => {\n if (item.active !== undefined) return item.active;\n if (!item.href) return false;\n if (!path) return false;\n // Root href \"/\" must match exactly — otherwise every path would match.\n if (item.href === \"/\") return path === \"/\";\n // Normalize trailing slashes for consistent matching with findMostSpecific length computation.\n const normalizedHref = item.href.endsWith(\"/\") ? item.href.slice(0, -1) : item.href;\n return normalizedHref === path || path.startsWith(`${normalizedHref}/`);\n};\n\n// Natural matching helpers that ignore manual `active` overrides — used inside findMostSpecific\n// so that manually-set active flags don't hijack the length-based tiebreaker.\nconst isNaturalPrefixMatch = (href: string, path: string) => {\n if (href === \"/\") return path === \"/\";\n return path.startsWith(href);\n};\n\nconst isNaturalExactMatch = (href: string, path: string) => {\n if (href === \"/\") return path === \"/\";\n const normalizedHref = href.endsWith(\"/\") ? href.slice(0, -1) : href;\n return normalizedHref === path;\n};\n\nconst hrefLength = (href: string) => (href.endsWith(\"/\") ? href.length - 1 : href.length);\n\nconst findMostSpecific = (items: SidebarNavItem[], currentPath?: string): Set<string> => {\n const result = new Set<string>();\n if (!currentPath) return result;\n\n // Collect all items that naturally match the path — use natural matching helpers so that\n // manually-set `active` flags don't participate in the length-based tiebreaker.\n // Exclude disabled items from matching since they are not interactive targets.\n const matchingItems = items.filter(item => {\n if (item.disabled || !item.href) return false;\n return item.exact\n ? isNaturalExactMatch(item.href, currentPath)\n : isNaturalPrefixMatch(item.href, currentPath);\n });\n\n if (matchingItems.length === 0) return result;\n\n // Find the longest href among prefix matches.\n let maxLen = 0;\n for (const item of matchingItems) {\n if (!item.href) continue;\n const len = hrefLength(item.href);\n if (len > maxLen) maxLen = len;\n }\n\n // Only the items with the longest href are active.\n for (const item of matchingItems) {\n if (!item.href) continue;\n if (hrefLength(item.href) === maxLen) result.add(item.href);\n }\n\n return result;\n};\n\nexport function SidebarNav({\n items = [],\n sections,\n currentPath,\n getIsActive,\n matchStrategy = \"prefix\",\n onItemClick,\n header,\n footer,\n ariaLabel = \"Sidebar navigation\",\n collapsed = false,\n iconSize,\n className,\n itemClassName,\n sectionClassName,\n}: SidebarNavProps) {\n const resolvedSections = useMemo(() => {\n return sections?.length ? sections : [{ id: \"default\", items }];\n }, [sections, items]);\n\n // Stable reference to all items — avoids recreating on every render when `sections` is falsy.\n const allItems = useMemo(() => resolvedSections.flatMap(section => section.items), [resolvedSections]);\n\n // Build the default isActive function based on matchStrategy.\n const defaultIsActiveFn = useMemo<(item: SidebarNavItem, path?: string) => boolean>(() => {\n if (matchStrategy === \"most-specific\") {\n const mostSpecificHrefs = findMostSpecific(allItems, currentPath);\n return (item: SidebarNavItem) => {\n if (item.active !== undefined) return item.active;\n if (!item.href) return false;\n // Exact-flagged items participate in the length-based tiebreaker like all other candidates.\n return mostSpecificHrefs.has(item.href);\n };\n } else {\n return (item: SidebarNavItem, path?: string) => {\n if (item.active !== undefined) return item.active;\n if (item.exact) return isActiveExact(item, path);\n return isActivePrefix(item, path);\n };\n }\n }, [matchStrategy, allItems, currentPath]);\n\n const resolvedGetIsActive = getIsActive ?? defaultIsActiveFn;\n\n const style =\n iconSize !== undefined\n ? ({\n [\"--sidebar-nav-icon-size\" as string]:\n typeof iconSize === \"number\" ? `${iconSize}px` : iconSize,\n } satisfies CSSProperties)\n : undefined;\n\n return (\n <nav\n className={cx(\n styles.sidebarNav,\n collapsed && styles.sidebarNavCollapsed,\n className,\n )}\n aria-label={ariaLabel}\n style={style}\n >\n {header ? <div className={styles.header}>{header}</div> : null}\n <div className={styles.sections}>\n {resolvedSections.map((section, sectionIndex) => (\n <div\n key={section.id ?? `section-${sectionIndex}`}\n className={cx(styles.section, sectionClassName)}\n >\n {section.label && !collapsed ? (\n <div className={styles.sectionLabel}>{section.label}</div>\n ) : null}\n <div className={styles.sectionItems}>\n {section.items.map((item, itemIndex) => (\n <SidebarNavEntry\n key={`${section.id ?? sectionIndex}-${item.href ?? item.title ?? itemIndex}`}\n item={item}\n active={resolvedGetIsActive(item, currentPath)}\n collapsed={collapsed}\n itemClassName={itemClassName}\n onItemClick={onItemClick}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n {footer ? <div className={styles.footer}>{footer}</div> : null}\n </nav>\n );\n}\n\ntype SidebarNavEntryProps = {\n item: SidebarNavItem;\n active: boolean;\n collapsed: boolean;\n itemClassName?: string;\n onItemClick?: (item: SidebarNavItem) => void;\n};\n\nfunction SidebarNavEntry({\n item,\n active,\n collapsed,\n itemClassName,\n onItemClick,\n}: SidebarNavEntryProps) {\n const rel = item.rel ?? (item.target === \"_blank\" ? \"noreferrer\" : undefined);\n const title = item.title ?? (typeof item.label === \"string\" ? item.label : undefined);\n const hasIcon = Boolean(item.icon);\n const classes = cx(\n styles.item,\n !hasIcon && styles.itemWithoutIcon,\n active && styles.itemActive,\n collapsed && styles.itemCollapsed,\n item.disabled && styles.itemDisabled,\n itemClassName,\n );\n const content = (\n <>\n {hasIcon ? <span className={styles.icon}>{item.icon}</span> : null}\n {!collapsed ? (\n <span className={styles.itemBody}>\n <span className={styles.labelRow}>\n <span className={styles.label}>{item.label}</span>\n {item.badge && <span className={styles.badge}>{item.badge}</span>}\n </span>\n {item.description ? <span className={styles.description}>{item.description}</span> : null}\n </span>\n ) : null}\n </>\n );\n\n const handleClick = () => {\n if (item.disabled) return;\n item.onClick?.();\n onItemClick?.(item);\n };\n\n if (!item.href) {\n return (\n <button\n type=\"button\"\n className={classes}\n aria-current={active ? \"page\" : undefined}\n aria-disabled={item.disabled ? \"true\" : undefined}\n disabled={item.disabled}\n title={collapsed ? title : undefined}\n onClick={handleClick}\n >\n {content}\n </button>\n );\n }\n\n if (item.disabled) {\n return (\n <div\n className={classes}\n aria-current={active ? \"page\" : undefined}\n aria-disabled=\"true\"\n title={collapsed ? title : undefined}\n >\n {content}\n </div>\n );\n }\n\n return (\n <a\n className={classes}\n href={item.href}\n target={item.target}\n rel={rel}\n aria-current={active ? \"page\" : undefined}\n title={collapsed ? title : undefined}\n onClick={handleClick}\n >\n {content}\n </a>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index40.js","names":[],"sources":["../src/components/app-shell/AppShell.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { TopBar, type TopBarProps } from \"../top-bar/TopBar\";\nimport styles from \"./app-shell.module.css\";\n\nconst DESKTOP_BREAKPOINT = 960;\n\nfunction getIsDesktop() {\n if (typeof window === \"undefined\") return false;\n return window.innerWidth >= DESKTOP_BREAKPOINT;\n}\n\nexport type AppShellProps = {\n /** Primary page content rendered in the main area. */\n children: ReactNode;\n /** Sidebar navigation or custom content. */\n sidebar: ReactNode;\n /** Brand element rendered next to the hamburger (text or JSX). */\n brand?: ReactNode;\n /** Optional brand href; when provided the brand renders as an anchor. */\n brandHref?: string;\n /** Optional content after the brand on the left side of the top bar. */\n topbarStart?: ReactNode;\n /** Optional content aligned to the right side of the top bar. */\n topbarEnd?: ReactNode;\n /** Optional built-in theme toggle for the top bar. */\n showThemeToggle?: boolean;\n themeToggleProps?: TopBarProps[\"themeToggleProps\"];\n topBarBrandingLocation?: TopBarProps[\"brandingLocation\"];\n /** Custom class names for styling overrides. */\n className?: string;\n sidebarClassName?: string;\n topbarClassName?: string;\n mainClassName?: string;\n /** Sets the sidebar width (e.g., `260`, `\"18rem\"`). */\n sidebarWidth?: number | string;\n /**\n * Closes the sidebar on mobile whenever this value changes.\n * Useful for reacting to route/pathname changes.\n */\n closeSidebarOnChangeKey?: unknown;\n /** Label for the hamburger button (aria-label). */\n hamburgerLabel?: string;\n /** Optional callback fired whenever the sidebar open state changes. */\n onSidebarToggle?: (open: boolean) => void;\n};\n\n/**\n * Responsive application shell with a collapsible sidebar and sticky top bar.\n *\n * - Sidebar opens by default on desktop, collapses on mobile.\n * - Closes on outside click/scroll/touch when in mobile mode.\n * - Provides optional hook to close the sidebar when a prop value changes\n * (e.g., route transitions).\n */\nexport function AppShell({\n children,\n sidebar,\n brand,\n brandHref,\n topbarStart,\n topbarEnd,\n showThemeToggle = false,\n themeToggleProps,\n topBarBrandingLocation = \"left\",\n className,\n sidebarClassName,\n topbarClassName,\n mainClassName,\n sidebarWidth,\n closeSidebarOnChangeKey,\n hamburgerLabel = \"Toggle navigation\",\n onSidebarToggle,\n}: AppShellProps) {\n const [isDesktop, setIsDesktop] = useState(false);\n const [sidebarOpen, setSidebarOpen] = useState(false);\n const [transitionsReady, setTransitionsReady] = useState(false);\n const prevIsDesktopRef = useRef(false);\n const closeKeyRef = useRef(closeSidebarOnChangeKey);\n\n const sidebarRef = useRef<HTMLElement | null>(null);\n const hamburgerRef = useRef<HTMLButtonElement | null>(null);\n const mainRef = useRef<HTMLElement | null>(null);\n const sidebarId = useId();\n\n useEffect(() => {\n const desktop = getIsDesktop();\n setIsDesktop(desktop);\n setSidebarOpen(desktop);\n prevIsDesktopRef.current = desktop;\n const transitionFrame = window.requestAnimationFrame(() => {\n setTransitionsReady(true);\n });\n\n const handleResize = () => {\n const nowDesktop = getIsDesktop();\n setIsDesktop(nowDesktop);\n if (nowDesktop !== prevIsDesktopRef.current) {\n setSidebarOpen(nowDesktop);\n prevIsDesktopRef.current = nowDesktop;\n }\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.cancelAnimationFrame(transitionFrame);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, []);\n\n // Close the sidebar when clicking outside or scrolling on mobile.\n useEffect(() => {\n if (isDesktop || !sidebarOpen) return;\n\n const mainElement = mainRef.current;\n const closeSidebar = () => setSidebarOpen(false);\n\n const onPointerDown = (e: PointerEvent) => {\n const target = e.target as Node | null;\n if (!target) return;\n if (sidebarRef.current?.contains(target)) return;\n if (hamburgerRef.current?.contains(target)) return;\n closeSidebar();\n };\n\n const timeoutId = window.setTimeout(() => {\n document.addEventListener(\"pointerdown\", onPointerDown);\n window.addEventListener(\"scroll\", closeSidebar, { passive: true });\n mainElement?.addEventListener(\"scroll\", closeSidebar, { passive: true });\n document.addEventListener(\"touchmove\", closeSidebar, { passive: true });\n }, 10);\n\n return () => {\n window.clearTimeout(timeoutId);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n window.removeEventListener(\"scroll\", closeSidebar);\n mainElement?.removeEventListener(\"scroll\", closeSidebar);\n document.removeEventListener(\"touchmove\", closeSidebar);\n };\n }, [sidebarOpen, isDesktop]);\n\n // Allow consumers to request a mobile sidebar close when a value changes (e.g., pathname).\n useEffect(() => {\n if (!isDesktop && closeKeyRef.current !== closeSidebarOnChangeKey) {\n setSidebarOpen(false);\n }\n closeKeyRef.current = closeSidebarOnChangeKey;\n }, [closeSidebarOnChangeKey, isDesktop]);\n\n useEffect(() => {\n onSidebarToggle?.(sidebarOpen);\n }, [sidebarOpen, onSidebarToggle]);\n\n const toggleSidebar = () => setSidebarOpen((open) => !open);\n\n const sidebarWidthValue =\n sidebarWidth === undefined\n ? undefined\n : typeof sidebarWidth === \"number\"\n ? `${sidebarWidth}px`\n : sidebarWidth;\n\n const shellStyle: CSSProperties | undefined = sidebarWidthValue\n ? { [\"--app-shell-sidebar-width\" as string]: sidebarWidthValue }\n : undefined;\n\n const shellClasses = cx(\n styles.appShell,\n transitionsReady && styles.appShellAnimated,\n sidebarOpen ? styles.appShellOpen : styles.appShellCollapsed,\n className,\n );\n\n const sidebarClasses = cx(\n styles.appShellSidebar,\n sidebarOpen && styles.appShellSidebarOpen,\n sidebarClassName,\n );\n\n return (\n <div\n className={shellClasses}\n style={shellStyle}\n data-app-shell\n data-desktop={isDesktop ? \"true\" : \"false\"}\n data-sidebar-open={sidebarOpen ? \"true\" : \"false\"}\n >\n <TopBar\n className={cx(styles.appShellTopbar, topbarClassName)}\n leading={\n <button\n ref={hamburgerRef}\n type=\"button\"\n className={styles.appShellHamburger}\n onClick={toggleSidebar}\n aria-label={hamburgerLabel}\n aria-expanded={sidebarOpen}\n aria-controls={sidebarId}\n >\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path d=\"M3 6h18M3 12h18M3 18h18\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" />\n </svg>\n </button>\n }\n brand={brand}\n brandHref={brandHref}\n brandingLocation={topBarBrandingLocation}\n start={topbarStart}\n actions={topbarEnd}\n showThemeToggle={showThemeToggle}\n themeToggleProps={themeToggleProps}\n />\n {!isDesktop && sidebarOpen && (\n <div\n className={styles.appShellBackdrop}\n onClick={() => setSidebarOpen(false)}\n onTouchStart={() => setSidebarOpen(false)}\n aria-hidden=\"true\"\n />\n )}\n <aside ref={sidebarRef} id={sidebarId} className={sidebarClasses} aria-label=\"Sidebar navigation\">\n {sidebar}\n </aside>\n <main ref={mainRef} className={cx(styles.appShellMain, mainClassName)}>\n {children}\n </main>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAcA,IAAM,qBAAqB;AAE3B,SAAS,eAAe;CACtB,IAAI,OAAO,WAAW,aAAa,OAAO;CAC1C,OAAO,OAAO,cAAc;AAC9B;;;;;;;;;AA6CA,SAAgB,SAAS,EACvB,UACA,SACA,OACA,WACA,aACA,WACA,kBAAkB,OAClB,kBACA,yBAAyB,QACzB,WACA,kBACA,iBACA,eACA,cACA,yBACA,iBAAiB,qBACjB,mBACgB;CAChB,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAC9D,MAAM,mBAAmB,OAAO,KAAK;CACrC,MAAM,cAAc,OAAO,uBAAuB;CAElD,MAAM,aAAa,OAA2B,IAAI;CAClD,MAAM,eAAe,OAAiC,IAAI;CAC1D,MAAM,UAAU,OAA2B,IAAI;CAC/C,MAAM,YAAY,MAAM;CAExB,gBAAgB;EACd,MAAM,UAAU,aAAa;EAC7B,aAAa,OAAO;EACpB,eAAe,OAAO;EACtB,iBAAiB,UAAU;EAC3B,MAAM,kBAAkB,OAAO,4BAA4B;GACzD,oBAAoB,IAAI;EAC1B,CAAC;EAED,MAAM,qBAAqB;GACzB,MAAM,aAAa,aAAa;GAChC,aAAa,UAAU;GACvB,IAAI,eAAe,iBAAiB,SAAS;IAC3C,eAAe,UAAU;IACzB,iBAAiB,UAAU;GAC7B;EACF;EAEA,OAAO,iBAAiB,UAAU,YAAY;EAC9C,aAAa;GACX,OAAO,qBAAqB,eAAe;GAC3C,OAAO,oBAAoB,UAAU,YAAY;EACnD;CACF,GAAG,CAAC,CAAC;CAGL,gBAAgB;EACd,IAAI,aAAa,CAAC,aAAa;EAE/B,MAAM,cAAc,QAAQ;EAC5B,MAAM,qBAAqB,eAAe,KAAK;EAE/C,MAAM,iBAAiB,MAAoB;GACzC,MAAM,SAAS,EAAE;GACjB,IAAI,CAAC,QAAQ;GACb,IAAI,WAAW,SAAS,SAAS,MAAM,GAAG;GAC1C,IAAI,aAAa,SAAS,SAAS,MAAM,GAAG;GAC5C,aAAa;EACf;EAEA,MAAM,YAAY,OAAO,iBAAiB;GACxC,SAAS,iBAAiB,eAAe,aAAa;GACtD,OAAO,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;GACjE,aAAa,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;GACvE,SAAS,iBAAiB,aAAa,cAAc,EAAE,SAAS,KAAK,CAAC;EACxE,GAAG,EAAE;EAEL,aAAa;GACX,OAAO,aAAa,SAAS;GAC7B,SAAS,oBAAoB,eAAe,aAAa;GACzD,OAAO,oBAAoB,UAAU,YAAY;GACjD,aAAa,oBAAoB,UAAU,YAAY;GACvD,SAAS,oBAAoB,aAAa,YAAY;EACxD;CACF,GAAG,CAAC,aAAa,SAAS,CAAC;CAG3B,gBAAgB;EACd,IAAI,CAAC,aAAa,YAAY,YAAY,yBACxC,eAAe,KAAK;EAEtB,YAAY,UAAU;CACxB,GAAG,CAAC,yBAAyB,SAAS,CAAC;CAEvC,gBAAgB;EACd,kBAAkB,WAAW;CAC/B,GAAG,CAAC,aAAa,eAAe,CAAC;CAEjC,MAAM,sBAAsB,gBAAgB,SAAS,CAAC,IAAI;CAE1D,MAAM,oBACJ,iBAAiB,KAAA,IACb,KAAA,IACA,OAAO,iBAAiB,WACtB,GAAG,aAAa,MAChB;CAER,MAAM,aAAwC,oBAC1C,GAAG,8BAAwC,kBAAkB,IAC7D,KAAA;CAEJ,MAAM,eAAe,GACnB,yBAAO,UACP,oBAAoB,yBAAO,kBAC3B,cAAc,yBAAO,eAAe,yBAAO,mBAC3C,SACF;CAEA,MAAM,iBAAiB,GACrB,yBAAO,iBACP,eAAe,yBAAO,qBACtB,gBACF;CAEA,OACE,qBAAC,OAAD;EACE,WAAW;EACX,OAAO;EACP,kBAAA;EACA,gBAAc,YAAY,SAAS;EACnC,qBAAmB,cAAc,SAAS;YAL5C;GAOE,oBAAC,QAAD;IACE,WAAW,GAAG,yBAAO,gBAAgB,eAAe;IACpD,SACE,oBAAC,UAAD;KACE,KAAK;KACL,MAAK;KACL,WAAW,yBAAO;KAClB,SAAS;KACT,cAAY;KACZ,iBAAe;KACf,iBAAe;eAEf,oBAAC,OAAD;MAAK,SAAQ;MAAY,eAAY;gBACnC,oBAAC,QAAD;OAAM,GAAE;OAA0B,QAAO;OAAe,aAAY;OAAM,eAAc;MAAS,CAAA;KAC9F,CAAA;IACC,CAAA;IAEH;IACI;IACX,kBAAkB;IAClB,OAAO;IACP,SAAS;IACQ;IACC;GACnB,CAAA;GACA,CAAC,aAAa,eACb,oBAAC,OAAD;IACE,WAAW,yBAAO;IAClB,eAAe,eAAe,KAAK;IACnC,oBAAoB,eAAe,KAAK;IACxC,eAAY;GACb,CAAA;GAEH,oBAAC,SAAD;IAAO,KAAK;IAAY,IAAI;IAAW,WAAW;IAAgB,cAAW;cAC1E;GACI,CAAA;GACP,oBAAC,QAAD;IAAM,KAAK;IAAS,WAAW,GAAG,yBAAO,cAAc,aAAa;IACjE;GACG,CAAA;EACH;;AAET"}
package/dist/index41.cjs CHANGED
@@ -1,174 +1,150 @@
1
1
  "use client";
2
2
  const require_cx = require("./index4.cjs");
3
- const require_sidebar_nav_module = require("./index40.cjs");
3
+ const require_TopBar = require("./index39.cjs");
4
+ const require_app_shell_module = require("./index40.cjs");
4
5
  let react = require("react");
5
6
  let react_jsx_runtime = require("react/jsx-runtime");
6
- //#region src/components/sidebar-nav/SidebarNav.tsx
7
- var isActivePrefix = (item, path) => {
8
- if (item.active !== void 0) return item.active;
9
- if (!item.href) return false;
10
- if (!path) return false;
11
- if (item.href === "/") return path === "/";
12
- return path.startsWith(item.href);
13
- };
14
- var isActiveExact = (item, path) => {
15
- if (item.active !== void 0) return item.active;
16
- if (!item.href) return false;
17
- if (!path) return false;
18
- if (item.href === "/") return path === "/";
19
- const normalizedHref = item.href.endsWith("/") ? item.href.slice(0, -1) : item.href;
20
- return normalizedHref === path || path.startsWith(`${normalizedHref}/`);
21
- };
22
- var isNaturalPrefixMatch = (href, path) => {
23
- if (href === "/") return path === "/";
24
- return path.startsWith(href);
25
- };
26
- var isNaturalExactMatch = (href, path) => {
27
- if (href === "/") return path === "/";
28
- return (href.endsWith("/") ? href.slice(0, -1) : href) === path;
29
- };
30
- var hrefLength = (href) => href.endsWith("/") ? href.length - 1 : href.length;
31
- var findMostSpecific = (items, currentPath) => {
32
- const result = /* @__PURE__ */ new Set();
33
- if (!currentPath) return result;
34
- const matchingItems = items.filter((item) => {
35
- if (item.disabled || !item.href) return false;
36
- return item.exact ? isNaturalExactMatch(item.href, currentPath) : isNaturalPrefixMatch(item.href, currentPath);
37
- });
38
- if (matchingItems.length === 0) return result;
39
- let maxLen = 0;
40
- for (const item of matchingItems) {
41
- if (!item.href) continue;
42
- const len = hrefLength(item.href);
43
- if (len > maxLen) maxLen = len;
44
- }
45
- for (const item of matchingItems) {
46
- if (!item.href) continue;
47
- if (hrefLength(item.href) === maxLen) result.add(item.href);
48
- }
49
- return result;
50
- };
51
- function SidebarNav({ items = [], sections, currentPath, getIsActive, matchStrategy = "prefix", onItemClick, header, footer, ariaLabel = "Sidebar navigation", collapsed = false, iconSize, className, itemClassName, sectionClassName }) {
52
- const resolvedSections = (0, react.useMemo)(() => {
53
- return sections?.length ? sections : [{
54
- id: "default",
55
- items
56
- }];
57
- }, [sections, items]);
58
- const allItems = (0, react.useMemo)(() => resolvedSections.flatMap((section) => section.items), [resolvedSections]);
59
- const defaultIsActiveFn = (0, react.useMemo)(() => {
60
- if (matchStrategy === "most-specific") {
61
- const mostSpecificHrefs = findMostSpecific(allItems, currentPath);
62
- return (item) => {
63
- if (item.active !== void 0) return item.active;
64
- if (!item.href) return false;
65
- return mostSpecificHrefs.has(item.href);
66
- };
67
- } else return (item, path) => {
68
- if (item.active !== void 0) return item.active;
69
- if (item.exact) return isActiveExact(item, path);
70
- return isActivePrefix(item, path);
7
+ //#region src/components/app-shell/AppShell.tsx
8
+ var DESKTOP_BREAKPOINT = 960;
9
+ function getIsDesktop() {
10
+ if (typeof window === "undefined") return false;
11
+ return window.innerWidth >= DESKTOP_BREAKPOINT;
12
+ }
13
+ /**
14
+ * Responsive application shell with a collapsible sidebar and sticky top bar.
15
+ *
16
+ * - Sidebar opens by default on desktop, collapses on mobile.
17
+ * - Closes on outside click/scroll/touch when in mobile mode.
18
+ * - Provides optional hook to close the sidebar when a prop value changes
19
+ * (e.g., route transitions).
20
+ */
21
+ function AppShell({ children, sidebar, brand, brandHref, topbarStart, topbarEnd, showThemeToggle = false, themeToggleProps, topBarBrandingLocation = "left", className, sidebarClassName, topbarClassName, mainClassName, sidebarWidth, closeSidebarOnChangeKey, hamburgerLabel = "Toggle navigation", onSidebarToggle }) {
22
+ const [isDesktop, setIsDesktop] = (0, react.useState)(false);
23
+ const [sidebarOpen, setSidebarOpen] = (0, react.useState)(false);
24
+ const [transitionsReady, setTransitionsReady] = (0, react.useState)(false);
25
+ const prevIsDesktopRef = (0, react.useRef)(false);
26
+ const closeKeyRef = (0, react.useRef)(closeSidebarOnChangeKey);
27
+ const sidebarRef = (0, react.useRef)(null);
28
+ const hamburgerRef = (0, react.useRef)(null);
29
+ const mainRef = (0, react.useRef)(null);
30
+ const sidebarId = (0, react.useId)();
31
+ (0, react.useEffect)(() => {
32
+ const desktop = getIsDesktop();
33
+ setIsDesktop(desktop);
34
+ setSidebarOpen(desktop);
35
+ prevIsDesktopRef.current = desktop;
36
+ const transitionFrame = window.requestAnimationFrame(() => {
37
+ setTransitionsReady(true);
38
+ });
39
+ const handleResize = () => {
40
+ const nowDesktop = getIsDesktop();
41
+ setIsDesktop(nowDesktop);
42
+ if (nowDesktop !== prevIsDesktopRef.current) {
43
+ setSidebarOpen(nowDesktop);
44
+ prevIsDesktopRef.current = nowDesktop;
45
+ }
46
+ };
47
+ window.addEventListener("resize", handleResize);
48
+ return () => {
49
+ window.cancelAnimationFrame(transitionFrame);
50
+ window.removeEventListener("resize", handleResize);
71
51
  };
72
- }, [
73
- matchStrategy,
74
- allItems,
75
- currentPath
76
- ]);
77
- const resolvedGetIsActive = getIsActive ?? defaultIsActiveFn;
78
- const style = iconSize !== void 0 ? { ["--sidebar-nav-icon-size"]: typeof iconSize === "number" ? `${iconSize}px` : iconSize } : void 0;
79
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
80
- className: require_cx.cx(require_sidebar_nav_module.default.sidebarNav, collapsed && require_sidebar_nav_module.default.sidebarNavCollapsed, className),
81
- "aria-label": ariaLabel,
82
- style,
52
+ }, []);
53
+ (0, react.useEffect)(() => {
54
+ if (isDesktop || !sidebarOpen) return;
55
+ const mainElement = mainRef.current;
56
+ const closeSidebar = () => setSidebarOpen(false);
57
+ const onPointerDown = (e) => {
58
+ const target = e.target;
59
+ if (!target) return;
60
+ if (sidebarRef.current?.contains(target)) return;
61
+ if (hamburgerRef.current?.contains(target)) return;
62
+ closeSidebar();
63
+ };
64
+ const timeoutId = window.setTimeout(() => {
65
+ document.addEventListener("pointerdown", onPointerDown);
66
+ window.addEventListener("scroll", closeSidebar, { passive: true });
67
+ mainElement?.addEventListener("scroll", closeSidebar, { passive: true });
68
+ document.addEventListener("touchmove", closeSidebar, { passive: true });
69
+ }, 10);
70
+ return () => {
71
+ window.clearTimeout(timeoutId);
72
+ document.removeEventListener("pointerdown", onPointerDown);
73
+ window.removeEventListener("scroll", closeSidebar);
74
+ mainElement?.removeEventListener("scroll", closeSidebar);
75
+ document.removeEventListener("touchmove", closeSidebar);
76
+ };
77
+ }, [sidebarOpen, isDesktop]);
78
+ (0, react.useEffect)(() => {
79
+ if (!isDesktop && closeKeyRef.current !== closeSidebarOnChangeKey) setSidebarOpen(false);
80
+ closeKeyRef.current = closeSidebarOnChangeKey;
81
+ }, [closeSidebarOnChangeKey, isDesktop]);
82
+ (0, react.useEffect)(() => {
83
+ onSidebarToggle?.(sidebarOpen);
84
+ }, [sidebarOpen, onSidebarToggle]);
85
+ const toggleSidebar = () => setSidebarOpen((open) => !open);
86
+ const sidebarWidthValue = sidebarWidth === void 0 ? void 0 : typeof sidebarWidth === "number" ? `${sidebarWidth}px` : sidebarWidth;
87
+ const shellStyle = sidebarWidthValue ? { ["--app-shell-sidebar-width"]: sidebarWidthValue } : void 0;
88
+ const shellClasses = require_cx.cx(require_app_shell_module.default.appShell, transitionsReady && require_app_shell_module.default.appShellAnimated, sidebarOpen ? require_app_shell_module.default.appShellOpen : require_app_shell_module.default.appShellCollapsed, className);
89
+ const sidebarClasses = require_cx.cx(require_app_shell_module.default.appShellSidebar, sidebarOpen && require_app_shell_module.default.appShellSidebarOpen, sidebarClassName);
90
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
91
+ className: shellClasses,
92
+ style: shellStyle,
93
+ "data-app-shell": true,
94
+ "data-desktop": isDesktop ? "true" : "false",
95
+ "data-sidebar-open": sidebarOpen ? "true" : "false",
83
96
  children: [
84
- header ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
85
- className: require_sidebar_nav_module.default.header,
86
- children: header
87
- }) : null,
88
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
89
- className: require_sidebar_nav_module.default.sections,
90
- children: resolvedSections.map((section, sectionIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
91
- className: require_cx.cx(require_sidebar_nav_module.default.section, sectionClassName),
92
- children: [section.label && !collapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
93
- className: require_sidebar_nav_module.default.sectionLabel,
94
- children: section.label
95
- }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
96
- className: require_sidebar_nav_module.default.sectionItems,
97
- children: section.items.map((item, itemIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarNavEntry, {
98
- item,
99
- active: resolvedGetIsActive(item, currentPath),
100
- collapsed,
101
- itemClassName,
102
- onItemClick
103
- }, `${section.id ?? sectionIndex}-${item.href ?? item.title ?? itemIndex}`))
104
- })]
105
- }, section.id ?? `section-${sectionIndex}`))
97
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_TopBar.TopBar, {
98
+ className: require_cx.cx(require_app_shell_module.default.appShellTopbar, topbarClassName),
99
+ leading: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
100
+ ref: hamburgerRef,
101
+ type: "button",
102
+ className: require_app_shell_module.default.appShellHamburger,
103
+ onClick: toggleSidebar,
104
+ "aria-label": hamburgerLabel,
105
+ "aria-expanded": sidebarOpen,
106
+ "aria-controls": sidebarId,
107
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
108
+ viewBox: "0 0 24 24",
109
+ "aria-hidden": "true",
110
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
111
+ d: "M3 6h18M3 12h18M3 18h18",
112
+ stroke: "currentColor",
113
+ strokeWidth: "2.5",
114
+ strokeLinecap: "round"
115
+ })
116
+ })
117
+ }),
118
+ brand,
119
+ brandHref,
120
+ brandingLocation: topBarBrandingLocation,
121
+ start: topbarStart,
122
+ actions: topbarEnd,
123
+ showThemeToggle,
124
+ themeToggleProps
125
+ }),
126
+ !isDesktop && sidebarOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
127
+ className: require_app_shell_module.default.appShellBackdrop,
128
+ onClick: () => setSidebarOpen(false),
129
+ onTouchStart: () => setSidebarOpen(false),
130
+ "aria-hidden": "true"
106
131
  }),
107
- footer ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
108
- className: require_sidebar_nav_module.default.footer,
109
- children: footer
110
- }) : null
132
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("aside", {
133
+ ref: sidebarRef,
134
+ id: sidebarId,
135
+ className: sidebarClasses,
136
+ "aria-label": "Sidebar navigation",
137
+ children: sidebar
138
+ }),
139
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("main", {
140
+ ref: mainRef,
141
+ className: require_cx.cx(require_app_shell_module.default.appShellMain, mainClassName),
142
+ children
143
+ })
111
144
  ]
112
145
  });
113
146
  }
114
- function SidebarNavEntry({ item, active, collapsed, itemClassName, onItemClick }) {
115
- const rel = item.rel ?? (item.target === "_blank" ? "noreferrer" : void 0);
116
- const title = item.title ?? (typeof item.label === "string" ? item.label : void 0);
117
- const hasIcon = Boolean(item.icon);
118
- const classes = require_cx.cx(require_sidebar_nav_module.default.item, !hasIcon && require_sidebar_nav_module.default.itemWithoutIcon, active && require_sidebar_nav_module.default.itemActive, collapsed && require_sidebar_nav_module.default.itemCollapsed, item.disabled && require_sidebar_nav_module.default.itemDisabled, itemClassName);
119
- const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [hasIcon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
120
- className: require_sidebar_nav_module.default.icon,
121
- children: item.icon
122
- }) : null, !collapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
123
- className: require_sidebar_nav_module.default.itemBody,
124
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
125
- className: require_sidebar_nav_module.default.labelRow,
126
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
127
- className: require_sidebar_nav_module.default.label,
128
- children: item.label
129
- }), item.badge && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
130
- className: require_sidebar_nav_module.default.badge,
131
- children: item.badge
132
- })]
133
- }), item.description ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
134
- className: require_sidebar_nav_module.default.description,
135
- children: item.description
136
- }) : null]
137
- }) : null] });
138
- const handleClick = () => {
139
- if (item.disabled) return;
140
- item.onClick?.();
141
- onItemClick?.(item);
142
- };
143
- if (!item.href) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
144
- type: "button",
145
- className: classes,
146
- "aria-current": active ? "page" : void 0,
147
- "aria-disabled": item.disabled ? "true" : void 0,
148
- disabled: item.disabled,
149
- title: collapsed ? title : void 0,
150
- onClick: handleClick,
151
- children: content
152
- });
153
- if (item.disabled) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
154
- className: classes,
155
- "aria-current": active ? "page" : void 0,
156
- "aria-disabled": "true",
157
- title: collapsed ? title : void 0,
158
- children: content
159
- });
160
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
161
- className: classes,
162
- href: item.href,
163
- target: item.target,
164
- rel,
165
- "aria-current": active ? "page" : void 0,
166
- title: collapsed ? title : void 0,
167
- onClick: handleClick,
168
- children: content
169
- });
170
- }
171
147
  //#endregion
172
- exports.SidebarNav = SidebarNav;
148
+ exports.AppShell = AppShell;
173
149
 
174
150
  //# sourceMappingURL=index41.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index41.cjs","names":[],"sources":["../src/components/sidebar-nav/SidebarNav.tsx"],"sourcesContent":["\"use client\";\n\nimport { type AnchorHTMLAttributes, type CSSProperties, type ReactNode, useMemo } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport styles from \"./sidebar-nav.module.css\";\n\nexport type SidebarNavItem = {\n label: string;\n href?: string;\n icon?: ReactNode;\n description?: ReactNode;\n badge?: ReactNode;\n active?: boolean;\n disabled?: boolean;\n /**\n * When `true`, this item uses exact matching (matches its own path and paths starting with `{href}/`)\n * instead of prefix matching. This flag takes precedence over the global `matchStrategy` prop on a\n * per-item basis — even when `matchStrategy=\"prefix\"`, an item with `exact: true` will use exact matching.\n * When `matchStrategy=\"most-specific\"`, exact-flagged items participate in the length-based tiebreaker\n * like all other candidates, provided they pass their own match check first.\n */\n exact?: boolean;\n title?: string;\n target?: AnchorHTMLAttributes<HTMLAnchorElement>[\"target\"];\n rel?: AnchorHTMLAttributes<HTMLAnchorElement>[\"rel\"];\n onClick?: () => void;\n};\n\nexport type SidebarNavSection = {\n id?: string;\n label?: ReactNode;\n items: SidebarNavItem[];\n};\n\nexport type SidebarNavProps = {\n items?: SidebarNavItem[];\n sections?: SidebarNavSection[];\n currentPath?: string;\n getIsActive?: (item: SidebarNavItem, currentPath?: string) => boolean;\n matchStrategy?: \"prefix\" | \"most-specific\";\n onItemClick?: (item: SidebarNavItem) => void;\n header?: ReactNode;\n footer?: ReactNode;\n ariaLabel?: string;\n collapsed?: boolean;\n iconSize?: number | string;\n className?: string;\n itemClassName?: string;\n sectionClassName?: string;\n};\n\nconst isActivePrefix = (item: SidebarNavItem, path?: string) => {\n if (item.active !== undefined) return item.active;\n if (!item.href) return false;\n if (!path) return false;\n if (item.href === \"/\") return path === \"/\";\n return path.startsWith(item.href);\n};\n\nconst isActiveExact = (item: SidebarNavItem, path?: string) => {\n if (item.active !== undefined) return item.active;\n if (!item.href) return false;\n if (!path) return false;\n // Root href \"/\" must match exactly — otherwise every path would match.\n if (item.href === \"/\") return path === \"/\";\n // Normalize trailing slashes for consistent matching with findMostSpecific length computation.\n const normalizedHref = item.href.endsWith(\"/\") ? item.href.slice(0, -1) : item.href;\n return normalizedHref === path || path.startsWith(`${normalizedHref}/`);\n};\n\n// Natural matching helpers that ignore manual `active` overrides — used inside findMostSpecific\n// so that manually-set active flags don't hijack the length-based tiebreaker.\nconst isNaturalPrefixMatch = (href: string, path: string) => {\n if (href === \"/\") return path === \"/\";\n return path.startsWith(href);\n};\n\nconst isNaturalExactMatch = (href: string, path: string) => {\n if (href === \"/\") return path === \"/\";\n const normalizedHref = href.endsWith(\"/\") ? href.slice(0, -1) : href;\n return normalizedHref === path;\n};\n\nconst hrefLength = (href: string) => (href.endsWith(\"/\") ? href.length - 1 : href.length);\n\nconst findMostSpecific = (items: SidebarNavItem[], currentPath?: string): Set<string> => {\n const result = new Set<string>();\n if (!currentPath) return result;\n\n // Collect all items that naturally match the path — use natural matching helpers so that\n // manually-set `active` flags don't participate in the length-based tiebreaker.\n // Exclude disabled items from matching since they are not interactive targets.\n const matchingItems = items.filter(item => {\n if (item.disabled || !item.href) return false;\n return item.exact\n ? isNaturalExactMatch(item.href, currentPath)\n : isNaturalPrefixMatch(item.href, currentPath);\n });\n\n if (matchingItems.length === 0) return result;\n\n // Find the longest href among prefix matches.\n let maxLen = 0;\n for (const item of matchingItems) {\n if (!item.href) continue;\n const len = hrefLength(item.href);\n if (len > maxLen) maxLen = len;\n }\n\n // Only the items with the longest href are active.\n for (const item of matchingItems) {\n if (!item.href) continue;\n if (hrefLength(item.href) === maxLen) result.add(item.href);\n }\n\n return result;\n};\n\nexport function SidebarNav({\n items = [],\n sections,\n currentPath,\n getIsActive,\n matchStrategy = \"prefix\",\n onItemClick,\n header,\n footer,\n ariaLabel = \"Sidebar navigation\",\n collapsed = false,\n iconSize,\n className,\n itemClassName,\n sectionClassName,\n}: SidebarNavProps) {\n const resolvedSections = useMemo(() => {\n return sections?.length ? sections : [{ id: \"default\", items }];\n }, [sections, items]);\n\n // Stable reference to all items — avoids recreating on every render when `sections` is falsy.\n const allItems = useMemo(() => resolvedSections.flatMap(section => section.items), [resolvedSections]);\n\n // Build the default isActive function based on matchStrategy.\n const defaultIsActiveFn = useMemo<(item: SidebarNavItem, path?: string) => boolean>(() => {\n if (matchStrategy === \"most-specific\") {\n const mostSpecificHrefs = findMostSpecific(allItems, currentPath);\n return (item: SidebarNavItem) => {\n if (item.active !== undefined) return item.active;\n if (!item.href) return false;\n // Exact-flagged items participate in the length-based tiebreaker like all other candidates.\n return mostSpecificHrefs.has(item.href);\n };\n } else {\n return (item: SidebarNavItem, path?: string) => {\n if (item.active !== undefined) return item.active;\n if (item.exact) return isActiveExact(item, path);\n return isActivePrefix(item, path);\n };\n }\n }, [matchStrategy, allItems, currentPath]);\n\n const resolvedGetIsActive = getIsActive ?? defaultIsActiveFn;\n\n const style =\n iconSize !== undefined\n ? ({\n [\"--sidebar-nav-icon-size\" as string]:\n typeof iconSize === \"number\" ? `${iconSize}px` : iconSize,\n } satisfies CSSProperties)\n : undefined;\n\n return (\n <nav\n className={cx(\n styles.sidebarNav,\n collapsed && styles.sidebarNavCollapsed,\n className,\n )}\n aria-label={ariaLabel}\n style={style}\n >\n {header ? <div className={styles.header}>{header}</div> : null}\n <div className={styles.sections}>\n {resolvedSections.map((section, sectionIndex) => (\n <div\n key={section.id ?? `section-${sectionIndex}`}\n className={cx(styles.section, sectionClassName)}\n >\n {section.label && !collapsed ? (\n <div className={styles.sectionLabel}>{section.label}</div>\n ) : null}\n <div className={styles.sectionItems}>\n {section.items.map((item, itemIndex) => (\n <SidebarNavEntry\n key={`${section.id ?? sectionIndex}-${item.href ?? item.title ?? itemIndex}`}\n item={item}\n active={resolvedGetIsActive(item, currentPath)}\n collapsed={collapsed}\n itemClassName={itemClassName}\n onItemClick={onItemClick}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n {footer ? <div className={styles.footer}>{footer}</div> : null}\n </nav>\n );\n}\n\ntype SidebarNavEntryProps = {\n item: SidebarNavItem;\n active: boolean;\n collapsed: boolean;\n itemClassName?: string;\n onItemClick?: (item: SidebarNavItem) => void;\n};\n\nfunction SidebarNavEntry({\n item,\n active,\n collapsed,\n itemClassName,\n onItemClick,\n}: SidebarNavEntryProps) {\n const rel = item.rel ?? (item.target === \"_blank\" ? \"noreferrer\" : undefined);\n const title = item.title ?? (typeof item.label === \"string\" ? item.label : undefined);\n const hasIcon = Boolean(item.icon);\n const classes = cx(\n styles.item,\n !hasIcon && styles.itemWithoutIcon,\n active && styles.itemActive,\n collapsed && styles.itemCollapsed,\n item.disabled && styles.itemDisabled,\n itemClassName,\n );\n const content = (\n <>\n {hasIcon ? <span className={styles.icon}>{item.icon}</span> : null}\n {!collapsed ? (\n <span className={styles.itemBody}>\n <span className={styles.labelRow}>\n <span className={styles.label}>{item.label}</span>\n {item.badge && <span className={styles.badge}>{item.badge}</span>}\n </span>\n {item.description ? <span className={styles.description}>{item.description}</span> : null}\n </span>\n ) : null}\n </>\n );\n\n const handleClick = () => {\n if (item.disabled) return;\n item.onClick?.();\n onItemClick?.(item);\n };\n\n if (!item.href) {\n return (\n <button\n type=\"button\"\n className={classes}\n aria-current={active ? \"page\" : undefined}\n aria-disabled={item.disabled ? \"true\" : undefined}\n disabled={item.disabled}\n title={collapsed ? title : undefined}\n onClick={handleClick}\n >\n {content}\n </button>\n );\n }\n\n if (item.disabled) {\n return (\n <div\n className={classes}\n aria-current={active ? \"page\" : undefined}\n aria-disabled=\"true\"\n title={collapsed ? title : undefined}\n >\n {content}\n </div>\n );\n }\n\n return (\n <a\n className={classes}\n href={item.href}\n target={item.target}\n rel={rel}\n aria-current={active ? \"page\" : undefined}\n title={collapsed ? title : undefined}\n onClick={handleClick}\n >\n {content}\n </a>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index41.cjs","names":[],"sources":["../src/components/app-shell/AppShell.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { TopBar, type TopBarProps } from \"../top-bar/TopBar\";\nimport styles from \"./app-shell.module.css\";\n\nconst DESKTOP_BREAKPOINT = 960;\n\nfunction getIsDesktop() {\n if (typeof window === \"undefined\") return false;\n return window.innerWidth >= DESKTOP_BREAKPOINT;\n}\n\nexport type AppShellProps = {\n /** Primary page content rendered in the main area. */\n children: ReactNode;\n /** Sidebar navigation or custom content. */\n sidebar: ReactNode;\n /** Brand element rendered next to the hamburger (text or JSX). */\n brand?: ReactNode;\n /** Optional brand href; when provided the brand renders as an anchor. */\n brandHref?: string;\n /** Optional content after the brand on the left side of the top bar. */\n topbarStart?: ReactNode;\n /** Optional content aligned to the right side of the top bar. */\n topbarEnd?: ReactNode;\n /** Optional built-in theme toggle for the top bar. */\n showThemeToggle?: boolean;\n themeToggleProps?: TopBarProps[\"themeToggleProps\"];\n topBarBrandingLocation?: TopBarProps[\"brandingLocation\"];\n /** Custom class names for styling overrides. */\n className?: string;\n sidebarClassName?: string;\n topbarClassName?: string;\n mainClassName?: string;\n /** Sets the sidebar width (e.g., `260`, `\"18rem\"`). */\n sidebarWidth?: number | string;\n /**\n * Closes the sidebar on mobile whenever this value changes.\n * Useful for reacting to route/pathname changes.\n */\n closeSidebarOnChangeKey?: unknown;\n /** Label for the hamburger button (aria-label). */\n hamburgerLabel?: string;\n /** Optional callback fired whenever the sidebar open state changes. */\n onSidebarToggle?: (open: boolean) => void;\n};\n\n/**\n * Responsive application shell with a collapsible sidebar and sticky top bar.\n *\n * - Sidebar opens by default on desktop, collapses on mobile.\n * - Closes on outside click/scroll/touch when in mobile mode.\n * - Provides optional hook to close the sidebar when a prop value changes\n * (e.g., route transitions).\n */\nexport function AppShell({\n children,\n sidebar,\n brand,\n brandHref,\n topbarStart,\n topbarEnd,\n showThemeToggle = false,\n themeToggleProps,\n topBarBrandingLocation = \"left\",\n className,\n sidebarClassName,\n topbarClassName,\n mainClassName,\n sidebarWidth,\n closeSidebarOnChangeKey,\n hamburgerLabel = \"Toggle navigation\",\n onSidebarToggle,\n}: AppShellProps) {\n const [isDesktop, setIsDesktop] = useState(false);\n const [sidebarOpen, setSidebarOpen] = useState(false);\n const [transitionsReady, setTransitionsReady] = useState(false);\n const prevIsDesktopRef = useRef(false);\n const closeKeyRef = useRef(closeSidebarOnChangeKey);\n\n const sidebarRef = useRef<HTMLElement | null>(null);\n const hamburgerRef = useRef<HTMLButtonElement | null>(null);\n const mainRef = useRef<HTMLElement | null>(null);\n const sidebarId = useId();\n\n useEffect(() => {\n const desktop = getIsDesktop();\n setIsDesktop(desktop);\n setSidebarOpen(desktop);\n prevIsDesktopRef.current = desktop;\n const transitionFrame = window.requestAnimationFrame(() => {\n setTransitionsReady(true);\n });\n\n const handleResize = () => {\n const nowDesktop = getIsDesktop();\n setIsDesktop(nowDesktop);\n if (nowDesktop !== prevIsDesktopRef.current) {\n setSidebarOpen(nowDesktop);\n prevIsDesktopRef.current = nowDesktop;\n }\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.cancelAnimationFrame(transitionFrame);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, []);\n\n // Close the sidebar when clicking outside or scrolling on mobile.\n useEffect(() => {\n if (isDesktop || !sidebarOpen) return;\n\n const mainElement = mainRef.current;\n const closeSidebar = () => setSidebarOpen(false);\n\n const onPointerDown = (e: PointerEvent) => {\n const target = e.target as Node | null;\n if (!target) return;\n if (sidebarRef.current?.contains(target)) return;\n if (hamburgerRef.current?.contains(target)) return;\n closeSidebar();\n };\n\n const timeoutId = window.setTimeout(() => {\n document.addEventListener(\"pointerdown\", onPointerDown);\n window.addEventListener(\"scroll\", closeSidebar, { passive: true });\n mainElement?.addEventListener(\"scroll\", closeSidebar, { passive: true });\n document.addEventListener(\"touchmove\", closeSidebar, { passive: true });\n }, 10);\n\n return () => {\n window.clearTimeout(timeoutId);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n window.removeEventListener(\"scroll\", closeSidebar);\n mainElement?.removeEventListener(\"scroll\", closeSidebar);\n document.removeEventListener(\"touchmove\", closeSidebar);\n };\n }, [sidebarOpen, isDesktop]);\n\n // Allow consumers to request a mobile sidebar close when a value changes (e.g., pathname).\n useEffect(() => {\n if (!isDesktop && closeKeyRef.current !== closeSidebarOnChangeKey) {\n setSidebarOpen(false);\n }\n closeKeyRef.current = closeSidebarOnChangeKey;\n }, [closeSidebarOnChangeKey, isDesktop]);\n\n useEffect(() => {\n onSidebarToggle?.(sidebarOpen);\n }, [sidebarOpen, onSidebarToggle]);\n\n const toggleSidebar = () => setSidebarOpen((open) => !open);\n\n const sidebarWidthValue =\n sidebarWidth === undefined\n ? undefined\n : typeof sidebarWidth === \"number\"\n ? `${sidebarWidth}px`\n : sidebarWidth;\n\n const shellStyle: CSSProperties | undefined = sidebarWidthValue\n ? { [\"--app-shell-sidebar-width\" as string]: sidebarWidthValue }\n : undefined;\n\n const shellClasses = cx(\n styles.appShell,\n transitionsReady && styles.appShellAnimated,\n sidebarOpen ? styles.appShellOpen : styles.appShellCollapsed,\n className,\n );\n\n const sidebarClasses = cx(\n styles.appShellSidebar,\n sidebarOpen && styles.appShellSidebarOpen,\n sidebarClassName,\n );\n\n return (\n <div\n className={shellClasses}\n style={shellStyle}\n data-app-shell\n data-desktop={isDesktop ? \"true\" : \"false\"}\n data-sidebar-open={sidebarOpen ? \"true\" : \"false\"}\n >\n <TopBar\n className={cx(styles.appShellTopbar, topbarClassName)}\n leading={\n <button\n ref={hamburgerRef}\n type=\"button\"\n className={styles.appShellHamburger}\n onClick={toggleSidebar}\n aria-label={hamburgerLabel}\n aria-expanded={sidebarOpen}\n aria-controls={sidebarId}\n >\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path d=\"M3 6h18M3 12h18M3 18h18\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" />\n </svg>\n </button>\n }\n brand={brand}\n brandHref={brandHref}\n brandingLocation={topBarBrandingLocation}\n start={topbarStart}\n actions={topbarEnd}\n showThemeToggle={showThemeToggle}\n themeToggleProps={themeToggleProps}\n />\n {!isDesktop && sidebarOpen && (\n <div\n className={styles.appShellBackdrop}\n onClick={() => setSidebarOpen(false)}\n onTouchStart={() => setSidebarOpen(false)}\n aria-hidden=\"true\"\n />\n )}\n <aside ref={sidebarRef} id={sidebarId} className={sidebarClasses} aria-label=\"Sidebar navigation\">\n {sidebar}\n </aside>\n <main ref={mainRef} className={cx(styles.appShellMain, mainClassName)}>\n {children}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
package/dist/index41.js CHANGED
@@ -1,16 +1,45 @@
1
- //#region src/components/page-container/page-container.module.css
2
- var container = "uzi-page-container-module__container__o7e1A";
3
- var bleed = "uzi-page-container-module__bleed__8rKR8";
4
- var page_container_module_default = {
5
- container,
6
- "width-sm": "uzi-page-container-module__width-sm__8Mpln",
7
- "width-md": "uzi-page-container-module__width-md__KSmd5",
8
- "width-lg": "uzi-page-container-module__width-lg__GpJ-B",
9
- "width-xl": "uzi-page-container-module__width-xl__S2q8u",
10
- "width-full": "uzi-page-container-module__width-full__eHJdY",
11
- bleed
1
+ //#region src/components/sidebar-nav/sidebar-nav.module.css
2
+ var sidebarNav = "uzi-sidebar-nav-module__sidebarNav__eUI5c";
3
+ var sidebarNavCollapsed = "uzi-sidebar-nav-module__sidebarNavCollapsed__xTM9s";
4
+ var header = "uzi-sidebar-nav-module__header__Y4NLy";
5
+ var footer = "uzi-sidebar-nav-module__footer__GjWky";
6
+ var sections = "uzi-sidebar-nav-module__sections__mXuGQ";
7
+ var section = "uzi-sidebar-nav-module__section__yjtCY";
8
+ var sectionItems = "uzi-sidebar-nav-module__sectionItems__tNcph";
9
+ var sectionLabel = "uzi-sidebar-nav-module__sectionLabel__Wx94m";
10
+ var item = "uzi-sidebar-nav-module__item__uMHkJ";
11
+ var itemWithoutIcon = "uzi-sidebar-nav-module__itemWithoutIcon__7gzPd";
12
+ var itemActive = "uzi-sidebar-nav-module__itemActive__wBbiS";
13
+ var itemCollapsed = "uzi-sidebar-nav-module__itemCollapsed__jLJN-";
14
+ var itemDisabled = "uzi-sidebar-nav-module__itemDisabled__Yf8Il";
15
+ var icon = "uzi-sidebar-nav-module__icon__tyrUg";
16
+ var itemBody = "uzi-sidebar-nav-module__itemBody__wI0iy";
17
+ var labelRow = "uzi-sidebar-nav-module__labelRow__D8sEJ";
18
+ var label = "uzi-sidebar-nav-module__label__A-nt6";
19
+ var description = "uzi-sidebar-nav-module__description__Xf3Si";
20
+ var badge = "uzi-sidebar-nav-module__badge__-hnFd";
21
+ var sidebar_nav_module_default = {
22
+ sidebarNav,
23
+ sidebarNavCollapsed,
24
+ header,
25
+ footer,
26
+ sections,
27
+ section,
28
+ sectionItems,
29
+ sectionLabel,
30
+ item,
31
+ itemWithoutIcon,
32
+ itemActive,
33
+ itemCollapsed,
34
+ itemDisabled,
35
+ icon,
36
+ itemBody,
37
+ labelRow,
38
+ label,
39
+ description,
40
+ badge
12
41
  };
13
42
  //#endregion
14
- export { bleed, container, page_container_module_default as default };
43
+ export { badge, sidebar_nav_module_default as default, description, footer, header, icon, item, itemActive, itemBody, itemCollapsed, itemDisabled, itemWithoutIcon, label, labelRow, section, sectionItems, sectionLabel, sections, sidebarNav, sidebarNavCollapsed };
15
44
 
16
45
  //# sourceMappingURL=index41.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index41.js","names":[],"sources":["../src/components/page-container/page-container.module.css"],"sourcesContent":[".container {\n width: 100%;\n margin-inline: auto;\n padding-inline: var(--uzi-page-gutter, clamp(1rem, 3vw, 2rem));\n}\n\n.width-sm { max-width: 48rem; }\n.width-md { max-width: 64rem; }\n.width-lg { max-width: 75rem; }\n.width-xl { max-width: 90rem; }\n.width-full { max-width: none; }\n\n.bleed {\n padding-inline: 0;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"index41.js","names":[],"sources":["../src/components/sidebar-nav/sidebar-nav.module.css"],"sourcesContent":[".sidebarNav {\n --sidebar-nav-icon-size: 18px;\n --sidebar-nav-icon-size-mobile: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: stretch;\n min-height: 0;\n}\n\n.sidebarNavCollapsed {\n gap: 10px;\n}\n\n.header,\n.footer {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.footer {\n margin-top: auto;\n padding-top: 12px;\n border-top: 1px solid var(--border);\n}\n\n.sections {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: 14px;\n}\n\n.section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sectionItems {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sectionLabel {\n padding: 0 10px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--muted-foreground);\n opacity: 0.75;\n}\n\n.item {\n color: var(--foreground);\n background: transparent;\n border: none;\n box-shadow: none;\n padding: 10px 12px 10px 10px;\n border-radius: 10px;\n text-decoration: none;\n font-size: 14px;\n display: grid;\n grid-template-columns: var(--sidebar-nav-icon-size) minmax(0, 1fr);\n align-items: center;\n column-gap: 10px;\n width: 100%;\n text-align: left;\n box-sizing: border-box;\n line-height: 1.2;\n transition: background 120ms ease, color 120ms ease;\n}\n\n.item.itemWithoutIcon {\n grid-template-columns: minmax(0, 1fr);\n}\n\nbutton.item {\n font-family: inherit;\n cursor: pointer;\n}\n\n.item:focus-visible {\n outline: var(--focus-ring);\n outline-offset: var(--focus-ring-offset);\n}\n\n.item:hover {\n background: color-mix(in srgb, var(--primary) 10%, transparent);\n}\n\n.item.itemActive {\n background: color-mix(in srgb, var(--primary) 18%, transparent);\n color: var(--foreground);\n font-weight: 700;\n}\n\n.itemCollapsed {\n grid-template-columns: 1fr;\n justify-items: center;\n padding-right: 10px;\n padding-left: 10px;\n}\n\n.itemDisabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.icon {\n width: var(--sidebar-nav-icon-size);\n height: var(--sidebar-nav-icon-size);\n min-width: var(--sidebar-nav-icon-size);\n color: var(--muted-foreground);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n}\n\n.icon > * {\n width: 100% !important;\n height: 100% !important;\n max-width: 100%;\n max-height: 100%;\n}\n\n.icon :where(svg) {\n width: 100%;\n height: 100%;\n display: block;\n stroke: currentColor;\n}\n\n.item.itemActive .icon {\n color: var(--primary);\n}\n\n.itemBody {\n display: flex;\n min-width: 0;\n flex: 1 1 auto;\n flex-direction: column;\n gap: 3px;\n overflow: hidden;\n}\n\n.labelRow {\n display: flex;\n min-width: 0;\n align-items: center;\n gap: 8px;\n}\n\n.label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.description {\n color: var(--muted-foreground);\n font-size: 12px;\n line-height: 1.35;\n}\n\n.badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 999px;\n border: 1px solid var(--border);\n background: color-mix(in srgb, var(--foreground) 4%, transparent);\n color: var(--muted-foreground);\n font-size: 11px;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n@media (max-width: 960px) {\n .sidebarNav {\n gap: 10px;\n }\n\n .sections {\n gap: 12px;\n }\n\n .sectionItems {\n gap: 6px;\n }\n\n .item {\n padding: 9px 10px 9px 8px;\n border-radius: 9px;\n font-size: 14px;\n grid-template-columns: var(--sidebar-nav-icon-size-mobile) minmax(0, 1fr);\n column-gap: 8px;\n }\n\n .icon {\n width: var(--sidebar-nav-icon-size-mobile);\n height: var(--sidebar-nav-icon-size-mobile);\n min-width: var(--sidebar-nav-icon-size-mobile);\n }\n\n .icon :where(svg) {\n width: var(--sidebar-nav-icon-size-mobile);\n height: var(--sidebar-nav-icon-size-mobile);\n }\n\n .description {\n font-size: 11px;\n }\n}\n\n@media (max-width: 480px) {\n .item {\n padding: 8px 9px 8px 7px;\n font-size: 13px;\n }\n}\n"],"mappings":""}
package/dist/index42.cjs CHANGED
@@ -1,18 +1,64 @@
1
- //#region src/components/page-container/page-container.module.css
2
- var container = "uzi-page-container-module__container__o7e1A";
3
- var bleed = "uzi-page-container-module__bleed__8rKR8";
4
- var page_container_module_default = {
5
- container,
6
- "width-sm": "uzi-page-container-module__width-sm__8Mpln",
7
- "width-md": "uzi-page-container-module__width-md__KSmd5",
8
- "width-lg": "uzi-page-container-module__width-lg__GpJ-B",
9
- "width-xl": "uzi-page-container-module__width-xl__S2q8u",
10
- "width-full": "uzi-page-container-module__width-full__eHJdY",
11
- bleed
1
+ //#region src/components/sidebar-nav/sidebar-nav.module.css
2
+ var sidebarNav = "uzi-sidebar-nav-module__sidebarNav__eUI5c";
3
+ var sidebarNavCollapsed = "uzi-sidebar-nav-module__sidebarNavCollapsed__xTM9s";
4
+ var header = "uzi-sidebar-nav-module__header__Y4NLy";
5
+ var footer = "uzi-sidebar-nav-module__footer__GjWky";
6
+ var sections = "uzi-sidebar-nav-module__sections__mXuGQ";
7
+ var section = "uzi-sidebar-nav-module__section__yjtCY";
8
+ var sectionItems = "uzi-sidebar-nav-module__sectionItems__tNcph";
9
+ var sectionLabel = "uzi-sidebar-nav-module__sectionLabel__Wx94m";
10
+ var item = "uzi-sidebar-nav-module__item__uMHkJ";
11
+ var itemWithoutIcon = "uzi-sidebar-nav-module__itemWithoutIcon__7gzPd";
12
+ var itemActive = "uzi-sidebar-nav-module__itemActive__wBbiS";
13
+ var itemCollapsed = "uzi-sidebar-nav-module__itemCollapsed__jLJN-";
14
+ var itemDisabled = "uzi-sidebar-nav-module__itemDisabled__Yf8Il";
15
+ var icon = "uzi-sidebar-nav-module__icon__tyrUg";
16
+ var itemBody = "uzi-sidebar-nav-module__itemBody__wI0iy";
17
+ var labelRow = "uzi-sidebar-nav-module__labelRow__D8sEJ";
18
+ var label = "uzi-sidebar-nav-module__label__A-nt6";
19
+ var description = "uzi-sidebar-nav-module__description__Xf3Si";
20
+ var badge = "uzi-sidebar-nav-module__badge__-hnFd";
21
+ var sidebar_nav_module_default = {
22
+ sidebarNav,
23
+ sidebarNavCollapsed,
24
+ header,
25
+ footer,
26
+ sections,
27
+ section,
28
+ sectionItems,
29
+ sectionLabel,
30
+ item,
31
+ itemWithoutIcon,
32
+ itemActive,
33
+ itemCollapsed,
34
+ itemDisabled,
35
+ icon,
36
+ itemBody,
37
+ labelRow,
38
+ label,
39
+ description,
40
+ badge
12
41
  };
13
42
  //#endregion
14
- exports.bleed = bleed;
15
- exports.container = container;
16
- exports.default = page_container_module_default;
43
+ exports.badge = badge;
44
+ exports.default = sidebar_nav_module_default;
45
+ exports.description = description;
46
+ exports.footer = footer;
47
+ exports.header = header;
48
+ exports.icon = icon;
49
+ exports.item = item;
50
+ exports.itemActive = itemActive;
51
+ exports.itemBody = itemBody;
52
+ exports.itemCollapsed = itemCollapsed;
53
+ exports.itemDisabled = itemDisabled;
54
+ exports.itemWithoutIcon = itemWithoutIcon;
55
+ exports.label = label;
56
+ exports.labelRow = labelRow;
57
+ exports.section = section;
58
+ exports.sectionItems = sectionItems;
59
+ exports.sectionLabel = sectionLabel;
60
+ exports.sections = sections;
61
+ exports.sidebarNav = sidebarNav;
62
+ exports.sidebarNavCollapsed = sidebarNavCollapsed;
17
63
 
18
64
  //# sourceMappingURL=index42.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index42.cjs","names":[],"sources":["../src/components/page-container/page-container.module.css"],"sourcesContent":[".container {\n width: 100%;\n margin-inline: auto;\n padding-inline: var(--uzi-page-gutter, clamp(1rem, 3vw, 2rem));\n}\n\n.width-sm { max-width: 48rem; }\n.width-md { max-width: 64rem; }\n.width-lg { max-width: 75rem; }\n.width-xl { max-width: 90rem; }\n.width-full { max-width: none; }\n\n.bleed {\n padding-inline: 0;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"index42.cjs","names":[],"sources":["../src/components/sidebar-nav/sidebar-nav.module.css"],"sourcesContent":[".sidebarNav {\n --sidebar-nav-icon-size: 18px;\n --sidebar-nav-icon-size-mobile: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: stretch;\n min-height: 0;\n}\n\n.sidebarNavCollapsed {\n gap: 10px;\n}\n\n.header,\n.footer {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.footer {\n margin-top: auto;\n padding-top: 12px;\n border-top: 1px solid var(--border);\n}\n\n.sections {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: 14px;\n}\n\n.section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sectionItems {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sectionLabel {\n padding: 0 10px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--muted-foreground);\n opacity: 0.75;\n}\n\n.item {\n color: var(--foreground);\n background: transparent;\n border: none;\n box-shadow: none;\n padding: 10px 12px 10px 10px;\n border-radius: 10px;\n text-decoration: none;\n font-size: 14px;\n display: grid;\n grid-template-columns: var(--sidebar-nav-icon-size) minmax(0, 1fr);\n align-items: center;\n column-gap: 10px;\n width: 100%;\n text-align: left;\n box-sizing: border-box;\n line-height: 1.2;\n transition: background 120ms ease, color 120ms ease;\n}\n\n.item.itemWithoutIcon {\n grid-template-columns: minmax(0, 1fr);\n}\n\nbutton.item {\n font-family: inherit;\n cursor: pointer;\n}\n\n.item:focus-visible {\n outline: var(--focus-ring);\n outline-offset: var(--focus-ring-offset);\n}\n\n.item:hover {\n background: color-mix(in srgb, var(--primary) 10%, transparent);\n}\n\n.item.itemActive {\n background: color-mix(in srgb, var(--primary) 18%, transparent);\n color: var(--foreground);\n font-weight: 700;\n}\n\n.itemCollapsed {\n grid-template-columns: 1fr;\n justify-items: center;\n padding-right: 10px;\n padding-left: 10px;\n}\n\n.itemDisabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.icon {\n width: var(--sidebar-nav-icon-size);\n height: var(--sidebar-nav-icon-size);\n min-width: var(--sidebar-nav-icon-size);\n color: var(--muted-foreground);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n}\n\n.icon > * {\n width: 100% !important;\n height: 100% !important;\n max-width: 100%;\n max-height: 100%;\n}\n\n.icon :where(svg) {\n width: 100%;\n height: 100%;\n display: block;\n stroke: currentColor;\n}\n\n.item.itemActive .icon {\n color: var(--primary);\n}\n\n.itemBody {\n display: flex;\n min-width: 0;\n flex: 1 1 auto;\n flex-direction: column;\n gap: 3px;\n overflow: hidden;\n}\n\n.labelRow {\n display: flex;\n min-width: 0;\n align-items: center;\n gap: 8px;\n}\n\n.label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.description {\n color: var(--muted-foreground);\n font-size: 12px;\n line-height: 1.35;\n}\n\n.badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 999px;\n border: 1px solid var(--border);\n background: color-mix(in srgb, var(--foreground) 4%, transparent);\n color: var(--muted-foreground);\n font-size: 11px;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n@media (max-width: 960px) {\n .sidebarNav {\n gap: 10px;\n }\n\n .sections {\n gap: 12px;\n }\n\n .sectionItems {\n gap: 6px;\n }\n\n .item {\n padding: 9px 10px 9px 8px;\n border-radius: 9px;\n font-size: 14px;\n grid-template-columns: var(--sidebar-nav-icon-size-mobile) minmax(0, 1fr);\n column-gap: 8px;\n }\n\n .icon {\n width: var(--sidebar-nav-icon-size-mobile);\n height: var(--sidebar-nav-icon-size-mobile);\n min-width: var(--sidebar-nav-icon-size-mobile);\n }\n\n .icon :where(svg) {\n width: var(--sidebar-nav-icon-size-mobile);\n height: var(--sidebar-nav-icon-size-mobile);\n }\n\n .description {\n font-size: 11px;\n }\n}\n\n@media (max-width: 480px) {\n .item {\n padding: 8px 9px 8px 7px;\n font-size: 13px;\n }\n}\n"],"mappings":""}