@yarcl/react 0.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/color.d.ts +12 -0
  4. package/dist/color.js +41 -0
  5. package/dist/css.d.ts +10 -0
  6. package/dist/css.js +175 -0
  7. package/dist/define.d.ts +383 -0
  8. package/dist/define.js +29 -0
  9. package/dist/plugin.d.ts +33 -0
  10. package/dist/plugin.js +80 -0
  11. package/package.json +66 -0
  12. package/src/apply.ts +46 -0
  13. package/src/classes.ts +23 -0
  14. package/src/color.ts +48 -0
  15. package/src/components/Accordion.tsx +274 -0
  16. package/src/components/Alert.tsx +85 -0
  17. package/src/components/Badge.tsx +79 -0
  18. package/src/components/Breadcrumb.tsx +239 -0
  19. package/src/components/Button.tsx +58 -0
  20. package/src/components/ButtonGroup.tsx +61 -0
  21. package/src/components/Card.tsx +50 -0
  22. package/src/components/Checkbox.tsx +49 -0
  23. package/src/components/Combobox.tsx +522 -0
  24. package/src/components/CommandPalette.tsx +452 -0
  25. package/src/components/DatePicker.tsx +432 -0
  26. package/src/components/Dialog.tsx +39 -0
  27. package/src/components/Divider.tsx +34 -0
  28. package/src/components/Drawer.tsx +31 -0
  29. package/src/components/Field.tsx +61 -0
  30. package/src/components/Heading.tsx +40 -0
  31. package/src/components/HoverCard.tsx +108 -0
  32. package/src/components/IconButton.tsx +59 -0
  33. package/src/components/Inline.tsx +42 -0
  34. package/src/components/Input.tsx +28 -0
  35. package/src/components/Label.tsx +58 -0
  36. package/src/components/Link.tsx +41 -0
  37. package/src/components/Menu.tsx +207 -0
  38. package/src/components/Modal.tsx +164 -0
  39. package/src/components/NumberInput.tsx +208 -0
  40. package/src/components/Pagination.tsx +227 -0
  41. package/src/components/Popover.tsx +140 -0
  42. package/src/components/Progress.tsx +122 -0
  43. package/src/components/Radio.tsx +59 -0
  44. package/src/components/RadioGroup.tsx +114 -0
  45. package/src/components/Select.tsx +197 -0
  46. package/src/components/Skeleton.tsx +95 -0
  47. package/src/components/Slider.tsx +315 -0
  48. package/src/components/Spinner.tsx +38 -0
  49. package/src/components/Stack.tsx +57 -0
  50. package/src/components/Switch.tsx +42 -0
  51. package/src/components/Table.tsx +99 -0
  52. package/src/components/Tabs.tsx +159 -0
  53. package/src/components/Text.tsx +67 -0
  54. package/src/components/Textarea.tsx +26 -0
  55. package/src/components/Toast.tsx +190 -0
  56. package/src/components/ToggleGroup.tsx +227 -0
  57. package/src/components/Tooltip.tsx +78 -0
  58. package/src/contrast.ts +82 -0
  59. package/src/css.ts +228 -0
  60. package/src/define.check.ts +259 -0
  61. package/src/define.ts +379 -0
  62. package/src/field-context.ts +31 -0
  63. package/src/floating.tsx +61 -0
  64. package/src/hooks.ts +19 -0
  65. package/src/index.ts +119 -0
  66. package/src/plugin.ts +94 -0
  67. package/src/reference/DesignReference.tsx +374 -0
  68. package/src/reference/index.ts +2 -0
  69. package/src/reference/reference.css +58 -0
  70. package/src/runtime.ts +38 -0
  71. package/src/styles.css +1971 -0
  72. package/src/themes/bloom.ts +72 -0
  73. package/src/themes/brutalist.ts +63 -0
  74. package/src/themes/compact.ts +63 -0
  75. package/src/themes/contract.ts +24 -0
  76. package/src/themes/editorial.ts +55 -0
  77. package/src/themes/index.ts +47 -0
  78. package/src/types.ts +69 -0
  79. package/src/yarcl.config.ts +104 -0
