@greese/ui 0.0.0-stage → 1.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.
Files changed (288) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -2
  3. package/bin/greese-utilities.mjs +56 -0
  4. package/dist/_layers.scss +2 -0
  5. package/dist/_maps.scss +1884 -0
  6. package/dist/_tokens-base.scss +174 -0
  7. package/dist/_tokens.scss +2140 -0
  8. package/dist/base.css +67 -0
  9. package/dist/colorScheme.d.ts +16 -0
  10. package/dist/colorScheme.js +13 -0
  11. package/dist/contrast.d.ts +15 -0
  12. package/dist/contrast.js +43 -0
  13. package/dist/css/Accordion.css +9 -0
  14. package/dist/css/ActionSelect.css +6 -0
  15. package/dist/css/Alert.css +84 -0
  16. package/dist/css/AppBar.css +35 -0
  17. package/dist/css/AspectRatio.css +40 -0
  18. package/dist/css/AutoLayout.css +508 -0
  19. package/dist/css/Avatar.css +88 -0
  20. package/dist/css/Badge.css +66 -0
  21. package/dist/css/Box.css +640 -0
  22. package/dist/css/Breadcrumbs.css +57 -0
  23. package/dist/css/Button.css +275 -0
  24. package/dist/css/ButtonGroup.css +40 -0
  25. package/dist/css/Card.css +101 -0
  26. package/dist/css/Carousel.css +170 -0
  27. package/dist/css/Center.css +11 -0
  28. package/dist/css/ChatBubble.css +128 -0
  29. package/dist/css/Checkbox.css +65 -0
  30. package/dist/css/Chip.css +124 -0
  31. package/dist/css/ChoiceGroup.css +57 -0
  32. package/dist/css/Code.css +29 -0
  33. package/dist/css/Collapsible.css +126 -0
  34. package/dist/css/ColorPicker.css +191 -0
  35. package/dist/css/Combobox.css +90 -0
  36. package/dist/css/Container.css +30 -0
  37. package/dist/css/Countdown.css +25 -0
  38. package/dist/css/DateField.css +15 -0
  39. package/dist/css/Dialog.css +640 -0
  40. package/dist/css/Diff.css +103 -0
  41. package/dist/css/Divider.css +19 -0
  42. package/dist/css/Dock.css +91 -0
  43. package/dist/css/Field.css +33 -0
  44. package/dist/css/Fieldset.css +54 -0
  45. package/dist/css/FileInput.css +65 -0
  46. package/dist/css/Footer.css +72 -0
  47. package/dist/css/Grid.css +998 -0
  48. package/dist/css/Header.css +89 -0
  49. package/dist/css/Heading.css +6 -0
  50. package/dist/css/Icon.css +12 -0
  51. package/dist/css/IconButton.css +7 -0
  52. package/dist/css/Image.css +69 -0
  53. package/dist/css/Indicator.css +41 -0
  54. package/dist/css/Input.css +115 -0
  55. package/dist/css/Key.css +42 -0
  56. package/dist/css/Link.css +72 -0
  57. package/dist/css/List.css +52 -0
  58. package/dist/css/Media.css +8 -0
  59. package/dist/css/Menu.css +161 -0
  60. package/dist/css/Motion.css +1356 -0
  61. package/dist/css/NumberField.css +49 -0
  62. package/dist/css/OtpField.css +90 -0
  63. package/dist/css/PageTransition.css +991 -0
  64. package/dist/css/Pagination.css +43 -0
  65. package/dist/css/Popover.css +93 -0
  66. package/dist/css/Progress.css +101 -0
  67. package/dist/css/RadialProgress.css +44 -0
  68. package/dist/css/Radio.css +41 -0
  69. package/dist/css/Rating.css +100 -0
  70. package/dist/css/ScrollSpy.css +6 -0
  71. package/dist/css/SegmentedControl.css +101 -0
  72. package/dist/css/Select.css +115 -0
  73. package/dist/css/Sidebar.css +207 -0
  74. package/dist/css/Skeleton.css +48 -0
  75. package/dist/css/Slider.css +75 -0
  76. package/dist/css/Spacer.css +34 -0
  77. package/dist/css/SpeedDial.css +165 -0
  78. package/dist/css/Spinner.css +44 -0
  79. package/dist/css/Stack.css +528 -0
  80. package/dist/css/Stat.css +107 -0
  81. package/dist/css/Status.css +86 -0
  82. package/dist/css/Steps.css +201 -0
  83. package/dist/css/Swap.css +49 -0
  84. package/dist/css/Switch.css +66 -0
  85. package/dist/css/Table.css +269 -0
  86. package/dist/css/Tabs.css +119 -0
  87. package/dist/css/Text.css +60 -0
  88. package/dist/css/TextRotate.css +147 -0
  89. package/dist/css/Textarea.css +107 -0
  90. package/dist/css/ThemeProvider.css +6 -0
  91. package/dist/css/Tile.css +18 -0
  92. package/dist/css/Toast.css +110 -0
  93. package/dist/css/ToggleButton.css +20 -0
  94. package/dist/css/Tooltip.css +94 -0
  95. package/dist/css/Type.css +211 -0
  96. package/dist/css/Visibility.css +78 -0
  97. package/dist/css/VisuallyHidden.css +15 -0
  98. package/dist/css/core.css +251 -0
  99. package/dist/css.d.ts +29 -0
  100. package/dist/css.js +28 -0
  101. package/dist/effect-classes.d.ts +8 -0
  102. package/dist/effect-classes.js +5 -0
  103. package/dist/effects/css.d.ts +71 -0
  104. package/dist/effects/css.js +184 -0
  105. package/dist/effects/definitions.d.ts +555 -0
  106. package/dist/effects/definitions.js +379 -0
  107. package/dist/effects/frames.d.ts +18 -0
  108. package/dist/effects/frames.js +68 -0
  109. package/dist/effects/sequence.d.ts +33 -0
  110. package/dist/effects/sequence.js +106 -0
  111. package/dist/effects.d.ts +30 -0
  112. package/dist/effects.js +30 -0
  113. package/dist/greese.css +11919 -0
  114. package/dist/index.d.ts +10 -0
  115. package/dist/index.js +10 -0
  116. package/dist/kebab.d.ts +2 -0
  117. package/dist/kebab.js +2 -0
  118. package/dist/palette.css +249 -0
  119. package/dist/palette.d.ts +599 -0
  120. package/dist/palette.js +334 -0
  121. package/dist/shapes.d.ts +193 -0
  122. package/dist/shapes.js +852 -0
  123. package/dist/storage.d.ts +47 -0
  124. package/dist/storage.js +118 -0
  125. package/dist/style-manifest.json +3017 -0
  126. package/dist/theme.d.ts +71 -0
  127. package/dist/theme.js +180 -0
  128. package/dist/tokens.css +253 -0
  129. package/dist/tokens.d.ts +343 -0
  130. package/dist/tokens.js +179 -0
  131. package/dist/typography.d.ts +55 -0
  132. package/dist/typography.js +144 -0
  133. package/dist/utilities.css +6975 -0
  134. package/dist/utilities.d.ts +82 -0
  135. package/dist/utilities.js +636 -0
  136. package/dist/utilitiesFiles.d.ts +18 -0
  137. package/dist/utilitiesFiles.js +26 -0
  138. package/dist/vite.d.ts +40 -0
  139. package/dist/vite.js +43 -0
  140. package/package.json +131 -4
  141. package/src/components/Accordion/Accordion.scss +9 -0
  142. package/src/components/ActionSelect/ActionSelect.scss +6 -0
  143. package/src/components/Alert/Alert.scss +71 -0
  144. package/src/components/AppBar/AppBar.scss +43 -0
  145. package/src/components/AspectRatio/AspectRatio.scss +22 -0
  146. package/src/components/AutoLayout/AutoLayout.scss +90 -0
  147. package/src/components/Avatar/Avatar.scss +91 -0
  148. package/src/components/Badge/Badge.scss +52 -0
  149. package/src/components/Box/Box.scss +63 -0
  150. package/src/components/Breadcrumbs/Breadcrumbs.scss +59 -0
  151. package/src/components/Button/Button.scss +231 -0
  152. package/src/components/ButtonGroup/ButtonGroup.scss +56 -0
  153. package/src/components/Card/Card.scss +99 -0
  154. package/src/components/Carousel/Carousel.scss +161 -0
  155. package/src/components/Center/Center.scss +11 -0
  156. package/src/components/ChatBubble/ChatBubble.scss +119 -0
  157. package/src/components/Checkbox/Checkbox.scss +66 -0
  158. package/src/components/Chip/Chip.scss +119 -0
  159. package/src/components/ChoiceGroup/ChoiceGroup.scss +69 -0
  160. package/src/components/Code/Code.scss +28 -0
  161. package/src/components/Collapsible/Collapsible.scss +136 -0
  162. package/src/components/ColorPicker/ColorPicker.scss +235 -0
  163. package/src/components/Combobox/Combobox.scss +83 -0
  164. package/src/components/Container/Container.scss +28 -0
  165. package/src/components/Countdown/Countdown.scss +28 -0
  166. package/src/components/DateField/DateField.scss +19 -0
  167. package/src/components/Dialog/Dialog.scss +268 -0
  168. package/src/components/Diff/Diff.scss +125 -0
  169. package/src/components/Divider/Divider.scss +22 -0
  170. package/src/components/Dock/Dock.scss +86 -0
  171. package/src/components/Field/Field.scss +38 -0
  172. package/src/components/Fieldset/Fieldset.scss +63 -0
  173. package/src/components/FileInput/FileInput.scss +66 -0
  174. package/src/components/Footer/Footer.scss +79 -0
  175. package/src/components/Grid/Grid.scss +86 -0
  176. package/src/components/Header/Header.scss +111 -0
  177. package/src/components/Heading/Heading.scss +7 -0
  178. package/src/components/Icon/Icon.scss +12 -0
  179. package/src/components/IconButton/IconButton.scss +6 -0
  180. package/src/components/Image/Image.scss +46 -0
  181. package/src/components/Indicator/Indicator.scss +48 -0
  182. package/src/components/Input/Input.scss +58 -0
  183. package/src/components/Key/Key.scss +48 -0
  184. package/src/components/Link/Link.scss +50 -0
  185. package/src/components/List/List.scss +62 -0
  186. package/src/components/Media/Media.scss +7 -0
  187. package/src/components/Menu/Menu.scss +91 -0
  188. package/src/components/Motion/Motion.scss +106 -0
  189. package/src/components/NumberField/NumberField.scss +44 -0
  190. package/src/components/OtpField/OtpField.scss +91 -0
  191. package/src/components/PageTransition/PageTransition.scss +197 -0
  192. package/src/components/Pagination/Pagination.scss +55 -0
  193. package/src/components/Popover/Popover.scss +13 -0
  194. package/src/components/Progress/Progress.scss +126 -0
  195. package/src/components/RadialProgress/RadialProgress.scss +65 -0
  196. package/src/components/Radio/Radio.scss +36 -0
  197. package/src/components/Rating/Rating.scss +121 -0
  198. package/src/components/ScrollSpy/ScrollSpy.scss +6 -0
  199. package/src/components/SegmentedControl/SegmentedControl.scss +107 -0
  200. package/src/components/Select/Select.scss +59 -0
  201. package/src/components/Sidebar/Sidebar.scss +88 -0
  202. package/src/components/Skeleton/Skeleton.scss +60 -0
  203. package/src/components/Slider/Slider.scss +96 -0
  204. package/src/components/Spacer/Spacer.scss +15 -0
  205. package/src/components/SpeedDial/SpeedDial.scss +109 -0
  206. package/src/components/Spinner/Spinner.scss +43 -0
  207. package/src/components/Stack/Stack.scss +57 -0
  208. package/src/components/Stat/Stat.scss +96 -0
  209. package/src/components/Status/Status.scss +60 -0
  210. package/src/components/Steps/Steps.scss +216 -0
  211. package/src/components/Swap/Swap.scss +62 -0
  212. package/src/components/Switch/Switch.scss +63 -0
  213. package/src/components/Table/Table.scss +183 -0
  214. package/src/components/Tabs/Tabs.scss +108 -0
  215. package/src/components/Text/Text.scss +34 -0
  216. package/src/components/TextRotate/TextRotate.scss +51 -0
  217. package/src/components/Textarea/Textarea.scss +56 -0
  218. package/src/components/ThemeProvider/ThemeProvider.scss +7 -0
  219. package/src/components/Tile/Tile.scss +23 -0
  220. package/src/components/Toast/Toast.scss +93 -0
  221. package/src/components/ToggleButton/ToggleButton.scss +23 -0
  222. package/src/components/Tooltip/Tooltip.scss +21 -0
  223. package/src/components/Type/Type.scss +35 -0
  224. package/src/components/Visibility/Visibility.scss +39 -0
  225. package/src/components/VisuallyHidden/VisuallyHidden.scss +17 -0
  226. package/src/styles/_breakpoint-vars.scss +16 -0
  227. package/src/styles/_config.scss +48 -0
  228. package/src/styles/_controls.scss +88 -0
  229. package/src/styles/_core.scss +4 -0
  230. package/src/styles/_effect.scss +51 -0
  231. package/src/styles/_floating.scss +141 -0
  232. package/src/styles/_kit.scss +1548 -0
  233. package/src/styles/_manifest.scss +670 -0
  234. package/src/styles/_mixins.scss +261 -0
  235. package/src/styles/_tones.scss +63 -0
  236. package/src/styles/_type-emit.scss +76 -0
  237. package/src/styles/_typography-vars.scss +8 -0
  238. package/src/styles/base.scss +80 -0
  239. package/src/styles/breakpoints.test.ts +73 -0
  240. package/src/styles/entryPoints.test.ts +68 -0
  241. package/src/styles/index.scss +93 -0
  242. package/src/styles/kit.test.ts +754 -0
  243. package/src/styles/public/_controls.scss +3 -0
  244. package/src/styles/public/_floating.scss +3 -0
  245. package/src/styles/public/_mixins.scss +5 -0
  246. package/src/styles/public/_tones.scss +4 -0
  247. package/themes/bevel.css +1077 -0
  248. package/themes/bevel.scss +1166 -0
  249. package/themes/candy.css +87 -0
  250. package/themes/candy.scss +32 -0
  251. package/themes/depth.css +123 -0
  252. package/themes/depth.scss +46 -0
  253. package/themes/extrude.css +219 -0
  254. package/themes/extrude.scss +255 -0
  255. package/themes/folio.css +986 -0
  256. package/themes/folio.scss +1047 -0
  257. package/themes/forest.css +87 -0
  258. package/themes/forest.scss +32 -0
  259. package/themes/gentle.css +66 -0
  260. package/themes/gentle.scss +39 -0
  261. package/themes/grape.css +87 -0
  262. package/themes/grape.scss +32 -0
  263. package/themes/greese.css +36 -0
  264. package/themes/greese.scss +21 -0
  265. package/themes/mono.css +87 -0
  266. package/themes/mono.scss +32 -0
  267. package/themes/ocean.css +87 -0
  268. package/themes/ocean.scss +32 -0
  269. package/themes/outline.css +127 -0
  270. package/themes/outline.scss +126 -0
  271. package/themes/pebble.css +65 -0
  272. package/themes/pebble.scss +69 -0
  273. package/themes/pocket.css +137 -0
  274. package/themes/pocket.scss +45 -0
  275. package/themes/ridge.css +927 -0
  276. package/themes/ridge.scss +998 -0
  277. package/themes/snappy.css +82 -0
  278. package/themes/snappy.scss +40 -0
  279. package/themes/soft.css +79 -0
  280. package/themes/soft.scss +84 -0
  281. package/themes/sunset.css +87 -0
  282. package/themes/sunset.scss +32 -0
  283. package/themes/ticket.css +960 -0
  284. package/themes/ticket.scss +1031 -0
  285. package/themes/tilt.css +148 -0
  286. package/themes/tilt.scss +169 -0
  287. package/themes/wipe.css +186 -0
  288. package/themes/wipe.scss +46 -0
