@nocoo/basalt 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -15
- package/ai/COMPATIBILITY.md +180 -0
- package/ai/INTEGRATION.md +1760 -0
- package/ai/RECIPES.md +161 -0
- package/ai/USAGE.md +99 -0
- package/ai/registry.json +38099 -0
- package/ai/sources.json +10 -0
- package/dist/assets/brand-mark.d.ts +1 -0
- package/dist/assets/brand-mark.js +7 -0
- package/dist/assets/brand-mark.js.map +1 -0
- package/dist/charts/area.d.ts +58 -5
- package/dist/charts/area.js +20 -12
- package/dist/charts/area.js.map +1 -1
- package/dist/charts/bar.d.ts +54 -5
- package/dist/charts/bar.js +16 -10
- package/dist/charts/bar.js.map +1 -1
- package/dist/charts/bullet.d.ts +18 -1
- package/dist/charts/bullet.js +6 -3
- package/dist/charts/bullet.js.map +1 -1
- package/dist/charts/charts.d.ts +58 -5
- package/dist/charts/charts.js +13 -2
- package/dist/charts/charts.js.map +1 -1
- package/dist/charts/config.d.ts +7 -0
- package/dist/charts/config.js +5 -1
- package/dist/charts/config.js.map +1 -1
- package/dist/charts/custom-chart.d.ts +58 -5
- package/dist/charts/custom-chart.js +13 -2
- package/dist/charts/custom-chart.js.map +1 -1
- package/dist/charts/donut.d.ts +18 -1
- package/dist/charts/donut.js +6 -3
- package/dist/charts/donut.js.map +1 -1
- package/dist/charts/frame.d.ts +40 -3
- package/dist/charts/frame.js +55 -28
- package/dist/charts/frame.js.map +1 -1
- package/dist/charts/funnel.d.ts +18 -1
- package/dist/charts/funnel.js +5 -1
- package/dist/charts/funnel.js.map +1 -1
- package/dist/charts/gauge.d.ts +18 -1
- package/dist/charts/gauge.js +38 -20
- package/dist/charts/gauge.js.map +1 -1
- package/dist/charts/grouped-bar.d.ts +54 -5
- package/dist/charts/grouped-bar.js +16 -10
- package/dist/charts/grouped-bar.js.map +1 -1
- package/dist/charts/heatmap-calendar.d.ts +61 -0
- package/dist/charts/heatmap-calendar.js +287 -96
- package/dist/charts/heatmap-calendar.js.map +1 -1
- package/dist/charts/heatmap-matrix.d.ts +99 -0
- package/dist/charts/heatmap-matrix.js +249 -0
- package/dist/charts/heatmap-matrix.js.map +1 -0
- package/dist/charts/line.d.ts +66 -5
- package/dist/charts/line.js +37 -30
- package/dist/charts/line.js.map +1 -1
- package/dist/charts/palette.d.ts +1 -0
- package/dist/charts/palette.js +7 -1
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/radar.d.ts +18 -1
- package/dist/charts/radar.js +26 -19
- package/dist/charts/radar.js.map +1 -1
- package/dist/charts/sankey.d.ts +18 -1
- package/dist/charts/sankey.js +4 -1
- package/dist/charts/sankey.js.map +1 -1
- package/dist/charts/series.d.ts +5 -7
- package/dist/charts/series.js.map +1 -1
- package/dist/charts/slot-bar.d.ts +38 -6
- package/dist/charts/slot-bar.js +5 -2
- package/dist/charts/slot-bar.js.map +1 -1
- package/dist/charts/sparkline.d.ts +35 -5
- package/dist/charts/sparkline.js +22 -18
- package/dist/charts/sparkline.js.map +1 -1
- package/dist/charts/stacked-bar.d.ts +58 -5
- package/dist/charts/stacked-bar.js +19 -12
- package/dist/charts/stacked-bar.js.map +1 -1
- package/dist/charts/stat-card.d.ts +51 -1
- package/dist/charts/stat-card.js +66 -39
- package/dist/charts/stat-card.js.map +1 -1
- package/dist/charts/timeline.d.ts +3 -0
- package/dist/charts/timeline.js +4 -3
- package/dist/charts/timeline.js.map +1 -1
- package/dist/charts/timeseries.d.ts +58 -5
- package/dist/charts/timeseries.js +13 -2
- package/dist/charts/timeseries.js.map +1 -1
- package/dist/charts/tooltip.d.ts +57 -0
- package/dist/charts/tooltip.js +119 -2
- package/dist/charts/tooltip.js.map +1 -1
- package/dist/components/accordion.d.ts +117 -2
- package/dist/components/accordion.js +20 -13
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/alert-dialog.d.ts +131 -13
- package/dist/components/alert-dialog.js +12 -9
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/app-header.js +18 -17
- package/dist/components/app-header.js.map +1 -1
- package/dist/components/app-shell.js +15 -14
- package/dist/components/app-shell.js.map +1 -1
- package/dist/components/autocomplete.d.ts +4 -0
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/avatar.d.ts +76 -3
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/badge.d.ts +15 -1
- package/dist/components/badge.js +17 -16
- package/dist/components/badge.js.map +1 -1
- package/dist/components/banner.d.ts +88 -2
- package/dist/components/banner.js +41 -40
- package/dist/components/banner.js.map +1 -1
- package/dist/components/basalt-mark.js +14 -8
- package/dist/components/basalt-mark.js.map +1 -1
- package/dist/components/battery-meter.d.ts +10 -0
- package/dist/components/battery-meter.js +56 -0
- package/dist/components/battery-meter.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +27 -7
- package/dist/components/breadcrumbs.js +21 -20
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button.d.ts +48 -2
- package/dist/components/button.js +87 -36
- package/dist/components/button.js.map +1 -1
- package/dist/components/chat-bubble.d.ts +7 -0
- package/dist/components/chat-bubble.js +14 -13
- package/dist/components/chat-bubble.js.map +1 -1
- package/dist/components/chat-composer.d.ts +7 -3
- package/dist/components/chat-composer.js.map +1 -1
- package/dist/components/chat-header.d.ts +6 -1
- package/dist/components/chat-header.js +17 -16
- package/dist/components/chat-header.js.map +1 -1
- package/dist/components/chat-inbox.d.ts +7 -2
- package/dist/components/chat-inbox.js.map +1 -1
- package/dist/components/checkbox.js +84 -53
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/clipboard-text.d.ts +13 -2
- package/dist/components/clipboard-text.js +4 -4
- package/dist/components/clipboard-text.js.map +1 -1
- package/dist/components/collapsible.d.ts +58 -15
- package/dist/components/collapsible.js.map +1 -1
- package/dist/components/command-palette.d.ts +151 -61
- package/dist/components/command-palette.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +1 -1
- package/dist/components/confirm-dialog.js +6 -4
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/context-menu.d.ts +210 -2
- package/dist/components/context-menu.js +7 -4
- package/dist/components/context-menu.js.map +1 -1
- package/dist/components/data-table.d.ts +40 -2
- package/dist/components/data-table.js +168 -120
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +53 -2
- package/dist/components/date-picker.js +387 -219
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/delete-resource.d.ts +7 -1
- package/dist/components/delete-resource.js +22 -18
- package/dist/components/delete-resource.js.map +1 -1
- package/dist/components/description-list.js +16 -15
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog.d.ts +141 -12
- package/dist/components/dialog.js +42 -38
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dock.d.ts +1 -1
- package/dist/components/dock.js +39 -58
- package/dist/components/dock.js.map +1 -1
- package/dist/components/dropdown-menu.d.ts +229 -15
- package/dist/components/dropdown-menu.js +9 -6
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editable-nav-item.d.ts +33 -0
- package/dist/components/editable-nav-item.js +90 -0
- package/dist/components/editable-nav-item.js.map +1 -0
- package/dist/components/empty.d.ts +22 -2
- package/dist/components/empty.js +22 -13
- package/dist/components/empty.js.map +1 -1
- package/dist/components/field.js +31 -30
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +37 -0
- package/dist/components/file-dropzone.js +103 -0
- package/dist/components/file-dropzone.js.map +1 -0
- package/dist/components/filter-bar.d.ts +34 -0
- package/dist/components/filter-bar.js +52 -0
- package/dist/components/filter-bar.js.map +1 -0
- package/dist/components/flow.js +19 -18
- package/dist/components/flow.js.map +1 -1
- package/dist/components/grid.d.ts +3 -1
- package/dist/components/grid.js.map +1 -1
- package/dist/components/hover-card.d.ts +111 -1
- package/dist/components/hover-card.js +9 -6
- package/dist/components/hover-card.js.map +1 -1
- package/dist/components/icon-picker.d.ts +34 -0
- package/dist/components/icon-picker.js +77 -0
- package/dist/components/icon-picker.js.map +1 -0
- package/dist/components/inline-editable.d.ts +46 -0
- package/dist/components/inline-editable.js +124 -0
- package/dist/components/inline-editable.js.map +1 -0
- package/dist/components/input-area.js +3 -3
- package/dist/components/input-group.js +7 -7
- package/dist/components/input.js +3 -3
- package/dist/components/label.js +18 -17
- package/dist/components/label.js.map +1 -1
- package/dist/components/layer-card.d.ts +10 -2
- package/dist/components/layer-card.js +71 -68
- package/dist/components/layer-card.js.map +1 -1
- package/dist/components/loader.d.ts +10 -2
- package/dist/components/loader.js.map +1 -1
- package/dist/components/menu-bar.d.ts +174 -6
- package/dist/components/menu-bar.js +33 -29
- package/dist/components/menu-bar.js.map +1 -1
- package/dist/components/meter.d.ts +27 -2
- package/dist/components/meter.js.map +1 -1
- package/dist/components/multi-select.d.ts +64 -0
- package/dist/components/multi-select.js +218 -0
- package/dist/components/multi-select.js.map +1 -0
- package/dist/components/navigation-menu.d.ts +88 -5
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/overlay.js +6 -5
- package/dist/components/overlay.js.map +1 -1
- package/dist/components/page-header.js +23 -21
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/pagination.js +7 -7
- package/dist/components/popover.d.ts +136 -16
- package/dist/components/popover.js +32 -28
- package/dist/components/popover.js.map +1 -1
- package/dist/components/radio.js +38 -37
- package/dist/components/radio.js.map +1 -1
- package/dist/components/resource-list.d.ts +26 -1
- package/dist/components/resource-list.js +28 -15
- package/dist/components/resource-list.js.map +1 -1
- package/dist/components/responsive-master-detail.d.ts +27 -0
- package/dist/components/responsive-master-detail.js +85 -0
- package/dist/components/responsive-master-detail.js.map +1 -0
- package/dist/components/section-rule.js +23 -22
- package/dist/components/section-rule.js.map +1 -1
- package/dist/components/select.d.ts +27 -3
- package/dist/components/select.js +11 -11
- package/dist/components/select.js.map +1 -1
- package/dist/components/sheet.d.ts +115 -11
- package/dist/components/sheet.js +37 -30
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/sidebar.d.ts +109 -17
- package/dist/components/sidebar.js +109 -108
- package/dist/components/sidebar.js.map +1 -1
- package/dist/components/skeleton-line.d.ts +22 -2
- package/dist/components/skeleton-line.js.map +1 -1
- package/dist/components/slider.d.ts +61 -1
- package/dist/components/slider.js +31 -15
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stat-strip.js +16 -15
- package/dist/components/stat-strip.js.map +1 -1
- package/dist/components/switch.js +78 -47
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table-of-contents.js +18 -17
- package/dist/components/table-of-contents.js.map +1 -1
- package/dist/components/table-pager.js +20 -19
- package/dist/components/table-pager.js.map +1 -1
- package/dist/components/table.d.ts +9 -3
- package/dist/components/table.js +19 -18
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.js +29 -22
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag-badge.d.ts +58 -0
- package/dist/components/tag-badge.js +72 -0
- package/dist/components/tag-badge.js.map +1 -0
- package/dist/components/tag-color-picker.d.ts +20 -0
- package/dist/components/tag-color-picker.js +42 -0
- package/dist/components/tag-color-picker.js.map +1 -0
- package/dist/components/text.js +17 -16
- package/dist/components/text.js.map +1 -1
- package/dist/components/toast.d.ts +173 -3
- package/dist/components/toast.js +1 -1
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toggle-group.d.ts +88 -2
- package/dist/components/toggle-group.js +32 -31
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle.d.ts +35 -2
- package/dist/components/toggle.js +12 -11
- package/dist/components/toggle.js.map +1 -1
- package/dist/components/tooltip.d.ts +144 -6
- package/dist/components/tooltip.js +9 -6
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/typeahead-field.js +193 -132
- package/dist/components/typeahead-field.js.map +1 -1
- package/dist/components/upload-queue.d.ts +51 -0
- package/dist/components/upload-queue.js +116 -0
- package/dist/components/upload-queue.js.map +1 -0
- package/dist/providers/accent.d.ts +46 -2
- package/dist/providers/accent.js +358 -172
- package/dist/providers/accent.js.map +1 -1
- package/dist/providers/link.d.ts +14 -4
- package/dist/providers/link.js.map +1 -1
- package/dist/providers/theme.d.ts +38 -2
- package/dist/providers/theme.js +160 -27
- package/dist/providers/theme.js.map +1 -1
- package/dist/styles/base.css +83 -0
- package/dist/styles/standalone.css +711 -120
- package/dist/styles/tailwind.css +21 -7
- package/dist/styles/tokens.css +145 -91
- package/dist/utils/control-surface.d.ts +2 -1
- package/dist/utils/control-surface.js +4 -4
- package/dist/utils/control-surface.js.map +1 -1
- package/dist/utils/selection-indicator.js +2 -2
- package/dist/utils/selection-indicator.js.map +1 -1
- package/package.json +8 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accent.js","names":[],"sources":["../../src/providers/accent.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseSyncExternalStore,\n} from \"react\";\n\nexport type AccentSwatch = {\n\tid: string;\n\tlabel: string;\n\ttoken: string;\n\tlight: string;\n\tdark: string;\n};\n\nexport const ACCENT_SWATCHES: readonly AccentSwatch[] = [\n\t{\n\t\tid: \"primary\",\n\t\tlabel: \"Primary\",\n\t\ttoken: \"--basalt-chart-1\",\n\t\tlight: \"217 91% 60%\",\n\t\tdark: \"217 91% 65%\",\n\t},\n\t{ id: \"sky\", label: \"Sky\", token: \"--basalt-chart-2\", light: \"200 90% 55%\", dark: \"200 90% 60%\" },\n\t{\n\t\tid: \"teal\",\n\t\tlabel: \"Teal\",\n\t\ttoken: \"--basalt-chart-3\",\n\t\tlight: \"186 80% 45%\",\n\t\tdark: \"186 80% 50%\",\n\t},\n\t{\n\t\tid: \"jade\",\n\t\tlabel: \"Jade\",\n\t\ttoken: \"--basalt-chart-4\",\n\t\tlight: \"166 72% 44%\",\n\t\tdark: \"166 72% 50%\",\n\t},\n\t{\n\t\tid: \"green\",\n\t\tlabel: \"Green\",\n\t\ttoken: \"--basalt-chart-5\",\n\t\tlight: \"142 71% 45%\",\n\t\tdark: \"142 71% 50%\",\n\t},\n\t{ id: \"lime\", label: \"Lime\", token: \"--basalt-chart-6\", light: \"84 65% 46%\", dark: \"84 65% 52%\" },\n\t{\n\t\tid: \"amber\",\n\t\tlabel: \"Amber\",\n\t\ttoken: \"--basalt-chart-7\",\n\t\tlight: \"45 93% 47%\",\n\t\tdark: \"45 93% 52%\",\n\t},\n\t{\n\t\tid: \"orange\",\n\t\tlabel: \"Orange\",\n\t\ttoken: \"--basalt-chart-8\",\n\t\tlight: \"30 90% 55%\",\n\t\tdark: \"30 90% 60%\",\n\t},\n\t{\n\t\tid: \"vermilion\",\n\t\tlabel: \"Vermilion\",\n\t\ttoken: \"--basalt-chart-9\",\n\t\tlight: \"15 85% 52%\",\n\t\tdark: \"15 85% 57%\",\n\t},\n\t{ id: \"red\", label: \"Red\", token: \"--basalt-chart-10\", light: \"0 72% 51%\", dark: \"0 72% 56%\" },\n\t{\n\t\tid: \"rose\",\n\t\tlabel: \"Rose\",\n\t\ttoken: \"--basalt-chart-11\",\n\t\tlight: \"340 82% 55%\",\n\t\tdark: \"340 82% 60%\",\n\t},\n\t{\n\t\tid: \"magenta\",\n\t\tlabel: \"Magenta\",\n\t\ttoken: \"--basalt-chart-12\",\n\t\tlight: \"320 70% 55%\",\n\t\tdark: \"320 70% 60%\",\n\t},\n\t{\n\t\tid: \"orchid\",\n\t\tlabel: \"Orchid\",\n\t\ttoken: \"--basalt-chart-13\",\n\t\tlight: \"290 65% 55%\",\n\t\tdark: \"290 65% 60%\",\n\t},\n\t{\n\t\tid: \"purple\",\n\t\tlabel: \"Purple\",\n\t\ttoken: \"--basalt-chart-14\",\n\t\tlight: \"270 70% 60%\",\n\t\tdark: \"270 70% 65%\",\n\t},\n\t{\n\t\tid: \"indigo\",\n\t\tlabel: \"Indigo\",\n\t\ttoken: \"--basalt-chart-15\",\n\t\tlight: \"250 65% 58%\",\n\t\tdark: \"250 65% 63%\",\n\t},\n\t{\n\t\tid: \"cobalt\",\n\t\tlabel: \"Cobalt\",\n\t\ttoken: \"--basalt-chart-16\",\n\t\tlight: \"230 70% 56%\",\n\t\tdark: \"230 70% 61%\",\n\t},\n\t{\n\t\tid: \"steel\",\n\t\tlabel: \"Steel\",\n\t\ttoken: \"--basalt-chart-17\",\n\t\tlight: \"210 55% 50%\",\n\t\tdark: \"210 55% 56%\",\n\t},\n\t{\n\t\tid: \"cadet\",\n\t\tlabel: \"Cadet\",\n\t\ttoken: \"--basalt-chart-18\",\n\t\tlight: \"195 45% 55%\",\n\t\tdark: \"195 45% 60%\",\n\t},\n\t{\n\t\tid: \"seafoam\",\n\t\tlabel: \"Seafoam\",\n\t\ttoken: \"--basalt-chart-19\",\n\t\tlight: \"160 50% 50%\",\n\t\tdark: \"160 50% 55%\",\n\t},\n\t{\n\t\tid: \"olive\",\n\t\tlabel: \"Olive\",\n\t\ttoken: \"--basalt-chart-20\",\n\t\tlight: \"100 50% 48%\",\n\t\tdark: \"100 50% 53%\",\n\t},\n\t{\n\t\tid: \"gold\",\n\t\tlabel: \"Gold\",\n\t\ttoken: \"--basalt-chart-21\",\n\t\tlight: \"60 65% 45%\",\n\t\tdark: \"60 65% 50%\",\n\t},\n\t{\n\t\tid: \"tangerine\",\n\t\tlabel: \"Tangerine\",\n\t\ttoken: \"--basalt-chart-22\",\n\t\tlight: \"22 80% 50%\",\n\t\tdark: \"22 80% 55%\",\n\t},\n\t{\n\t\tid: \"crimson\",\n\t\tlabel: \"Crimson\",\n\t\ttoken: \"--basalt-chart-23\",\n\t\tlight: \"350 65% 50%\",\n\t\tdark: \"350 65% 55%\",\n\t},\n\t{ id: \"gray\", label: \"Gray\", token: \"--basalt-chart-24\", light: \"0 0% 25%\", dark: \"0 0% 65%\" },\n] as const;\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\treturn ACCENT_SWATCHES.find((swatch) => swatch.id === id) ?? 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\nexport function accentForeground(hsl: string) {\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\tconst a = s * Math.min(l, 1 - l);\n\tconst f = (n: number) => {\n\t\tconst k = (n + h / 30) % 12;\n\t\treturn l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n\t};\n\tconst luminance = 0.2126 * channel(f(0)) + 0.7152 * channel(f(8)) + 0.0722 * channel(f(4));\n\treturn luminance > 0.35 ? \"0 0% 10%\" : \"0 0% 100%\";\n}\n\nexport function applyAccent(id: string, dark = false) {\n\tconst swatch = accentSwatchById(id);\n\tconst value = dark ? swatch.dark : swatch.light;\n\tconst root = document.documentElement;\n\troot.style.setProperty(\"--basalt-primary\", value);\n\troot.style.setProperty(\"--basalt-primary-foreground\", accentForeground(value));\n\troot.style.setProperty(\"--basalt-ring\", value);\n\troot.dataset.accent = swatch.id;\n}\n\nfunction readAccent(): string {\n\treturn accentSwatchById(window.localStorage.getItem(STORAGE_KEY)).id;\n}\n\nfunction subscribe(onStoreChange: () => void) {\n\twindow.addEventListener(\"storage\", onStoreChange);\n\treturn () => window.removeEventListener(\"storage\", onStoreChange);\n}\n\nfunction isDarkMode(): boolean {\n\treturn document.documentElement.classList.contains(\"dark\");\n}\n\nexport function AccentProvider({ children }: { children: ReactNode }) {\n\tconst accent = useSyncExternalStore(subscribe, readAccent, () => DEFAULT_ACCENT_ID);\n\tuseEffect(() => {\n\t\tapplyAccent(accent, isDarkMode());\n\t\tconst observer = new MutationObserver(() => applyAccent(accent, isDarkMode()));\n\t\tobserver.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] });\n\t\treturn () => observer.disconnect();\n\t}, [accent]);\n\tconst setAccent = useCallback((id: string) => {\n\t\tconst next = accentSwatchById(id).id;\n\t\twindow.localStorage.setItem(STORAGE_KEY, next);\n\t\tapplyAccent(next, isDarkMode());\n\t\twindow.dispatchEvent(new Event(\"storage\"));\n\t}, []);\n\tconst value = useMemo(\n\t\t() => ({ accent, setAccent, swatches: ACCENT_SWATCHES }),\n\t\t[accent, setAccent],\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":[],"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\";\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\n\tif (!dark) {\n\t\tfor (let l = Math.min(Math.round(origL * 100), 60); l >= 15; l--) {\n\t\t\tconst rgb = hslToRgbChannels(h, s, l / 100);\n\t\t\tconst minTextR = Math.min(...targetSurfaces.map((bg) => wcagContrast(rgb, bg)));\n\t\t\tif (minTextR < 4.55) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst cWhite = wcagContrast(rgb, WHITE_TEXT_RGB);\n\t\t\tif (cWhite < 4.55) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet hoverOk = true;\n\t\t\tfor (const bg of targetSurfaces) {\n\t\t\t\tconst hoverBg = compositeRgb([...rgb, 0.9], bg);\n\t\t\t\tif (wcagContrast(hoverBg, WHITE_TEXT_RGB) < 4.55) {\n\t\t\t\t\thoverOk = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (hoverOk) {\n\t\t\t\treturn `${h} ${Math.round(s * 100)}% ${l}%`;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (let l = Math.max(Math.round(origL * 100), 45); l <= 85; l++) {\n\t\t\tconst rgb = hslToRgbChannels(h, s, l / 100);\n\t\t\tconst minTextR = Math.min(...targetSurfaces.map((bg) => wcagContrast(rgb, bg)));\n\t\t\tif (minTextR < 4.55) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst cDark = wcagContrast(rgb, DARK_TEXT_RGB);\n\t\t\tif (cDark < 4.55) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet hoverOk = true;\n\t\t\tfor (const bg of targetSurfaces) {\n\t\t\t\tconst hoverBg = compositeRgb([...rgb, 0.9], bg);\n\t\t\t\tif (wcagContrast(hoverBg, DARK_TEXT_RGB) < 4.55) {\n\t\t\t\t\thoverOk = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (hoverOk) {\n\t\t\t\treturn `${h} ${Math.round(s * 100)}% ${l}%`;\n\t\t\t}\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\ninterface AccentStore {\n\tgetSnapshot: () => string;\n\tsubscribe: (listener: () => void) => () => void;\n\tsetAccent: (next: string) => void;\n\tupdateConfig: (config: { storageKey: string; defaultAccent: string; persist: boolean }) => void;\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\ntype StorageReadResult = { status: \"success\"; value: string | null } | { status: \"error\" };\n\nfunction safeGetStorageItem(key: string): StorageReadResult {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn { status: \"error\" };\n\t\t}\n\t\tconst value = window.localStorage.getItem(key);\n\t\treturn { status: \"success\", value };\n\t} catch {\n\t\treturn { status: \"error\" };\n\t}\n}\n\nfunction safeSetStorageItem(key: string, value: string): boolean {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn false;\n\t\t}\n\t\twindow.localStorage.setItem(key, value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isLocalStorageArea(area: Storage | null | undefined): boolean {\n\tif (!area) {\n\t\treturn true;\n\t}\n\ttry {\n\t\tif (typeof window !== \"undefined\" && window.localStorage) {\n\t\t\treturn area === window.localStorage;\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n\treturn false;\n}\n\nconst ACCENT_CHANGE_EVENT = \"basalt:accent-change\";\n\ninterface AccentChangeEventDetail {\n\tkey: string;\n\tvalue: string;\n\twriteSucceeded: boolean;\n}\n\nfunction createAccentStore(\n\tinitialStorageKey: string,\n\tinitialDefaultAccent: string,\n\tinitialPersist: boolean,\n): AccentStore {\n\tlet storageKey = initialStorageKey;\n\tlet defaultAccent = accentSwatchById(initialDefaultAccent).id;\n\tlet persist = initialPersist;\n\n\tlet memoryAccent: string = defaultAccent;\n\tlet hasExplicitSelection = false;\n\tlet lastSetFailed = false;\n\n\tif (persist) {\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"success\" && isValidAccentId(res.value)) {\n\t\t\tmemoryAccent = accentSwatchById(res.value).id;\n\t\t\thasExplicitSelection = true;\n\t\t}\n\t}\n\n\tconst listeners = new Set<() => void>();\n\n\tconst notify = () => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t};\n\n\tconst onInternalChange = (event: Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst customEv = event as CustomEvent<AccentChangeEventDetail>;\n\t\tif (!customEv.detail || customEv.detail.key !== storageKey) {\n\t\t\treturn;\n\t\t}\n\t\tconst { value, writeSucceeded } = customEv.detail;\n\t\tif (writeSucceeded) {\n\t\t\tlastSetFailed = false;\n\t\t} else {\n\t\t\tlastSetFailed = true;\n\t\t}\n\t\tmemoryAccent = value;\n\t\thasExplicitSelection = true;\n\t\tnotify();\n\t};\n\n\tconst onStorage = (event: StorageEvent | Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst storageEv = event as Partial<StorageEvent>;\n\t\tif (\"key\" in storageEv && storageEv.key !== undefined) {\n\t\t\tif (!isLocalStorageArea(storageEv.storageArea)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (storageEv.key !== null && storageEv.key !== storageKey) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlastSetFailed = false;\n\t\t\tconst rawVal = storageEv.newValue;\n\t\t\tif (rawVal === null || rawVal === undefined || !isValidAccentId(rawVal)) {\n\t\t\t\tmemoryAccent = defaultAccent;\n\t\t\t\thasExplicitSelection = false;\n\t\t\t\tnotify();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmemoryAccent = accentSwatchById(rawVal).id;\n\t\t\thasExplicitSelection = true;\n\t\t\tnotify();\n\t\t\treturn;\n\t\t}\n\t\tif (lastSetFailed) {\n\t\t\treturn;\n\t\t}\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"error\") {\n\t\t\t// Read failed: preserve current cached memory accent, do not revert to default\n\t\t\treturn;\n\t\t}\n\t\tif (isValidAccentId(res.value)) {\n\t\t\tmemoryAccent = accentSwatchById(res.value).id;\n\t\t\thasExplicitSelection = true;\n\t\t\tnotify();\n\t\t} else {\n\t\t\t// Key removed or invalid value stored: revert to default\n\t\t\tmemoryAccent = defaultAccent;\n\t\t\thasExplicitSelection = false;\n\t\t\tnotify();\n\t\t}\n\t};\n\n\tlet cleanupStorageListener: (() => void) | null = null;\n\tconst attachStorageListener = () => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tif (listeners.size === 1 && !cleanupStorageListener) {\n\t\t\twindow.addEventListener(\"storage\", onStorage);\n\t\t\twindow.addEventListener(ACCENT_CHANGE_EVENT, onInternalChange);\n\t\t\tcleanupStorageListener = () => {\n\t\t\t\twindow.removeEventListener(\"storage\", onStorage);\n\t\t\t\twindow.removeEventListener(ACCENT_CHANGE_EVENT, onInternalChange);\n\t\t\t\tcleanupStorageListener = null;\n\t\t\t};\n\t\t}\n\t};\n\n\tconst detachStorageListener = () => {\n\t\tif (listeners.size === 0 && cleanupStorageListener) {\n\t\t\tcleanupStorageListener();\n\t\t}\n\t};\n\n\treturn {\n\t\tgetSnapshot: () => memoryAccent,\n\t\tsubscribe: (listener: () => void) => {\n\t\t\tlisteners.add(listener);\n\t\t\tattachStorageListener();\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tdetachStorageListener();\n\t\t\t};\n\t\t},\n\t\tsetAccent: (next: string) => {\n\t\t\tconst validId = accentSwatchById(next).id;\n\t\t\tmemoryAccent = validId;\n\t\t\thasExplicitSelection = true;\n\t\t\tlet writeSucceeded = true;\n\t\t\tif (persist) {\n\t\t\t\tconst success = safeSetStorageItem(storageKey, validId);\n\t\t\t\tlastSetFailed = !success;\n\t\t\t\twriteSucceeded = success;\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\t\tnew CustomEvent<AccentChangeEventDetail>(ACCENT_CHANGE_EVENT, {\n\t\t\t\t\t\t\t\tdetail: { key: storageKey, value: validId, writeSucceeded },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnotify();\n\t\t},\n\t\tupdateConfig: (config) => {\n\t\t\tconst keyChanged = storageKey !== config.storageKey;\n\t\t\tconst persistChanged = persist !== config.persist;\n\t\t\tconst normalizedDefault = accentSwatchById(config.defaultAccent).id;\n\t\t\tconst defaultChanged = defaultAccent !== normalizedDefault;\n\n\t\t\tconst oldPersist = persist;\n\t\t\tstorageKey = config.storageKey;\n\t\t\tdefaultAccent = normalizedDefault;\n\t\t\tpersist = config.persist;\n\n\t\t\tif (keyChanged) {\n\t\t\t\tif (persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValidAccentId(res.value)) {\n\t\t\t\t\t\t\tmemoryAccent = accentSwatchById(res.value).id;\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmemoryAccent = defaultAccent;\n\t\t\t\t\t\t\thasExplicitSelection = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnotify();\n\t\t\t\t}\n\t\t\t} else if (persistChanged) {\n\t\t\t\tif (!oldPersist && persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValidAccentId(res.value)) {\n\t\t\t\t\t\t\tmemoryAccent = accentSwatchById(res.value).id;\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (defaultChanged) {\n\t\t\t\tif (!hasExplicitSelection) {\n\t\t\t\t\tif (persist) {\n\t\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\t\tif (res.status === \"success\" && !isValidAccentId(res.value)) {\n\t\t\t\t\t\t\tmemoryAccent = defaultAccent;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmemoryAccent = defaultAccent;\n\t\t\t\t\t\tnotify();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\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(() => createAccentStore(storageKey, defaultAccent, persist));\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, 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.setAccent(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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"}
|
package/dist/providers/link.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
-
type LinkComponent = ComponentType<{
|
|
2
|
+
export type LinkComponent = ComponentType<{
|
|
3
3
|
href: string;
|
|
4
4
|
className?: string;
|
|
5
5
|
children?: ReactNode;
|
|
6
6
|
}>;
|
|
7
|
-
export
|
|
7
|
+
export interface LinkProviderProps {
|
|
8
|
+
/**
|
|
9
|
+
* Custom link renderer component injected into Basalt Link.
|
|
10
|
+
* When omitted (undefined), Basalt Link internally falls back to a standard HTML "a" element.
|
|
11
|
+
* Note: this prop only accepts a custom React component (ComponentType<{ href: string; className?: string; children?: ReactNode }>); string literals like "a" are not accepted.
|
|
12
|
+
* useLinkComponent() returns the custom LinkComponent or "a" when no custom renderer is configured, and safely returns "a" even without LinkProvider without throwing.
|
|
13
|
+
* Component renders a React context provider without native HTML rest attribute forwarding or forwarded ref.
|
|
14
|
+
*/
|
|
8
15
|
render?: LinkComponent;
|
|
16
|
+
/**
|
|
17
|
+
* Application components wrapped by the link routing context.
|
|
18
|
+
*/
|
|
9
19
|
children: ReactNode;
|
|
10
|
-
}
|
|
20
|
+
}
|
|
21
|
+
export declare function LinkProvider({ render, children }: LinkProviderProps): import("react").JSX.Element;
|
|
11
22
|
export declare function useLinkComponent(): "a" | LinkComponent;
|
|
12
|
-
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.js","names":[],"sources":["../../src/providers/link.tsx"],"sourcesContent":["import { type ComponentType, createContext, type ReactNode, useContext } from \"react\";\n\
|
|
1
|
+
{"version":3,"file":"link.js","names":[],"sources":["../../src/providers/link.tsx"],"sourcesContent":["import { type ComponentType, createContext, type ReactNode, useContext } from \"react\";\n\nexport type LinkComponent = ComponentType<{\n\thref: string;\n\tclassName?: string;\n\tchildren?: ReactNode;\n}>;\n\nexport interface LinkProviderProps {\n\t/**\n\t * Custom link renderer component injected into Basalt Link.\n\t * When omitted (undefined), Basalt Link internally falls back to a standard HTML \"a\" element.\n\t * Note: this prop only accepts a custom React component (ComponentType<{ href: string; className?: string; children?: ReactNode }>); string literals like \"a\" are not accepted.\n\t * useLinkComponent() returns the custom LinkComponent or \"a\" when no custom renderer is configured, and safely returns \"a\" even without LinkProvider without throwing.\n\t * Component renders a React context provider without native HTML rest attribute forwarding or forwarded ref.\n\t */\n\trender?: LinkComponent;\n\t/**\n\t * Application components wrapped by the link routing context.\n\t */\n\tchildren: ReactNode;\n}\n\nconst LinkContext = createContext<LinkComponent | \"a\">(\"a\");\n\nexport function LinkProvider({ render, children }: LinkProviderProps) {\n\treturn <LinkContext.Provider value={render ?? \"a\"}>{children}</LinkContext.Provider>;\n}\n\nexport function useLinkComponent() {\n\treturn useContext(LinkContext);\n}\n"],"mappings":";;;;AAuBA,IAAM,IAAc,EAAmC,GAAG;AAE1D,SAAgB,EAAa,EAAE,WAAQ,eAA+B;CACrE,OAAO,kBAAC,EAAY,UAAb;EAAsB,OAAO,KAAU;EAAM;CAA+B,CAAA;AACpF;AAEA,SAAgB,IAAmB;CAClC,OAAO,EAAW,CAAW;AAC9B"}
|
|
@@ -4,8 +4,44 @@ type ThemeContextValue = {
|
|
|
4
4
|
theme: BasaltTheme;
|
|
5
5
|
setTheme: (theme: BasaltTheme) => void;
|
|
6
6
|
};
|
|
7
|
-
export
|
|
7
|
+
export interface ThemeProviderProps {
|
|
8
|
+
/**
|
|
9
|
+
* Application components wrapped by the theme context.
|
|
10
|
+
*/
|
|
8
11
|
children: ReactNode;
|
|
9
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Storage key used for theme persistence.
|
|
14
|
+
* @default "theme"
|
|
15
|
+
*/
|
|
16
|
+
storageKey?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Initial theme used when no stored preference exists or during SSR.
|
|
19
|
+
* @default "system"
|
|
20
|
+
*/
|
|
21
|
+
defaultTheme?: BasaltTheme;
|
|
22
|
+
/**
|
|
23
|
+
* Whether to persist theme changes to localStorage.
|
|
24
|
+
* If false, localStorage is never read or written.
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
persist?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Controlled theme value. When provided, the provider acts as a controlled component
|
|
30
|
+
* and internal state is driven by this prop.
|
|
31
|
+
*/
|
|
32
|
+
theme?: BasaltTheme;
|
|
33
|
+
/**
|
|
34
|
+
* Callback fired when theme change is requested.
|
|
35
|
+
* In controlled mode, callers are responsible for updating `theme`.
|
|
36
|
+
*/
|
|
37
|
+
onThemeChange?: (theme: BasaltTheme) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Whether to apply mode classes and data-mode attribute to document.documentElement.
|
|
40
|
+
* Set to false when a host theme system manages the document root.
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
applyToDocument?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function ThemeProvider({ children, storageKey, defaultTheme, persist, theme: controlledTheme, onThemeChange, applyToDocument, }: ThemeProviderProps): import("react").JSX.Element;
|
|
10
46
|
export declare function useTheme(): ThemeContextValue;
|
|
11
47
|
export {};
|
package/dist/providers/theme.js
CHANGED
|
@@ -1,43 +1,176 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { createContext as e, useCallback as t, useContext as n, useEffect as r, useMemo as i,
|
|
3
|
-
import { jsx as
|
|
2
|
+
import { createContext as e, useCallback as t, useContext as n, useEffect as r, useMemo as i, useState as a, useSyncExternalStore as o } from "react";
|
|
3
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
4
4
|
//#region src/providers/theme.tsx
|
|
5
|
-
var
|
|
6
|
-
function l() {
|
|
7
|
-
let e = window.localStorage.getItem(s);
|
|
8
|
-
return e === "light" || e === "dark" || e === "system" ? e : "system";
|
|
9
|
-
}
|
|
5
|
+
var c = "theme", l = e(null);
|
|
10
6
|
function u(e) {
|
|
11
|
-
|
|
7
|
+
if (typeof document > "u") return;
|
|
8
|
+
let t = document.documentElement, n = !1;
|
|
9
|
+
try {
|
|
10
|
+
typeof window < "u" && typeof window.matchMedia == "function" && (n = window.matchMedia("(prefers-color-scheme: dark)").matches);
|
|
11
|
+
} catch {
|
|
12
|
+
n = !1;
|
|
13
|
+
}
|
|
14
|
+
let r = e === "dark" || e === "system" && n;
|
|
15
|
+
t.classList.toggle("dark", r), t.classList.toggle("light", !r), t.dataset.mode = r ? "dark" : "light";
|
|
12
16
|
}
|
|
13
17
|
function d(e) {
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
return e === "light" || e === "dark" || e === "system";
|
|
19
|
+
}
|
|
20
|
+
function f(e) {
|
|
21
|
+
try {
|
|
22
|
+
return typeof window > "u" || !window.localStorage ? { status: "error" } : {
|
|
23
|
+
status: "success",
|
|
24
|
+
value: window.localStorage.getItem(e)
|
|
25
|
+
};
|
|
26
|
+
} catch {
|
|
27
|
+
return { status: "error" };
|
|
28
|
+
}
|
|
16
29
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
30
|
+
function p(e, t) {
|
|
31
|
+
try {
|
|
32
|
+
return typeof window > "u" || !window.localStorage ? !1 : (window.localStorage.setItem(e, t), !0);
|
|
33
|
+
} catch {
|
|
34
|
+
return !1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function m(e) {
|
|
38
|
+
if (!e) return !0;
|
|
39
|
+
try {
|
|
40
|
+
if (typeof window < "u" && window.localStorage) return e === window.localStorage;
|
|
41
|
+
} catch {
|
|
42
|
+
return !1;
|
|
43
|
+
}
|
|
44
|
+
return !1;
|
|
45
|
+
}
|
|
46
|
+
var h = "basalt:theme-change";
|
|
47
|
+
function g(e, t, n) {
|
|
48
|
+
let r = e, i = t, a = n, o = i, s = !1, c = !1;
|
|
49
|
+
if (a) {
|
|
50
|
+
let e = f(r);
|
|
51
|
+
e.status === "success" && d(e.value) && (o = e.value, s = !0);
|
|
52
|
+
}
|
|
53
|
+
let l = /* @__PURE__ */ new Set(), u = () => {
|
|
54
|
+
for (let e of l) e();
|
|
55
|
+
}, g = (e) => {
|
|
56
|
+
if (!a) return;
|
|
57
|
+
let t = e;
|
|
58
|
+
if (!t.detail || t.detail.key !== r) return;
|
|
59
|
+
let { value: n, writeSucceeded: i } = t.detail;
|
|
60
|
+
c = !i, o = n, s = !0, u();
|
|
61
|
+
}, _ = (e) => {
|
|
62
|
+
if (!a) return;
|
|
63
|
+
let t = e;
|
|
64
|
+
if ("key" in t && t.key !== void 0) {
|
|
65
|
+
if (!m(t.storageArea) || t.key !== null && t.key !== r) return;
|
|
66
|
+
c = !1;
|
|
67
|
+
let e = t.newValue;
|
|
68
|
+
if (e == null || !d(e)) {
|
|
69
|
+
o = i, s = !1, u();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
o = e, s = !0, u();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (c) return;
|
|
76
|
+
let n = f(r);
|
|
77
|
+
n.status !== "error" && (d(n.value) ? (o = n.value, s = !0, u()) : (o = i, s = !1, u()));
|
|
78
|
+
}, v = null, y = () => {
|
|
79
|
+
typeof window > "u" || l.size === 1 && !v && (window.addEventListener("storage", _), window.addEventListener(h, g), v = () => {
|
|
80
|
+
window.removeEventListener("storage", _), window.removeEventListener(h, g), v = null;
|
|
81
|
+
});
|
|
82
|
+
}, b = () => {
|
|
83
|
+
l.size === 0 && v && v();
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
getSnapshot: () => o,
|
|
87
|
+
subscribe: (e) => (l.add(e), y(), () => {
|
|
88
|
+
l.delete(e), b();
|
|
89
|
+
}),
|
|
90
|
+
setTheme: (e) => {
|
|
91
|
+
o = e, s = !0;
|
|
92
|
+
let t = !0;
|
|
93
|
+
if (a) {
|
|
94
|
+
let n = p(r, e);
|
|
95
|
+
if (c = !n, t = n, typeof window < "u") try {
|
|
96
|
+
window.dispatchEvent(new CustomEvent(h, { detail: {
|
|
97
|
+
key: r,
|
|
98
|
+
value: e,
|
|
99
|
+
writeSucceeded: t
|
|
100
|
+
} }));
|
|
101
|
+
} catch {}
|
|
102
|
+
}
|
|
103
|
+
u();
|
|
104
|
+
},
|
|
105
|
+
updateConfig: (e) => {
|
|
106
|
+
let t = r !== e.storageKey, n = a !== e.persist, l = i !== e.defaultTheme, p = a;
|
|
107
|
+
if (r = e.storageKey, i = e.defaultTheme, a = e.persist, t) {
|
|
108
|
+
if (a) {
|
|
109
|
+
let e = f(r);
|
|
110
|
+
e.status === "success" && (c = !1, d(e.value) ? (o = e.value, s = !0) : (o = i, s = !1)), u();
|
|
111
|
+
}
|
|
112
|
+
} else if (n) {
|
|
113
|
+
if (!p && a) {
|
|
114
|
+
let e = f(r);
|
|
115
|
+
e.status === "success" && (c = !1, d(e.value) && (o = e.value, s = !0, u()));
|
|
116
|
+
}
|
|
117
|
+
} else if (l && !s) {
|
|
118
|
+
if (a) {
|
|
119
|
+
let e = f(r);
|
|
120
|
+
e.status === "success" && !d(e.value) && (o = i, u());
|
|
121
|
+
} else o = i, u();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function _({ children: e, storageKey: n = c, defaultTheme: d = "system", persist: f = !0, theme: p, onThemeChange: m, applyToDocument: h = !0 }) {
|
|
127
|
+
let _ = p !== void 0, [v] = a(() => g(n, d, f));
|
|
128
|
+
r(() => {
|
|
129
|
+
v.updateConfig({
|
|
130
|
+
storageKey: n,
|
|
131
|
+
defaultTheme: d,
|
|
132
|
+
persist: f
|
|
133
|
+
});
|
|
134
|
+
}, [
|
|
135
|
+
v,
|
|
136
|
+
n,
|
|
137
|
+
d,
|
|
138
|
+
f
|
|
139
|
+
]);
|
|
140
|
+
let y = t(() => d, [d]), b = o(v.subscribe, v.getSnapshot, y), x = _ ? p : b;
|
|
19
141
|
r(() => {
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}, [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
142
|
+
if (!(!h || typeof window > "u") && (u(x), x === "system")) try {
|
|
143
|
+
let e = window.matchMedia("(prefers-color-scheme: dark)"), t = () => u("system");
|
|
144
|
+
return e.addEventListener("change", t), () => e.removeEventListener("change", t);
|
|
145
|
+
} catch {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}, [x, h]);
|
|
149
|
+
let S = t((e) => {
|
|
150
|
+
if (_) {
|
|
151
|
+
m?.(e);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
v.setTheme(e), m?.(e);
|
|
155
|
+
}, [
|
|
156
|
+
_,
|
|
157
|
+
m,
|
|
158
|
+
v
|
|
159
|
+
]), C = i(() => ({
|
|
160
|
+
theme: x,
|
|
161
|
+
setTheme: S
|
|
162
|
+
}), [x, S]);
|
|
163
|
+
return /* @__PURE__ */ s(l.Provider, {
|
|
164
|
+
value: C,
|
|
32
165
|
children: e
|
|
33
166
|
});
|
|
34
167
|
}
|
|
35
|
-
function
|
|
36
|
-
let e = n(
|
|
168
|
+
function v() {
|
|
169
|
+
let e = n(l);
|
|
37
170
|
if (!e) throw Error("useTheme must be used within ThemeProvider");
|
|
38
171
|
return e;
|
|
39
172
|
}
|
|
40
173
|
//#endregion
|
|
41
|
-
export {
|
|
174
|
+
export { _ as ThemeProvider, v as useTheme };
|
|
42
175
|
|
|
43
176
|
//# sourceMappingURL=theme.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","names":[],"sources":["../../src/providers/theme.tsx"],"sourcesContent":["import {\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseMemo,\n\tuseSyncExternalStore,\n} from \"react\";\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 readTheme(): BasaltTheme {\n\tconst value = window.localStorage.getItem(STORAGE_KEY);\n\tif (value === \"light\" || value === \"dark\" || value === \"system\") {\n\t\treturn value;\n\t}\n\treturn \"system\";\n}\n\nfunction subscribe(onStoreChange: () => void) {\n\twindow.addEventListener(\"storage\", onStoreChange);\n\treturn () => window.removeEventListener(\"storage\", onStoreChange);\n}\n\nfunction applyTheme(theme: BasaltTheme) {\n\tconst root = document.documentElement;\n\tconst systemDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\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 function ThemeProvider({ children }: { children: ReactNode }) {\n\tconst theme = useSyncExternalStore(subscribe, readTheme, () => \"system\" as const);\n\tuseEffect(() => {\n\t\tapplyTheme(theme);\n\t\tif (theme !== \"system\") {\n\t\t\treturn;\n\t\t}\n\t\tconst mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\t\tconst onChange = () => applyTheme(\"system\");\n\t\tmq.addEventListener(\"change\", onChange);\n\t\treturn () => mq.removeEventListener(\"change\", onChange);\n\t}, [theme]);\n\tconst setTheme = useCallback((next: BasaltTheme) => {\n\t\twindow.localStorage.setItem(STORAGE_KEY, next);\n\t\tapplyTheme(next);\n\t\twindow.dispatchEvent(new Event(\"storage\"));\n\t}, []);\n\tconst value = useMemo(() => ({ theme, setTheme }), [theme, setTheme]);\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":";;;;AAYA,IAAM,IAAc,SAOd,IAAe,EAAwC,IAAI;AAEjE,SAAS,IAAyB;CACjC,IAAM,IAAQ,OAAO,aAAa,QAAQ,CAAW;CAIrD,OAHI,MAAU,WAAW,MAAU,UAAU,MAAU,WAC/C,IAED;AACR;AAEA,SAAS,EAAU,GAA2B;CAE7C,OADA,OAAO,iBAAiB,WAAW,CAAa,SACnC,OAAO,oBAAoB,WAAW,CAAa;AACjE;AAEA,SAAS,EAAW,GAAoB;CACvC,IAAM,IAAO,SAAS,iBAChB,IAAa,OAAO,WAAW,8BAA8B,CAAC,CAAC,SAC/D,IAAO,MAAU,UAAW,MAAU,YAAY;CAGxD,AAFA,EAAK,UAAU,OAAO,QAAQ,CAAI,GAClC,EAAK,UAAU,OAAO,SAAS,CAAC,CAAI,GACpC,EAAK,QAAQ,OAAO,IAAO,SAAS;AACrC;AAEA,SAAgB,EAAc,EAAE,eAAqC;CACpE,IAAM,IAAQ,EAAqB,GAAW,SAAiB,QAAiB;CAChF,QAAgB;EAEf,IADA,EAAW,CAAK,GACZ,MAAU,UACb;EAED,IAAM,IAAK,OAAO,WAAW,8BAA8B,GACrD,UAAiB,EAAW,QAAQ;EAE1C,OADA,EAAG,iBAAiB,UAAU,CAAQ,SACzB,EAAG,oBAAoB,UAAU,CAAQ;CACvD,GAAG,CAAC,CAAK,CAAC;CACV,IAAM,IAAW,GAAa,MAAsB;EAGnD,AAFA,OAAO,aAAa,QAAQ,GAAa,CAAI,GAC7C,EAAW,CAAI,GACf,OAAO,cAAc,IAAI,MAAM,SAAS,CAAC;CAC1C,GAAG,CAAC,CAAC,GACC,IAAQ,SAAe;EAAE;EAAO;CAAS,IAAI,CAAC,GAAO,CAAQ,CAAC;CACpE,OAAO,kBAAC,EAAa,UAAd;EAA8B;EAAQ;CAAgC,CAAA;AAC9E;AAEA,SAAgB,IAAW;CAC1B,IAAM,IAAM,EAAW,CAAY;CACnC,IAAI,CAAC,GACJ,MAAU,MAAM,4CAA4C;CAE7D,OAAO;AACR"}
|
|
1
|
+
{"version":3,"file":"theme.js","names":[],"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\";\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\ninterface ThemeStore {\n\tgetSnapshot: () => BasaltTheme;\n\tsubscribe: (listener: () => void) => () => void;\n\tsetTheme: (next: BasaltTheme) => void;\n\tupdateConfig: (config: {\n\t\tstorageKey: string;\n\t\tdefaultTheme: BasaltTheme;\n\t\tpersist: boolean;\n\t}) => void;\n}\n\nfunction isValidTheme(value: unknown): value is BasaltTheme {\n\treturn value === \"light\" || value === \"dark\" || value === \"system\";\n}\n\ntype StorageReadResult = { status: \"success\"; value: string | null } | { status: \"error\" };\n\nfunction safeGetStorageItem(key: string): StorageReadResult {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn { status: \"error\" };\n\t\t}\n\t\tconst value = window.localStorage.getItem(key);\n\t\treturn { status: \"success\", value };\n\t} catch {\n\t\treturn { status: \"error\" };\n\t}\n}\n\nfunction safeSetStorageItem(key: string, value: string): boolean {\n\ttry {\n\t\tif (typeof window === \"undefined\" || !window.localStorage) {\n\t\t\treturn false;\n\t\t}\n\t\twindow.localStorage.setItem(key, value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isLocalStorageArea(area: Storage | null | undefined): boolean {\n\tif (!area) {\n\t\treturn true;\n\t}\n\ttry {\n\t\tif (typeof window !== \"undefined\" && window.localStorage) {\n\t\t\treturn area === window.localStorage;\n\t\t}\n\t} catch {\n\t\t// localStorage getter threw\n\t\treturn false;\n\t}\n\treturn false;\n}\n\nconst THEME_CHANGE_EVENT = \"basalt:theme-change\";\n\ninterface ThemeChangeEventDetail {\n\tkey: string;\n\tvalue: BasaltTheme;\n\twriteSucceeded: boolean;\n}\n\nfunction createThemeStore(\n\tinitialStorageKey: string,\n\tinitialDefaultTheme: BasaltTheme,\n\tinitialPersist: boolean,\n): ThemeStore {\n\tlet storageKey = initialStorageKey;\n\tlet defaultTheme = initialDefaultTheme;\n\tlet persist = initialPersist;\n\n\t// In-memory fallback / cache value\n\tlet memoryTheme: BasaltTheme = defaultTheme;\n\tlet hasExplicitSelection = false;\n\tlet lastSetFailed = false;\n\n\tif (persist) {\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"success\" && isValidTheme(res.value)) {\n\t\t\tmemoryTheme = res.value;\n\t\t\thasExplicitSelection = true;\n\t\t}\n\t}\n\n\tconst listeners = new Set<() => void>();\n\n\tconst notify = () => {\n\t\tfor (const listener of listeners) {\n\t\t\tlistener();\n\t\t}\n\t};\n\n\tconst onInternalChange = (event: Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst customEv = event as CustomEvent<ThemeChangeEventDetail>;\n\t\tif (!customEv.detail || customEv.detail.key !== storageKey) {\n\t\t\treturn;\n\t\t}\n\t\tconst { value, writeSucceeded } = customEv.detail;\n\t\tif (writeSucceeded) {\n\t\t\tlastSetFailed = false;\n\t\t} else {\n\t\t\tlastSetFailed = true;\n\t\t}\n\t\tmemoryTheme = value;\n\t\thasExplicitSelection = true;\n\t\tnotify();\n\t};\n\n\tconst onStorage = (event: StorageEvent | Event) => {\n\t\tif (!persist) {\n\t\t\treturn;\n\t\t}\n\t\tconst storageEv = event as Partial<StorageEvent>;\n\t\tif (\"key\" in storageEv && storageEv.key !== undefined) {\n\t\t\tif (!isLocalStorageArea(storageEv.storageArea)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (storageEv.key !== null && storageEv.key !== storageKey) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlastSetFailed = false;\n\t\t\tconst rawVal = storageEv.newValue;\n\t\t\tif (rawVal === null || rawVal === undefined || !isValidTheme(rawVal)) {\n\t\t\t\t// Key removed or invalid value: revert to configured default\n\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\thasExplicitSelection = false;\n\t\t\t\tnotify();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmemoryTheme = rawVal;\n\t\t\thasExplicitSelection = true;\n\t\t\tnotify();\n\t\t\treturn;\n\t\t}\n\t\t// Untyped/bare storage event: e.g. dispatchEvent(new Event(\"storage\"))\n\t\t// If last set failed, ignore so stale storage cannot overwrite in-memory switch\n\t\tif (lastSetFailed) {\n\t\t\treturn;\n\t\t}\n\t\tconst res = safeGetStorageItem(storageKey);\n\t\tif (res.status === \"error\") {\n\t\t\t// Read failed: preserve current cached memory theme, do not revert to default\n\t\t\treturn;\n\t\t}\n\t\tif (isValidTheme(res.value)) {\n\t\t\tmemoryTheme = res.value;\n\t\t\thasExplicitSelection = true;\n\t\t\tnotify();\n\t\t} else {\n\t\t\t// Key removed or invalid value stored: revert to default\n\t\t\tmemoryTheme = defaultTheme;\n\t\t\thasExplicitSelection = false;\n\t\t\tnotify();\n\t\t}\n\t};\n\n\tlet cleanupStorageListener: (() => void) | null = null;\n\tconst attachStorageListener = () => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\t\tif (listeners.size === 1 && !cleanupStorageListener) {\n\t\t\twindow.addEventListener(\"storage\", onStorage);\n\t\t\twindow.addEventListener(THEME_CHANGE_EVENT, onInternalChange);\n\t\t\tcleanupStorageListener = () => {\n\t\t\t\twindow.removeEventListener(\"storage\", onStorage);\n\t\t\t\twindow.removeEventListener(THEME_CHANGE_EVENT, onInternalChange);\n\t\t\t\tcleanupStorageListener = null;\n\t\t\t};\n\t\t}\n\t};\n\n\tconst detachStorageListener = () => {\n\t\tif (listeners.size === 0 && cleanupStorageListener) {\n\t\t\tcleanupStorageListener();\n\t\t}\n\t};\n\n\treturn {\n\t\tgetSnapshot: () => memoryTheme,\n\t\tsubscribe: (listener: () => void) => {\n\t\t\tlisteners.add(listener);\n\t\t\tattachStorageListener();\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tdetachStorageListener();\n\t\t\t};\n\t\t},\n\t\tsetTheme: (next: BasaltTheme) => {\n\t\t\tmemoryTheme = next;\n\t\t\thasExplicitSelection = true;\n\t\t\tlet writeSucceeded = true;\n\t\t\tif (persist) {\n\t\t\t\tconst success = safeSetStorageItem(storageKey, next);\n\t\t\t\tlastSetFailed = !success;\n\t\t\t\twriteSucceeded = success;\n\t\t\t\tif (typeof window !== \"undefined\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\twindow.dispatchEvent(\n\t\t\t\t\t\t\tnew CustomEvent<ThemeChangeEventDetail>(THEME_CHANGE_EVENT, {\n\t\t\t\t\t\t\t\tdetail: { key: storageKey, value: next, writeSucceeded },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnotify();\n\t\t},\n\t\tupdateConfig: (config) => {\n\t\t\tconst keyChanged = storageKey !== config.storageKey;\n\t\t\tconst persistChanged = persist !== config.persist;\n\t\t\tconst defaultChanged = defaultTheme !== config.defaultTheme;\n\n\t\t\tconst oldPersist = persist;\n\t\t\tstorageKey = config.storageKey;\n\t\t\tdefaultTheme = config.defaultTheme;\n\t\t\tpersist = config.persist;\n\n\t\t\tif (keyChanged) {\n\t\t\t\tif (persist) {\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValidTheme(res.value)) {\n\t\t\t\t\t\t\tmemoryTheme = res.value;\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\t\t\t\thasExplicitSelection = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnotify();\n\t\t\t\t}\n\t\t\t\t// persist=false: changing storageKey does not reset current memoryTheme\n\t\t\t} else if (persistChanged) {\n\t\t\t\tif (!oldPersist && persist) {\n\t\t\t\t\t// persist flipped false -> true: read from storage or keep current\n\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\tif (res.status === \"success\") {\n\t\t\t\t\t\tlastSetFailed = false;\n\t\t\t\t\t\tif (isValidTheme(res.value)) {\n\t\t\t\t\t\t\tmemoryTheme = res.value;\n\t\t\t\t\t\t\thasExplicitSelection = true;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// persist flipped true -> false: only disable persistence, keep current memoryTheme, no storage read/write\n\t\t\t} else if (defaultChanged) {\n\t\t\t\t// defaultTheme changed: only update if no explicit selection was made\n\t\t\t\tif (!hasExplicitSelection) {\n\t\t\t\t\tif (persist) {\n\t\t\t\t\t\tconst res = safeGetStorageItem(storageKey);\n\t\t\t\t\t\tif (res.status === \"success\" && !isValidTheme(res.value)) {\n\t\t\t\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\t\t\t\tnotify();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmemoryTheme = defaultTheme;\n\t\t\t\t\t\tnotify();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\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(() => createThemeStore(storageKey, defaultTheme, persist));\n\n\tuseEffect(() => {\n\t\tstore.updateConfig({ storageKey, 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.setTheme(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":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
@layer base {
|
|
2
|
+
/* Scoped Basalt base reset for standalone and Tailwind environments.
|
|
3
|
+
Does NOT leak globally to host elements. */
|
|
4
|
+
:where(
|
|
5
|
+
.basalt-ui,
|
|
6
|
+
.basalt-ui *,
|
|
7
|
+
.basalt-ui *::before,
|
|
8
|
+
.basalt-ui *::after,
|
|
9
|
+
.basalt-ui::before,
|
|
10
|
+
.basalt-ui::after
|
|
11
|
+
) {
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
border-width: 0;
|
|
14
|
+
border-style: solid;
|
|
15
|
+
border-color: currentColor;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:where(
|
|
19
|
+
.basalt-ui:is(button, input, optgroup, select, textarea),
|
|
20
|
+
.basalt-ui :is(button, input, optgroup, select, textarea)
|
|
21
|
+
) {
|
|
22
|
+
font-family: inherit;
|
|
23
|
+
font-feature-settings: inherit;
|
|
24
|
+
font-variation-settings: inherit;
|
|
25
|
+
font-size: 100%;
|
|
26
|
+
font-weight: inherit;
|
|
27
|
+
line-height: inherit;
|
|
28
|
+
letter-spacing: inherit;
|
|
29
|
+
color: inherit;
|
|
30
|
+
margin: 0;
|
|
31
|
+
padding: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:where(
|
|
35
|
+
.basalt-ui:is(button, select, [role="button"]),
|
|
36
|
+
.basalt-ui :is(button, select, [role="button"])
|
|
37
|
+
) {
|
|
38
|
+
text-transform: none;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
:where(
|
|
42
|
+
.basalt-ui:is(button, input:is([type="button"], [type="reset"], [type="submit"])),
|
|
43
|
+
.basalt-ui :is(button, input:is([type="button"], [type="reset"], [type="submit"]))
|
|
44
|
+
) {
|
|
45
|
+
appearance: button;
|
|
46
|
+
-webkit-appearance: button;
|
|
47
|
+
background-color: transparent;
|
|
48
|
+
background-image: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:where(.basalt-ui:is(a), .basalt-ui :is(a)) {
|
|
52
|
+
color: inherit;
|
|
53
|
+
text-decoration: inherit;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
:where(.basalt-ui:is(h1, h2, h3, h4, h5, h6), .basalt-ui :is(h1, h2, h3, h4, h5, h6)) {
|
|
57
|
+
font-size: inherit;
|
|
58
|
+
font-weight: inherit;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:where(
|
|
62
|
+
.basalt-ui:is(h1, h2, h3, h4, h5, h6, p, blockquote, figure, pre, dl, dd),
|
|
63
|
+
.basalt-ui :is(h1, h2, h3, h4, h5, h6, p, blockquote, figure, pre, dl, dd)
|
|
64
|
+
) {
|
|
65
|
+
margin: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:where(.basalt-ui:is(dd), .basalt-ui :is(dd)) {
|
|
69
|
+
margin-left: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
:where(.basalt-ui:is(ol, ul, menu), .basalt-ui :is(ol, ul, menu)) {
|
|
73
|
+
list-style: none;
|
|
74
|
+
margin: 0;
|
|
75
|
+
padding: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:where(.basalt-ui:is(table), .basalt-ui :is(table)) {
|
|
79
|
+
text-indent: 0;
|
|
80
|
+
border-color: inherit;
|
|
81
|
+
border-collapse: collapse;
|
|
82
|
+
}
|
|
83
|
+
}
|