@brokenrubik/ui 0.0.0-stage → 0.1.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 (190) hide show
  1. package/README.md +264 -2
  2. package/dist/components/accordion.d.ts +13 -0
  3. package/dist/components/accordion.d.ts.map +1 -0
  4. package/dist/components/accordion.js +25 -0
  5. package/dist/components/accordion.js.map +1 -0
  6. package/dist/components/alert-dialog.d.ts +21 -0
  7. package/dist/components/alert-dialog.d.ts.map +1 -0
  8. package/dist/components/alert-dialog.js +46 -0
  9. package/dist/components/alert-dialog.js.map +1 -0
  10. package/dist/components/alert.d.ts +24 -0
  11. package/dist/components/alert.d.ts.map +1 -0
  12. package/dist/components/alert.js +42 -0
  13. package/dist/components/alert.js.map +1 -0
  14. package/dist/components/avatar.d.ts +27 -0
  15. package/dist/components/avatar.d.ts.map +1 -0
  16. package/dist/components/avatar.js +53 -0
  17. package/dist/components/avatar.js.map +1 -0
  18. package/dist/components/badge.d.ts +21 -0
  19. package/dist/components/badge.d.ts.map +1 -0
  20. package/dist/components/badge.js +40 -0
  21. package/dist/components/badge.js.map +1 -0
  22. package/dist/components/button.d.ts +18 -0
  23. package/dist/components/button.d.ts.map +1 -0
  24. package/dist/components/button.js +39 -0
  25. package/dist/components/button.js.map +1 -0
  26. package/dist/components/calendar.d.ts +13 -0
  27. package/dist/components/calendar.d.ts.map +1 -0
  28. package/dist/components/calendar.js +68 -0
  29. package/dist/components/calendar.js.map +1 -0
  30. package/dist/components/card.d.ts +15 -0
  31. package/dist/components/card.d.ts.map +1 -0
  32. package/dist/components/card.js +31 -0
  33. package/dist/components/card.js.map +1 -0
  34. package/dist/components/checkbox.d.ts +6 -0
  35. package/dist/components/checkbox.d.ts.map +1 -0
  36. package/dist/components/checkbox.js +12 -0
  37. package/dist/components/checkbox.js.map +1 -0
  38. package/dist/components/command.d.ts +24 -0
  39. package/dist/components/command.d.ts.map +1 -0
  40. package/dist/components/command.js +41 -0
  41. package/dist/components/command.js.map +1 -0
  42. package/dist/components/date-picker.d.ts +24 -0
  43. package/dist/components/date-picker.d.ts.map +1 -0
  44. package/dist/components/date-picker.js +18 -0
  45. package/dist/components/date-picker.js.map +1 -0
  46. package/dist/components/dialog.d.ts +23 -0
  47. package/dist/components/dialog.d.ts.map +1 -0
  48. package/dist/components/dialog.js +45 -0
  49. package/dist/components/dialog.js.map +1 -0
  50. package/dist/components/dropdown-menu.d.ts +34 -0
  51. package/dist/components/dropdown-menu.d.ts.map +1 -0
  52. package/dist/components/dropdown-menu.js +61 -0
  53. package/dist/components/dropdown-menu.js.map +1 -0
  54. package/dist/components/empty-state.d.ts +13 -0
  55. package/dist/components/empty-state.d.ts.map +1 -0
  56. package/dist/components/empty-state.js +25 -0
  57. package/dist/components/empty-state.js.map +1 -0
  58. package/dist/components/field.d.ts +24 -0
  59. package/dist/components/field.d.ts.map +1 -0
  60. package/dist/components/field.js +34 -0
  61. package/dist/components/field.js.map +1 -0
  62. package/dist/components/input.d.ts +17 -0
  63. package/dist/components/input.d.ts.map +1 -0
  64. package/dist/components/input.js +18 -0
  65. package/dist/components/input.js.map +1 -0
  66. package/dist/components/kbd.d.ts +14 -0
  67. package/dist/components/kbd.d.ts.map +1 -0
  68. package/dist/components/kbd.js +31 -0
  69. package/dist/components/kbd.js.map +1 -0
  70. package/dist/components/label.d.ts +6 -0
  71. package/dist/components/label.d.ts.map +1 -0
  72. package/dist/components/label.js +11 -0
  73. package/dist/components/label.js.map +1 -0
  74. package/dist/components/pagination.d.ts +18 -0
  75. package/dist/components/pagination.d.ts.map +1 -0
  76. package/dist/components/pagination.js +33 -0
  77. package/dist/components/pagination.js.map +1 -0
  78. package/dist/components/popover.d.ts +12 -0
  79. package/dist/components/popover.d.ts.map +1 -0
  80. package/dist/components/popover.js +29 -0
  81. package/dist/components/popover.js.map +1 -0
  82. package/dist/components/progress.d.ts +17 -0
  83. package/dist/components/progress.d.ts.map +1 -0
  84. package/dist/components/progress.js +26 -0
  85. package/dist/components/progress.js.map +1 -0
  86. package/dist/components/radio-group.d.ts +7 -0
  87. package/dist/components/radio-group.d.ts.map +1 -0
  88. package/dist/components/radio-group.js +14 -0
  89. package/dist/components/radio-group.js.map +1 -0
  90. package/dist/components/select.d.ts +20 -0
  91. package/dist/components/select.d.ts.map +1 -0
  92. package/dist/components/select.js +46 -0
  93. package/dist/components/select.js.map +1 -0
  94. package/dist/components/separator.d.ts +6 -0
  95. package/dist/components/separator.d.ts.map +1 -0
  96. package/dist/components/separator.js +11 -0
  97. package/dist/components/separator.js.map +1 -0
  98. package/dist/components/sheet.d.ts +19 -0
  99. package/dist/components/sheet.d.ts.map +1 -0
  100. package/dist/components/sheet.js +47 -0
  101. package/dist/components/sheet.js.map +1 -0
  102. package/dist/components/skeleton.d.ts +5 -0
  103. package/dist/components/skeleton.d.ts.map +1 -0
  104. package/dist/components/skeleton.js +9 -0
  105. package/dist/components/skeleton.js.map +1 -0
  106. package/dist/components/sonner.d.ts +13 -0
  107. package/dist/components/sonner.d.ts.map +1 -0
  108. package/dist/components/sonner.js +40 -0
  109. package/dist/components/sonner.js.map +1 -0
  110. package/dist/components/switch.d.ts +6 -0
  111. package/dist/components/switch.d.ts.map +1 -0
  112. package/dist/components/switch.js +11 -0
  113. package/dist/components/switch.js.map +1 -0
  114. package/dist/components/tabs.d.ts +13 -0
  115. package/dist/components/tabs.d.ts.map +1 -0
  116. package/dist/components/tabs.js +24 -0
  117. package/dist/components/tabs.js.map +1 -0
  118. package/dist/components/textarea.d.ts +5 -0
  119. package/dist/components/textarea.d.ts.map +1 -0
  120. package/dist/components/textarea.js +10 -0
  121. package/dist/components/textarea.js.map +1 -0
  122. package/dist/components/toggle-group.d.ts +11 -0
  123. package/dist/components/toggle-group.d.ts.map +1 -0
  124. package/dist/components/toggle-group.js +18 -0
  125. package/dist/components/toggle-group.js.map +1 -0
  126. package/dist/components/tooltip.d.ts +13 -0
  127. package/dist/components/tooltip.d.ts.map +1 -0
  128. package/dist/components/tooltip.js +24 -0
  129. package/dist/components/tooltip.js.map +1 -0
  130. package/dist/index.d.ts +34 -0
  131. package/dist/index.d.ts.map +1 -0
  132. package/dist/index.js +36 -0
  133. package/dist/index.js.map +1 -0
  134. package/dist/lib/tone.d.ts +8 -0
  135. package/dist/lib/tone.d.ts.map +1 -0
  136. package/dist/lib/tone.js +14 -0
  137. package/dist/lib/tone.js.map +1 -0
  138. package/dist/lib/utils.d.ts +20 -0
  139. package/dist/lib/utils.d.ts.map +1 -0
  140. package/dist/lib/utils.js +40 -0
  141. package/dist/lib/utils.js.map +1 -0
  142. package/dist/styles/base.css +37 -0
  143. package/dist/styles/fonts.css +16 -0
  144. package/dist/styles/styles.css +14 -0
  145. package/dist/styles/theme.css +170 -0
  146. package/dist/styles/tokens.css +228 -0
  147. package/docs/design-handoff.md +112 -0
  148. package/docs/figma-vs-tailwind.md +135 -0
  149. package/docs/visual-testing.md +156 -0
  150. package/package.json +97 -4
  151. package/src/components/accordion.tsx +66 -0
  152. package/src/components/alert-dialog.tsx +139 -0
  153. package/src/components/alert.tsx +87 -0
  154. package/src/components/avatar.tsx +105 -0
  155. package/src/components/badge.tsx +63 -0
  156. package/src/components/button.tsx +70 -0
  157. package/src/components/calendar.tsx +131 -0
  158. package/src/components/card.tsx +72 -0
  159. package/src/components/checkbox.tsx +31 -0
  160. package/src/components/command.tsx +149 -0
  161. package/src/components/date-picker.tsx +86 -0
  162. package/src/components/dialog.tsx +126 -0
  163. package/src/components/dropdown-menu.tsx +225 -0
  164. package/src/components/empty-state.tsx +63 -0
  165. package/src/components/field.tsx +79 -0
  166. package/src/components/input.tsx +49 -0
  167. package/src/components/kbd.tsx +48 -0
  168. package/src/components/label.tsx +22 -0
  169. package/src/components/pagination.tsx +94 -0
  170. package/src/components/popover.tsx +65 -0
  171. package/src/components/progress.tsx +52 -0
  172. package/src/components/radio-group.tsx +42 -0
  173. package/src/components/select.tsx +167 -0
  174. package/src/components/separator.tsx +29 -0
  175. package/src/components/sheet.tsx +112 -0
  176. package/src/components/skeleton.tsx +16 -0
  177. package/src/components/sonner.tsx +58 -0
  178. package/src/components/switch.tsx +27 -0
  179. package/src/components/tabs.tsx +56 -0
  180. package/src/components/textarea.tsx +17 -0
  181. package/src/components/toggle-group.tsx +42 -0
  182. package/src/components/tooltip.tsx +55 -0
  183. package/src/index.ts +35 -0
  184. package/src/lib/tone.ts +16 -0
  185. package/src/lib/utils.ts +46 -0
  186. package/src/styles/base.css +37 -0
  187. package/src/styles/fonts.css +16 -0
  188. package/src/styles/styles.css +14 -0
  189. package/src/styles/theme.css +170 -0
  190. package/src/styles/tokens.css +228 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAC7C,OAAO,EAAqC,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEzF;;;;GAIG;AACH,eAAO,MAAM,WAAW,YACtB,SAAS,EACT,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,SAAS,EACT,MAAM,EACN,SAAS,EACT,SAAS,EACT,UAAU,EACV,KAAK,EACL,WAAW,EACX,UAAU,EACV,aAAa,EACb,MAAM,EACN,SAAS,EACT,WAAW,EACX,QAAQ,EACR,UAAU,CACF,CAAC;AAEX,KAAK,WAAW,GAAG,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,eAIxB,UAAU,EAAE,YAChC;AAED,+EAA+E;AAC/E,eAAO,MAAM,EAAE,cAJM,UAAU,EAAE,WAIL,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { clsx } from 'clsx';
