@sabrenski/spire-ui 0.0.1

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 (237) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -0
  3. package/dist/index.d.ts +4981 -0
  4. package/dist/spire-ui.css +1 -0
  5. package/dist/spire-ui.es.js +18403 -0
  6. package/dist/spire-ui.umd.js +45 -0
  7. package/package.json +83 -0
  8. package/src/components/Accordion/Accordion.test.ts +218 -0
  9. package/src/components/Accordion/AccordionContent.vue +112 -0
  10. package/src/components/Accordion/AccordionItem.vue +87 -0
  11. package/src/components/Accordion/AccordionRoot.vue +111 -0
  12. package/src/components/Accordion/AccordionTrigger.vue +125 -0
  13. package/src/components/Accordion/index.ts +11 -0
  14. package/src/components/Accordion/keys.ts +23 -0
  15. package/src/components/Avatar/Avatar.test.ts +181 -0
  16. package/src/components/Avatar/Avatar.vue +150 -0
  17. package/src/components/Avatar/index.ts +2 -0
  18. package/src/components/Badge/Badge.test.ts +141 -0
  19. package/src/components/Badge/Badge.vue +133 -0
  20. package/src/components/Badge/index.ts +2 -0
  21. package/src/components/BadgeContainer/BadgeContainer.test.ts +150 -0
  22. package/src/components/BadgeContainer/BadgeContainer.vue +90 -0
  23. package/src/components/BadgeContainer/index.ts +2 -0
  24. package/src/components/Breadcrumb/Breadcrumb.test.ts +342 -0
  25. package/src/components/Breadcrumb/BreadcrumbEllipsis.vue +96 -0
  26. package/src/components/Breadcrumb/BreadcrumbItem.vue +16 -0
  27. package/src/components/Breadcrumb/BreadcrumbLink.vue +67 -0
  28. package/src/components/Breadcrumb/BreadcrumbList.vue +20 -0
  29. package/src/components/Breadcrumb/BreadcrumbPage.vue +25 -0
  30. package/src/components/Breadcrumb/BreadcrumbRoot.vue +41 -0
  31. package/src/components/Breadcrumb/BreadcrumbSeparator.vue +63 -0
  32. package/src/components/Breadcrumb/index.ts +13 -0
  33. package/src/components/Breadcrumb/keys.ts +7 -0
  34. package/src/components/Button/Button.test.ts +231 -0
  35. package/src/components/Button/Button.vue +349 -0
  36. package/src/components/Button/index.ts +2 -0
  37. package/src/components/Callout/Callout.test.ts +260 -0
  38. package/src/components/Callout/Callout.vue +341 -0
  39. package/src/components/Callout/index.ts +2 -0
  40. package/src/components/Card/Card.test.ts +565 -0
  41. package/src/components/Card/Card.vue +209 -0
  42. package/src/components/Card/CardContent.vue +57 -0
  43. package/src/components/Card/CardFooter.vue +72 -0
  44. package/src/components/Card/CardHeader.vue +111 -0
  45. package/src/components/Card/CardImage.vue +124 -0
  46. package/src/components/Card/index.ts +14 -0
  47. package/src/components/Chart/BarChart.vue +208 -0
  48. package/src/components/Chart/BaseChart.vue +444 -0
  49. package/src/components/Chart/Chart.test.ts +359 -0
  50. package/src/components/Chart/DonutChart.vue +283 -0
  51. package/src/components/Chart/LineChart.vue +211 -0
  52. package/src/components/Chart/index.ts +20 -0
  53. package/src/components/Chart/useChartTheme.ts +192 -0
  54. package/src/components/Checkbox/Checkbox.test.ts +209 -0
  55. package/src/components/Checkbox/Checkbox.vue +285 -0
  56. package/src/components/Checkbox/index.ts +2 -0
  57. package/src/components/ChoiceChip/ChoiceChip.test.ts +142 -0
  58. package/src/components/ChoiceChip/ChoiceChip.vue +218 -0
  59. package/src/components/ChoiceChip/index.ts +2 -0
  60. package/src/components/ChoiceChipGroup/ChoiceChipGroup.test.ts +151 -0
  61. package/src/components/ChoiceChipGroup/ChoiceChipGroup.vue +70 -0
  62. package/src/components/ChoiceChipGroup/index.ts +2 -0
  63. package/src/components/ColorPicker/ColorArea.vue +159 -0
  64. package/src/components/ColorPicker/ColorPicker.test.ts +250 -0
  65. package/src/components/ColorPicker/ColorPicker.vue +339 -0
  66. package/src/components/ColorPicker/ColorSlider.vue +191 -0
  67. package/src/components/ColorPicker/index.ts +7 -0
  68. package/src/components/Combobox/Combobox.test.ts +891 -0
  69. package/src/components/Combobox/Combobox.vue +934 -0
  70. package/src/components/Combobox/index.ts +2 -0
  71. package/src/components/DataTable/DataTable.test.ts +1221 -0
  72. package/src/components/DataTable/DataTable.vue +1415 -0
  73. package/src/components/DataTable/index.ts +10 -0
  74. package/src/components/DatePicker/DatePicker.test.ts +625 -0
  75. package/src/components/DatePicker/DatePicker.vue +1586 -0
  76. package/src/components/DatePicker/index.ts +2 -0
  77. package/src/components/Drawer/Drawer.test.ts +336 -0
  78. package/src/components/Drawer/Drawer.vue +466 -0
  79. package/src/components/Drawer/index.ts +2 -0
  80. package/src/components/Dropdown/Dropdown.test.ts +607 -0
  81. package/src/components/Dropdown/Dropdown.vue +807 -0
  82. package/src/components/Dropdown/DropdownItem.vue +227 -0
  83. package/src/components/Dropdown/DropdownSeparator.vue +14 -0
  84. package/src/components/Dropdown/DropdownSub.vue +104 -0
  85. package/src/components/Dropdown/DropdownSubContent.vue +187 -0
  86. package/src/components/Dropdown/DropdownSubTrigger.vue +151 -0
  87. package/src/components/Dropdown/index.ts +14 -0
  88. package/src/components/EmptyState/EmptyState.test.ts +180 -0
  89. package/src/components/EmptyState/EmptyState.vue +137 -0
  90. package/src/components/EmptyState/index.ts +2 -0
  91. package/src/components/FileUpload/FileUpload.test.ts +1151 -0
  92. package/src/components/FileUpload/FileUpload.vue +1042 -0
  93. package/src/components/FileUpload/index.ts +2 -0
  94. package/src/components/Heading/Heading.test.ts +107 -0
  95. package/src/components/Heading/Heading.vue +67 -0
  96. package/src/components/Heading/index.ts +2 -0
  97. package/src/components/Icon/Icon.test.ts +157 -0
  98. package/src/components/Icon/Icon.vue +86 -0
  99. package/src/components/Icon/index.ts +2 -0
  100. package/src/components/Input/Input.test.ts +273 -0
  101. package/src/components/Input/Input.vue +388 -0
  102. package/src/components/Input/index.ts +2 -0
  103. package/src/components/Layout/Container.vue +67 -0
  104. package/src/components/Layout/Grid.vue +159 -0
  105. package/src/components/Layout/GridItem.vue +154 -0
  106. package/src/components/Layout/Layout.test.ts +202 -0
  107. package/src/components/Layout/Stack.vue +128 -0
  108. package/src/components/Layout/index.ts +9 -0
  109. package/src/components/Layout/keys.ts +7 -0
  110. package/src/components/Modal/Modal.test.ts +311 -0
  111. package/src/components/Modal/Modal.vue +336 -0
  112. package/src/components/Modal/index.ts +2 -0
  113. package/src/components/Pagination/Pagination.test.ts +303 -0
  114. package/src/components/Pagination/Pagination.vue +212 -0
  115. package/src/components/Pagination/index.ts +3 -0
  116. package/src/components/Pagination/utils.ts +86 -0
  117. package/src/components/Popover/Popover.test.ts +285 -0
  118. package/src/components/Popover/Popover.vue +441 -0
  119. package/src/components/Popover/index.ts +2 -0
  120. package/src/components/Progress/Progress.test.ts +361 -0
  121. package/src/components/Progress/Progress.vue +363 -0
  122. package/src/components/Progress/index.ts +7 -0
  123. package/src/components/Radio/Radio.test.ts +216 -0
  124. package/src/components/Radio/Radio.vue +214 -0
  125. package/src/components/Radio/index.ts +2 -0
  126. package/src/components/Rating/Rating.test.ts +319 -0
  127. package/src/components/Rating/Rating.vue +247 -0
  128. package/src/components/Rating/index.ts +2 -0
  129. package/src/components/SegmentedControl/SegmentedControl.test.ts +292 -0
  130. package/src/components/SegmentedControl/SegmentedControl.vue +288 -0
  131. package/src/components/SegmentedControl/index.ts +2 -0
  132. package/src/components/Select/Select.test.ts +589 -0
  133. package/src/components/Select/Select.vue +666 -0
  134. package/src/components/Select/index.ts +2 -0
  135. package/src/components/Sidebar/Sidebar.test.ts +301 -0
  136. package/src/components/Sidebar/SidebarGroup.vue +103 -0
  137. package/src/components/Sidebar/SidebarItem.vue +196 -0
  138. package/src/components/Sidebar/SidebarLayout.vue +42 -0
  139. package/src/components/Sidebar/SidebarRoot.vue +122 -0
  140. package/src/components/Sidebar/index.ts +11 -0
  141. package/src/components/Sidebar/keys.ts +14 -0
  142. package/src/components/Skeleton/Skeleton.test.ts +130 -0
  143. package/src/components/Skeleton/Skeleton.vue +104 -0
  144. package/src/components/Skeleton/index.ts +2 -0
  145. package/src/components/Slider/Slider.test.ts +416 -0
  146. package/src/components/Slider/Slider.vue +435 -0
  147. package/src/components/Slider/index.ts +2 -0
  148. package/src/components/Slider/utils.ts +91 -0
  149. package/src/components/Spinner/Spinner.test.ts +79 -0
  150. package/src/components/Spinner/Spinner.vue +159 -0
  151. package/src/components/Spinner/index.ts +2 -0
  152. package/src/components/SpireProvider/SpireProvider.vue +71 -0
  153. package/src/components/SpireProvider/index.ts +11 -0
  154. package/src/components/Stepper/Stepper.test.ts +221 -0
  155. package/src/components/Stepper/StepperContent.vue +51 -0
  156. package/src/components/Stepper/StepperItem.vue +89 -0
  157. package/src/components/Stepper/StepperRoot.vue +101 -0
  158. package/src/components/Stepper/StepperSeparator.vue +52 -0
  159. package/src/components/Stepper/StepperTrigger.vue +144 -0
  160. package/src/components/Stepper/index.ts +11 -0
  161. package/src/components/Stepper/keys.ts +27 -0
  162. package/src/components/Switch/Switch.test.ts +214 -0
  163. package/src/components/Switch/Switch.vue +235 -0
  164. package/src/components/Switch/index.ts +2 -0
  165. package/src/components/Tabs/Tabs.test.ts +363 -0
  166. package/src/components/Tabs/Tabs.vue +318 -0
  167. package/src/components/Tabs/index.ts +2 -0
  168. package/src/components/Text/Text.test.ts +154 -0
  169. package/src/components/Text/Text.vue +100 -0
  170. package/src/components/Text/index.ts +2 -0
  171. package/src/components/Textarea/Textarea.test.ts +432 -0
  172. package/src/components/Textarea/Textarea.vue +411 -0
  173. package/src/components/Textarea/index.ts +2 -0
  174. package/src/components/TimePicker/TimePicker.test.ts +352 -0
  175. package/src/components/TimePicker/TimePicker.vue +569 -0
  176. package/src/components/TimePicker/index.ts +2 -0
  177. package/src/components/Timeline/Timeline.test.ts +193 -0
  178. package/src/components/Timeline/Timeline.vue +111 -0
  179. package/src/components/Timeline/TimelineItem.vue +167 -0
  180. package/src/components/Timeline/index.ts +13 -0
  181. package/src/components/Timeline/keys.ts +21 -0
  182. package/src/components/Toast/ToastItem.test.ts +289 -0
  183. package/src/components/Toast/ToastItem.vue +370 -0
  184. package/src/components/Toast/ToastProvider.test.ts +158 -0
  185. package/src/components/Toast/ToastProvider.vue +181 -0
  186. package/src/components/Toast/index.ts +83 -0
  187. package/src/components/Toast/toastState.test.ts +165 -0
  188. package/src/components/Toast/toastState.ts +161 -0
  189. package/src/components/ToggleButton/ToggleButton.test.ts +166 -0
  190. package/src/components/ToggleButton/ToggleButton.vue +197 -0
  191. package/src/components/ToggleButton/index.ts +2 -0
  192. package/src/components/ToggleGroup/ToggleGroup.test.ts +181 -0
  193. package/src/components/ToggleGroup/ToggleGroup.vue +130 -0
  194. package/src/components/ToggleGroup/index.ts +2 -0
  195. package/src/components/Tooltip/Tooltip.test.ts +238 -0
  196. package/src/components/Tooltip/Tooltip.vue +217 -0
  197. package/src/components/Tooltip/index.ts +2 -0
  198. package/src/components/TreeView/TreeView.test.ts +357 -0
  199. package/src/components/TreeView/TreeView.vue +251 -0
  200. package/src/components/TreeView/TreeViewItem.vue +288 -0
  201. package/src/components/TreeView/index.ts +11 -0
  202. package/src/components/TreeView/keys.ts +35 -0
  203. package/src/composables/index.ts +12 -0
  204. package/src/composables/useClickOutside.ts +36 -0
  205. package/src/composables/useClipboard.ts +35 -0
  206. package/src/composables/useEventListener.ts +48 -0
  207. package/src/composables/useFocusTrap.ts +58 -0
  208. package/src/composables/useHoverReveal.ts +98 -0
  209. package/src/composables/useId.ts +10 -0
  210. package/src/composables/useMagnetic.ts +171 -0
  211. package/src/composables/useRelativePosition.ts +127 -0
  212. package/src/composables/useRipple.ts +146 -0
  213. package/src/composables/useScrollLock.ts +25 -0
  214. package/src/composables/useSpireConfig.ts +27 -0
  215. package/src/composables/useStagger.ts +224 -0
  216. package/src/config/icons.test.ts +115 -0
  217. package/src/config/icons.ts +170 -0
  218. package/src/index.ts +361 -0
  219. package/src/styles/depth.css +129 -0
  220. package/src/styles/effects.css +169 -0
  221. package/src/styles/fallback.css +152 -0
  222. package/src/styles/main.css +25 -0
  223. package/src/styles/mood.css +211 -0
  224. package/src/styles/motion.css +159 -0
  225. package/src/styles/reset.css +97 -0
  226. package/src/styles/theme.css +708 -0
  227. package/src/styles/tokens.css +183 -0
  228. package/src/utils/.gitkeep +0 -0
  229. package/src/utils/color.ts +277 -0
  230. package/src/utils/date.test.ts +522 -0
  231. package/src/utils/date.ts +380 -0
  232. package/src/utils/index.ts +23 -0
  233. package/src/utils/object.test.ts +80 -0
  234. package/src/utils/object.ts +25 -0
  235. package/src/utils/string.test.ts +64 -0
  236. package/src/utils/string.ts +32 -0
  237. package/src/utils/time.ts +156 -0