@@ -0,0 +1,72 @@
1
+ import { defineConfig } from '../define';
2
+ import defaults from '../yarcl.config';
3
+ import type { ThemeContract } from './contract';
4
+
5
+ const glow = (geometry: string, alpha: number) =>
6
+ `${geometry} light-dark(rgb(91 33 182 / ${alpha}), rgb(0 0 0 / ${Math.min(alpha * 5, 0.7)}))`;
7
+
8
+ /** Friendly and airy: violet on lavender, pill-shaped controls, rounded cards, large targets, soft tinted shadows. */
9
+ export const bloom = defineConfig({
10
+ ...defaults,
11
+ colors: {
12
+ primary: { light: '#7c3aed', dark: '#c4b5fd' },
13
+ neutral: { light: '#6b6485', dark: '#b5aecf' },
14
+ success: { light: '#0f8a5f', dark: '#5eead4' },
15
+ warning: { light: '#c2410c', dark: '#fdba74' },
16
+ danger: { light: '#e11d48', dark: '#fb7185' },
17
+ info: { light: '#0369a1', dark: '#7dd3fc' },
18
+ },
19
+ neutrals: {
20
+ bg: { light: '#f7f4ff', dark: '#14111f' },
21
+ surface: { light: '#ffffff', dark: '#1f1a30' },
22
+ text: { light: '#2a2540', dark: '#efeafc' },
23
+ muted: { light: '#6b6485', dark: '#aaa3c4' },
24
+ border: { light: '#e6dff7', dark: '#342c4d' },
25
+ },
26
+ sizes: {
27
+ xs: { height: '2rem', paddingX: '0.875rem', fontSize: '0.8125rem', iconSize: '0.875rem' },
28
+ sm: { height: '2.25rem', paddingX: '1rem', fontSize: '0.875rem', iconSize: '1rem' },
29
+ md: { height: '2.75rem', paddingX: '1.25rem', fontSize: '0.9375rem', iconSize: '1.125rem' },
30
+ lg: { height: '3.25rem', paddingX: '1.625rem', fontSize: '1.0625rem', iconSize: '1.25rem' },
31
+ xl: { height: '3.75rem', paddingX: '2rem', fontSize: '1.1875rem', iconSize: '1.5rem' },
32
+ },
33
+ radii: { square: '0', sm: '0.75rem', md: '1rem', lg: '1.5rem', xl: '2rem', rounded: '9999px' },
34
+ spacing: { xs: '0.375rem', sm: '0.75rem', md: '1.25rem', lg: '1.75rem', xl: '2.5rem' },
35
+ shadows: {
36
+ sm: glow('0 2px 8px', 0.08),
37
+ md: glow('0 10px 30px', 0.14),
38
+ lg: glow('0 20px 60px', 0.2),
39
+ },
40
+ density: {
41
+ compact: { paddingX: '0.75rem', paddingY: '0.5rem', fontSize: '0.875rem' },
42
+ comfortable: { paddingX: '1.25rem', paddingY: '0.875rem', fontSize: '0.9375rem' },
43
+ },
44
+ typography: {
45
+ families: {
46
+ sans: 'Nunito, "SF Pro Rounded", ui-rounded, "Varela Round", system-ui, sans-serif',
47
+ mono: 'ui-monospace, "SF Mono", Menlo, Consolas, monospace',
48
+ },
49
+ styles: {
50
+ display: { family: 'sans', size: '2.5rem', weight: 800, lineHeight: 1.1, letterSpacing: '-0.02em' },
51
+ heading: { family: 'sans', size: '1.625rem', weight: 800, lineHeight: 1.2 },
52
+ subheading: { family: 'sans', size: '1.1875rem', weight: 700, lineHeight: 1.35 },
53
+ body: { family: 'sans', size: '1rem', weight: 500, lineHeight: 1.55 },
54
+ caption: { family: 'sans', size: '0.8125rem', weight: 500, lineHeight: 1.45 },
55
+ code: { family: 'mono', size: '0.875rem', weight: 400, lineHeight: 1.5 },
56
+ label: { family: 'sans', size: '0.9375rem', weight: 700, lineHeight: 1.4 },
57
+ },
58
+ headings: { h1: 'display', h2: 'heading', h3: 'heading', h4: 'subheading', h5: 'subheading', h6: 'label' },
59
+ },
60
+ focusRing: { width: '3px', offset: '3px', color: 'primary' },
61
+ components: {
62
+ ...defaults.components,
63
+ Button: { radius: 'rounded' },
64
+ IconButton: { radius: 'rounded' },
65
+ ToggleGroup: { radius: 'rounded' },
66
+ Badge: { radius: 'rounded' },
67
+ Input: { radius: 'rounded' },
68
+ Select: { radius: 'rounded' },
69
+ Combobox: { radius: 'rounded' },
70
+ },
71
+ defaults: { ...defaults.defaults, radius: 'lg', padding: 'lg', gap: 'md' },
72
+ }) satisfies ThemeContract;
@@ -0,0 +1,63 @@
1
+ import { defineConfig } from '../define';
2
+ import defaults from '../yarcl.config';
3
+ import type { ThemeContract } from './contract';
4
+
5
+ const ink = 'light-dark(#000000, #ffffff)';
6
+
7
+ /** Loud and flat: red on black and white, square corners, thick borders, hard offset shadows, monospace type. */
8
+ export const brutalist = defineConfig({
9
+ ...defaults,
10
+ colors: {
11
+ primary: { light: '#ff3d2e', dark: '#ff5a4d' },
12
+ neutral: { light: '#1a1a1a', dark: '#f5f5f5' },
13
+ success: { light: '#00b862', dark: '#3dfc9a' },
14
+ warning: { light: '#ff8a00', dark: '#ffb14a' },
15
+ danger: { light: '#c2005a', dark: '#ff5ca1' },
16
+ info: { light: '#2f6bff', dark: '#7aa2ff' },
17
+ },
18
+ neutrals: {
19
+ bg: { light: '#fffdf2', dark: '#0f0f0f' },
20
+ surface: { light: '#ffffff', dark: '#1a1a1a' },
21
+ text: { light: '#000000', dark: '#ffffff' },
22
+ muted: { light: '#3d3d3d', dark: '#cfcfcf' },
23
+ border: { light: '#000000', dark: '#ffffff' },
24
+ },
25
+ sizes: {
26
+ xs: { height: '1.75rem', paddingX: '0.625rem', fontSize: '0.75rem', iconSize: '0.75rem' },
27
+ sm: { height: '2rem', paddingX: '0.75rem', fontSize: '0.8125rem', iconSize: '0.875rem' },
28
+ md: { height: '2.5rem', paddingX: '1rem', fontSize: '0.875rem', iconSize: '1rem' },
29
+ lg: { height: '3rem', paddingX: '1.25rem', fontSize: '1rem', iconSize: '1.25rem' },
30
+ xl: { height: '3.5rem', paddingX: '1.5rem', fontSize: '1.125rem', iconSize: '1.5rem' },
31
+ },
32
+ radii: { square: '0', sm: '0', md: '0', lg: '0', xl: '0', rounded: '9999px' },
33
+ variants: {
34
+ solid: { background: 'fill', border: 'neutral', text: 'on' },
35
+ soft: { background: 'tint', border: 'neutral', text: 'neutral' },
36
+ outline: { background: 'none', border: 'neutral', text: 'neutral' },
37
+ ghost: { background: 'none', border: 'none', text: 'neutral' },
38
+ },
39
+ shadows: {
40
+ sm: `3px 3px 0 0 ${ink}`,
41
+ md: `5px 5px 0 0 ${ink}`,
42
+ lg: `8px 8px 0 0 ${ink}`,
43
+ },
44
+ borders: { width: '2px' },
45
+ typography: {
46
+ families: {
47
+ sans: '"JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace',
48
+ mono: '"JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace',
49
+ },
50
+ styles: {
51
+ display: { family: 'sans', size: '2.5rem', weight: 800, lineHeight: 1, letterSpacing: '-0.04em' },
52
+ heading: { family: 'sans', size: '1.5rem', weight: 800, lineHeight: 1.15, letterSpacing: '-0.02em' },
53
+ subheading: { family: 'sans', size: '1.125rem', weight: 700, lineHeight: 1.3 },
54
+ body: { family: 'sans', size: '0.875rem', weight: 400, lineHeight: 1.55 },
55
+ caption: { family: 'sans', size: '0.75rem', weight: 400, lineHeight: 1.45 },
56
+ code: { family: 'mono', size: '0.8125rem', weight: 400, lineHeight: 1.5 },
57
+ label: { family: 'sans', size: '0.8125rem', weight: 700, lineHeight: 1.4, letterSpacing: '0.04em' },
58
+ },
59
+ headings: { h1: 'display', h2: 'heading', h3: 'heading', h4: 'subheading', h5: 'subheading', h6: 'label' },
60
+ },
61
+ focusRing: { width: '3px', offset: '3px', color: 'neutral', style: 'dashed' },
62
+ defaults: { ...defaults.defaults, radius: 'md', padding: 'lg', floatingShadow: 'md' },
63
+ }) satisfies ThemeContract;
@@ -0,0 +1,63 @@
1
+ import { defineConfig } from '../define';
2
+ import defaults from '../yarcl.config';
3
+ import type { ThemeContract } from './contract';
4
+
5
+ /** Dense and businesslike: teal on cool gray, small 28px controls, tight spacing, 13px text, compact tables, nearly flat. */
6
+ export const compact = defineConfig({
7
+ ...defaults,
8
+ colors: {
9
+ primary: { light: '#0f766e', dark: '#2dd4bf' },
10
+ neutral: { light: '#52606d', dark: '#9aa5b1' },
11
+ success: { light: '#15803d', dark: '#4ade80' },
12
+ warning: { light: '#a16207', dark: '#facc15' },
13
+ danger: { light: '#b91c1c', dark: '#f87171' },
14
+ info: { light: '#1d4ed8', dark: '#60a5fa' },
15
+ },
16
+ neutrals: {
17
+ bg: { light: '#eef1f4', dark: '#0b0f14' },
18
+ surface: { light: '#ffffff', dark: '#141a21' },
19
+ text: { light: '#1f2933', dark: '#e4e7eb' },
20
+ muted: { light: '#52606d', dark: '#9aa5b1' },
21
+ border: { light: '#cbd2d9', dark: '#2a333d' },
22
+ },
23
+ sizes: {
24
+ xs: { height: '1.25rem', paddingX: '0.375rem', fontSize: '0.6875rem', iconSize: '0.75rem' },
25
+ sm: { height: '1.5rem', paddingX: '0.5rem', fontSize: '0.75rem', iconSize: '0.75rem' },
26
+ md: { height: '1.75rem', paddingX: '0.625rem', fontSize: '0.8125rem', iconSize: '0.875rem' },
27
+ lg: { height: '2.25rem', paddingX: '0.875rem', fontSize: '0.875rem', iconSize: '1rem' },
28
+ xl: { height: '2.75rem', paddingX: '1rem', fontSize: '1rem', iconSize: '1.125rem' },
29
+ },
30
+ radii: { square: '0', sm: '2px', md: '3px', lg: '4px', xl: '6px', rounded: '9999px' },
31
+ variants: {
32
+ ...defaults.variants,
33
+ outline: { background: 'none', border: 'neutral', text: 'neutral' },
34
+ },
35
+ spacing: { xs: '0.125rem', sm: '0.25rem', md: '0.5rem', lg: '0.75rem', xl: '1rem' },
36
+ shadows: {
37
+ sm: '0 1px 0 light-dark(rgb(15 23 42 / 0.05), rgb(0 0 0 / 0.4))',
38
+ md: '0 2px 8px light-dark(rgb(15 23 42 / 0.14), rgb(0 0 0 / 0.55))',
39
+ lg: '0 8px 24px light-dark(rgb(15 23 42 / 0.18), rgb(0 0 0 / 0.6))',
40
+ },
41
+ density: {
42
+ compact: { paddingX: '0.5rem', paddingY: '0.25rem', fontSize: '0.75rem' },
43
+ comfortable: { paddingX: '0.625rem', paddingY: '0.375rem', fontSize: '0.8125rem' },
44
+ },
45
+ typography: {
46
+ families: {
47
+ sans: '"IBM Plex Sans", "Segoe UI", system-ui, -apple-system, sans-serif',
48
+ mono: '"IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace',
49
+ },
50
+ styles: {
51
+ display: { family: 'sans', size: '1.5rem', weight: 600, lineHeight: 1.25 },
52
+ heading: { family: 'sans', size: '1.125rem', weight: 600, lineHeight: 1.3 },
53
+ subheading: { family: 'sans', size: '0.9375rem', weight: 600, lineHeight: 1.35 },
54
+ body: { family: 'sans', size: '0.8125rem', weight: 400, lineHeight: 1.45 },
55
+ caption: { family: 'sans', size: '0.75rem', weight: 400, lineHeight: 1.4 },
56
+ code: { family: 'mono', size: '0.75rem', weight: 400, lineHeight: 1.45 },
57
+ label: { family: 'sans', size: '0.75rem', weight: 600, lineHeight: 1.35, letterSpacing: '0.02em' },
58
+ },
59
+ headings: { h1: 'display', h2: 'heading', h3: 'heading', h4: 'subheading', h5: 'subheading', h6: 'label' },
60
+ },
61
+ focusRing: { width: '2px', offset: '1px', color: 'info' },
62
+ defaults: { ...defaults.defaults, radius: 'sm', padding: 'lg', gap: 'md', density: 'compact' },
63
+ }) satisfies ThemeContract;
@@ -0,0 +1,24 @@
1
+ import type { ColorToken, DensityToken, SizeToken, TextStyleToken, VariantToken } from '../define';
2
+ import type defaults from '../yarcl.config';
3
+
4
+ type Defaults = typeof defaults;
5
+
6
+ /**
7
+ * The keys every bundled theme defines: the same keys as the library defaults.
8
+ * Apps written against these keys work with any theme that satisfies the contract.
9
+ * Values are free; extra keys are allowed.
10
+ */
11
+ export interface ThemeContract {
12
+ colors: Record<keyof Defaults['colors'], ColorToken>;
13
+ sizes: Record<keyof Defaults['sizes'], SizeToken>;
14
+ radii: Record<keyof Defaults['radii'], string>;
15
+ variants: Record<keyof Defaults['variants'], VariantToken>;
16
+ spacing: Record<keyof Defaults['spacing'], string>;
17
+ shadows: Record<keyof Defaults['shadows'], string>;
18
+ density: Record<keyof Defaults['density'], DensityToken>;
19
+ modalSizes: Record<keyof Defaults['modalSizes'], string>;
20
+ typography: {
21
+ families: Record<keyof Defaults['typography']['families'], string>;
22
+ styles: Record<keyof Defaults['typography']['styles'], TextStyleToken>;
23
+ };
24
+ }
@@ -0,0 +1,55 @@
1
+ import { defineConfig } from '../define';
2
+ import defaults from '../yarcl.config';
3
+ import type { ThemeContract } from './contract';
4
+
5
+ /** Calm and considered: terracotta on cream, light grotesque type, square corners, flat surfaces, generous spacing. */
6
+ export const editorial = defineConfig({
7
+ ...defaults,
8
+ colors: {
9
+ primary: { light: '#9a3412', dark: '#fb923c' },
10
+ neutral: { light: '#57534e', dark: '#a8a29e' },
11
+ success: { light: '#3f6212', dark: '#a3e635' },
12
+ warning: { light: '#a16207', dark: '#fcd34d' },
13
+ danger: { light: '#9f1239', dark: '#fda4af' },
14
+ info: { light: '#1e3a8a', dark: '#93c5fd' },
15
+ },
16
+ neutrals: {
17
+ bg: { light: '#f6f1e7', dark: '#1c1917' },
18
+ surface: { light: '#fffdf8', dark: '#262220' },
19
+ text: { light: '#1c1917', dark: '#f5efe3' },
20
+ muted: { light: '#57534e', dark: '#aaa39b' },
21
+ border: { light: '#d6cdbd', dark: '#48413b' },
22
+ },
23
+ sizes: {
24
+ xs: { height: '1.75rem', paddingX: '0.75rem', fontSize: '0.8125rem', iconSize: '0.75rem' },
25
+ sm: { height: '2rem', paddingX: '0.875rem', fontSize: '0.875rem', iconSize: '0.875rem' },
26
+ md: { height: '2.625rem', paddingX: '1.375rem', fontSize: '1rem', iconSize: '1rem' },
27
+ lg: { height: '3.25rem', paddingX: '1.75rem', fontSize: '1.0625rem', iconSize: '1.25rem' },
28
+ xl: { height: '3.875rem', paddingX: '2.125rem', fontSize: '1.1875rem', iconSize: '1.375rem' },
29
+ },
30
+ radii: { square: '0', sm: '1px', md: '2px', lg: '3px', xl: '4px', rounded: '9999px' },
31
+ spacing: { xs: '0.375rem', sm: '0.75rem', md: '1.25rem', lg: '2rem', xl: '3rem' },
32
+ shadows: {
33
+ sm: 'none',
34
+ md: '0 18px 40px -18px light-dark(rgb(68 44 20 / 0.35), rgb(0 0 0 / 0.75))',
35
+ lg: '0 30px 60px -20px light-dark(rgb(68 44 20 / 0.4), rgb(0 0 0 / 0.8))',
36
+ },
37
+ typography: {
38
+ families: {
39
+ sans: '"Helvetica Neue", Helvetica, "Inter", "Segoe UI", Arial, sans-serif',
40
+ mono: 'ui-monospace, "SF Mono", Menlo, Consolas, monospace',
41
+ },
42
+ styles: {
43
+ display: { family: 'sans', size: '2.75rem', weight: 300, lineHeight: 1.05, letterSpacing: '-0.03em' },
44
+ heading: { family: 'sans', size: '1.75rem', weight: 300, lineHeight: 1.2, letterSpacing: '-0.015em' },
45
+ subheading: { family: 'sans', size: '1.25rem', weight: 600, lineHeight: 1.3 },
46
+ body: { family: 'sans', size: '1rem', weight: 400, lineHeight: 1.6 },
47
+ caption: { family: 'sans', size: '0.875rem', weight: 400, lineHeight: 1.5 },
48
+ code: { family: 'mono', size: '0.875rem', weight: 400, lineHeight: 1.5 },
49
+ label: { family: 'sans', size: '0.8125rem', weight: 700, lineHeight: 1.4, letterSpacing: '0.08em' },
50
+ },
51
+ headings: { h1: 'display', h2: 'heading', h3: 'heading', h4: 'subheading', h5: 'subheading', h6: 'label' },
52
+ },
53
+ focusRing: { width: '3px', offset: '3px', color: 'primary', style: 'double' },
54
+ defaults: { ...defaults.defaults, radius: 'square', padding: 'lg', gap: 'md', floatingShadow: 'md' },
55
+ }) satisfies ThemeContract;
@@ -0,0 +1,47 @@
1
+ import defaults from '../yarcl.config';
2
+ import { brutalist } from './brutalist';
3
+ import { compact } from './compact';
4
+ import { editorial } from './editorial';
5
+ import { bloom } from './bloom';
6
+
7
+ export type { ThemeContract } from './contract';
8
+ export { brutalist, compact, editorial, bloom };
9
+
10
+ /**
11
+ * Every bundled theme, keyed by id, including the library defaults as `yarcl`.
12
+ * All of them satisfy {@link ThemeContract}, so they're interchangeable.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * // src/yarcl.config.ts: use a theme as is
17
+ * export { editorial as default } from '@yarcl/react/themes';
18
+ * ```
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // or start from one and change what you need
23
+ * import { defineConfig } from '@yarcl/react/define';
24
+ * import { bloom } from '@yarcl/react/themes';
25
+ *
26
+ * export default defineConfig({
27
+ * ...bloom,
28
+ * colors: { ...bloom.colors, primary: { light: '#db2777', dark: '#f9a8d4' } },
29
+ * });
30
+ * ```
31
+ */
32
+ export const themes = {
33
+ yarcl: defaults,
34
+ brutalist,
35
+ bloom,
36
+ compact,
37
+ editorial,
38
+ };
39
+
40
+ /** Display names of the bundled themes. */
41
+ export const themeNames: Record<keyof typeof themes, string> = {
42
+ yarcl: 'yarcl (default)',
43
+ brutalist: 'Brutalist',
44
+ bloom: 'Bloom',
45
+ compact: 'Compact',
46
+ editorial: 'Editorial',
47
+ };
package/src/types.ts ADDED
@@ -0,0 +1,69 @@
1
+ import type config from '@yarcl/config';
2
+
3
+ type Config = typeof config;
4
+
5
+ /** A key of the consumer's `sizes` config. */
6
+ export type Size = keyof Config['sizes'] & string;
7
+ /** A key of the consumer's `radii` config. */
8
+ export type Radius = keyof Config['radii'] & string;
9
+ /** A key of the consumer's `colors` config. */
10
+ export type Color = keyof Config['colors'] & string;
11
+ /** A key of the consumer's `variants` config. */
12
+ export type Variant = keyof Config['variants'] & string;
13
+ /** A key of the consumer's `spacing` config. */
14
+ export type Spacing = keyof Config['spacing'] & string;
15
+ /** A key of the consumer's `shadows` config. */
16
+ export type Shadow = keyof Config['shadows'] & string;
17
+ /** A key of the consumer's `density` config. */
18
+ export type Density = keyof Config['density'] & string;
19
+ /** A key of the consumer's `modalSizes` config. */
20
+ export type ModalSize = keyof Config['modalSizes'] & string;
21
+ /** A key of the consumer's `typography.styles` config. */
22
+ export type TextStyle = keyof Config['typography']['styles'] & string;
23
+
24
+ /** Design token props shared by every sized, colored component. */
25
+ export interface TokenProps {
26
+ /**
27
+ * Control size, from the `sizes` config.
28
+ * @default config.defaults.size
29
+ */
30
+ size?: Size;
31
+ /**
32
+ * Border radius, from the `radii` config, or `'size'` for the radius named like the control's size.
33
+ * @default config.defaults.radius
34
+ */
35
+ radius?: Radius | 'size';
36
+ /**
37
+ * Semantic color, from the `colors` config.
38
+ * @default config.defaults.color
39
+ */
40
+ color?: Color;
41
+ }
42
+
43
+ /** Cross-axis alignment for layout components. */
44
+ export type Align = 'start' | 'center' | 'end' | 'stretch' | 'baseline';
45
+ /** Main-axis distribution for layout components. */
46
+ export type Justify = 'start' | 'center' | 'end' | 'between';
47
+
48
+ /** The `variant` prop shared by components that apply a style recipe. */
49
+ export interface VariantProps {
50
+ /**
51
+ * Style recipe, from the `variants` config.
52
+ * @default config.defaults.variant
53
+ */
54
+ variant?: Variant;
55
+ }
56
+
57
+ /** Values a component can receive from `components` in the config. */
58
+ export interface ComponentDefaults {
59
+ size?: Size;
60
+ radius?: Radius | 'size';
61
+ color?: Color;
62
+ variant?: Variant;
63
+ selectedVariant?: Variant;
64
+ gap?: Spacing;
65
+ padding?: Spacing;
66
+ shadow?: Shadow;
67
+ density?: Density;
68
+ textStyle?: TextStyle;
69
+ }
@@ -0,0 +1,104 @@
1
+ import { defineConfig } from './define';
2
+
3
+ /** The library's default design system, used when the consumer provides no config. */
4
+ export default defineConfig({
5
+ colors: {
6
+ primary: { light: '#2d4bb8', dark: '#8aa2ff' },
7
+ neutral: { light: '#4b5263', dark: '#a3a9b8' },
8
+ success: { light: '#15803d', dark: '#4ade80' },
9
+ warning: { light: '#b45309', dark: '#fbbf24' },
10
+ danger: { light: '#dc2626', dark: '#f87171' },
11
+ info: { light: '#0369a1', dark: '#38bdf8' },
12
+ },
13
+ neutrals: {
14
+ bg: { light: '#f8f9fb', dark: '#0f1115' },
15
+ surface: { light: '#ffffff', dark: '#181b21' },
16
+ text: { light: '#101828', dark: '#e6e8ec' },
17
+ muted: { light: '#667085', dark: '#8b93a1' },
18
+ border: { light: '#d0d5dd', dark: '#2e333d' },
19
+ },
20
+ sizes: {
21
+ xs: { height: '1.75rem', paddingX: '0.625rem', fontSize: '0.75rem', iconSize: '0.75rem' },
22
+ sm: { height: '2rem', paddingX: '0.75rem', fontSize: '0.8125rem', iconSize: '0.875rem' },
23
+ md: { height: '2.5rem', paddingX: '1rem', fontSize: '0.875rem', iconSize: '1rem' },
24
+ lg: { height: '3rem', paddingX: '1.25rem', fontSize: '1rem', iconSize: '1.25rem' },
25
+ xl: { height: '3.5rem', paddingX: '1.5rem', fontSize: '1.125rem', iconSize: '1.5rem' },
26
+ },
27
+ radii: {
28
+ square: '0',
29
+ sm: '0.25rem',
30
+ md: '0.375rem',
31
+ lg: '0.5rem',
32
+ xl: '0.75rem',
33
+ rounded: '9999px',
34
+ },
35
+ variants: {
36
+ solid: { background: 'fill', border: 'color', text: 'on' },
37
+ soft: { background: 'tint', border: 'none', text: 'color' },
38
+ outline: { background: 'none', border: 'color', text: 'color' },
39
+ ghost: { background: 'none', border: 'none', text: 'color' },
40
+ },
41
+ spacing: {
42
+ xs: '0.25rem',
43
+ sm: '0.5rem',
44
+ md: '1rem',
45
+ lg: '1.5rem',
46
+ xl: '2rem',
47
+ },
48
+ shadows: {
49
+ sm: '0 1px 2px light-dark(rgb(0 0 0 / 0.08), rgb(0 0 0 / 0.5))',
50
+ md: '0 4px 12px light-dark(rgb(0 0 0 / 0.12), rgb(0 0 0 / 0.6))',
51
+ lg: '0 12px 32px light-dark(rgb(0 0 0 / 0.18), rgb(0 0 0 / 0.7))',
52
+ },
53
+ density: {
54
+ compact: { paddingX: '0.5rem', paddingY: '0.25rem', fontSize: '0.8125rem' },
55
+ comfortable: { paddingX: '0.75rem', paddingY: '0.625rem', fontSize: '0.875rem' },
56
+ },
57
+ modalSizes: {
58
+ sm: '24rem',
59
+ md: '32rem',
60
+ lg: '48rem',
61
+ xl: '64rem',
62
+ full: '100vw',
63
+ },
64
+ typography: {
65
+ families: {
66
+ sans: 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
67
+ mono: 'ui-monospace, "SF Mono", Menlo, Consolas, monospace',
68
+ },
69
+ styles: {
70
+ display: { family: 'sans', size: '2.25rem', weight: 800, lineHeight: 1.1, letterSpacing: '-0.02em' },
71
+ heading: { family: 'sans', size: '1.5rem', weight: 700, lineHeight: 1.25, letterSpacing: '-0.01em' },
72
+ subheading: { family: 'sans', size: '1.125rem', weight: 600, lineHeight: 1.35 },
73
+ body: { family: 'sans', size: '1rem', weight: 400, lineHeight: 1.5 },
74
+ caption: { family: 'sans', size: '0.8125rem', weight: 400, lineHeight: 1.4 },
75
+ code: { family: 'mono', size: '0.875rem', weight: 400, lineHeight: 1.5 },
76
+ label: { family: 'sans', size: '0.875rem', weight: 500, lineHeight: 1.4 },
77
+ },
78
+ headings: { h1: 'display', h2: 'heading', h3: 'subheading', h4: 'subheading', h5: 'label', h6: 'label' },
79
+ },
80
+ zIndex: { dropdown: 1000, tooltip: 1100, dialog: 1200, toast: 1300 },
81
+ motion: { fast: '120ms', base: '200ms', easing: 'cubic-bezier(0.2, 0, 0, 1)' },
82
+ timing: { tooltipDelay: 400, hoverOpenDelay: 300, hoverCloseDelay: 150, toastDuration: 5000 },
83
+ borders: { width: '1px' },
84
+ focusRing: { width: '2px', offset: '2px', color: 'primary' },
85
+ defaults: {
86
+ size: 'md',
87
+ radius: 'md',
88
+ color: 'primary',
89
+ variant: 'solid',
90
+ errorColor: 'danger',
91
+ textStyle: 'body',
92
+ labelStyle: 'label',
93
+ helperStyle: 'caption',
94
+ gap: 'md',
95
+ padding: 'lg',
96
+ floatingShadow: 'md',
97
+ density: 'comfortable',
98
+ softVariant: 'soft',
99
+ modalSize: 'md',
100
+ },
101
+ components: {
102
+ Drawer: { size: 'sm' },
103
+ },
104
+ });