2
+ import { extendTailwindMerge, mergeConfigs } from 'tailwind-merge';
3
+ /**
4
+ * The BR text styles registered as `text-*` font sizes in theme.css. tailwind-merge must
5
+ * know them: by default it reads an unknown `text-foo` as a color, so `cn('text-body',
6
+ * 'text-muted-foreground')` would drop `text-body`.
7
+ */
8
+ export const brTextSizes = [
9
+ 'display',
10
+ 'page-title',
11
+ 'section',
12
+ 'card-title',
13
+ 'body-lg',
14
+ 'body',
15
+ 'body-sm',
16
+ 'caption',
17
+ 'overline',
18
+ 'nav',
19
+ 'nav-label',
20
+ 'initials',
21
+ 'initials-sm',
22
+ 'mono',
23
+ 'mono-sm',
24
+ 'doc-title',
25
+ 'doc-h2',
26
+ 'doc-body',
27
+ ];
28
+ /**
29
+ * Builds a `cn` for an app that adds its own scales on top of the BR theme (for example
30
+ * extra `text-*` sizes or `shadow-*` names), so tailwind-merge groups them right.
31
+ *
32
+ * export const cn = createCn({ extend: { theme: { text: ['hero'] } } });
33
+ */
34
+ export function createCn(config) {
35
+ const merge = extendTailwindMerge({ extend: { theme: { text: [...brTextSizes] } } }, (base) => config ? mergeConfigs(base, config) : base);
36
+ return (...inputs) => merge(clsx(inputs));
37
+ }
38
+ /** Joins class names and resolves Tailwind conflicts (the last class wins). */
39
+ export const cn = createCn();
40
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAwB,MAAM,gBAAgB,CAAC;AAEzF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS;IACT,YAAY;IACZ,SAAS;IACT,YAAY;IACZ,SAAS;IACT,MAAM;IACN,SAAS;IACT,SAAS;IACT,UAAU;IACV,KAAK;IACL,WAAW;IACX,UAAU;IACV,aAAa;IACb,MAAM;IACN,SAAS;IACT,WAAW;IACX,QAAQ;IACR,UAAU;CACF,CAAC;AAIX;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAoB;IAC3C,MAAM,KAAK,GAAG,mBAAmB,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAC5F,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAC3C,CAAC;IACF,OAAO,CAAC,GAAG,MAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,37 @@
1
+ /*
2
+ * @brokenrubik/ui — base styles (optional). Page defaults from the BR Admin Library:
3
+ * Body/Default (13/20 IBM Plex Sans) on --background, slate borders, balanced headings.
4
+ * Skip this file if the app sets its own base; tokens.css and theme.css work without it.
5
+ */
6
+ @layer base {
7
+ *,
8
+ ::before,
9
+ ::after {
10
+ border-color: var(--color-border);
11
+ outline-color: color-mix(in oklab, var(--color-ring) 50%, transparent);
12
+ }
13
+
14
+ html {
15
+ font-family: var(--font-sans);
16
+ }
17
+
18
+ body {
19
+ background-color: var(--color-background);
20
+ color: var(--color-foreground);
21
+ font-size: var(--text-body);
22
+ line-height: var(--text-body--line-height);
23
+ -webkit-font-smoothing: antialiased;
24
+ -moz-osx-font-smoothing: grayscale;
25
+ text-rendering: optimizeLegibility;
26
+ }
27
+
28
+ h1,
29
+ h2,
30
+ h3 {
31
+ text-wrap: balance;
32
+ }
33
+
34
+ p {
35
+ text-wrap: pretty;
36
+ }
37
+ }
@@ -0,0 +1,16 @@
1
+ /*
2
+ * @brokenrubik/ui — fonts: IBM Plex Sans 400/500/600 and IBM Plex Mono 400/500 (the weights
3
+ * the BR Admin Library uses). styles.css imports this file, so apps get the fonts with no
4
+ * extra setup. The font files come from the @fontsource packages (dependencies of this
5
+ * package); the app's bundler copies them. Each @font-face has a unicode-range, so the
6
+ * browser downloads only the subsets (latin, latin-ext…) that the page uses.
7
+ *
8
+ * The families are "IBM Plex Sans" and "IBM Plex Mono", the default of --font-sans and
9
+ * --font-mono in theme.css. An app that loads the fonts in a different way (next/font) can
10
+ * set --font-plex-sans / --font-plex-mono; these faces are then never downloaded.
11
+ */
12
+ @import "@fontsource/ibm-plex-sans/400.css";
13
+ @import "@fontsource/ibm-plex-sans/500.css";
14
+ @import "@fontsource/ibm-plex-sans/600.css";
15
+ @import "@fontsource/ibm-plex-mono/400.css";
16
+ @import "@fontsource/ibm-plex-mono/500.css";
@@ -0,0 +1,14 @@
1
+ /*
2
+ * @brokenrubik/ui — everything: fonts, tokens, Tailwind theme, animations, base styles.
3
+ *
4
+ * @import "tailwindcss";
5
+ * @import "@brokenrubik/ui/styles.css";
6
+ *
7
+ * Need less? Import the parts: fonts.css (IBM Plex), tokens.css (CSS variables only),
8
+ * theme.css (Tailwind mapping), base.css (page defaults). Components need tokens.css + theme.css + tw-animate-css.
9
+ */
10
+ @import "./fonts.css";
11
+ @import "tw-animate-css";
12
+ @import "./tokens.css";
13
+ @import "./theme.css";
14
+ @import "./base.css";
@@ -0,0 +1,170 @@
1
+ /*
2
+ * @brokenrubik/ui — Tailwind v4 theme.
3
+ *
4
+ * Maps the tokens (tokens.css) to Tailwind utilities and sets the BR Admin Library scales
5
+ * (radius, shadow, type). Import it after `tailwindcss`:
6
+ *
7
+ * @import "tailwindcss";
8
+ * @import "@brokenrubik/ui/styles.css"; // tokens + theme + base (or this file alone)
9
+ *
10
+ * Tailwind v4 has no JS config to inherit: this file IS the shared config. To extend or
11
+ * change it in an app, add your own `@theme { … }` block after the import. A later
12
+ * declaration of the same variable wins.
13
+ */
14
+
15
+ /* The components live in this package; let the app's Tailwind find their classes. */
16
+ @source "../";
17
+
18
+ /* `dark:` follows the `.dark` class on <html> (all BR apps), not the OS preference. */
19
+ @custom-variant dark (&:where(.dark, .dark *));
20
+
21
+ @theme inline {
22
+ --color-background: var(--background);
23
+ --color-foreground: var(--foreground);
24
+ --color-card: var(--card);
25
+ --color-card-foreground: var(--card-foreground);
26
+ --color-popover: var(--popover);
27
+ --color-popover-foreground: var(--popover-foreground);
28
+
29
+ --color-primary: var(--primary);
30
+ --color-primary-foreground: var(--primary-foreground);
31
+ --color-primary-strong: var(--primary-strong);
32
+ --color-primary-tint: var(--primary-tint);
33
+
34
+ --color-secondary: var(--secondary);
35
+ --color-secondary-foreground: var(--secondary-foreground);
36
+ --color-muted: var(--muted);
37
+ --color-muted-foreground: var(--muted-foreground);
38
+ --color-accent: var(--accent);
39
+ --color-accent-foreground: var(--accent-foreground);
40
+
41
+ --color-destructive: var(--destructive);
42
+ --color-destructive-foreground: var(--destructive-foreground);
43
+ --color-destructive-strong: var(--destructive-strong);
44
+ --color-destructive-tint: var(--destructive-tint);
45
+ --color-success: var(--success);
46
+ --color-success-strong: var(--success-strong);
47
+ --color-success-tint: var(--success-tint);
48
+ --color-warning: var(--warning);
49
+ --color-warning-strong: var(--warning-strong);
50
+ --color-warning-tint: var(--warning-tint);
51
+ --color-info: var(--info);
52
+ --color-info-strong: var(--info-strong);
53
+ --color-info-tint: var(--info-tint);
54
+
55
+ --color-highlight: var(--highlight);
56
+ --color-highlight-foreground: var(--highlight-foreground);
57
+ --color-brand-coral: var(--brand-coral);
58
+
59
+ --color-border: var(--border);
60
+ --color-input: var(--input);
61
+ --color-ring: var(--ring);
62
+ --color-overlay: var(--overlay);
63
+ --color-surface-subtle: var(--surface-subtle);
64
+
65
+ --color-chart-1: var(--chart-1);
66
+ --color-chart-2: var(--chart-2);
67
+ --color-chart-3: var(--chart-3);
68
+ --color-chart-4: var(--chart-4);
69
+ --color-chart-5: var(--chart-5);
70
+
71
+ --color-sidebar: var(--sidebar);
72
+ --color-sidebar-foreground: var(--sidebar-foreground);
73
+ --color-sidebar-muted-foreground: var(--sidebar-muted-foreground);
74
+ --color-sidebar-label: var(--sidebar-label);
75
+ --color-sidebar-primary: var(--sidebar-primary);
76
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
77
+ --color-sidebar-accent: var(--sidebar-accent);
78
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
79
+ --color-sidebar-accent-strong: var(--sidebar-accent-strong);
80
+ --color-sidebar-border: var(--sidebar-border);
81
+ --color-sidebar-ring: var(--sidebar-ring);
82
+
83
+ --color-app-proma: var(--app-proma);
84
+ --color-app-folio: var(--app-folio);
85
+ --color-app-docubuilder: var(--app-docubuilder);
86
+ --color-app-timma: var(--app-timma);
87
+ --color-app-mara: var(--app-mara);
88
+
89
+ /* Figma radius/*: xs 4 · sm 5 · md 6 · lg 8 · xl 12 · full. One knob: --radius. */
90
+ --radius-xs: calc(var(--radius) - 4px);
91
+ --radius-sm: calc(var(--radius) - 3px);
92
+ --radius-md: calc(var(--radius) - 2px);
93
+ --radius-lg: var(--radius);
94
+ --radius-xl: calc(var(--radius) + 4px);
95
+
96
+ /* IBM Plex: fonts.css (in styles.css) loads "IBM Plex Sans" / "IBM Plex Mono". An app that
97
+ loads the fonts another way (next/font) sets --font-plex-sans / --font-plex-mono. */
98
+ --font-sans: var(--font-plex-sans, "IBM Plex Sans"), ui-sans-serif, system-ui, sans-serif;
99
+ --font-mono: var(--font-plex-mono, "IBM Plex Mono"), ui-monospace, SFMono-Regular, Menlo, monospace;
100
+ }
101
+
102
+ @theme {
103
+ /* Figma effect styles Shadow/xs, Shadow/md, Shadow/lg (slate-900 based). */
104
+ --shadow-xs: 0 1px 2px 0 rgb(15 23 42 / 0.05);
105
+ --shadow-md: 0 4px 12px -2px rgb(15 23 42 / 0.08), 0 2px 4px -2px rgb(15 23 42 / 0.05);
106
+ --shadow-lg: 0 16px 32px -8px rgb(15 23 42 / 0.16), 0 4px 8px -4px rgb(15 23 42 / 0.06);
107
+
108
+ /*
109
+ * Figma text styles as `text-*` utilities (size + line height + letter spacing + weight).
110
+ * A dense admin scale on a 13 px base. Tailwind's own text-xs … text-9xl stay available.
111
+ * "… Medium" styles: add `font-medium`.
112
+ */
113
+ --text-display: 32px; /* Heading/Display */
114
+ --text-display--line-height: 40px;
115
+ --text-display--letter-spacing: -0.48px;
116
+ --text-display--font-weight: 600;
117
+ --text-page-title: 20px; /* Heading/Page title */
118
+ --text-page-title--line-height: 28px;
119
+ --text-page-title--letter-spacing: -0.4px;
120
+ --text-page-title--font-weight: 600;
121
+ --text-section: 15px; /* Heading/Section */
122
+ --text-section--line-height: 20px;
123
+ --text-section--letter-spacing: -0.2px;
124
+ --text-section--font-weight: 600;
125
+ --text-card-title: 14px; /* Heading/Card */
126
+ --text-card-title--line-height: 20px;
127
+ --text-card-title--letter-spacing: -0.1px;
128
+ --text-card-title--font-weight: 600;
129
+ --text-body-lg: 15px; /* Body/Large */
130
+ --text-body-lg--line-height: 22px;
131
+ --text-body: 13px; /* Body/Default */
132
+ --text-body--line-height: 20px;
133
+ --text-body-sm: 12px; /* Body/Small */
134
+ --text-body-sm--line-height: 16px;
135
+ --text-caption: 11px; /* Label/Caption */
136
+ --text-caption--line-height: 16px;
137
+ --text-overline: 11px; /* Label/Overline (add `uppercase`) */
138
+ --text-overline--line-height: 16px;
139
+ --text-overline--letter-spacing: 0.4px;
140
+ --text-overline--font-weight: 500;
141
+ --text-nav: 14px; /* Nav/Item */
142
+ --text-nav--line-height: 20px;
143
+ --text-nav--letter-spacing: -0.15px;
144
+ --text-nav--font-weight: 500;
145
+ --text-nav-label: 12px; /* Nav/Group label */
146
+ --text-nav-label--line-height: 16px;
147
+ --text-nav-label--font-weight: 500;
148
+ --text-initials: 11px; /* Label/Initials */
149
+ --text-initials--line-height: 16px;
150
+ --text-initials--letter-spacing: 0.2px;
151
+ --text-initials--font-weight: 600;
152
+ --text-initials-sm: 8px; /* Label/Initials small */
153
+ --text-initials-sm--line-height: 12px;
154
+ --text-initials-sm--letter-spacing: 0.2px;
155
+ --text-initials-sm--font-weight: 600;
156
+ --text-mono: 12px; /* Mono/Default (with font-mono) */
157
+ --text-mono--line-height: 16px;
158
+ --text-mono-sm: 11px; /* Mono/Small (with font-mono) */
159
+ --text-mono-sm--line-height: 16px;
160
+ --text-doc-title: 36px; /* Doc/Title */
161
+ --text-doc-title--line-height: 44px;
162
+ --text-doc-title--letter-spacing: -0.72px;
163
+ --text-doc-title--font-weight: 600;
164
+ --text-doc-h2: 20px; /* Doc/H2 */
165
+ --text-doc-h2--line-height: 28px;
166
+ --text-doc-h2--letter-spacing: -0.2px;
167
+ --text-doc-h2--font-weight: 600;
168
+ --text-doc-body: 15px; /* Doc/Body */
169
+ --text-doc-body--line-height: 26px;
170
+ }
@@ -0,0 +1,228 @@
1
+ /*
2
+ * @brokenrubik/ui — design tokens (BR Admin Library, Figma file ONZyUryZr526mtbex2HVPk).
3
+ *
4
+ * Plain CSS custom properties, no Tailwind needed: an app without Tailwind (or app-shell)
5
+ * can import only this file. Names match shadcn/ui, so `var(--primary)` here is `primary`
6
+ * in Figma (every Theme variable has the code syntax var(--name)). Modes of the Figma
7
+ * "Theme" collection:
8
+ * Light → :root
9
+ * Dark → .dark (class on <html>)
10
+ * Light · Sidebar claro → .sidebar-light on <html>
11
+ * Dark · Sidebar claro → .dark.sidebar-light on <html>
12
+ *
13
+ * Every color is a Figma variable. Values read from Figma on 2026-11-11 through the Figma
14
+ * MCP (all 58 Theme variables, all modes). Check again: scripts/figma-sync.mjs.
15
+ * --radius is not a Figma variable: the Figma Radius collection (4/5/6/8/12) is derived from it
16
+ * in theme.css.
17
+ *
18
+ * Override any token in the app, after this file: :root { --primary: #7c3aed; }
19
+ */
20
+
21
+ :root {
22
+ color-scheme: light;
23
+
24
+ /* Radius scale base: lg = radius, md = -2px, sm = -3px, xs = -4px, xl = +4px
25
+ → 8 / 6 / 5 / 4 / 12 px, as Figma's radius/* variables. */
26
+ --radius: 0.5rem;
27
+
28
+ /* Surfaces */
29
+ --background: #ffffff;
30
+ --foreground: #0f172a;
31
+ --card: #ffffff;
32
+ --card-foreground: #0f172a;
33
+ --popover: #ffffff;
34
+ --popover-foreground: #0f172a;
35
+
36
+ /* BR violet: the click color. Never use --primary for text: use --primary-strong. */
37
+ --primary: #9547ff;
38
+ --primary-foreground: #ffffff;
39
+ --primary-strong: #6b1fd0;
40
+ --primary-tint: #f4edff;
41
+
42
+ /* Neutrals (shadcn meaning: secondary and accent are slate, not brand) */
43
+ --secondary: #f1f5f9;
44
+ --secondary-foreground: #0f172a;
45
+ --muted: #f1f5f9;
46
+ --muted-foreground: #64748b;
47
+ --accent: #f1f5f9;
48
+ --accent-foreground: #0f172a;
49
+
50
+ /* States: base for dots and bars, -strong for text and icons, -tint for soft fills */
51
+ --destructive: #dc2626;
52
+ --destructive-foreground: #ffffff;
53
+ --destructive-strong: #dc2626;
54
+ --destructive-tint: #fef2f2;
55
+ --success: #10b981;
56
+ --success-strong: #047857;
57
+ --success-tint: #ecfdf5;
58
+ --warning: #f59e0b;
59
+ --warning-strong: #b45309;
60
+ --warning-tint: #fffbeb;
61
+ --info: #3b82f6;
62
+ --info-strong: #1d4ed8;
63
+ --info-tint: #eff6ff;
64
+
65
+ /* BR lime: "you are here" only (active nav item, active space chip). Never body text. */
66
+ --highlight: #dff95f;
67
+ --highlight-foreground: #0f172a;
68
+ /* Marketing and illustration only, never in product UI. */
69
+ --brand-coral: #ff707a;
70
+
71
+ /* Lines and focus */
72
+ --border: #e2e8f0;
73
+ /* Form-control borders: 3:1 against white (WCAG 2.2 non-text contrast). */
74
+ --input: #8391a7;
75
+ --ring: #9547ff;
76
+ /* The dialog and sheet backdrop. */
77
+ --overlay: rgb(0 0 0 / 0.5);
78
+ /* A slightly raised page area (Figma surface-subtle). */
79
+ --surface-subtle: #fbfdfd;
80
+
81
+ /* Data series */
82
+ --chart-1: #9547ff;
83
+ --chart-2: #64748b;
84
+ --chart-3: #c4a6ff;
85
+ --chart-4: #cbd5e1;
86
+ --chart-5: #6b1fd0;
87
+
88
+ /* Sidebar and App Rail: navy in both themes */
89
+ --sidebar: #0f172a;
90
+ --sidebar-foreground: #ffffff;
91
+ --sidebar-muted-foreground: #cbd5e1;
92
+ --sidebar-label: #94a3b8;
93
+ --sidebar-primary: #dff95f;
94
+ --sidebar-primary-foreground: #0f172a;
95
+ --sidebar-accent: rgb(255 255 255 / 0.08);
96
+ --sidebar-accent-foreground: #ffffff;
97
+ /* A stronger hover/selected fill on the sidebar. */
98
+ --sidebar-accent-strong: rgb(255 255 255 / 0.15);
99
+ --sidebar-border: rgb(255 255 255 / 0.1);
100
+ --sidebar-ring: #a875ff;
101
+
102
+ /* App identity (Brand · Product family): logo, app icon, App Rail only. */
103
+ --app-proma: #3e63dd;
104
+ --app-folio: #0d9488;
105
+ --app-docubuilder: #9d3f8c;
106
+ --app-timma: #c2581c;
107
+ --app-mara: #2f855a;
108
+ }
109
+
110
+ .dark {
111
+ color-scheme: dark;
112
+
113
+ --background: #0f172a;
114
+ --foreground: #e2e8f0;
115
+ --card: #162032;
116
+ --card-foreground: #e2e8f0;
117
+ --popover: #162032;
118
+ --popover-foreground: #e2e8f0;
119
+
120
+ --primary: #9547ff;
121
+ --primary-foreground: #ffffff;
122
+ --primary-strong: #a875ff;
123
+ --primary-tint: rgb(149 71 255 / 0.2);
124
+
125
+ --secondary: #1e293b;
126
+ --secondary-foreground: #f8fafc;
127
+ --muted: #1e293b;
128
+ --muted-foreground: #94a3b8;
129
+ --accent: rgb(255 255 255 / 0.05);
130
+ --accent-foreground: #f8fafc;
131
+
132
+ --destructive: #dc2626;
133
+ --destructive-foreground: #ffffff;
134
+ --destructive-strong: #f87171;
135
+ --destructive-tint: rgb(239 68 68 / 0.15);
136
+ --success: #10b981;
137
+ --success-strong: #34d399;
138
+ --success-tint: rgb(16 185 129 / 0.15);
139
+ --warning: #f59e0b;
140
+ --warning-strong: #fbbf24;
141
+ --warning-tint: rgb(245 158 11 / 0.15);
142
+ --info: #3b82f6;
143
+ --info-strong: #60a5fa;
144
+ --info-tint: rgb(59 130 246 / 0.15);
145
+
146
+ --highlight: #dff95f;
147
+ --highlight-foreground: #0f172a;
148
+
149
+ --border: rgb(255 255 255 / 0.1);
150
+ --input: #64748b;
151
+ --ring: #9547ff;
152
+ --overlay: rgb(0 0 0 / 0.6);
153
+ --surface-subtle: #0f172a;
154
+
155
+ --chart-2: #94a3b8;
156
+ --chart-4: #475569;
157
+ --chart-5: #a875ff;
158
+
159
+ --sidebar: #0b1120;
160
+ --sidebar-foreground: #e2e8f0;
161
+
162
+ --app-proma: #5b7bea;
163
+ --app-folio: #14a89a;
164
+ --app-docubuilder: #b65aa5;
165
+ --app-timma: #e07a3e;
166
+ --app-mara: #48a878;
167
+ }
168
+
169
+ /* Sidebar claro: a personal choice, in the light and the dark theme. Only sidebar-* change. */
170
+ :root.sidebar-light {
171
+ --sidebar: #f1f5f9;
172
+ --sidebar-foreground: #0f172a;
173
+ --sidebar-muted-foreground: #334155;
174
+ --sidebar-label: #64748b;
175
+ --sidebar-primary: #9547ff;
176
+ --sidebar-primary-foreground: #ffffff;
177
+ --sidebar-accent: #ffffff;
178
+ --sidebar-accent-foreground: #0f172a;
179
+ --sidebar-accent-strong: #e2e8f0;
180
+ --sidebar-border: #e2e8f0;
181
+ --sidebar-ring: #9547ff;
182
+ }
183
+
184
+ /* Dark · Sidebar claro: the app identity colors sit on the light sidebar, so they keep
185
+ their light values. */
186
+ :root.dark.sidebar-light {
187
+ --app-proma: #3e63dd;
188
+ --app-folio: #0d9488;
189
+ --app-docubuilder: #9d3f8c;
190
+ --app-timma: #c2581c;
191
+ --app-mara: #2f855a;
192
+ }
193
+
194
+ /*
195
+ * Put .sidebar-surface on the sidebar element: inside it the shared tokens point at the
196
+ * sidebar-* ones, so every component reads right on navy (or on the light sidebar)
197
+ * without per-component styles. Menus and dialogs render in portals and keep the page theme.
198
+ */
199
+ .sidebar-surface {
200
+ color-scheme: dark;
201
+ --background: var(--sidebar);
202
+ --card: #1e293b;
203
+ --foreground: var(--sidebar-foreground);
204
+ --muted: rgb(255 255 255 / 0.06);
205
+ --muted-foreground: var(--sidebar-label);
206
+ --accent: var(--sidebar-accent);
207
+ --accent-foreground: var(--sidebar-accent-foreground);
208
+ --primary: var(--sidebar-primary);
209
+ --primary-foreground: var(--sidebar-primary-foreground);
210
+ --primary-strong: var(--sidebar-primary);
211
+ --primary-tint: var(--sidebar-accent);
212
+ --border: var(--sidebar-border);
213
+ --input: rgb(255 255 255 / 0.12);
214
+ --ring: var(--sidebar-ring);
215
+ --success-strong: #34d399;
216
+ --destructive-strong: #f87171;
217
+ --warning-strong: #fbbf24;
218
+ }
219
+
220
+ :root.sidebar-light .sidebar-surface {
221
+ color-scheme: light;
222
+ --card: #ffffff;
223
+ --muted: #e2e8f0;
224
+ --input: #cbd5e1;
225
+ --success-strong: #047857;
226
+ --destructive-strong: #dc2626;
227
+ --warning-strong: #b45309;
228
+ }
@@ -0,0 +1,112 @@
1
+ # Design handoff: requests for the BR Admin Library
2
+
3
+ For: the designer who owns the Figma file *BR Admin Library* (`ONZyUryZr526mtbex2HVPk`).
4
+ From: the `@brokenrubik/ui` package, which builds the components from this file.
5
+ Date: 2026-11-11.
6
+
7
+ The code reads the Figma file to check that the apps look the same as Figma. These changes make
8
+ Figma and the code use the same names and the same values. Then a developer, or an AI agent,
9
+ can go from a Figma layer to the code without a translation table.
10
+
11
+ ## Status
12
+
13
+ | Part | Status |
14
+ | --- | --- |
15
+ | 1. Color variables | **Done (2026-11-11).** All 58 Theme variables have the code syntax `var(--name)` and a swatch on Foundations. The code now uses the exact Figma values in all 4 modes. |
16
+ | 2. Confirm dark values | **Done (2026-11-11).** Read from the variables through the Figma MCP. |
17
+ | 3. Component and property names | **Open.** See below. |
18
+
19
+ ### What changed in the code after parts 1 and 2
20
+
21
+ The code follows Figma. These values changed in `src/styles/tokens.css`:
22
+
23
+ - `info`: `#3B82F6` (blue/500) in light and dark.
24
+ - `overlay`: black at 50 % (light) and 60 % (dark).
25
+ - `sidebar-ring`: `#A875FF` (violet-400) on the navy sidebar, `#9547FF` on the light sidebar.
26
+ - New: `surface-subtle`, `sidebar-accent-strong`, and the mode *Dark · Sidebar claro*.
27
+
28
+ When you add or change a variable, keep the code syntax `var(--name)` and the swatch. A
29
+ developer then reads all values through the Figma MCP (`scripts/figma/read-variables.js`) and
30
+ the CI check shows every difference.
31
+
32
+ ## Part 3: Rename components and properties to the code names
33
+
34
+ The code uses the shadcn/ui names. When Figma uses the same names, Dev Mode, the layer panel and
35
+ the code all say the same thing.
36
+
37
+ ### Rules (use them for every component, also for future ones)
38
+
39
+ 1. **Component set name = the code component name**, in PascalCase, without spaces:
40
+ `DropdownMenuItem`, not "Menu Item". The table below has each name.
41
+ 2. **Property name = the code prop name**, in lowercase: `variant`, `size`, `tone`,
42
+ `orientation`.
43
+ 3. **Property value = the code value**, in lowercase: `default`, `outline`, `sm`. The main
44
+ style is called `default` (not "Primary"), as in shadcn.
45
+ 4. **A yes/no property** is a variant property with the values `false` and `true` (Figma then
46
+ shows a toggle): `checked=true`, `disabled=true`.
47
+ 5. **An interaction state that is not a prop** (hover, focus, open) stays as a property called
48
+ `state`, with lowercase values: `state=hover`, `state=focus`.
49
+ 6. **Text and boolean component properties** (Label, Show icon…) do not change. They are only
50
+ example content.
51
+
52
+ Renaming in Figma is safe. Instances keep their link and their selected variants.
53
+
54
+ ### Table
55
+
56
+ Only the parts that change are listed. Anything not in the table stays as it is today.
57
+
58
+ | Figma today | Rename the set to | Property changes |
59
+ | --- | --- | --- |
60
+ | Button | `Button` | `Variant` → `variant`: Primary → `default`, Secondary → `secondary`, Outline → `outline`, Ghost → `ghost`, Destructive → `destructive`. `Size` → `size`: md → `default`, sm → `sm` |
61
+ | Icon Button | merge into `Button` | In code, an icon button is a `Button` with `size="icon"`. Move the 4 variants into the Button set as `size` = `icon` (md) and `icon-sm` (sm), with `variant` = `ghost` or `outline`. If you prefer a separate set, name it `Button/Icon`. |
62
+ | Badge | `Badge` | `Tone` → `variant`: lowercase values (`neutral`, `primary`, `success`, `warning`, `destructive`, `highlight`, `info`) |
63
+ | Avatar | `Avatar` | `Size` → `size`. `Tone` → `tone`: lowercase values; Photo → `image` |
64
+ | Key Chip | `Kbd` | `Variant` → `variant`: `highlight`, `muted`. `Size` → `size` |
65
+ | Input | `Input` | `State` → `state`: `default`, `focus`, `disabled` |
66
+ | Tab | `TabsTrigger` | `State` → `state`: Active → `active`, Inactive → `inactive` |
67
+ | Switch | `Switch` | `State` → `checked`: Off → `false`, On → `true` |
68
+ | Menu Item | `DropdownMenuItem` | `State` → `state`: `default`, `hover` |
69
+ | Tooltip | `Tooltip` | `Side` → `side`: `top` |
70
+ | Checkbox | `Checkbox` | `State` → `checked`: Unchecked → `false`, Checked → `true` |
71
+ | Select | `Select` | `State` → `state`: lowercase |
72
+ | Textarea | `Textarea` | `State` → `state`: lowercase |
73
+ | Date Picker | `DatePicker` | `State` → `state`: lowercase |
74
+ | Calendar Day | `CalendarDay` | `State` → `state`: lowercase |
75
+ | Radio | `RadioGroupItem` | `State` → split into `checked` (`false`, `true`) and `disabled` (`false`, `true`) |
76
+ | Form Field | `Field` | `State` → split into `invalid` (`false`, `true`) and `disabled` (`false`, `true`) |
77
+ | Dropdown Menu | `DropdownMenu` | — |
78
+ | Dialog | `Dialog` | `Type` → `variant`: `default`, `destructive` (in code, the destructive one is `AlertDialog`) |
79
+ | Alert | `Alert` | `Tone` → `variant`: lowercase (`info`, `success`, `warning`, `destructive`) |
80
+ | Toast | `Toast` | `Tone` → `type`: Default → `default`, Success → `success`, Destructive → `error` |
81
+ | Progress | `Progress` | `Tone` → `variant`: lowercase |
82
+ | Skeleton | `Skeleton` | `Shape` → `shape`: lowercase |
83
+ | Empty State | `EmptyState` | — |
84
+ | Separator | `Separator` | `Orientation` → `orientation`: lowercase |
85
+ | Toggle Group Item | `ToggleGroupItem` | `State` → `state`: Off → `off`, On → `on` |
86
+ | Toggle Group | `ToggleGroup` | — |
87
+ | Pagination Item | `PaginationLink` | `State` → `isActive`: Default → `false`, Active → `true` |
88
+ | Pagination | `Pagination` | — |
89
+ | Accordion Item | `AccordionItem` | `State` → `state`: Closed → `closed`, Open → `open` |
90
+
91
+ Badge, Alert and Progress use `variant` because the code accepts `variant` and `tone` as the
92
+ same prop, and shadcn uses `variant`. Avatar keeps `tone`, because there `variant` would mean
93
+ nothing to a developer.
94
+
95
+ ### Before you rename
96
+
97
+ Tell the developers the day before. The visual test in the code finds components by their Figma
98
+ names. After the rename, a developer runs `pnpm figma:pull` and updates the names in the test
99
+ (`playground/src/spec/Spec.tsx`) in the same pull request. If you rename without notice, the
100
+ weekly *Figma drift* check fails, which is safe but noisy.
101
+
102
+ ## How to tell the developers about a future change
103
+
104
+ 1. Make the change in Figma.
105
+ 2. Open an issue in `BrokenRubik/ui` (or post in the team channel) with:
106
+ - the link to the changed node (right-click → *Copy link to selection*),
107
+ - one line per change: "Badge · Tone=Info: text is now `info-strong`".
108
+ 3. A developer updates the code, runs the visual test, and sends you the link to the docs site
109
+ to check.
110
+
111
+ Every Monday, the *Figma drift* check compares the code with Figma and reports any difference,
112
+ so a change that nobody announces is still found within a week.