@@ -0,0 +1,71 @@
1
+ import { type TypeSpec, type TypeVariant } from './typography.ts';
2
+ import { scalarTokens, type ColorRole, type ScalarGroup, type TokenPair } from './tokens.ts';
3
+ /** A color override: one value for both schemes, or a light/dark pair. */
4
+ export type ColorValue = string | TokenPair;
5
+ /** Tokens the system doesn't have, by group: `{ color: { 'brand-ink': '#1b1340' } }`. */
6
+ export type ExtendTokens = {
7
+ /** A new color role: one value, or a light/dark pair. */
8
+ color?: Record<string, ColorValue>;
9
+ } & {
10
+ [G in ScalarGroup]?: Record<string, string>;
11
+ };
12
+ export type ThemeOptions = {
13
+ /** Scopes the theme: `[data-greese-theme="<name>"]`. Letters, digits, `-`. */
14
+ name: string;
15
+ color?: Partial<Record<ColorRole, ColorValue>>;
16
+ /**
17
+ * Adds tokens that don't exist yet, each declared as
18
+ * `--greese-<group>-<key>` in this theme (in both schemes, for a color).
19
+ * Names that already exist, and groups that don't, throw: set an existing
20
+ * token through its group above.
21
+ */
22
+ extend?: ExtendTokens;
23
+ /**
24
+ * Type system values by variant, then `base` or a breakpoint, then property
25
+ * (`{ h1: { base: { size: '2rem' }, lg: { size: '4rem' } } }`). What you set
26
+ * replaces the default at that point and the rest stays. The breakpoints are
27
+ * the defaults' widths; a build with its own uses the SCSS kit's
28
+ * `typography()` instead.
29
+ */
30
+ typography?: Partial<Record<TypeVariant, TypeSpec>>;
31
+ } & {
32
+ [G in ScalarGroup]?: Partial<Record<keyof (typeof scalarTokens)[G], string>>;
33
+ };
34
+ export interface Theme {
35
+ readonly name: string;
36
+ /**
37
+ * Static CSS for this theme, in `@layer greese.theme`. Generated once, here;
38
+ * nothing is computed per render. ThemeProvider injects it, or serve it
39
+ * yourself and set `data-greese-theme` on any element (`<html>` included).
40
+ */
41
+ readonly css: string;
42
+ }
43
+ /**
44
+ * Fills in what follows a brand color the theme set: its `Content` color,
45
+ * the more readable of white and near-black (WCAG AA), measured per scheme,
46
+ * and its `Strong` shade, mixed by the browser from the color itself
47
+ * (darker in light, lighter in dark). Anything the theme sets wins, and a
48
+ * color that can't be measured (not a hex) keeps the default content.
49
+ */
50
+ export declare const deriveColors: (overrides: Partial<Record<ColorRole, ColorValue>>) => Partial<Record<ColorRole, ColorValue>>;
51
+ /**
52
+ * Builds a theme: the default tokens with your overrides applied. Setting a
53
+ * brand color (`primary`, `secondary`, `tertiary`, `accent`, `negative`)
54
+ * also sets its `Content` and `Strong` colors unless you set them: see
55
+ * {@link deriveColors}.
56
+ *
57
+ * ```ts
58
+ * export const brand = createTheme({
59
+ * name: 'brand',
60
+ * color: { primary: { light: '#7c3aed', dark: '#c4b5fd' } },
61
+ * radius: { md: '12px' },
62
+ * })
63
+ * ```
64
+ *
65
+ * A theme is complete, not a delta: its CSS declares every token, so a
66
+ * ThemeProvider renders exactly that theme whatever its ancestors are. Themes
67
+ * do not stack; to extend one, create another with more overrides.
68
+ *
69
+ * Call it at module scope, not during render: the result is meant to be static.
70
+ */
71
+ export declare const createTheme: (options: ThemeOptions) => Theme;
package/dist/theme.js ADDED
@@ -0,0 +1,180 @@
1
+ import { allDurationKeys, cssVar, decls, kebab, LAYER_ORDER, reducedMotionDecls, SCHEME_ATTR, THEME_ATTR, } from "./css.js";
2
+ import { contentColor } from "./contrast.js";
3
+ import { mergeTypography, typography as defaultTypography, typographyByBreakpoint, } from "./typography.js";
4
+ import { color, scalarTokens, } from "./tokens.js";
5
+ const NAME = /^[a-z][a-z0-9-]*$/i;
6
+ // Theme values land inside a <style> element: refuse anything that could end a
7
+ // declaration, a rule, or the element itself.
8
+ const UNSAFE_VALUE = /[;{}<>]/;
9
+ const check = (property, value) => {
10
+ if (UNSAFE_VALUE.test(value)) {
11
+ throw new Error(`createTheme: invalid value for ${property}: ${JSON.stringify(value)}`);
12
+ }
13
+ return value;
14
+ };
15
+ /** Colors whose `Content` (and, where it exists, `Strong`) follow them. */
16
+ const DERIVED = ['primary', 'secondary', 'tertiary', 'accent', 'negative'];
17
+ const toPair = (value) => typeof value === 'string' ? { light: value, dark: value } : value;
18
+ /**
19
+ * Fills in what follows a brand color the theme set: its `Content` color,
20
+ * the more readable of white and near-black (WCAG AA), measured per scheme,
21
+ * and its `Strong` shade, mixed by the browser from the color itself
22
+ * (darker in light, lighter in dark). Anything the theme sets wins, and a
23
+ * color that can't be measured (not a hex) keeps the default content.
24
+ */
25
+ export const deriveColors = (overrides) => {
26
+ const out = { ...overrides };
27
+ for (const role of DERIVED) {
28
+ const main = overrides[role];
29
+ if (main === undefined)
30
+ continue;
31
+ const pair = toPair(main);
32
+ const content = `${role}Content`;
33
+ if (overrides[content] === undefined) {
34
+ const fallback = color[content];
35
+ out[content] = {
36
+ light: contentColor(pair.light) ?? fallback.light,
37
+ dark: contentColor(pair.dark) ?? fallback.dark,
38
+ };
39
+ }
40
+ const strong = `${role}Strong`;
41
+ if (strong in color && overrides[strong] === undefined) {
42
+ const self = `var(${cssVar('color', role)})`;
43
+ out[strong] = {
44
+ light: `color-mix(in oklab, ${self} 80%, #000)`,
45
+ dark: `color-mix(in oklab, ${self} 70%, #fff)`,
46
+ };
47
+ }
48
+ }
49
+ return out;
50
+ };
51
+ /**
52
+ * Builds a theme: the default tokens with your overrides applied. Setting a
53
+ * brand color (`primary`, `secondary`, `tertiary`, `accent`, `negative`)
54
+ * also sets its `Content` and `Strong` colors unless you set them: see
55
+ * {@link deriveColors}.
56
+ *
57
+ * ```ts
58
+ * export const brand = createTheme({
59
+ * name: 'brand',
60
+ * color: { primary: { light: '#7c3aed', dark: '#c4b5fd' } },
61
+ * radius: { md: '12px' },
62
+ * })
63
+ * ```
64
+ *
65
+ * A theme is complete, not a delta: its CSS declares every token, so a
66
+ * ThemeProvider renders exactly that theme whatever its ancestors are. Themes
67
+ * do not stack; to extend one, create another with more overrides.
68
+ *
69
+ * Call it at module scope, not during render: the result is meant to be static.
70
+ */
71
+ export const createTheme = (options) => {
72
+ const { name, color: colorOverrides = {}, extend = {}, typography: typeChanges, ...scalarOverrides } = options;
73
+ if (!NAME.test(name)) {
74
+ throw new Error(`createTheme: name must match ${NAME}, got ${JSON.stringify(name)}`);
75
+ }
76
+ const light = [];
77
+ const dark = [];
78
+ const colors = deriveColors(colorOverrides);
79
+ for (const [role, fallback] of Object.entries(color)) {
80
+ const prop = cssVar('color', role);
81
+ const pair = toPair(colors[role] ?? fallback);
82
+ light.push([prop, check(prop, pair.light)]);
83
+ dark.push([prop, check(prop, pair.dark)]);
84
+ }
85
+ const base = [];
86
+ for (const [group, defaults] of Object.entries(scalarTokens)) {
87
+ const overrides = scalarOverrides[group] ?? {};
88
+ for (const [key, fallback] of Object.entries(defaults)) {
89
+ const prop = cssVar(group, key);
90
+ base.push([prop, check(prop, overrides[key] ?? fallback)]);
91
+ }
92
+ }
93
+ addExtended(extend, base, light, dark);
94
+ // Complete like the rest: every variant, the smallest screen's values with
95
+ // the theme's tokens and the changes in media queries.
96
+ const steps = typographyByBreakpoint(mergeTypography(defaultTypography, typeChanges));
97
+ for (const [, list] of steps)
98
+ for (const [prop, value] of list)
99
+ check(prop, value);
100
+ base.push(...steps.filter(([min]) => min === 0).flatMap(([, list]) => list));
101
+ return {
102
+ name,
103
+ css: themeCss(name, base, light, dark, steps.filter(([min]) => min > 0)),
104
+ };
105
+ };
106
+ const TOKEN_KEY = /^[a-z0-9][a-z0-9-]*$/;
107
+ /** Declares `extend`'s new tokens, refusing names that exist or groups that don't. */
108
+ const addExtended = (extend, base, light, dark) => {
109
+ for (const [group, values] of Object.entries(extend)) {
110
+ const known = group === 'color'
111
+ ? color
112
+ : scalarTokens[group];
113
+ if (!known)
114
+ throw new Error(`createTheme: no token group ${group} to extend`);
115
+ for (const [key, value] of Object.entries(values ?? {})) {
116
+ const name = kebab(key);
117
+ if (!TOKEN_KEY.test(name) || Object.keys(known).some((k) => kebab(k) === name)) {
118
+ throw new Error(`createTheme: ${group} token ${key} is invalid or already exists`);
119
+ }
120
+ const prop = cssVar(group, name);
121
+ if (group === 'color') {
122
+ const pair = toPair(value);
123
+ light.push([prop, check(prop, pair.light)]);
124
+ dark.push([prop, check(prop, pair.dark)]);
125
+ }
126
+ else {
127
+ base.push([prop, check(prop, value)]);
128
+ }
129
+ }
130
+ }
131
+ };
132
+ /*
133
+ * Every scheme boundary inside a ThemeProvider stamps both attributes on one
134
+ * element, so these rules only need compound selectors on that element. The
135
+ * `:root[scheme] T:not([scheme])` rules cover a scheme forced on <html> (by
136
+ * useColorScheme) above a theme that sets none itself.
137
+ *
138
+ * Layer `greese.theme` sits above `greese.tokens`, so a theme beats the default
139
+ * scheme rules on the same element regardless of specificity.
140
+ */
141
+ const themeCss = (name, base, light, dark, media) => {
142
+ const T = `[${THEME_ATTR}='${name}']`;
143
+ const S = (scheme) => `[${SCHEME_ATTR}='${scheme}']`;
144
+ return `${LAYER_ORDER}
145
+ @layer greese.theme {
146
+ ${T} {
147
+ ${decls([...base, ...light], ' ')}
148
+ }
149
+
150
+ @media (prefers-color-scheme: dark) {
151
+ ${T}:not(${S('light')}) {
152
+ ${decls(dark, ' ')}
153
+ }
154
+ }
155
+
156
+ ${T}${S('dark')},
157
+ :root${S('dark')} ${T}:not([${SCHEME_ATTR}]) {
158
+ ${decls(dark, ' ')}
159
+ }
160
+
161
+ :root${S('light')} ${T}:not([${SCHEME_ATTR}]) {
162
+ ${decls(light, ' ')}
163
+ }
164
+
165
+ @media (prefers-reduced-motion: reduce) {
166
+ ${T} {
167
+ ${decls(reducedMotionDecls(allDurationKeys), ' ')}
168
+ }
169
+ }
170
+ ${media
171
+ .map(([min, list]) => `
172
+ @media (width >= ${min}px) {
173
+ ${T} {
174
+ ${decls(list, ' ')}
175
+ }
176
+ }`)
177
+ .join('\n')}
178
+ }
179
+ `;
180
+ };
@@ -0,0 +1,253 @@
1
+ /* GENERATED by @greese/ui from src/tokens.ts - do not edit. */
2
+ @layer greese.reset, greese.tokens, greese.theme, greese.base, greese.components, greese.overrides, greese.utilities;
3
+ @layer greese.tokens {
4
+ :root {
5
+ --greese-loaded: 1;
6
+ --greese-space-0: 0;
7
+ --greese-space-1: 0.25rem;
8
+ --greese-space-2: 0.5rem;
9
+ --greese-space-3: 0.75rem;
10
+ --greese-space-4: 1rem;
11
+ --greese-space-5: 1.5rem;
12
+ --greese-space-6: 2rem;
13
+ --greese-space-7: 3rem;
14
+ --greese-space-8: 4rem;
15
+ --greese-radius-none: 0;
16
+ --greese-radius-sm: 4px;
17
+ --greese-radius-md: 8px;
18
+ --greese-radius-lg: 16px;
19
+ --greese-radius-xl: 24px;
20
+ --greese-radius-pill: 999px;
21
+ --greese-radius-round: 50%;
22
+ --greese-corner-control: var(--greese-radius-md);
23
+ --greese-corner-field: var(--greese-radius-md);
24
+ --greese-corner-surface: var(--greese-radius-lg);
25
+ --greese-corner-panel: var(--greese-radius-md);
26
+ --greese-corner-inset: var(--greese-radius-sm);
27
+ --greese-corner-pill: var(--greese-radius-pill);
28
+ --greese-corner-round: var(--greese-radius-round);
29
+ --greese-font-body: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
30
+ --greese-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
31
+ --greese-font-weight-regular: 400;
32
+ --greese-font-weight-medium: 500;
33
+ --greese-font-weight-semibold: 600;
34
+ --greese-font-weight-bold: 700;
35
+ --greese-line-height-tight: 1.25;
36
+ --greese-line-height-snug: 1.375;
37
+ --greese-line-height-normal: 1.5;
38
+ --greese-shadow-sm: 0 1px 2px color-mix(in srgb, var(--greese-color-black) 8%, transparent);
39
+ --greese-shadow-md: 0 4px 12px color-mix(in srgb, var(--greese-color-black) 12%, transparent);
40
+ --greese-shadow-lg: 0 12px 32px color-mix(in srgb, var(--greese-color-black) 18%, transparent);
41
+ --greese-z-index-dropdown: 1000;
42
+ --greese-z-index-sticky: 1100;
43
+ --greese-z-index-overlay: 1300;
44
+ --greese-z-index-modal: 1400;
45
+ --greese-z-index-popover: 1500;
46
+ --greese-z-index-toast: 1600;
47
+ --greese-z-index-tooltip: 1700;
48
+ --greese-duration-fast: 120ms;
49
+ --greese-duration-normal: 200ms;
50
+ --greese-duration-slow: 320ms;
51
+ --greese-easing-standard: cubic-bezier(0.2, 0, 0, 1);
52
+ --greese-easing-enter: cubic-bezier(0, 0, 0, 1);
53
+ --greese-easing-exit: cubic-bezier(0.3, 0, 1, 1);
54
+ --greese-breakpoint-xs: 0px;
55
+ --greese-breakpoint-sm: 600px;
56
+ --greese-breakpoint-md: 900px;
57
+ --greese-breakpoint-lg: 1200px;
58
+ --greese-breakpoint-xl: 1536px;
59
+ --greese-type-p1-font-size: 1.125rem;
60
+ --greese-type-p1-font-weight: 400;
61
+ --greese-type-p1-line-height: 1.6;
62
+ --greese-type-p1-letter-spacing: 0;
63
+ --greese-type-p2-font-size: 1rem;
64
+ --greese-type-p2-font-weight: 400;
65
+ --greese-type-p2-line-height: 1.55;
66
+ --greese-type-p2-letter-spacing: 0;
67
+ --greese-type-p3-font-size: 0.875rem;
68
+ --greese-type-p3-font-weight: 400;
69
+ --greese-type-p3-line-height: 1.5;
70
+ --greese-type-p3-letter-spacing: 0;
71
+ --greese-type-h1-font-size: 2.25rem;
72
+ --greese-type-h1-font-weight: 700;
73
+ --greese-type-h1-line-height: 1.15;
74
+ --greese-type-h1-letter-spacing: -0.02em;
75
+ --greese-type-h1-text-wrap: balance;
76
+ --greese-type-h2-font-size: 1.875rem;
77
+ --greese-type-h2-font-weight: 700;
78
+ --greese-type-h2-line-height: 1.2;
79
+ --greese-type-h2-letter-spacing: -0.015em;
80
+ --greese-type-h2-text-wrap: balance;
81
+ --greese-type-h3-font-size: 1.5rem;
82
+ --greese-type-h3-font-weight: 600;
83
+ --greese-type-h3-line-height: 1.25;
84
+ --greese-type-h3-letter-spacing: -0.01em;
85
+ --greese-type-h3-text-wrap: balance;
86
+ --greese-type-h4-font-size: 1.25rem;
87
+ --greese-type-h4-font-weight: 600;
88
+ --greese-type-h4-line-height: 1.3;
89
+ --greese-type-h4-letter-spacing: 0;
90
+ --greese-type-h4-text-wrap: balance;
91
+ --greese-type-h5-font-size: 1.125rem;
92
+ --greese-type-h5-font-weight: 600;
93
+ --greese-type-h5-line-height: 1.35;
94
+ --greese-type-h5-letter-spacing: 0;
95
+ --greese-type-h5-text-wrap: balance;
96
+ --greese-type-h6-font-size: 1rem;
97
+ --greese-type-h6-font-weight: 600;
98
+ --greese-type-h6-line-height: 1.4;
99
+ --greese-type-h6-letter-spacing: 0;
100
+ --greese-type-h6-text-wrap: balance;
101
+ --greese-type-s1-font-size: 1.25rem;
102
+ --greese-type-s1-font-weight: 500;
103
+ --greese-type-s1-line-height: 1.4;
104
+ --greese-type-s1-letter-spacing: 0;
105
+ --greese-type-s2-font-size: 1.125rem;
106
+ --greese-type-s2-font-weight: 500;
107
+ --greese-type-s2-line-height: 1.45;
108
+ --greese-type-s2-letter-spacing: 0;
109
+ --greese-type-caption-font-size: 0.75rem;
110
+ --greese-type-caption-font-weight: 400;
111
+ --greese-type-caption-line-height: 1.4;
112
+ --greese-type-caption-letter-spacing: 0.02em;
113
+ --greese-type-button-font-size: 0.9375rem;
114
+ --greese-type-button-font-weight: 600;
115
+ --greese-type-button-line-height: 1.25;
116
+ --greese-type-button-letter-spacing: 0;
117
+ }
118
+
119
+ @media (width >= 900px) {
120
+ :root {
121
+ --greese-type-p1-font-size: 1.25rem;
122
+ --greese-type-h1-font-size: 2.75rem;
123
+ --greese-type-h2-font-size: 2.25rem;
124
+ --greese-type-h3-font-size: 1.75rem;
125
+ --greese-type-h4-font-size: 1.375rem;
126
+ --greese-type-h5-font-size: 1.25rem;
127
+ --greese-type-h6-font-size: 1.0625rem;
128
+ --greese-type-s1-font-size: 1.375rem;
129
+ }
130
+ }
131
+
132
+ @media (width >= 1200px) {
133
+ :root {
134
+ --greese-type-h1-font-size: 3.5rem;
135
+ --greese-type-h1-line-height: 1.1;
136
+ --greese-type-h2-font-size: 2.75rem;
137
+ --greese-type-h3-font-size: 2rem;
138
+ --greese-type-h4-font-size: 1.5rem;
139
+ }
140
+ }
141
+
142
+ :root,
143
+ [data-greese-scheme='light'],
144
+ [data-greese-scheme='system'] {
145
+ color-scheme: light;
146
+ --greese-color-canvas: #ffffff;
147
+ --greese-color-surface: #f5f7f9;
148
+ --greese-color-surface-overlay: #ffffff;
149
+ --greese-color-fg: #11171c;
150
+ --greese-color-fg-muted: #505e6d;
151
+ --greese-color-border: #d7dfe7;
152
+ --greese-color-border-strong: #a3b3c4;
153
+ --greese-color-track: #d7dfe7;
154
+ --greese-color-primary: #2771e0;
155
+ --greese-color-primary-strong: #1356b8;
156
+ --greese-color-primary-content: #ffffff;
157
+ --greese-color-secondary: #7e5bd0;
158
+ --greese-color-secondary-strong: #6443ab;
159
+ --greese-color-secondary-content: #ffffff;
160
+ --greese-color-tertiary: #007069;
161
+ --greese-color-tertiary-strong: #00544f;
162
+ --greese-color-tertiary-content: #ffffff;
163
+ --greese-color-accent: #c13b7b;
164
+ --greese-color-accent-strong: #9c2661;
165
+ --greese-color-accent-content: #ffffff;
166
+ --greese-color-focus-ring: var(--greese-color-primary);
167
+ --greese-color-positive: #007231;
168
+ --greese-color-negative: #ae0914;
169
+ --greese-color-negative-content: #ffffff;
170
+ --greese-color-warning: #8a5f00;
171
+ --greese-color-info: #00668f;
172
+ --greese-color-white: #ffffff;
173
+ --greese-color-black: #000000;
174
+ --greese-color-scrim: color-mix(in srgb, var(--greese-color-black) 45%, transparent);
175
+ }
176
+
177
+ @media (prefers-color-scheme: dark) {
178
+ :root:not([data-greese-scheme='light']),
179
+ [data-greese-scheme='system'] {
180
+ color-scheme: dark;
181
+ --greese-color-canvas: #11171c;
182
+ --greese-color-surface: #2a333c;
183
+ --greese-color-surface-overlay: #3c4854;
184
+ --greese-color-fg: #e9edf2;
185
+ --greese-color-fg-muted: #a3b3c4;
186
+ --greese-color-border: #3c4854;
187
+ --greese-color-border-strong: #505e6d;
188
+ --greese-color-track: #687889;
189
+ --greese-color-primary: #81b2ff;
190
+ --greese-color-primary-strong: #aaccff;
191
+ --greese-color-primary-content: #11171c;
192
+ --greese-color-secondary: #b69fff;
193
+ --greese-color-secondary-strong: #cdbfff;
194
+ --greese-color-secondary-content: #11171c;
195
+ --greese-color-tertiary: #5dcec5;
196
+ --greese-color-tertiary-strong: #94e1da;
197
+ --greese-color-tertiary-content: #11171c;
198
+ --greese-color-accent: #ff81b6;
199
+ --greese-color-accent-strong: #ffaecd;
200
+ --greese-color-accent-content: #11171c;
201
+ --greese-color-focus-ring: var(--greese-color-primary-strong);
202
+ --greese-color-positive: #61cf7e;
203
+ --greese-color-negative: #ff8b7f;
204
+ --greese-color-negative-content: #11171c;
205
+ --greese-color-warning: #feb93d;
206
+ --greese-color-info: #5ac0f7;
207
+ --greese-color-white: #ffffff;
208
+ --greese-color-black: #000000;
209
+ --greese-color-scrim: color-mix(in srgb, var(--greese-color-black) 60%, transparent);
210
+ }
211
+ }
212
+
213
+ [data-greese-scheme='dark'] {
214
+ color-scheme: dark;
215
+ --greese-color-canvas: #11171c;
216
+ --greese-color-surface: #2a333c;
217
+ --greese-color-surface-overlay: #3c4854;
218
+ --greese-color-fg: #e9edf2;
219
+ --greese-color-fg-muted: #a3b3c4;
220
+ --greese-color-border: #3c4854;
221
+ --greese-color-border-strong: #505e6d;
222
+ --greese-color-track: #687889;
223
+ --greese-color-primary: #81b2ff;
224
+ --greese-color-primary-strong: #aaccff;
225
+ --greese-color-primary-content: #11171c;
226
+ --greese-color-secondary: #b69fff;
227
+ --greese-color-secondary-strong: #cdbfff;
228
+ --greese-color-secondary-content: #11171c;
229
+ --greese-color-tertiary: #5dcec5;
230
+ --greese-color-tertiary-strong: #94e1da;
231
+ --greese-color-tertiary-content: #11171c;
232
+ --greese-color-accent: #ff81b6;
233
+ --greese-color-accent-strong: #ffaecd;
234
+ --greese-color-accent-content: #11171c;
235
+ --greese-color-focus-ring: var(--greese-color-primary-strong);
236
+ --greese-color-positive: #61cf7e;
237
+ --greese-color-negative: #ff8b7f;
238
+ --greese-color-negative-content: #11171c;
239
+ --greese-color-warning: #feb93d;
240
+ --greese-color-info: #5ac0f7;
241
+ --greese-color-white: #ffffff;
242
+ --greese-color-black: #000000;
243
+ --greese-color-scrim: color-mix(in srgb, var(--greese-color-black) 60%, transparent);
244
+ }
245
+
246
+ @media (prefers-reduced-motion: reduce) {
247
+ :root {
248
+ --greese-duration-fast: 0.01ms;
249
+ --greese-duration-normal: 0.01ms;
250
+ --greese-duration-slow: 0.01ms;
251
+ }
252
+ }
253
+ }