@@ -0,0 +1,183 @@
1
+ :root {
2
+ /* Spacing Scale (8pt grid) */
3
+ --space-0: 0;
4
+ --space-1: 0.25rem; /* 4px */
5
+ --space-2: 0.5rem; /* 8px */
6
+ --space-3: 0.75rem; /* 12px */
7
+ --space-4: 1rem; /* 16px */
8
+ --space-5: 1.25rem; /* 20px */
9
+ --space-6: 1.5rem; /* 24px */
10
+ --space-8: 2rem; /* 32px */
11
+ --space-10: 2.5rem; /* 40px */
12
+ --space-12: 3rem; /* 48px */
13
+
14
+ /* OKLCH Color Primitives - Stone (Warm neutral, Hue ~60) */
15
+ --color-stone-50: oklch(0.985 0.004 60);
16
+ --color-stone-100: oklch(0.970 0.007 60);
17
+ --color-stone-200: oklch(0.923 0.01 60);
18
+ --color-stone-300: oklch(0.865 0.016 60);
19
+ --color-stone-400: oklch(0.706 0.027 60);
20
+ --color-stone-500: oklch(0.553 0.027 60);
21
+ --color-stone-600: oklch(0.444 0.024 60);
22
+ --color-stone-700: oklch(0.374 0.022 60);
23
+ --color-stone-800: oklch(0.268 0.018 60);
24
+ --color-stone-900: oklch(0.216 0.016 60);
25
+ --color-stone-950: oklch(0.147 0.014 60);
26
+
27
+ /* OKLCH Color Primitives - Indigo (Rich primary, Hue ~275) */
28
+ --color-indigo-50: oklch(0.962 0.018 275);
29
+ --color-indigo-100: oklch(0.930 0.034 275);
30
+ --color-indigo-200: oklch(0.870 0.065 275);
31
+ --color-indigo-300: oklch(0.785 0.115 275);
32
+ --color-indigo-400: oklch(0.673 0.182 275);
33
+ --color-indigo-500: oklch(0.585 0.233 275);
34
+ --color-indigo-600: oklch(0.511 0.262 275);
35
+ --color-indigo-700: oklch(0.457 0.24 275);
36
+ --color-indigo-800: oklch(0.398 0.195 275);
37
+ --color-indigo-900: oklch(0.359 0.144 275);
38
+
39
+ /* Semantic Primary Color (defaults to indigo, overridden by moods) */
40
+ --color-primary-50: oklch(0.962 0.018 275);
41
+ --color-primary-100: oklch(0.930 0.034 275);
42
+ --color-primary-200: oklch(0.870 0.065 275);
43
+ --color-primary-300: oklch(0.785 0.115 275);
44
+ --color-primary-400: oklch(0.673 0.182 275);
45
+ --color-primary-500: oklch(0.585 0.233 275);
46
+ --color-primary-600: oklch(0.511 0.262 275);
47
+ --color-primary-700: oklch(0.457 0.240 275);
48
+ --color-primary-800: oklch(0.398 0.195 275);
49
+ --color-primary-900: oklch(0.359 0.144 275);
50
+
51
+ /* OKLCH Color Primitives - Teal (Success, Hue ~180) */
52
+ --color-teal-50: oklch(0.984 0.014 180);
53
+ --color-teal-100: oklch(0.953 0.051 180);
54
+ --color-teal-500: oklch(0.704 0.14 180);
55
+ --color-teal-600: oklch(0.6 0.13 180);
56
+ --color-teal-700: oklch(0.511 0.096 180);
57
+
58
+ /* OKLCH Color Primitives - Coral (Destructive, Hue ~20) */
59
+ --color-coral-50: oklch(0.975 0.014 20);
60
+ --color-coral-100: oklch(0.945 0.038 20);
61
+ --color-coral-500: oklch(0.63 0.19 20);
62
+ --color-coral-600: oklch(0.56 0.195 20);
63
+ --color-coral-700: oklch(0.49 0.17 20);
64
+
65
+ /* OKLCH Color Primitives - Amber (Warning, Hue ~70) */
66
+ --color-amber-50: oklch(0.987 0.022 80);
67
+ --color-amber-100: oklch(0.962 0.055 80);
68
+ --color-amber-500: oklch(0.769 0.16 70);
69
+ --color-amber-600: oklch(0.666 0.15 55);
70
+
71
+ /* Neutral */
72
+ --color-white: oklch(1 0 0);
73
+ --color-black: oklch(0 0 0);
74
+
75
+ /* Typography - Inter preferred, with quality fallbacks */
76
+ --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
77
+ --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
78
+
79
+ /* Text Sizes */
80
+ --text-xs: 0.75rem; /* 12px */
81
+ --text-sm: 0.875rem; /* 14px */
82
+ --text-base: 0.9375rem; /* 15px */
83
+ --text-md: 1rem; /* 16px */
84
+ --text-lg: 1.125rem; /* 18px */
85
+ --text-xl: 1.25rem; /* 20px */
86
+
87
+ /* Heading Sizes */
88
+ --heading-md: 1rem; /* 16px */
89
+ --heading-lg: 1.25rem; /* 20px */
90
+ --heading-xl: 1.5rem; /* 24px */
91
+ --heading-2xl: 1.875rem; /* 30px */
92
+ --heading-3xl: 2.25rem; /* 36px */
93
+ --heading-4xl: 3rem; /* 48px */
94
+
95
+ /* Icon Sizes (standalone) */
96
+ --icon-xs: 0.75rem; /* 12px */
97
+ --icon-sm: 1rem; /* 16px */
98
+ --icon-md: 1.25rem; /* 20px */
99
+ --icon-lg: 1.5rem; /* 24px */
100
+ --icon-xl: 2rem; /* 32px */
101
+
102
+ /* Spinner Sizes */
103
+ --spinner-xs: 1rem; /* 16px */
104
+ --spinner-sm: 1.5rem; /* 24px */
105
+ --spinner-md: 2rem; /* 32px */
106
+ --spinner-lg: 2.5rem; /* 40px */
107
+ --spinner-xl: 3rem; /* 48px */
108
+
109
+ /* Input/Button Heights (consistent across all form controls) */
110
+ --input-height-xs: 1.5rem; /* 24px */
111
+ --input-height-sm: 1.75rem; /* 28px */
112
+ --input-height-md: 2rem; /* 32px */
113
+ --input-height-lg: 2.25rem; /* 36px */
114
+ --input-height-xl: 2.5rem; /* 40px */
115
+
116
+ /* Line Heights */
117
+ --leading-none: 1;
118
+ --leading-tight: 1.25;
119
+ --leading-snug: 1.375;
120
+ --leading-normal: 1.5;
121
+ --leading-relaxed: 1.625;
122
+
123
+ /* Font Weights */
124
+ --font-normal: 400;
125
+ --font-medium: 500;
126
+ --font-semibold: 600;
127
+ --font-bold: 700;
128
+
129
+ /* Border Radius - slightly softer for modern feel */
130
+ --radius-none: 0;
131
+ --radius-sm: 0.25rem; /* 4px */
132
+ --radius-md: 0.5rem; /* 8px */
133
+ --radius-lg: 0.625rem; /* 10px */
134
+ --radius-xl: 0.875rem; /* 14px */
135
+ --radius-2xl: 1.25rem; /* 20px */
136
+ --radius-full: 9999px;
137
+
138
+ /* Shadows (soft, subtle - using oklch for consistency) */
139
+ --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.03);
140
+ --shadow-md: 0 2px 4px -1px oklch(0 0 0 / 0.04), 0 1px 2px -1px oklch(0 0 0 / 0.03);
141
+ --shadow-lg: 0 4px 8px -2px oklch(0 0 0 / 0.05), 0 2px 4px -2px oklch(0 0 0 / 0.03);
142
+ --shadow-xl: 0 8px 16px -4px oklch(0 0 0 / 0.06), 0 4px 6px -4px oklch(0 0 0 / 0.04);
143
+ --shadow-2xl: 0 16px 32px -8px oklch(0 0 0 / 0.08), 0 8px 12px -6px oklch(0 0 0 / 0.05);
144
+
145
+ /* Motion: Durations */
146
+ --duration-fast: 150ms; /* Tooltips, toggles, hover states */
147
+ --duration-normal: 200ms; /* Dropdowns, popovers */
148
+ --duration-slow: 300ms; /* Modals, drawers */
149
+
150
+ /* Motion: Easings */
151
+ --ease-default: cubic-bezier(0.4, 0, 0.2, 1); /* Standard Material easing */
152
+ --ease-in: cubic-bezier(0.4, 0, 1, 1); /* Accelerate */
153
+ --ease-out: cubic-bezier(0, 0, 0.2, 1); /* Decelerate */
154
+ --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* Snappy - fast start, soft landing */
155
+ --ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1); /* Bouncy - slight overshoot */
156
+
157
+ /* Legacy aliases (deprecated, use --duration-*) */
158
+ --transition-fast: var(--duration-fast);
159
+ --transition-base: var(--duration-normal);
160
+ --transition-slow: var(--duration-slow);
161
+
162
+ /* Breakpoints (for reference - CSS can't use vars in media queries) */
163
+ --breakpoint-sm: 640px;
164
+ --breakpoint-md: 768px;
165
+ --breakpoint-lg: 1024px;
166
+ --breakpoint-xl: 1280px;
167
+ --breakpoint-2xl: 1536px;
168
+
169
+ /* Container Max-Widths */
170
+ --container-sm: 640px;
171
+ --container-md: 768px;
172
+ --container-lg: 1024px;
173
+ --container-xl: 1280px;
174
+
175
+ /* Z-Index Scale */
176
+ --z-dropdown: 100;
177
+ --z-sticky: 200;
178
+ --z-fixed: 300;
179
+ --z-modal-backdrop: 400;
180
+ --z-modal: 500;
181
+ --z-popover: 600;
182
+ --z-tooltip: 700;
183
+ }
File without changes
@@ -0,0 +1,277 @@
1
+ export interface RGB {
2
+ r: number // 0-255
3
+ g: number // 0-255
4
+ b: number // 0-255
5
+ }
6
+
7
+ export interface HSV {
8
+ h: number // 0-360
9
+ s: number // 0-1
10
+ v: number // 0-1
11
+ }
12
+
13
+ export interface OKLCH {
14
+ l: number // 0-1 (lightness)
15
+ c: number // 0-0.4+ (chroma)
16
+ h: number // 0-360 (hue)
17
+ }
18
+
19
+ export interface RGBA extends RGB {
20
+ a: number // 0-1
21
+ }
22
+
23
+ export interface HSVA extends HSV {
24
+ a: number // 0-1
25
+ }
26
+
27
+ export function clamp(value: number, min: number, max: number): number {
28
+ return Math.min(Math.max(value, min), max)
29
+ }
30
+
31
+ export function hexToRgb(hex: string): RGB {
32
+ const cleaned = hex.replace(/^#/, '')
33
+ const expanded = cleaned.length === 3
34
+ ? cleaned.split('').map(c => c + c).join('')
35
+ : cleaned
36
+
37
+ const num = parseInt(expanded, 16)
38
+ return {
39
+ r: (num >> 16) & 255,
40
+ g: (num >> 8) & 255,
41
+ b: num & 255
42
+ }
43
+ }
44
+
45
+ export function rgbToHex(rgb: RGB): string {
46
+ const toHex = (n: number) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, '0')
47
+ return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`
48
+ }
49
+
50
+ export function rgbToHsv(rgb: RGB): HSV {
51
+ const r = rgb.r / 255
52
+ const g = rgb.g / 255
53
+ const b = rgb.b / 255
54
+
55
+ const max = Math.max(r, g, b)
56
+ const min = Math.min(r, g, b)
57
+ const delta = max - min
58
+
59
+ let h = 0
60
+ if (delta !== 0) {
61
+ if (max === r) {
62
+ h = ((g - b) / delta) % 6
63
+ } else if (max === g) {
64
+ h = (b - r) / delta + 2
65
+ } else {
66
+ h = (r - g) / delta + 4
67
+ }
68
+ h = Math.round(h * 60)
69
+ if (h < 0) h += 360
70
+ }
71
+
72
+ const s = max === 0 ? 0 : delta / max
73
+ const v = max
74
+
75
+ return { h, s, v }
76
+ }
77
+
78
+ export function hsvToRgb(hsv: HSV): RGB {
79
+ const { h, s, v } = hsv
80
+ const c = v * s
81
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
82
+ const m = v - c
83
+
84
+ let r = 0, g = 0, b = 0
85
+
86
+ if (h >= 0 && h < 60) {
87
+ r = c; g = x; b = 0
88
+ } else if (h >= 60 && h < 120) {
89
+ r = x; g = c; b = 0
90
+ } else if (h >= 120 && h < 180) {
91
+ r = 0; g = c; b = x
92
+ } else if (h >= 180 && h < 240) {
93
+ r = 0; g = x; b = c
94
+ } else if (h >= 240 && h < 300) {
95
+ r = x; g = 0; b = c
96
+ } else {
97
+ r = c; g = 0; b = x
98
+ }
99
+
100
+ return {
101
+ r: Math.round((r + m) * 255),
102
+ g: Math.round((g + m) * 255),
103
+ b: Math.round((b + m) * 255)
104
+ }
105
+ }
106
+
107
+ export function hexToHsv(hex: string): HSV {
108
+ return rgbToHsv(hexToRgb(hex))
109
+ }
110
+
111
+ export function hsvToHex(hsv: HSV): string {
112
+ return rgbToHex(hsvToRgb(hsv))
113
+ }
114
+
115
+ function linearToSrgb(c: number): number {
116
+ return c <= 0.0031308
117
+ ? c * 12.92
118
+ : 1.055 * Math.pow(c, 1 / 2.4) - 0.055
119
+ }
120
+
121
+ function srgbToLinear(c: number): number {
122
+ return c <= 0.04045
123
+ ? c / 12.92
124
+ : Math.pow((c + 0.055) / 1.055, 2.4)
125
+ }
126
+
127
+ export function oklabToLinearRgb(L: number, a: number, b: number): { r: number; g: number; b: number } {
128
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b
129
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b
130
+ const s_ = L - 0.0894841775 * a - 1.2914855480 * b
131
+
132
+ const l = l_ * l_ * l_
133
+ const m = m_ * m_ * m_
134
+ const s = s_ * s_ * s_
135
+
136
+ return {
137
+ r: +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
138
+ g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
139
+ b: -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
140
+ }
141
+ }
142
+
143
+ export function linearRgbToOklab(r: number, g: number, b: number): { L: number; a: number; b: number } {
144
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b
145
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b
146
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b
147
+
148
+ const l_ = Math.cbrt(l)
149
+ const m_ = Math.cbrt(m)
150
+ const s_ = Math.cbrt(s)
151
+
152
+ return {
153
+ L: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,
154
+ a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,
155
+ b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_
156
+ }
157
+ }
158
+
159
+ export function oklchToRgb(oklch: OKLCH): RGB {
160
+ const { l, c, h } = oklch
161
+ const hRad = (h * Math.PI) / 180
162
+ const a = c * Math.cos(hRad)
163
+ const b = c * Math.sin(hRad)
164
+
165
+ const linear = oklabToLinearRgb(l, a, b)
166
+
167
+ return {
168
+ r: clamp(Math.round(linearToSrgb(linear.r) * 255), 0, 255),
169
+ g: clamp(Math.round(linearToSrgb(linear.g) * 255), 0, 255),
170
+ b: clamp(Math.round(linearToSrgb(linear.b) * 255), 0, 255)
171
+ }
172
+ }
173
+
174
+ export function rgbToOklch(rgb: RGB): OKLCH {
175
+ const r = srgbToLinear(rgb.r / 255)
176
+ const g = srgbToLinear(rgb.g / 255)
177
+ const b = srgbToLinear(rgb.b / 255)
178
+
179
+ const lab = linearRgbToOklab(r, g, b)
180
+
181
+ const c = Math.sqrt(lab.a * lab.a + lab.b * lab.b)
182
+ let h = (Math.atan2(lab.b, lab.a) * 180) / Math.PI
183
+ if (h < 0) h += 360
184
+
185
+ return {
186
+ l: lab.L,
187
+ c,
188
+ h: c < 0.0001 ? 0 : h
189
+ }
190
+ }
191
+
192
+ export function hsvToOklch(hsv: HSV): OKLCH {
193
+ return rgbToOklch(hsvToRgb(hsv))
194
+ }
195
+
196
+ export function oklchToHsv(oklch: OKLCH): HSV {
197
+ return rgbToHsv(oklchToRgb(oklch))
198
+ }
199
+
200
+ export function formatRgb(rgb: RGB, alpha?: number): string {
201
+ if (alpha !== undefined && alpha < 1) {
202
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`
203
+ }
204
+ return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`
205
+ }
206
+
207
+ export function formatOklch(oklch: OKLCH, alpha?: number): string {
208
+ const l = (oklch.l * 100).toFixed(1)
209
+ const c = oklch.c.toFixed(3)
210
+ const h = oklch.h.toFixed(0)
211
+
212
+ if (alpha !== undefined && alpha < 1) {
213
+ return `oklch(${l}% ${c} ${h} / ${alpha})`
214
+ }
215
+ return `oklch(${l}% ${c} ${h})`
216
+ }
217
+
218
+ export function parseColorString(color: string): { hsv: HSV; alpha: number; format: 'hex' | 'rgb' | 'oklch' } | null {
219
+ const trimmed = color.trim().toLowerCase()
220
+
221
+ // Hex format
222
+ if (trimmed.startsWith('#')) {
223
+ const hex = trimmed.slice(1)
224
+ if (/^[0-9a-f]{3}$/.test(hex) || /^[0-9a-f]{6}$/.test(hex)) {
225
+ return { hsv: hexToHsv(trimmed), alpha: 1, format: 'hex' }
226
+ }
227
+ if (/^[0-9a-f]{8}$/.test(hex)) {
228
+ const alpha = parseInt(hex.slice(6, 8), 16) / 255
229
+ return { hsv: hexToHsv('#' + hex.slice(0, 6)), alpha, format: 'hex' }
230
+ }
231
+ return null
232
+ }
233
+
234
+ // RGB/RGBA format
235
+ const rgbMatch = trimmed.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)$/)
236
+ if (rgbMatch) {
237
+ const rgb: RGB = {
238
+ r: clamp(parseInt(rgbMatch[1], 10), 0, 255),
239
+ g: clamp(parseInt(rgbMatch[2], 10), 0, 255),
240
+ b: clamp(parseInt(rgbMatch[3], 10), 0, 255)
241
+ }
242
+ const alpha = rgbMatch[4] ? clamp(parseFloat(rgbMatch[4]), 0, 1) : 1
243
+ return { hsv: rgbToHsv(rgb), alpha, format: 'rgb' }
244
+ }
245
+
246
+ // OKLCH format: oklch(L% C H) or oklch(L% C H / A)
247
+ const oklchMatch = trimmed.match(/^oklch\(\s*([\d.]+)%?\s+([\d.]+)\s+([\d.]+)\s*(?:\/\s*([\d.]+))?\s*\)$/)
248
+ if (oklchMatch) {
249
+ const l = parseFloat(oklchMatch[1]) / (oklchMatch[1].includes('%') ? 1 : 100)
250
+ const oklch: OKLCH = {
251
+ l: clamp(l > 1 ? l / 100 : l, 0, 1),
252
+ c: clamp(parseFloat(oklchMatch[2]), 0, 0.5),
253
+ h: parseFloat(oklchMatch[3]) % 360
254
+ }
255
+ const alpha = oklchMatch[4] ? clamp(parseFloat(oklchMatch[4]), 0, 1) : 1
256
+ return { hsv: oklchToHsv(oklch), alpha, format: 'oklch' }
257
+ }
258
+
259
+ return null
260
+ }
261
+
262
+ export function formatColor(hsv: HSV, alpha: number, format: 'hex' | 'rgb' | 'oklch'): string {
263
+ switch (format) {
264
+ case 'hex': {
265
+ const hex = hsvToHex(hsv)
266
+ if (alpha < 1) {
267
+ const alphaHex = Math.round(alpha * 255).toString(16).padStart(2, '0')
268
+ return hex + alphaHex
269
+ }
270
+ return hex
271
+ }
272
+ case 'rgb':
273
+ return formatRgb(hsvToRgb(hsv), alpha)
274
+ case 'oklch':
275
+ return formatOklch(hsvToOklch(hsv), alpha)
276
+ }
277
+ }