@nocoo/basalt 3.2.1 → 3.2.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.
Files changed (192) hide show
  1. package/README.md +25 -19
  2. package/ai/COMPATIBILITY.md +41 -36
  3. package/ai/DESIGN.md +53 -47
  4. package/ai/INTEGRATION.md +814 -820
  5. package/ai/RECIPES.md +334 -135
  6. package/ai/USAGE.md +2 -2
  7. package/ai/registry.json +384 -27
  8. package/ai/sources.json +2 -2
  9. package/dist/assets/brand-mark.js +1 -2
  10. package/dist/charts/area.js +1 -2
  11. package/dist/charts/bar.js +1 -2
  12. package/dist/charts/bullet.js +1 -2
  13. package/dist/charts/chart-colors.js +1 -2
  14. package/dist/charts/charts.js +1 -2
  15. package/dist/charts/config.js +1 -2
  16. package/dist/charts/custom-chart.js +1 -2
  17. package/dist/charts/date-navigation.js +1 -2
  18. package/dist/charts/donut.js +1 -2
  19. package/dist/charts/frame.js +1 -2
  20. package/dist/charts/frame.js.map +1 -1
  21. package/dist/charts/funnel.js +1 -2
  22. package/dist/charts/gauge.js +1 -2
  23. package/dist/charts/grouped-bar.js +1 -2
  24. package/dist/charts/heatmap-calendar.js +3 -7
  25. package/dist/charts/heatmap-calendar.js.map +1 -1
  26. package/dist/charts/heatmap-matrix.js +1 -2
  27. package/dist/charts/item-list.js +1 -2
  28. package/dist/charts/legend.js +1 -2
  29. package/dist/charts/line.js +1 -2
  30. package/dist/charts/palette.js +1 -2
  31. package/dist/charts/radar.js +1 -2
  32. package/dist/charts/sample.js +1 -2
  33. package/dist/charts/sankey.js +1 -2
  34. package/dist/charts/series.js +1 -2
  35. package/dist/charts/slot-bar.js +1 -2
  36. package/dist/charts/sparkline.js +1 -2
  37. package/dist/charts/stacked-bar.js +1 -2
  38. package/dist/charts/stat-card.js +1 -2
  39. package/dist/charts/timeline.js +1 -2
  40. package/dist/charts/timeseries.js +1 -2
  41. package/dist/charts/tooltip.js +31 -27
  42. package/dist/charts/tooltip.js.map +1 -1
  43. package/dist/components/accordion.js +1 -2
  44. package/dist/components/alert-dialog.js +1 -2
  45. package/dist/components/app-header.js +1 -2
  46. package/dist/components/app-shell.js +1 -2
  47. package/dist/components/approval-card.js +1 -2
  48. package/dist/components/autocomplete.js +1 -2
  49. package/dist/components/avatar.js +1 -2
  50. package/dist/components/badge.js +1 -2
  51. package/dist/components/banner.js +1 -2
  52. package/dist/components/basalt-mark.js +1 -2
  53. package/dist/components/battery-meter.js +1 -2
  54. package/dist/components/breadcrumbs.js +1 -2
  55. package/dist/components/button.d.ts +1 -1
  56. package/dist/components/button.js +3 -3
  57. package/dist/components/button.js.map +1 -1
  58. package/dist/components/chat-bubble.js +1 -2
  59. package/dist/components/chat-composer.js +1 -2
  60. package/dist/components/chat-header.js +1 -2
  61. package/dist/components/chat-inbox.js +1 -2
  62. package/dist/components/chat-markdown.js +1 -2
  63. package/dist/components/chat-message.js +1 -2
  64. package/dist/components/checkbox.js +1 -2
  65. package/dist/components/clipboard-text.js +1 -2
  66. package/dist/components/code.js +1 -2
  67. package/dist/components/collapsible.js +1 -2
  68. package/dist/components/collapsible.js.map +1 -1
  69. package/dist/components/combobox.js +1 -2
  70. package/dist/components/command-palette.js +1 -2
  71. package/dist/components/confirm-dialog.js +3 -12
  72. package/dist/components/confirm-dialog.js.map +1 -1
  73. package/dist/components/context-cards.js +1 -2
  74. package/dist/components/context-menu.js +1 -2
  75. package/dist/components/data-table.js +2 -7
  76. package/dist/components/data-table.js.map +1 -1
  77. package/dist/components/date-picker.js +7 -18
  78. package/dist/components/date-picker.js.map +1 -1
  79. package/dist/components/delete-resource.js +1 -2
  80. package/dist/components/description-list.js +1 -2
  81. package/dist/components/dialog.js +1 -2
  82. package/dist/components/diff-table.js +1 -2
  83. package/dist/components/dock.js +1 -2
  84. package/dist/components/dock.js.map +1 -1
  85. package/dist/components/dropdown-menu.js +1 -2
  86. package/dist/components/editable-nav-item.js +1 -2
  87. package/dist/components/empty.js +1 -2
  88. package/dist/components/fab.js +1 -2
  89. package/dist/components/field.js +1 -2
  90. package/dist/components/file-dropzone.js +1 -2
  91. package/dist/components/filter-bar.js +1 -2
  92. package/dist/components/flow.js +1 -2
  93. package/dist/components/grid.js +1 -2
  94. package/dist/components/hover-card.js +1 -2
  95. package/dist/components/icon-picker.js +1 -2
  96. package/dist/components/inline-editable.js +1 -2
  97. package/dist/components/input-area.js +1 -2
  98. package/dist/components/input-group.js +2 -3
  99. package/dist/components/input-group.js.map +1 -1
  100. package/dist/components/input.js +1 -2
  101. package/dist/components/label.js +1 -2
  102. package/dist/components/layer-card.js +1 -2
  103. package/dist/components/link.js +1 -2
  104. package/dist/components/loader.js +1 -2
  105. package/dist/components/loading-screen.js +1 -2
  106. package/dist/components/menu-bar.js +1 -2
  107. package/dist/components/meter.js +1 -2
  108. package/dist/components/multi-select.js +1 -2
  109. package/dist/components/navigation-menu.js +1 -2
  110. package/dist/components/overlay.js +1 -2
  111. package/dist/components/page-header.js +1 -2
  112. package/dist/components/pagination.js +1 -2
  113. package/dist/components/popover.js +1 -2
  114. package/dist/components/prompt-bar.js +1 -2
  115. package/dist/components/radio.js +2 -7
  116. package/dist/components/radio.js.map +1 -1
  117. package/dist/components/recommendation-card.js +1 -2
  118. package/dist/components/resource-list.js +1 -2
  119. package/dist/components/responsive-master-detail.js +1 -2
  120. package/dist/components/scroll-area.js +1 -2
  121. package/dist/components/section-rule.js +1 -2
  122. package/dist/components/segment-control.js +1 -2
  123. package/dist/components/select.js +1 -2
  124. package/dist/components/sensitive-input.js +1 -2
  125. package/dist/components/separator.js +1 -2
  126. package/dist/components/sheet.js +1 -2
  127. package/dist/components/sidebar.d.ts +53 -19
  128. package/dist/components/sidebar.js +201 -100
  129. package/dist/components/sidebar.js.map +1 -1
  130. package/dist/components/skeleton-line.js +1 -2
  131. package/dist/components/slider.js +1 -2
  132. package/dist/components/stat-strip.js +1 -2
  133. package/dist/components/switch.js +1 -2
  134. package/dist/components/table-of-contents.js +1 -2
  135. package/dist/components/table-pager.js +1 -2
  136. package/dist/components/table.js +1 -2
  137. package/dist/components/tabs.js +1 -2
  138. package/dist/components/tag-badge.js +1 -2
  139. package/dist/components/tag-color-picker.js +1 -2
  140. package/dist/components/text.js +1 -2
  141. package/dist/components/theme-toggle.js +1 -2
  142. package/dist/components/thinking.js +1 -2
  143. package/dist/components/toast.js +1 -2
  144. package/dist/components/toggle-group.js +1 -2
  145. package/dist/components/toggle.js +1 -2
  146. package/dist/components/tool-chips.js +1 -2
  147. package/dist/components/toolbar.js +1 -2
  148. package/dist/components/tooltip.js +1 -2
  149. package/dist/components/typeahead-field.js +6 -21
  150. package/dist/components/typeahead-field.js.map +1 -1
  151. package/dist/components/upload-queue.js +1 -2
  152. package/dist/index.d.ts +1 -1
  153. package/dist/index.js +11 -11
  154. package/dist/models/agent-feedback.js +1 -2
  155. package/dist/models/avatar.js +1 -2
  156. package/dist/models/code.js +1 -2
  157. package/dist/models/context-cards.js +1 -2
  158. package/dist/models/diff-table.js +1 -2
  159. package/dist/models/recommendation.js +1 -2
  160. package/dist/providers/accent.js +2 -7
  161. package/dist/providers/accent.js.map +1 -1
  162. package/dist/providers/link.js +1 -2
  163. package/dist/providers/theme.js +2 -7
  164. package/dist/providers/theme.js.map +1 -1
  165. package/dist/styles/standalone.css +55 -11
  166. package/dist/styles/tailwind.css +2 -0
  167. package/dist/styles/tokens.css +51 -6
  168. package/dist/utils/cn.js +1 -2
  169. package/dist/utils/control-surface.js +1 -2
  170. package/dist/utils/navigation.d.ts +1 -1
  171. package/dist/utils/navigation.js +2 -3
  172. package/dist/utils/navigation.js.map +1 -1
  173. package/dist/utils/preference-store.js +1 -2
  174. package/dist/utils/selection-indicator.js +1 -2
  175. package/dist/utils/use-checkable-group.js +1 -2
  176. package/dist/utils/use-hover-highlight.js +2 -3
  177. package/dist/utils/use-hover-highlight.js.map +1 -1
  178. package/dist/viewmodels/use-approval-card.js +11 -13
  179. package/dist/viewmodels/use-approval-card.js.map +1 -1
  180. package/dist/viewmodels/use-chat-composer.js +1 -2
  181. package/dist/viewmodels/use-chat-message.js +1 -2
  182. package/dist/viewmodels/use-code-block.js +1 -2
  183. package/dist/viewmodels/use-code-block.js.map +1 -1
  184. package/dist/viewmodels/use-context-cards.js +1 -2
  185. package/dist/viewmodels/use-diff-table.js +1 -2
  186. package/dist/viewmodels/use-diff-table.js.map +1 -1
  187. package/dist/viewmodels/use-loader.js +1 -2
  188. package/dist/viewmodels/use-recommendation-card.js +1 -2
  189. package/dist/viewmodels/use-recommendation-card.js.map +1 -1
  190. package/dist/viewmodels/use-thinking.js +1 -2
  191. package/dist/viewmodels/use-tool-chips.js +1 -2
  192. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- //#region src/models/context-cards.ts
2
+ // src/models/context-cards.ts
3
3
  function e(e) {
4
4
  if (e && e === e.trim() && !Array.from(e).some((e) => e.charCodeAt(0) <= 32 || e === "\\")) {
5
5
  if (e.startsWith("/") && !e.startsWith("//")) return e;
@@ -11,7 +11,6 @@ function e(e) {
11
11
  }
12
12
  }
13
13
  }
14
- //#endregion
15
14
  export { e as contextSourceHref };
16
15
 
17
16
  //# sourceMappingURL=context-cards.js.map
@@ -1,9 +1,8 @@
1
1
  "use client";
2
- //#region src/models/diff-table.ts
2
+ // src/models/diff-table.ts
3
3
  function e(e, t) {
4
4
  return e.filter((e) => e.change !== "unchanged" && !t.includes(e.id));
5
5
  }
6
- //#endregion
7
6
  export { e as selectedDiffRows };
8
7
 
9
8
  //# sourceMappingURL=diff-table.js.map
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- //#region src/models/recommendation.ts
2
+ // src/models/recommendation.ts
3
3
  var e = {
4
4
  high: {
5
5
  label: "High confidence",
@@ -17,7 +17,6 @@ var e = {
17
17
  className: "text-basalt-muted-foreground"
18
18
  }
19
19
  };
20
- //#endregion
21
20
  export { e as RECOMMENDATION_CONFIDENCE };
22
21
 
23
22
  //# sourceMappingURL=recommendation.js.map
@@ -2,7 +2,7 @@
2
2
  import { createPreferenceStore as e } from "../utils/preference-store.js";
3
3
  import { createContext as t, useCallback as n, useContext as r, useEffect as i, useMemo as a, useState as o, useSyncExternalStore as s } from "react";
4
4
  import { jsx as c } from "react/jsx-runtime";
5
- //#region src/providers/accent.tsx
5
+ // src/providers/accent.tsx
6
6
  var l = [
7
7
  {
8
8
  id: "primary",
@@ -275,11 +275,7 @@ function M({ children: t, paletteOverrides: r, storageKey: u = f, defaultAccent:
275
275
  ]);
276
276
  let E = n((e) => {
277
277
  let t = m(e).id;
278
- if (b) {
279
- v?.(t);
280
- return;
281
- }
282
- S.setValue(t), v?.(t);
278
+ b || S.setValue(t), v?.(t);
283
279
  }, [
284
280
  b,
285
281
  v,
@@ -303,7 +299,6 @@ function N() {
303
299
  if (!e) throw Error("useAccent must be used within AccentProvider");
304
300
  return e;
305
301
  }
306
- //#endregion
307
302
  export { l as ACCENT_SWATCHES, M as AccentProvider, d as DEFAULT_ACCENT_ID, E as accentForeground, m as accentSwatchById, D as applyAccent, N as useAccent };
308
303
 
309
304
  //# sourceMappingURL=accent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"accent.js","names":["ACCENT_SWATCHES","LEGACY_ACCENT_IDS","DEFAULT_ACCENT_ID","STORAGE_KEY","AccentContext","createContext","accentSwatchById","normalized","id","swatch","channel","c","parseHslChannels","hue","sat","light","hsl","hslToRgbChannels","k","n","h","a","s","l","f","relativeLuminance","rgb","wcagContrast","lA","rgbA","lB","rgbB","DARK_TEXT_RGB","WHITE_TEXT_RGB","LIGHT_SURFACES_RGB","DARK_SURFACES_RGB","compositeRgb","top","bottom","deriveSemanticPrimary","origL","dark","targetSurfaces","foreground","start","bg","hoverOk","accentForeground","contrastWhite","applyAccent","applySwatch","semanticPrimary","root","isValidAccentId","value","validHsl","isDarkMode","AccentProvider","controlledAccent","isControlled","swatches","useMemo","override","paletteOverrides","store","useState","createPreferenceStore","defaultAccent","storageKey","persist","getServerSnapshot","useCallback","storeAccent","useSyncExternalStore","currentAccent","applyToDocument","apply","observer","setAccent","validId","next","onAccentChange","useAccent","ctx","useContext"],"sources":["../../src/providers/accent.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\nimport { createPreferenceStore } from \"../utils/preference-store\";\n\nexport type AccentSwatch = {\n\tid: string;\n\tlabel: string;\n\ttoken: string;\n\tlight: string;\n\tdark: string;\n};\n\n/** Twelve candy accents inspired by the translucent iMac and iPhone 5C finishes. */\nexport const ACCENT_SWATCHES: readonly AccentSwatch[] = [\n\t{\n\t\tid: \"primary\",\n\t\tlabel: \"Blue\",\n\t\ttoken: \"--basalt-accent-1\",\n\t\tlight: \"204 88% 62%\",\n\t\tdark: \"204 90% 70%\",\n\t},\n\t{\n\t\tid: \"sky\",\n\t\tlabel: \"Ice\",\n\t\ttoken: \"--basalt-accent-2\",\n\t\tlight: \"191 79% 70%\",\n\t\tdark: \"191 79% 74%\",\n\t},\n\t{\n\t\tid: \"teal\",\n\t\tlabel: \"Bondi\",\n\t\ttoken: \"--basalt-accent-3\",\n\t\tlight: \"182 62% 47%\",\n\t\tdark: \"182 62% 63%\",\n\t},\n\t{\n\t\tid: \"green\",\n\t\tlabel: \"Green\",\n\t\ttoken: \"--basalt-accent-4\",\n\t\tlight: \"113 58% 62%\",\n\t\tdark: \"113 58% 70%\",\n\t},\n\t{\n\t\tid: \"lime\",\n\t\tlabel: \"Lime\",\n\t\ttoken: \"--basalt-accent-5\",\n\t\tlight: \"79 70% 64%\",\n\t\tdark: \"79 70% 70%\",\n\t},\n\t{\n\t\tid: \"amber\",\n\t\tlabel: \"Yellow\",\n\t\ttoken: \"--basalt-accent-6\",\n\t\tlight: \"49 100% 69%\",\n\t\tdark: \"49 100% 73%\",\n\t},\n\t{\n\t\tid: \"orange\",\n\t\tlabel: \"Tangerine\",\n\t\ttoken: \"--basalt-accent-7\",\n\t\tlight: \"27 95% 65%\",\n\t\tdark: \"27 95% 72%\",\n\t},\n\t{\n\t\tid: \"red\",\n\t\tlabel: \"Strawberry\",\n\t\ttoken: \"--basalt-accent-8\",\n\t\tlight: \"5 85% 66%\",\n\t\tdark: \"5 85% 73%\",\n\t},\n\t{\n\t\tid: \"rose\",\n\t\tlabel: \"Pink\",\n\t\ttoken: \"--basalt-accent-9\",\n\t\tlight: \"345 88% 72%\",\n\t\tdark: \"345 88% 77%\",\n\t},\n\t{\n\t\tid: \"purple\",\n\t\tlabel: \"Grape\",\n\t\ttoken: \"--basalt-accent-10\",\n\t\tlight: \"280 53% 71%\",\n\t\tdark: \"280 53% 77%\",\n\t},\n\t{\n\t\tid: \"indigo\",\n\t\tlabel: \"Blueberry\",\n\t\ttoken: \"--basalt-accent-11\",\n\t\tlight: \"237 66% 69%\",\n\t\tdark: \"237 66% 77%\",\n\t},\n\t{\n\t\tid: \"gray\",\n\t\tlabel: \"Pearl\",\n\t\ttoken: \"--basalt-accent-12\",\n\t\tlight: \"210 20% 87%\",\n\t\tdark: \"210 20% 88%\",\n\t},\n];\n\nconst LEGACY_ACCENT_IDS = new Map<string, string>([\n\t[\"jade\", \"teal\"],\n\t[\"vermilion\", \"red\"],\n\t[\"magenta\", \"rose\"],\n\t[\"orchid\", \"purple\"],\n\t[\"cobalt\", \"indigo\"],\n\t[\"steel\", \"primary\"],\n\t[\"cadet\", \"sky\"],\n\t[\"seafoam\", \"teal\"],\n\t[\"olive\", \"lime\"],\n\t[\"gold\", \"amber\"],\n\t[\"tangerine\", \"orange\"],\n\t[\"crimson\", \"red\"],\n]);\n\nexport const DEFAULT_ACCENT_ID = \"primary\";\nconst STORAGE_KEY = \"basalt-accent\";\n\ntype AccentContextValue = {\n\taccent: string;\n\tsetAccent: (id: string) => void;\n\tswatches: readonly AccentSwatch[];\n};\n\nconst AccentContext = createContext<AccentContextValue | null>(null);\n\nexport function accentSwatchById(id: string | null | undefined): AccentSwatch {\n\tconst normalized = LEGACY_ACCENT_IDS.get(id ?? \"\") ?? id;\n\treturn ACCENT_SWATCHES.find((swatch) => swatch.id === normalized) ?? ACCENT_SWATCHES[0];\n}\n\nfunction channel(c: number) {\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\nfunction parseHslChannels(hsl: string): [number, number, number] {\n\tconst [hue, sat, light] = hsl.trim().split(/\\s+/);\n\tconst h = Number(hue);\n\tconst s = Number(sat.replace(\"%\", \"\")) / 100;\n\tconst l = Number(light.replace(\"%\", \"\")) / 100;\n\treturn [h, s, l];\n}\n\nfunction hslToRgbChannels(h: number, s: number, l: number): [number, number, number] {\n\tconst k = (n: number) => (n + h / 30) % 12;\n\tconst a = s * Math.min(l, 1 - l);\n\tconst f = (n: number) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));\n\treturn [255 * f(0), 255 * f(8), 255 * f(4)];\n}\n\nfunction relativeLuminance(rgb: [number, number, number]): number {\n\treturn (\n\t\t0.2126 * channel(rgb[0] / 255) + 0.7152 * channel(rgb[1] / 255) + 0.0722 * channel(rgb[2] / 255)\n\t);\n}\n\nfunction wcagContrast(rgbA: [number, number, number], rgbB: [number, number, number]): number {\n\tconst lA = relativeLuminance(rgbA);\n\tconst lB = relativeLuminance(rgbB);\n\treturn (Math.max(lA, lB) + 0.05) / (Math.min(lA, lB) + 0.05);\n}\n\nconst DARK_TEXT_RGB: [number, number, number] = [26, 26, 26]; // 0 0% 10%\nconst WHITE_TEXT_RGB: [number, number, number] = [255, 255, 255]; // 0 0% 100%\n\nconst LIGHT_SURFACES_RGB: [number, number, number][] = [\n\t[238, 239, 242], // background\n\t[246, 247, 248], // card\n\t[252, 252, 253], // secondary\n\t[255, 255, 255], // bright\n];\n\nconst DARK_SURFACES_RGB: [number, number, number][] = [\n\t[23, 23, 23], // background\n\t[27, 27, 27], // card\n\t[31, 31, 31], // secondary\n\t[36, 36, 36], // bright\n];\n\nfunction compositeRgb(\n\ttop: [number, number, number, number],\n\tbottom: [number, number, number],\n): [number, number, number] {\n\treturn [\n\t\ttop[0] * top[3] + bottom[0] * (1 - top[3]),\n\t\ttop[1] * top[3] + bottom[1] * (1 - top[3]),\n\t\ttop[2] * top[3] + bottom[2] * (1 - top[3]),\n\t];\n}\n\nfunction deriveSemanticPrimary(swatch: AccentSwatch, dark: boolean): string {\n\tconst [h, s, origL] = parseHslChannels(dark ? swatch.dark : swatch.light);\n\tconst targetSurfaces = dark ? DARK_SURFACES_RGB : LIGHT_SURFACES_RGB;\n\tconst foreground = dark ? DARK_TEXT_RGB : WHITE_TEXT_RGB;\n\tconst start = dark\n\t\t? Math.max(Math.round(origL * 100), 45)\n\t\t: Math.min(Math.round(origL * 100), 60);\n\n\tfor (let l = start; dark ? l <= 85 : l >= 15; l += dark ? 1 : -1) {\n\t\tconst rgb = hslToRgbChannels(h, s, l / 100);\n\t\tconst minTextR = Math.min(...targetSurfaces.map((bg) => wcagContrast(rgb, bg)));\n\t\tif (minTextR < 4.55) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (wcagContrast(rgb, foreground) < 4.55) {\n\t\t\tcontinue;\n\t\t}\n\t\tlet hoverOk = true;\n\t\tfor (const bg of targetSurfaces) {\n\t\t\tconst hoverBg = compositeRgb([...rgb, 0.9], bg);\n\t\t\tif (wcagContrast(hoverBg, foreground) < 4.55) {\n\t\t\t\thoverOk = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (hoverOk) {\n\t\t\treturn `${h} ${Math.round(s * 100)}% ${l}%`;\n\t\t}\n\t}\n\treturn dark ? swatch.dark : swatch.light;\n}\n\nexport function accentForeground(hsl: string) {\n\tconst [h, s, l] = parseHslChannels(hsl);\n\tconst rgb = hslToRgbChannels(h, s, l);\n\tconst contrastWhite = wcagContrast(rgb, WHITE_TEXT_RGB);\n\tconst contrastDark = wcagContrast(rgb, DARK_TEXT_RGB);\n\treturn contrastDark >= contrastWhite ? (\"0 0% 10%\" as const) : (\"0 0% 100%\" as const);\n}\n\nexport function applyAccent(id: string, dark = false) {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\tapplySwatch(accentSwatchById(id), dark);\n}\n\nfunction applySwatch(swatch: AccentSwatch, dark: boolean) {\n\tconst semanticPrimary = deriveSemanticPrimary(swatch, dark);\n\tconst root = document.documentElement;\n\troot.style.setProperty(\"--basalt-primary\", semanticPrimary);\n\troot.style.setProperty(\"--basalt-primary-foreground\", accentForeground(semanticPrimary));\n\troot.style.setProperty(\"--basalt-ring\", semanticPrimary);\n\troot.dataset.accent = swatch.id;\n}\n\nexport interface AccentProviderProps {\n\t/** Color overrides for the twelve preset IDs, using HSL channels (for example `204 88% 62%`).\n\t * Invalid pairs and unknown IDs are ignored. Persistence belongs to the application.\n\t * Chart colors remain fixed. */\n\tpaletteOverrides?: Readonly<Record<string, { light: string; dark: string }>>;\n\t/**\n\t * Application components wrapped by the accent context.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * Storage key used for accent persistence.\n\t * @default \"basalt-accent\"\n\t */\n\tstorageKey?: string;\n\t/**\n\t * Initial accent identifier used when no stored preference exists or during SSR.\n\t * @default \"primary\"\n\t */\n\tdefaultAccent?: string;\n\t/**\n\t * Whether to persist accent changes to localStorage.\n\t * If false, localStorage is never read or written.\n\t * @default true\n\t */\n\tpersist?: boolean;\n\t/**\n\t * Controlled accent identifier. When provided, the provider acts as a controlled component\n\t * and internal state is driven by this prop.\n\t */\n\taccent?: string;\n\t/**\n\t * Callback fired when accent change is requested.\n\t * In controlled mode, callers are responsible for updating `accent`.\n\t */\n\tonAccentChange?: (accent: string) => void;\n\t/**\n\t * Whether to apply accent CSS variables and data-accent attribute to document.documentElement.\n\t * Set to false when a host theme system manages CSS variables directly.\n\t * @default true\n\t */\n\tapplyToDocument?: boolean;\n}\n\nfunction isValidAccentId(value: unknown): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\t(ACCENT_SWATCHES.some((s) => s.id === value) || LEGACY_ACCENT_IDS.has(value))\n\t);\n}\n\nfunction validHsl(value: unknown): value is string {\n\tif (typeof value !== \"string\" || !/^\\d+(?:\\.\\d+)?\\s+\\d+(?:\\.\\d+)?%\\s+\\d+(?:\\.\\d+)?%$/.test(value))\n\t\treturn false;\n\tconst [h, s, l] = parseHslChannels(value);\n\treturn h <= 360 && s <= 1 && l <= 1;\n}\n\nfunction isDarkMode(): boolean {\n\tif (typeof document === \"undefined\") {\n\t\treturn false;\n\t}\n\treturn document.documentElement.classList.contains(\"dark\");\n}\n\nexport function AccentProvider({\n\tchildren,\n\tpaletteOverrides,\n\tstorageKey = STORAGE_KEY,\n\tdefaultAccent = DEFAULT_ACCENT_ID,\n\tpersist = true,\n\taccent: controlledAccent,\n\tonAccentChange,\n\tapplyToDocument = true,\n}: AccentProviderProps) {\n\tconst isControlled = controlledAccent !== undefined;\n\tconst swatches = useMemo(\n\t\t() =>\n\t\t\tACCENT_SWATCHES.map((swatch) => {\n\t\t\t\tconst override = paletteOverrides?.[swatch.id];\n\t\t\t\treturn override && validHsl(override.light) && validHsl(override.dark)\n\t\t\t\t\t? { ...swatch, light: override.light, dark: override.dark }\n\t\t\t\t\t: swatch;\n\t\t\t}),\n\t\t[paletteOverrides],\n\t);\n\n\tconst [store] = useState(() =>\n\t\tcreatePreferenceStore({\n\t\t\tstorageKey,\n\t\t\tdefaultValue: defaultAccent,\n\t\t\tpersist,\n\t\t\tisValid: isValidAccentId,\n\t\t\tnormalize: (value) => accentSwatchById(value).id,\n\t\t\teventName: \"basalt:accent-change\",\n\t\t}),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, defaultValue: defaultAccent, persist });\n\t}, [store, storageKey, defaultAccent, persist]);\n\n\tconst getServerSnapshot = useCallback(() => accentSwatchById(defaultAccent).id, [defaultAccent]);\n\n\tconst storeAccent = useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);\n\n\tconst currentAccent = isControlled ? accentSwatchById(controlledAccent).id : storeAccent;\n\n\tuseEffect(() => {\n\t\tif (!applyToDocument || typeof document === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tconst apply = () => {\n\t\t\tconst dark = isDarkMode();\n\t\t\tfor (const swatch of swatches)\n\t\t\t\tdocument.documentElement.style.setProperty(swatch.token, dark ? swatch.dark : swatch.light);\n\t\t\tapplySwatch(swatches.find((swatch) => swatch.id === currentAccent) ?? swatches[0], dark);\n\t\t};\n\t\tapply();\n\t\tconst observer = new MutationObserver(apply);\n\t\tobserver.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] });\n\t\treturn () => observer.disconnect();\n\t}, [currentAccent, applyToDocument, swatches]);\n\n\tconst setAccent = useCallback(\n\t\t(next: string) => {\n\t\t\tconst validId = accentSwatchById(next).id;\n\t\t\tif (isControlled) {\n\t\t\t\tonAccentChange?.(validId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstore.setValue(validId);\n\t\t\tonAccentChange?.(validId);\n\t\t},\n\t\t[isControlled, onAccentChange, store],\n\t);\n\n\tconst value = useMemo(\n\t\t() => ({ accent: currentAccent, setAccent, swatches }),\n\t\t[currentAccent, setAccent, swatches],\n\t);\n\treturn <AccentContext.Provider value={value}>{children}</AccentContext.Provider>;\n}\n\nexport function useAccent() {\n\tconst ctx = useContext(AccentContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useAccent must be used within AccentProvider\");\n\t}\n\treturn ctx;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"accent.js","names":["ACCENT_SWATCHES","LEGACY_ACCENT_IDS","DEFAULT_ACCENT_ID","STORAGE_KEY","AccentContext","createContext","accentSwatchById","normalized","id","swatch","channel","c","parseHslChannels","hue","sat","light","hsl","hslToRgbChannels","k","n","h","a","s","l","f","relativeLuminance","rgb","wcagContrast","lA","rgbA","lB","rgbB","DARK_TEXT_RGB","WHITE_TEXT_RGB","LIGHT_SURFACES_RGB","DARK_SURFACES_RGB","compositeRgb","top","bottom","deriveSemanticPrimary","origL","dark","targetSurfaces","foreground","start","bg","hoverOk","accentForeground","contrastWhite","applyAccent","applySwatch","semanticPrimary","root","isValidAccentId","value","validHsl","isDarkMode","AccentProvider","controlledAccent","isControlled","swatches","useMemo","override","paletteOverrides","store","useState","createPreferenceStore","defaultAccent","storageKey","persist","getServerSnapshot","useCallback","storeAccent","useSyncExternalStore","currentAccent","applyToDocument","apply","observer","setAccent","validId","next","onAccentChange","useAccent","ctx","useContext"],"sources":["../../src/providers/accent.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\nimport { createPreferenceStore } from \"../utils/preference-store\";\n\nexport type AccentSwatch = {\n\tid: string;\n\tlabel: string;\n\ttoken: string;\n\tlight: string;\n\tdark: string;\n};\n\n/** Twelve candy accents inspired by the translucent iMac and iPhone 5C finishes. */\nexport const ACCENT_SWATCHES: readonly AccentSwatch[] = [\n\t{\n\t\tid: \"primary\",\n\t\tlabel: \"Blue\",\n\t\ttoken: \"--basalt-accent-1\",\n\t\tlight: \"204 88% 62%\",\n\t\tdark: \"204 90% 70%\",\n\t},\n\t{\n\t\tid: \"sky\",\n\t\tlabel: \"Ice\",\n\t\ttoken: \"--basalt-accent-2\",\n\t\tlight: \"191 79% 70%\",\n\t\tdark: \"191 79% 74%\",\n\t},\n\t{\n\t\tid: \"teal\",\n\t\tlabel: \"Bondi\",\n\t\ttoken: \"--basalt-accent-3\",\n\t\tlight: \"182 62% 47%\",\n\t\tdark: \"182 62% 63%\",\n\t},\n\t{\n\t\tid: \"green\",\n\t\tlabel: \"Green\",\n\t\ttoken: \"--basalt-accent-4\",\n\t\tlight: \"113 58% 62%\",\n\t\tdark: \"113 58% 70%\",\n\t},\n\t{\n\t\tid: \"lime\",\n\t\tlabel: \"Lime\",\n\t\ttoken: \"--basalt-accent-5\",\n\t\tlight: \"79 70% 64%\",\n\t\tdark: \"79 70% 70%\",\n\t},\n\t{\n\t\tid: \"amber\",\n\t\tlabel: \"Yellow\",\n\t\ttoken: \"--basalt-accent-6\",\n\t\tlight: \"49 100% 69%\",\n\t\tdark: \"49 100% 73%\",\n\t},\n\t{\n\t\tid: \"orange\",\n\t\tlabel: \"Tangerine\",\n\t\ttoken: \"--basalt-accent-7\",\n\t\tlight: \"27 95% 65%\",\n\t\tdark: \"27 95% 72%\",\n\t},\n\t{\n\t\tid: \"red\",\n\t\tlabel: \"Strawberry\",\n\t\ttoken: \"--basalt-accent-8\",\n\t\tlight: \"5 85% 66%\",\n\t\tdark: \"5 85% 73%\",\n\t},\n\t{\n\t\tid: \"rose\",\n\t\tlabel: \"Pink\",\n\t\ttoken: \"--basalt-accent-9\",\n\t\tlight: \"345 88% 72%\",\n\t\tdark: \"345 88% 77%\",\n\t},\n\t{\n\t\tid: \"purple\",\n\t\tlabel: \"Grape\",\n\t\ttoken: \"--basalt-accent-10\",\n\t\tlight: \"280 53% 71%\",\n\t\tdark: \"280 53% 77%\",\n\t},\n\t{\n\t\tid: \"indigo\",\n\t\tlabel: \"Blueberry\",\n\t\ttoken: \"--basalt-accent-11\",\n\t\tlight: \"237 66% 69%\",\n\t\tdark: \"237 66% 77%\",\n\t},\n\t{\n\t\tid: \"gray\",\n\t\tlabel: \"Pearl\",\n\t\ttoken: \"--basalt-accent-12\",\n\t\tlight: \"210 20% 87%\",\n\t\tdark: \"210 20% 88%\",\n\t},\n];\n\nconst LEGACY_ACCENT_IDS = new Map<string, string>([\n\t[\"jade\", \"teal\"],\n\t[\"vermilion\", \"red\"],\n\t[\"magenta\", \"rose\"],\n\t[\"orchid\", \"purple\"],\n\t[\"cobalt\", \"indigo\"],\n\t[\"steel\", \"primary\"],\n\t[\"cadet\", \"sky\"],\n\t[\"seafoam\", \"teal\"],\n\t[\"olive\", \"lime\"],\n\t[\"gold\", \"amber\"],\n\t[\"tangerine\", \"orange\"],\n\t[\"crimson\", \"red\"],\n]);\n\nexport const DEFAULT_ACCENT_ID = \"primary\";\nconst STORAGE_KEY = \"basalt-accent\";\n\ntype AccentContextValue = {\n\taccent: string;\n\tsetAccent: (id: string) => void;\n\tswatches: readonly AccentSwatch[];\n};\n\nconst AccentContext = createContext<AccentContextValue | null>(null);\n\nexport function accentSwatchById(id: string | null | undefined): AccentSwatch {\n\tconst normalized = LEGACY_ACCENT_IDS.get(id ?? \"\") ?? id;\n\treturn ACCENT_SWATCHES.find((swatch) => swatch.id === normalized) ?? ACCENT_SWATCHES[0];\n}\n\nfunction channel(c: number) {\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\nfunction parseHslChannels(hsl: string): [number, number, number] {\n\tconst [hue, sat, light] = hsl.trim().split(/\\s+/);\n\tconst h = Number(hue);\n\tconst s = Number(sat.replace(\"%\", \"\")) / 100;\n\tconst l = Number(light.replace(\"%\", \"\")) / 100;\n\treturn [h, s, l];\n}\n\nfunction hslToRgbChannels(h: number, s: number, l: number): [number, number, number] {\n\tconst k = (n: number) => (n + h / 30) % 12;\n\tconst a = s * Math.min(l, 1 - l);\n\tconst f = (n: number) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));\n\treturn [255 * f(0), 255 * f(8), 255 * f(4)];\n}\n\nfunction relativeLuminance(rgb: [number, number, number]): number {\n\treturn (\n\t\t0.2126 * channel(rgb[0] / 255) + 0.7152 * channel(rgb[1] / 255) + 0.0722 * channel(rgb[2] / 255)\n\t);\n}\n\nfunction wcagContrast(rgbA: [number, number, number], rgbB: [number, number, number]): number {\n\tconst lA = relativeLuminance(rgbA);\n\tconst lB = relativeLuminance(rgbB);\n\treturn (Math.max(lA, lB) + 0.05) / (Math.min(lA, lB) + 0.05);\n}\n\nconst DARK_TEXT_RGB: [number, number, number] = [26, 26, 26]; // 0 0% 10%\nconst WHITE_TEXT_RGB: [number, number, number] = [255, 255, 255]; // 0 0% 100%\n\nconst LIGHT_SURFACES_RGB: [number, number, number][] = [\n\t[238, 239, 242], // background\n\t[246, 247, 248], // card\n\t[252, 252, 253], // secondary\n\t[255, 255, 255], // bright\n];\n\nconst DARK_SURFACES_RGB: [number, number, number][] = [\n\t[23, 23, 23], // background\n\t[27, 27, 27], // card\n\t[31, 31, 31], // secondary\n\t[36, 36, 36], // bright\n];\n\nfunction compositeRgb(\n\ttop: [number, number, number, number],\n\tbottom: [number, number, number],\n): [number, number, number] {\n\treturn [\n\t\ttop[0] * top[3] + bottom[0] * (1 - top[3]),\n\t\ttop[1] * top[3] + bottom[1] * (1 - top[3]),\n\t\ttop[2] * top[3] + bottom[2] * (1 - top[3]),\n\t];\n}\n\nfunction deriveSemanticPrimary(swatch: AccentSwatch, dark: boolean): string {\n\tconst [h, s, origL] = parseHslChannels(dark ? swatch.dark : swatch.light);\n\tconst targetSurfaces = dark ? DARK_SURFACES_RGB : LIGHT_SURFACES_RGB;\n\tconst foreground = dark ? DARK_TEXT_RGB : WHITE_TEXT_RGB;\n\tconst start = dark\n\t\t? Math.max(Math.round(origL * 100), 45)\n\t\t: Math.min(Math.round(origL * 100), 60);\n\n\tfor (let l = start; dark ? l <= 85 : l >= 15; l += dark ? 1 : -1) {\n\t\tconst rgb = hslToRgbChannels(h, s, l / 100);\n\t\tconst minTextR = Math.min(...targetSurfaces.map((bg) => wcagContrast(rgb, bg)));\n\t\tif (minTextR < 4.55) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (wcagContrast(rgb, foreground) < 4.55) {\n\t\t\tcontinue;\n\t\t}\n\t\tlet hoverOk = true;\n\t\tfor (const bg of targetSurfaces) {\n\t\t\tconst hoverBg = compositeRgb([...rgb, 0.9], bg);\n\t\t\tif (wcagContrast(hoverBg, foreground) < 4.55) {\n\t\t\t\thoverOk = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (hoverOk) {\n\t\t\treturn `${h} ${Math.round(s * 100)}% ${l}%`;\n\t\t}\n\t}\n\treturn dark ? swatch.dark : swatch.light;\n}\n\nexport function accentForeground(hsl: string) {\n\tconst [h, s, l] = parseHslChannels(hsl);\n\tconst rgb = hslToRgbChannels(h, s, l);\n\tconst contrastWhite = wcagContrast(rgb, WHITE_TEXT_RGB);\n\tconst contrastDark = wcagContrast(rgb, DARK_TEXT_RGB);\n\treturn contrastDark >= contrastWhite ? (\"0 0% 10%\" as const) : (\"0 0% 100%\" as const);\n}\n\nexport function applyAccent(id: string, dark = false) {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\tapplySwatch(accentSwatchById(id), dark);\n}\n\nfunction applySwatch(swatch: AccentSwatch, dark: boolean) {\n\tconst semanticPrimary = deriveSemanticPrimary(swatch, dark);\n\tconst root = document.documentElement;\n\troot.style.setProperty(\"--basalt-primary\", semanticPrimary);\n\troot.style.setProperty(\"--basalt-primary-foreground\", accentForeground(semanticPrimary));\n\troot.style.setProperty(\"--basalt-ring\", semanticPrimary);\n\troot.dataset.accent = swatch.id;\n}\n\nexport interface AccentProviderProps {\n\t/** Color overrides for the twelve preset IDs, using HSL channels (for example `204 88% 62%`).\n\t * Invalid pairs and unknown IDs are ignored. Persistence belongs to the application.\n\t * Chart colors remain fixed. */\n\tpaletteOverrides?: Readonly<Record<string, { light: string; dark: string }>>;\n\t/**\n\t * Application components wrapped by the accent context.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * Storage key used for accent persistence.\n\t * @default \"basalt-accent\"\n\t */\n\tstorageKey?: string;\n\t/**\n\t * Initial accent identifier used when no stored preference exists or during SSR.\n\t * @default \"primary\"\n\t */\n\tdefaultAccent?: string;\n\t/**\n\t * Whether to persist accent changes to localStorage.\n\t * If false, localStorage is never read or written.\n\t * @default true\n\t */\n\tpersist?: boolean;\n\t/**\n\t * Controlled accent identifier. When provided, the provider acts as a controlled component\n\t * and internal state is driven by this prop.\n\t */\n\taccent?: string;\n\t/**\n\t * Callback fired when accent change is requested.\n\t * In controlled mode, callers are responsible for updating `accent`.\n\t */\n\tonAccentChange?: (accent: string) => void;\n\t/**\n\t * Whether to apply accent CSS variables and data-accent attribute to document.documentElement.\n\t * Set to false when a host theme system manages CSS variables directly.\n\t * @default true\n\t */\n\tapplyToDocument?: boolean;\n}\n\nfunction isValidAccentId(value: unknown): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\t(ACCENT_SWATCHES.some((s) => s.id === value) || LEGACY_ACCENT_IDS.has(value))\n\t);\n}\n\nfunction validHsl(value: unknown): value is string {\n\tif (typeof value !== \"string\" || !/^\\d+(?:\\.\\d+)?\\s+\\d+(?:\\.\\d+)?%\\s+\\d+(?:\\.\\d+)?%$/.test(value))\n\t\treturn false;\n\tconst [h, s, l] = parseHslChannels(value);\n\treturn h <= 360 && s <= 1 && l <= 1;\n}\n\nfunction isDarkMode(): boolean {\n\tif (typeof document === \"undefined\") {\n\t\treturn false;\n\t}\n\treturn document.documentElement.classList.contains(\"dark\");\n}\n\nexport function AccentProvider({\n\tchildren,\n\tpaletteOverrides,\n\tstorageKey = STORAGE_KEY,\n\tdefaultAccent = DEFAULT_ACCENT_ID,\n\tpersist = true,\n\taccent: controlledAccent,\n\tonAccentChange,\n\tapplyToDocument = true,\n}: AccentProviderProps) {\n\tconst isControlled = controlledAccent !== undefined;\n\tconst swatches = useMemo(\n\t\t() =>\n\t\t\tACCENT_SWATCHES.map((swatch) => {\n\t\t\t\tconst override = paletteOverrides?.[swatch.id];\n\t\t\t\treturn override && validHsl(override.light) && validHsl(override.dark)\n\t\t\t\t\t? { ...swatch, light: override.light, dark: override.dark }\n\t\t\t\t\t: swatch;\n\t\t\t}),\n\t\t[paletteOverrides],\n\t);\n\n\tconst [store] = useState(() =>\n\t\tcreatePreferenceStore({\n\t\t\tstorageKey,\n\t\t\tdefaultValue: defaultAccent,\n\t\t\tpersist,\n\t\t\tisValid: isValidAccentId,\n\t\t\tnormalize: (value) => accentSwatchById(value).id,\n\t\t\teventName: \"basalt:accent-change\",\n\t\t}),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, defaultValue: defaultAccent, persist });\n\t}, [store, storageKey, defaultAccent, persist]);\n\n\tconst getServerSnapshot = useCallback(() => accentSwatchById(defaultAccent).id, [defaultAccent]);\n\n\tconst storeAccent = useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);\n\n\tconst currentAccent = isControlled ? accentSwatchById(controlledAccent).id : storeAccent;\n\n\tuseEffect(() => {\n\t\tif (!applyToDocument || typeof document === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tconst apply = () => {\n\t\t\tconst dark = isDarkMode();\n\t\t\tfor (const swatch of swatches)\n\t\t\t\tdocument.documentElement.style.setProperty(swatch.token, dark ? swatch.dark : swatch.light);\n\t\t\tapplySwatch(swatches.find((swatch) => swatch.id === currentAccent) ?? swatches[0], dark);\n\t\t};\n\t\tapply();\n\t\tconst observer = new MutationObserver(apply);\n\t\tobserver.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] });\n\t\treturn () => observer.disconnect();\n\t}, [currentAccent, applyToDocument, swatches]);\n\n\tconst setAccent = useCallback(\n\t\t(next: string) => {\n\t\t\tconst validId = accentSwatchById(next).id;\n\t\t\tif (isControlled) {\n\t\t\t\tonAccentChange?.(validId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstore.setValue(validId);\n\t\t\tonAccentChange?.(validId);\n\t\t},\n\t\t[isControlled, onAccentChange, store],\n\t);\n\n\tconst value = useMemo(\n\t\t() => ({ accent: currentAccent, setAccent, swatches }),\n\t\t[currentAccent, setAccent, swatches],\n\t);\n\treturn <AccentContext.Provider value={value}>{children}</AccentContext.Provider>;\n}\n\nexport function useAccent() {\n\tconst ctx = useContext(AccentContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useAccent must be used within AccentProvider\");\n\t}\n\treturn ctx;\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { createContext as e, useContext as t } from "react";
3
3
  import { jsx as n } from "react/jsx-runtime";
4
- //#region src/providers/link.tsx
4
+ // src/providers/link.tsx
5
5
  var r = e("a");
6
6
  function i({ render: e, children: t }) {
7
7
  return /* @__PURE__ */ n(r.Provider, {
@@ -12,7 +12,6 @@ function i({ render: e, children: t }) {
12
12
  function a() {
13
13
  return t(r);
14
14
  }
15
- //#endregion
16
15
  export { i as LinkProvider, a as useLinkComponent };
17
16
 
18
17
  //# sourceMappingURL=link.js.map
@@ -2,7 +2,7 @@
2
2
  import { createPreferenceStore as e } from "../utils/preference-store.js";
3
3
  import { createContext as t, useCallback as n, useContext as r, useEffect as i, useMemo as a, useState as o, useSyncExternalStore as s } from "react";
4
4
  import { jsx as c } from "react/jsx-runtime";
5
- //#region src/providers/theme.tsx
5
+ // src/providers/theme.tsx
6
6
  var l = "theme", u = t(null);
7
7
  function d(e) {
8
8
  if (typeof document > "u") return;
@@ -49,11 +49,7 @@ function p({ children: t, storageKey: r = l, defaultTheme: p = "system", persist
49
49
  }
50
50
  }, [S, _]);
51
51
  let C = n((e) => {
52
- if (v) {
53
- g?.(e);
54
- return;
55
- }
56
- y.setValue(e), g?.(e);
52
+ v || y.setValue(e), g?.(e);
57
53
  }, [
58
54
  v,
59
55
  g,
@@ -72,7 +68,6 @@ function m() {
72
68
  if (!e) throw Error("useTheme must be used within ThemeProvider");
73
69
  return e;
74
70
  }
75
- //#endregion
76
71
  export { p as ThemeProvider, m as useTheme };
77
72
 
78
73
  //# sourceMappingURL=theme.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme.js","names":["STORAGE_KEY","ThemeContext","createContext","applyTheme","root","systemDark","dark","theme","isValidTheme","value","ThemeProvider","controlledTheme","isControlled","store","useState","createPreferenceStore","defaultTheme","storageKey","persist","getServerSnapshot","useCallback","storeTheme","useSyncExternalStore","currentTheme","applyToDocument","mq","onChange","setTheme","next","onThemeChange","useMemo","useTheme","ctx","useContext"],"sources":["../../src/providers/theme.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\nimport { createPreferenceStore } from \"../utils/preference-store\";\n\nexport type BasaltTheme = \"light\" | \"dark\" | \"system\";\n\nconst STORAGE_KEY = \"theme\";\n\ntype ThemeContextValue = {\n\ttheme: BasaltTheme;\n\tsetTheme: (theme: BasaltTheme) => void;\n};\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null);\n\nfunction applyTheme(theme: BasaltTheme) {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\tconst root = document.documentElement;\n\tlet systemDark = false;\n\ttry {\n\t\tif (typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n\t\t\tsystemDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\t\t}\n\t} catch {\n\t\tsystemDark = false;\n\t}\n\tconst dark = theme === \"dark\" || (theme === \"system\" && systemDark);\n\troot.classList.toggle(\"dark\", dark);\n\troot.classList.toggle(\"light\", !dark);\n\troot.dataset.mode = dark ? \"dark\" : \"light\";\n}\n\nexport interface ThemeProviderProps {\n\t/**\n\t * Application components wrapped by the theme context.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * Storage key used for theme persistence.\n\t * @default \"theme\"\n\t */\n\tstorageKey?: string;\n\t/**\n\t * Initial theme used when no stored preference exists or during SSR.\n\t * @default \"system\"\n\t */\n\tdefaultTheme?: BasaltTheme;\n\t/**\n\t * Whether to persist theme changes to localStorage.\n\t * If false, localStorage is never read or written.\n\t * @default true\n\t */\n\tpersist?: boolean;\n\t/**\n\t * Controlled theme value. When provided, the provider acts as a controlled component\n\t * and internal state is driven by this prop.\n\t */\n\ttheme?: BasaltTheme;\n\t/**\n\t * Callback fired when theme change is requested.\n\t * In controlled mode, callers are responsible for updating `theme`.\n\t */\n\tonThemeChange?: (theme: BasaltTheme) => void;\n\t/**\n\t * Whether to apply mode classes and data-mode attribute to document.documentElement.\n\t * Set to false when a host theme system manages the document root.\n\t * @default true\n\t */\n\tapplyToDocument?: boolean;\n}\n\nfunction isValidTheme(value: unknown): value is BasaltTheme {\n\treturn value === \"light\" || value === \"dark\" || value === \"system\";\n}\n\nexport function ThemeProvider({\n\tchildren,\n\tstorageKey = STORAGE_KEY,\n\tdefaultTheme = \"system\",\n\tpersist = true,\n\ttheme: controlledTheme,\n\tonThemeChange,\n\tapplyToDocument = true,\n}: ThemeProviderProps) {\n\tconst isControlled = controlledTheme !== undefined;\n\n\tconst [store] = useState(() =>\n\t\tcreatePreferenceStore({\n\t\t\tstorageKey,\n\t\t\tdefaultValue: defaultTheme,\n\t\t\tpersist,\n\t\t\tisValid: isValidTheme,\n\t\t\tnormalize: (value) => value,\n\t\t\teventName: \"basalt:theme-change\",\n\t\t}),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, defaultValue: defaultTheme, persist });\n\t}, [store, storageKey, defaultTheme, persist]);\n\n\tconst getServerSnapshot = useCallback(() => defaultTheme, [defaultTheme]);\n\n\tconst storeTheme = useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);\n\n\tconst currentTheme = isControlled ? controlledTheme : storeTheme;\n\n\tuseEffect(() => {\n\t\tif (!applyToDocument || typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tapplyTheme(currentTheme);\n\t\tif (currentTheme !== \"system\") {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\t\t\tconst onChange = () => applyTheme(\"system\");\n\t\t\tmq.addEventListener(\"change\", onChange);\n\t\t\treturn () => mq.removeEventListener(\"change\", onChange);\n\t\t} catch {\n\t\t\t// matchMedia not supported or restricted\n\t\t\treturn;\n\t\t}\n\t}, [currentTheme, applyToDocument]);\n\n\tconst setTheme = useCallback(\n\t\t(next: BasaltTheme) => {\n\t\t\tif (isControlled) {\n\t\t\t\tonThemeChange?.(next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstore.setValue(next);\n\t\t\tonThemeChange?.(next);\n\t\t},\n\t\t[isControlled, onThemeChange, store],\n\t);\n\n\tconst value = useMemo(() => ({ theme: currentTheme, setTheme }), [currentTheme, setTheme]);\n\n\treturn <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme() {\n\tconst ctx = useContext(ThemeContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useTheme must be used within ThemeProvider\");\n\t}\n\treturn ctx;\n}\n"],"mappings":";;;;;AAcA,IAAMA,IAAc,SAOdC,IAAeC,EAAwC,IAAI;AAEjE,SAASC,EAAW,GAAoB;CACvC,IAAI,OAAO,WAAa,KACvB;CAED,IAAMC,IAAO,SAAS,iBAClBC,IAAa;CACjB,IAAI;EACH,AAAI,OAAO,SAAW,OAAe,OAAO,OAAO,cAAe,eACjE,IAAa,OAAO,WAAW,8BAA8B,CAAC,CAAC;CAEjE,QAAQ;EACP,IAAa;CACd;CACA,IAAMC,IAAOC,MAAU,UAAWA,MAAU,YAAYF;CAGxD,AAFAD,EAAK,UAAU,OAAO,QAAQE,CAAI,GAClCF,EAAK,UAAU,OAAO,SAAS,CAACE,CAAI,GACpC,EAAK,QAAQ,OAAOA,IAAO,SAAS;AACrC;AAyCA,SAASE,EAAa,GAAsC;CAC3D,OAAOC,MAAU,WAAWA,MAAU,UAAUA,MAAU;AAC3D;AAEA,SAAgBC,EAAc,EAC7B,aACA,gBAAaV,GACb,kBAAe,UACf,aAAU,IACV,OAAOW,GACP,kBACA,qBAAkB,MACI;CACtB,IAAMC,IAAeD,MAAoB,KAAA,GAEnC,CAACE,KAASC,QACfC,EAAsB;EACrB;EACA,cAAcC;EACd;EACA,SAASR;EACT,YAAY,MAAUC;EACtB,WAAW;CACZ,CAAC,CACF;CAEA,QAAgB;EACf,EAAM,aAAa;GAAE;GAAY,cAAcO;GAAc;EAAQ,CAAC;CACvE,GAAG;EAACH;EAAOI;EAAYD;EAAcE;CAAO,CAAC;CAE7C,IAAMC,IAAoBC,QAAkBJ,GAAc,CAACA,CAAY,CAAC,GAElEK,IAAaC,EAAqBT,EAAM,WAAWA,EAAM,aAAaM,CAAiB,GAEvFI,IAAeX,IAAeD,IAAkBU;CAEtD,QAAgB;EACf,IAAKG,KAAmB,OAAO,SAAW,QAG1CrB,EAAWoB,CAAY,GACnBA,MAAiB,WAGrB,IAAI;GACH,IAAME,IAAK,OAAO,WAAW,8BAA8B,GACrDC,UAAiBvB,EAAW,QAAQ;GAE1C,OADAsB,EAAG,iBAAiB,UAAUC,CAAQ,SACzBD,EAAG,oBAAoB,UAAUC,CAAQ;EACvD,QAAQ;GAEP;EACD;CACD,GAAG,CAACH,GAAcC,CAAe,CAAC;CAElC,IAAMG,IAAWP,GACf,MAAsB;EACtB,IAAIR,GAAc;GACjB,IAAgBgB,CAAI;GACpB;EACD;EAEA,AADAf,EAAM,SAASe,CAAI,GACnBC,IAAgBD,CAAI;CACrB,GACA;EAAChB;EAAciB;EAAehB;CAAK,CACpC,GAEMJ,IAAQqB,SAAe;EAAE,OAAOP;EAAc;CAAS,IAAI,CAACA,GAAcI,CAAQ,CAAC;CAEzF,OAAO,kBAAC1B,EAAa,UAAd;EAA8B;EAAQ;CAAgC,CAAA;AAC9E;AAEA,SAAgB8B,IAAW;CAC1B,IAAMC,IAAMC,EAAWhC,CAAY;CACnC,IAAI,CAAC+B,GACJ,MAAU,MAAM,4CAA4C;CAE7D,OAAOA;AACR"}
1
+ {"version":3,"file":"theme.js","names":["STORAGE_KEY","ThemeContext","createContext","applyTheme","root","systemDark","dark","theme","isValidTheme","value","ThemeProvider","controlledTheme","isControlled","store","useState","createPreferenceStore","defaultTheme","storageKey","persist","getServerSnapshot","useCallback","storeTheme","useSyncExternalStore","currentTheme","applyToDocument","mq","onChange","setTheme","next","onThemeChange","useMemo","useTheme","ctx","useContext"],"sources":["../../src/providers/theme.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n\tuseSyncExternalStore,\n} from \"react\";\nimport { createPreferenceStore } from \"../utils/preference-store\";\n\nexport type BasaltTheme = \"light\" | \"dark\" | \"system\";\n\nconst STORAGE_KEY = \"theme\";\n\ntype ThemeContextValue = {\n\ttheme: BasaltTheme;\n\tsetTheme: (theme: BasaltTheme) => void;\n};\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null);\n\nfunction applyTheme(theme: BasaltTheme) {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\tconst root = document.documentElement;\n\tlet systemDark = false;\n\ttry {\n\t\tif (typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n\t\t\tsystemDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\t\t}\n\t} catch {\n\t\tsystemDark = false;\n\t}\n\tconst dark = theme === \"dark\" || (theme === \"system\" && systemDark);\n\troot.classList.toggle(\"dark\", dark);\n\troot.classList.toggle(\"light\", !dark);\n\troot.dataset.mode = dark ? \"dark\" : \"light\";\n}\n\nexport interface ThemeProviderProps {\n\t/**\n\t * Application components wrapped by the theme context.\n\t */\n\tchildren: ReactNode;\n\t/**\n\t * Storage key used for theme persistence.\n\t * @default \"theme\"\n\t */\n\tstorageKey?: string;\n\t/**\n\t * Initial theme used when no stored preference exists or during SSR.\n\t * @default \"system\"\n\t */\n\tdefaultTheme?: BasaltTheme;\n\t/**\n\t * Whether to persist theme changes to localStorage.\n\t * If false, localStorage is never read or written.\n\t * @default true\n\t */\n\tpersist?: boolean;\n\t/**\n\t * Controlled theme value. When provided, the provider acts as a controlled component\n\t * and internal state is driven by this prop.\n\t */\n\ttheme?: BasaltTheme;\n\t/**\n\t * Callback fired when theme change is requested.\n\t * In controlled mode, callers are responsible for updating `theme`.\n\t */\n\tonThemeChange?: (theme: BasaltTheme) => void;\n\t/**\n\t * Whether to apply mode classes and data-mode attribute to document.documentElement.\n\t * Set to false when a host theme system manages the document root.\n\t * @default true\n\t */\n\tapplyToDocument?: boolean;\n}\n\nfunction isValidTheme(value: unknown): value is BasaltTheme {\n\treturn value === \"light\" || value === \"dark\" || value === \"system\";\n}\n\nexport function ThemeProvider({\n\tchildren,\n\tstorageKey = STORAGE_KEY,\n\tdefaultTheme = \"system\",\n\tpersist = true,\n\ttheme: controlledTheme,\n\tonThemeChange,\n\tapplyToDocument = true,\n}: ThemeProviderProps) {\n\tconst isControlled = controlledTheme !== undefined;\n\n\tconst [store] = useState(() =>\n\t\tcreatePreferenceStore({\n\t\t\tstorageKey,\n\t\t\tdefaultValue: defaultTheme,\n\t\t\tpersist,\n\t\t\tisValid: isValidTheme,\n\t\t\tnormalize: (value) => value,\n\t\t\teventName: \"basalt:theme-change\",\n\t\t}),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, defaultValue: defaultTheme, persist });\n\t}, [store, storageKey, defaultTheme, persist]);\n\n\tconst getServerSnapshot = useCallback(() => defaultTheme, [defaultTheme]);\n\n\tconst storeTheme = useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);\n\n\tconst currentTheme = isControlled ? controlledTheme : storeTheme;\n\n\tuseEffect(() => {\n\t\tif (!applyToDocument || typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tapplyTheme(currentTheme);\n\t\tif (currentTheme !== \"system\") {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\t\t\tconst onChange = () => applyTheme(\"system\");\n\t\t\tmq.addEventListener(\"change\", onChange);\n\t\t\treturn () => mq.removeEventListener(\"change\", onChange);\n\t\t} catch {\n\t\t\t// matchMedia not supported or restricted\n\t\t\treturn;\n\t\t}\n\t}, [currentTheme, applyToDocument]);\n\n\tconst setTheme = useCallback(\n\t\t(next: BasaltTheme) => {\n\t\t\tif (isControlled) {\n\t\t\t\tonThemeChange?.(next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstore.setValue(next);\n\t\t\tonThemeChange?.(next);\n\t\t},\n\t\t[isControlled, onThemeChange, store],\n\t);\n\n\tconst value = useMemo(() => ({ theme: currentTheme, setTheme }), [currentTheme, setTheme]);\n\n\treturn <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme() {\n\tconst ctx = useContext(ThemeContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useTheme must be used within ThemeProvider\");\n\t}\n\treturn ctx;\n}\n"],"mappings":";;;;;AAcA,IAAMA,IAAc,SAOdC,IAAeC,EAAwC,IAAI;AAEjE,SAASC,EAAW,GAAoB;CACvC,IAAI,OAAO,WAAa,KACvB;CAED,IAAMC,IAAO,SAAS,iBAClBC,IAAa;CACjB,IAAI;EACH,AAAI,OAAO,SAAW,OAAe,OAAO,OAAO,cAAe,eACjE,IAAa,OAAO,WAAW,8BAA8B,CAAC,CAAC;CAEjE,QAAQ;EACP,IAAa;CACd;CACA,IAAMC,IAAOC,MAAU,UAAWA,MAAU,YAAYF;CAGxD,AAFAD,EAAK,UAAU,OAAO,QAAQE,CAAI,GAClCF,EAAK,UAAU,OAAO,SAAS,CAACE,CAAI,GACpC,EAAK,QAAQ,OAAOA,IAAO,SAAS;AACrC;AAyCA,SAASE,EAAa,GAAsC;CAC3D,OAAOC,MAAU,WAAWA,MAAU,UAAUA,MAAU;AAC3D;AAEA,SAAgBC,EAAc,EAC7B,aACA,gBAAaV,GACb,kBAAe,UACf,aAAU,IACV,OAAOW,GACP,kBACA,qBAAkB,MACI;CACtB,IAAMC,IAAeD,MAAoB,KAAA,GAEnC,CAACE,KAASC,QACfC,EAAsB;EACrB;EACA,cAAcC;EACd;EACA,SAASR;EACT,YAAY,MAAUC;EACtB,WAAW;CACZ,CAAC,CACF;CAEA,QAAgB;EACf,EAAM,aAAa;GAAE;GAAY,cAAcO;GAAc;EAAQ,CAAC;CACvE,GAAG;EAACH;EAAOI;EAAYD;EAAcE;CAAO,CAAC;CAE7C,IAAMC,IAAoBC,QAAkBJ,GAAc,CAACA,CAAY,CAAC,GAElEK,IAAaC,EAAqBT,EAAM,WAAWA,EAAM,aAAaM,CAAiB,GAEvFI,IAAeX,IAAeD,IAAkBU;CAEtD,QAAgB;EACf,IAAKG,KAAmB,OAAO,SAAW,QAG1CrB,EAAWoB,CAAY,GACnBA,MAAiB,WAGrB,IAAI;GACH,IAAME,IAAK,OAAO,WAAW,8BAA8B,GACrDC,UAAiBvB,EAAW,QAAQ;GAE1C,OADAsB,EAAG,iBAAiB,UAAUC,CAAQ,SACzBD,EAAG,oBAAoB,UAAUC,CAAQ;EACvD,QAAQ;GAEP;EACD;CACD,GAAG,CAACH,GAAcC,CAAe,CAAC;CAElC,IAAMG,IAAWP,GACf,MAAsB;EACtB,AAAIR,KAIJC,EAAM,SAASe,CAAI,GACnBC,IAAgBD,CAAI;CACrB,GACA;EAAChB;EAAciB;EAAehB;CAAK,CACpC,GAEMJ,IAAQqB,SAAe;EAAE,OAAOP;EAAc;CAAS,IAAI,CAACA,GAAcI,CAAQ,CAAC;CAEzF,OAAO,kBAAC1B,EAAa,UAAd;EAA8B;EAAQ;CAAgC,CAAA;AAC9E;AAEA,SAAgB8B,IAAW;CAC1B,IAAMC,IAAMC,EAAWhC,CAAY;CACnC,IAAI,CAAC+B,GACJ,MAAU,MAAM,4CAA4C;CAE7D,OAAOA;AACR"}
@@ -147,8 +147,14 @@
147
147
  );
148
148
  --basalt-size-action: var(--basalt-size-control);
149
149
  --basalt-space-nav-inset: var(--basalt-space-lg);
150
+ --basalt-space-sidebar-inset: var(--basalt-space-layout);
150
151
  --basalt-space-nav-gap: var(--basalt-space-sm);
151
152
  --basalt-size-rail: 4.25rem;
153
+ --basalt-size-sidebar-brand-slot: calc(
154
+ var(--basalt-size-rail) -
155
+ 2 *
156
+ var(--basalt-space-layout-lg)
157
+ );
152
158
  }
153
159
  :root, .light, [data-mode="light"] {
154
160
  --basalt-background: 220 14% 94%;
@@ -584,6 +590,38 @@
584
590
  min-block-size: calc(1lh + 2 * var(--basalt-space-control-y) + 2 * var(--basalt-border-width));
585
591
  padding-inline: var(--basalt-space-sm);
586
592
  }
593
+ .basalt-action-icon-sm {
594
+ inline-size: var(--basalt-size-control-sm);
595
+ max-inline-size: var(--basalt-size-control-sm);
596
+ min-inline-size: var(--basalt-size-control-sm);
597
+ block-size: var(--basalt-size-control-sm);
598
+ max-block-size: var(--basalt-size-control-sm);
599
+ min-block-size: var(--basalt-size-control-sm);
600
+ padding: 0;
601
+ }
602
+ .basalt-nav-list {
603
+ padding: var(--basalt-space-nav-inset);
604
+ }
605
+ .basalt-sidebar-nav {
606
+ padding-inline: var(--basalt-space-sidebar-inset);
607
+ }
608
+ .basalt-sidebar-brand-action {
609
+ flex-shrink: 0;
610
+ margin-inline-end: calc(-1 * var(--basalt-space-md));
611
+ }
612
+ .p-basalt-nav-inset {
613
+ padding: var(--basalt-space-nav-inset);
614
+ }
615
+ .px-basalt-nav-inset {
616
+ padding-inline: var(--basalt-space-nav-inset);
617
+ }
618
+ .px-basalt-sidebar-inset {
619
+ padding-inline: var(--basalt-space-sidebar-inset);
620
+ }
621
+ .size-basalt-sidebar-brand-slot {
622
+ inline-size: var(--basalt-size-sidebar-brand-slot);
623
+ block-size: var(--basalt-size-sidebar-brand-slot);
624
+ }
587
625
  .basalt-action-inset {
588
626
  border-width: 0;
589
627
  min-block-size: calc(1lh + 2 * var(--basalt-space-control-y));
@@ -632,14 +670,19 @@
632
670
  pointer-events: none;
633
671
  opacity: 0.5;
634
672
  }
635
- [data-basalt-sidebar][data-collapsed] :is([data-slot="sidebar-header"], [data-slot="sidebar-footer"]) {
636
- justify-content: center;
637
- }
638
673
  [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-footer"] {
639
674
  align-items: center;
640
675
  }
641
- [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-nav"] .basalt-nav-item {
642
- margin-inline: auto;
676
+ [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-nav"] {
677
+ padding-inline: calc((var(--basalt-size-rail) - var(--basalt-size-control)) / 2);
678
+ padding-block-start: calc(var(--basalt-size-control-sm) + var(--basalt-space-lg));
679
+ }
680
+ [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-brand-action"] {
681
+ position: absolute;
682
+ inset-block-start: 100%;
683
+ inset-inline-start: calc( (var(--basalt-size-sidebar-brand-slot) - var(--basalt-size-control-sm)) / 2 );
684
+ z-index: 1;
685
+ margin: 0;
643
686
  }
644
687
  @media (prefers-reduced-motion: reduce) {
645
688
  .basalt-nav-item {
@@ -1593,6 +1636,10 @@
1593
1636
  width: var(--basalt-size-icon-sm);
1594
1637
  height: var(--basalt-size-icon-sm);
1595
1638
  }
1639
+ .size-basalt-sidebar-brand-slot {
1640
+ width: var(--basalt-size-sidebar-brand-slot);
1641
+ height: var(--basalt-size-sidebar-brand-slot);
1642
+ }
1596
1643
  .size-full {
1597
1644
  width: 100%;
1598
1645
  height: 100%;
@@ -1846,6 +1893,9 @@
1846
1893
  .w-basalt-rail {
1847
1894
  width: var(--basalt-size-rail);
1848
1895
  }
1896
+ .w-basalt-sidebar-brand-slot {
1897
+ width: var(--basalt-size-sidebar-brand-slot);
1898
+ }
1849
1899
  .w-fit {
1850
1900
  width: fit-content;
1851
1901
  }
@@ -2645,9 +2695,6 @@
2645
2695
  .p-basalt-menu-inset {
2646
2696
  padding: var(--basalt-space-menu-inset);
2647
2697
  }
2648
- .p-basalt-nav-inset {
2649
- padding: var(--basalt-space-nav-inset);
2650
- }
2651
2698
  .p-basalt-space-lg {
2652
2699
  padding: var(--basalt-space-lg);
2653
2700
  }
@@ -2696,9 +2743,6 @@
2696
2743
  .px-basalt-menu-x {
2697
2744
  padding-inline: var(--basalt-space-menu-x);
2698
2745
  }
2699
- .px-basalt-nav-inset {
2700
- padding-inline: var(--basalt-space-nav-inset);
2701
- }
2702
2746
  .px-basalt-panel-x {
2703
2747
  padding-inline: var(--basalt-space-panel-x);
2704
2748
  }
@@ -157,8 +157,10 @@
157
157
  --spacing-basalt-row-content: var(--basalt-space-row-content);
158
158
  --spacing-basalt-action: var(--basalt-size-action);
159
159
  --spacing-basalt-nav-inset: var(--basalt-space-nav-inset);
160
+ --spacing-basalt-sidebar-inset: var(--basalt-space-sidebar-inset);
160
161
  --spacing-basalt-nav-gap: var(--basalt-space-nav-gap);
161
162
  --spacing-basalt-rail: var(--basalt-size-rail);
163
+ --spacing-basalt-sidebar-brand-slot: var(--basalt-size-sidebar-brand-slot);
162
164
  --color-basalt-background: hsl(var(--basalt-background));
163
165
  --color-basalt-foreground: hsl(var(--basalt-foreground));
164
166
  --color-basalt-card: hsl(var(--basalt-card));
@@ -125,8 +125,14 @@
125
125
  );
126
126
  --basalt-size-action: var(--basalt-size-control);
127
127
  --basalt-space-nav-inset: var(--basalt-space-lg);
128
+ --basalt-space-sidebar-inset: var(--basalt-space-layout);
128
129
  --basalt-space-nav-gap: var(--basalt-space-sm);
129
130
  --basalt-size-rail: 4.25rem;
131
+ --basalt-size-sidebar-brand-slot: calc(
132
+ var(--basalt-size-rail) -
133
+ 2 *
134
+ var(--basalt-space-layout-lg)
135
+ );
130
136
  }
131
137
 
132
138
  :root,
@@ -572,6 +578,38 @@
572
578
  min-block-size: calc(1lh + 2 * var(--basalt-space-control-y) + 2 * var(--basalt-border-width));
573
579
  padding-inline: var(--basalt-space-sm);
574
580
  }
581
+ .basalt-action-icon-sm {
582
+ inline-size: var(--basalt-size-control-sm);
583
+ max-inline-size: var(--basalt-size-control-sm);
584
+ min-inline-size: var(--basalt-size-control-sm);
585
+ block-size: var(--basalt-size-control-sm);
586
+ max-block-size: var(--basalt-size-control-sm);
587
+ min-block-size: var(--basalt-size-control-sm);
588
+ padding: 0;
589
+ }
590
+ .basalt-nav-list {
591
+ padding: var(--basalt-space-nav-inset);
592
+ }
593
+ .basalt-sidebar-nav {
594
+ padding-inline: var(--basalt-space-sidebar-inset);
595
+ }
596
+ .basalt-sidebar-brand-action {
597
+ flex-shrink: 0;
598
+ margin-inline-end: calc(-1 * var(--basalt-space-md));
599
+ }
600
+ .p-basalt-nav-inset {
601
+ padding: var(--basalt-space-nav-inset);
602
+ }
603
+ .px-basalt-nav-inset {
604
+ padding-inline: var(--basalt-space-nav-inset);
605
+ }
606
+ .px-basalt-sidebar-inset {
607
+ padding-inline: var(--basalt-space-sidebar-inset);
608
+ }
609
+ .size-basalt-sidebar-brand-slot {
610
+ inline-size: var(--basalt-size-sidebar-brand-slot);
611
+ block-size: var(--basalt-size-sidebar-brand-slot);
612
+ }
575
613
  .basalt-action-inset {
576
614
  border-width: 0;
577
615
  min-block-size: calc(1lh + 2 * var(--basalt-space-control-y));
@@ -625,15 +663,22 @@
625
663
  pointer-events: none;
626
664
  opacity: 0.5;
627
665
  }
628
- [data-basalt-sidebar][data-collapsed]
629
- :is([data-slot="sidebar-header"], [data-slot="sidebar-footer"]) {
630
- justify-content: center;
631
- }
632
666
  [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-footer"] {
633
667
  align-items: center;
634
668
  }
635
- [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-nav"] .basalt-nav-item {
636
- margin-inline: auto;
669
+ [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-nav"] {
670
+ padding-inline: calc((var(--basalt-size-rail) - var(--basalt-size-control)) / 2);
671
+ padding-block-start: calc(var(--basalt-size-control-sm) + var(--basalt-space-lg));
672
+ }
673
+ [data-basalt-sidebar][data-collapsed] [data-slot="sidebar-brand-action"] {
674
+ position: absolute;
675
+ inset-block-start: 100%;
676
+ inset-inline-start: calc(
677
+ (var(--basalt-size-sidebar-brand-slot) - var(--basalt-size-control-sm)) /
678
+ 2
679
+ );
680
+ z-index: 1;
681
+ margin: 0;
637
682
  }
638
683
  @media (prefers-reduced-motion: reduce) {
639
684
  .basalt-nav-item {
package/dist/utils/cn.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { clsx as e } from "clsx";
3
3
  import { extendTailwindMerge as t } from "tailwind-merge";
4
- //#region src/utils/cn.ts
4
+ // src/utils/cn.ts
5
5
  var n = t({ extend: { theme: {
6
6
  spacing: [(e) => e.startsWith("basalt-")],
7
7
  radius: [(e) => e.startsWith("basalt-")],
@@ -26,7 +26,6 @@ var n = t({ extend: { theme: {
26
26
  function r(...t) {
27
27
  return n(e(t));
28
28
  }
29
- //#endregion
30
29
  export { r as cn };
31
30
 
32
31
  //# sourceMappingURL=cn.js.map
@@ -1,11 +1,10 @@
1
1
  "use client";
2
2
  import { cn as e } from "./cn.js";
3
- //#region src/utils/control-surface.ts
3
+ // src/utils/control-surface.ts
4
4
  var t = "basalt-ui", n = "basalt-ui rounded-basalt-md border border-basalt-border bg-basalt-control";
5
5
  function r(t) {
6
6
  return e(n, t);
7
7
  }
8
- //#endregion
9
8
  export { t as BASALT_UI_CLASS, n as CONTROL_SURFACE_CLASS, r as controlSurfaceClass };
10
9
 
11
10
  //# sourceMappingURL=control-surface.js.map
@@ -1,3 +1,3 @@
1
- export declare const NAV_LIST_CLASS = "basalt-ui basalt-hover-list flex gap-basalt-nav-gap p-basalt-nav-inset";
1
+ export declare const NAV_LIST_CLASS = "basalt-ui basalt-hover-list basalt-nav-list flex gap-basalt-nav-gap";
2
2
  export declare const NAV_ROW_CLASS = "flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0";
3
3
  export declare const NAV_ITEM_CLASS = "basalt-ui basalt-nav-item flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0 basalt-focus basalt-focus-inset";
@@ -1,8 +1,7 @@
1
1
  "use client";
2
2
  import { FOCUS_INSET as e } from "../components/overlay.js";
3
- //#region src/utils/navigation.ts
4
- var t = "basalt-ui basalt-hover-list flex gap-basalt-nav-gap p-basalt-nav-inset", n = "flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0", r = `basalt-ui basalt-nav-item ${n} ${e}`;
5
- //#endregion
3
+ // src/utils/navigation.ts
4
+ var t = "basalt-ui basalt-hover-list basalt-nav-list flex gap-basalt-nav-gap", n = "flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0", r = `basalt-ui basalt-nav-item ${n} ${e}`;
6
5
  export { r as NAV_ITEM_CLASS, t as NAV_LIST_CLASS, n as NAV_ROW_CLASS };
7
6
 
8
7
  //# sourceMappingURL=navigation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.js","names":["NAV_LIST_CLASS","NAV_ROW_CLASS","NAV_ITEM_CLASS","FOCUS_INSET"],"sources":["../../src/utils/navigation.ts"],"sourcesContent":["import { FOCUS_INSET } from \"../components/overlay\";\n\nexport const NAV_LIST_CLASS =\n\t\"basalt-ui basalt-hover-list flex gap-basalt-nav-gap p-basalt-nav-inset\";\n\nexport const NAV_ROW_CLASS =\n\t\"flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0\";\n\nexport const NAV_ITEM_CLASS = `basalt-ui basalt-nav-item ${NAV_ROW_CLASS} ${FOCUS_INSET}`;\n"],"mappings":";;;AAEA,IAAaA,IACZ,0EAEYC,IACZ,uOAEYC,IAAiB,6BAA6BD,EAAc,GAAGE"}
1
+ {"version":3,"file":"navigation.js","names":["NAV_LIST_CLASS","NAV_ROW_CLASS","NAV_ITEM_CLASS","FOCUS_INSET"],"sources":["../../src/utils/navigation.ts"],"sourcesContent":["import { FOCUS_INSET } from \"../components/overlay\";\n\nexport const NAV_LIST_CLASS = \"basalt-ui basalt-hover-list basalt-nav-list flex gap-basalt-nav-gap\";\n\nexport const NAV_ROW_CLASS =\n\t\"flex min-w-0 shrink-0 min-h-basalt-control items-center gap-basalt-row-gap rounded-basalt-md px-basalt-row-x py-basalt-row-y text-left text-basalt-base font-normal leading-basalt-row [&>svg]:size-basalt-icon-lg [&>svg]:shrink-0\";\n\nexport const NAV_ITEM_CLASS = `basalt-ui basalt-nav-item ${NAV_ROW_CLASS} ${FOCUS_INSET}`;\n"],"mappings":";;;AAEA,IAAaA,IAAiB,uEAEjBC,IACZ,uOAEYC,IAAiB,6BAA6BD,EAAc,GAAGE"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- //#region src/utils/preference-store.ts
2
+ // src/utils/preference-store.ts
3
3
  function e(e) {
4
4
  try {
5
5
  return typeof window > "u" || !window.localStorage ? { status: "error" } : {
@@ -100,7 +100,6 @@ function r({ storageKey: r, defaultValue: i, persist: a, isValid: o, normalize:
100
100
  }
101
101
  };
102
102
  }
103
- //#endregion
104
103
  export { r as createPreferenceStore };
105
104
 
106
105
  //# sourceMappingURL=preference-store.js.map
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import * as e from "react";
3
- //#region src/utils/selection-indicator.ts
3
+ // src/utils/selection-indicator.ts
4
4
  var t = "basalt-selection-motion", n = {
5
5
  left: 0,
6
6
  width: 0,
@@ -79,7 +79,6 @@ function a({ itemSelector: a, enabled: o = !0, mapGeometry: s, ref: c }) {
79
79
  motionClassName: d.animated ? t : void 0
80
80
  };
81
81
  }
82
- //#endregion
83
82
  export { t as SELECTION_INDICATOR_MOTION_CLASS, r as assignRef, i as measureSelectionItem, a as useSelectionIndicator };
84
83
 
85
84
  //# sourceMappingURL=selection-indicator.js.map
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import * as e from "react";
3
- //#region src/utils/use-checkable-group.ts
3
+ // src/utils/use-checkable-group.ts
4
4
  function t({ value: t, defaultValue: n, onValueChange: r, error: i, describedBy: a, ariaInvalid: o, form: s, ref: c }) {
5
5
  let l = e.useId(), u = e.useRef(null), [d, f] = e.useState(n ?? []), p = t ?? d, m = !!i, h = `${l}-error`, g = [m ? h : null, a].filter(Boolean).join(" ") || void 0, _ = e.useRef(null), v = e.useCallback((e) => {
6
6
  let n = _.current;
@@ -55,7 +55,6 @@ function t({ value: t, defaultValue: n, onValueChange: r, error: i, describedBy:
55
55
  ariaInvalid: m ? !0 : o
56
56
  };
57
57
  }
58
- //#endregion
59
58
  export { t as useCheckableGroup };
60
59
 
61
60
  //# sourceMappingURL=use-checkable-group.js.map
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { assignRef as e } from "./selection-indicator.js";
3
3
  import { useCallback as t } from "react";
4
- //#region src/utils/use-hover-highlight.ts
4
+ // src/utils/use-hover-highlight.ts
5
5
  var n = "[data-basalt-hover-item]", r = "[data-highlighted], [data-hover-active=\"true\"], [aria-selected=\"true\"], [data-state=\"checked\"], [data-hover-selected=\"true\"], [data-selected=\"true\"]";
6
6
  function i(i, { restoreOnPointerLeave: a = !0 } = {}) {
7
7
  return t((t) => {
@@ -40,7 +40,7 @@ function i(i, { restoreOnPointerLeave: a = !0 } = {}) {
40
40
  if (e.pointerType === "touch") return;
41
41
  s = !1;
42
42
  let t = v(e.target);
43
- t !== o && (!a && (!t || !o) && (c = !0), o = t, x());
43
+ t !== o && (a || t && o || (c = !0), o = t, x());
44
44
  }, C = () => {
45
45
  o = null, s = !a, a || (c = !0), x();
46
46
  }, w = (e) => {
@@ -76,7 +76,6 @@ function i(i, { restoreOnPointerLeave: a = !0 } = {}) {
76
76
  };
77
77
  }, [i, a]);
78
78
  }
79
- //#endregion
80
79
  export { i as useHoverHighlight };
81
80
 
82
81
  //# sourceMappingURL=use-hover-highlight.js.map