@robomous/ui-core 0.1.1 → 0.2.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 (135) hide show
  1. package/README.md +15 -7
  2. package/dist/{primitives → components}/alert.js +1 -1
  3. package/dist/{primitives → components}/badge.js +1 -1
  4. package/dist/{primitives → components}/button.d.ts +1 -1
  5. package/dist/{primitives → components}/button.js +4 -1
  6. package/dist/{primitives → components}/card.d.ts +1 -1
  7. package/dist/{primitives → components}/card.js +2 -2
  8. package/dist/{primitives → components}/combobox.js +3 -3
  9. package/dist/{primitives → components}/dialog.js +1 -1
  10. package/dist/{primitives → components}/dropdown-menu.js +11 -6
  11. package/dist/{primitives → components}/field.js +2 -4
  12. package/dist/{primitives → components}/input-group.js +1 -1
  13. package/dist/{primitives → components}/input.js +1 -1
  14. package/dist/{primitives → components}/label.js +1 -1
  15. package/dist/components/progress.js +7 -0
  16. package/dist/{primitives → components}/select.d.ts +3 -1
  17. package/dist/{primitives → components}/select.js +6 -4
  18. package/dist/{primitives → components}/separator.js +1 -1
  19. package/dist/{primitives → components}/sheet.js +1 -1
  20. package/dist/{primitives → components}/skeleton.js +1 -1
  21. package/dist/{primitives → components}/sonner.js +17 -12
  22. package/dist/{primitives → components}/table.d.ts +1 -1
  23. package/dist/{primitives → components}/table.js +3 -3
  24. package/dist/{primitives → components}/tabs.js +1 -1
  25. package/dist/{primitives → components}/textarea.js +1 -1
  26. package/dist/{primitives → components}/tooltip.js +1 -1
  27. package/dist/gates/index.d.ts +28 -0
  28. package/dist/gates/index.js +142 -0
  29. package/dist/index.d.ts +31 -32
  30. package/dist/index.js +32 -33
  31. package/dist/{tokens.d.ts → theme/tokens.d.ts} +5 -5
  32. package/dist/{tokens.js → theme/tokens.js} +12 -12
  33. package/package.json +23 -12
  34. package/{shadcn → src/components}/alert.tsx +14 -21
  35. package/src/{primitives → components}/badge.tsx +15 -21
  36. package/src/{primitives → components}/button.tsx +13 -10
  37. package/{shadcn → src/components}/card.tsx +16 -31
  38. package/src/{primitives → components}/combobox.test.tsx +15 -2
  39. package/src/{primitives → components}/combobox.tsx +45 -74
  40. package/src/{primitives/primitives.test.tsx → components/components.test.tsx} +106 -69
  41. package/src/{primitives → components}/dialog.tsx +31 -54
  42. package/src/{primitives → components}/dropdown-menu.tsx +51 -65
  43. package/src/{primitives → components}/field.tsx +48 -62
  44. package/src/{primitives → components}/input-group.tsx +37 -49
  45. package/{shadcn → src/components}/input.tsx +5 -5
  46. package/{shadcn → src/components}/label.tsx +7 -10
  47. package/src/{primitives → components}/progress.tsx +7 -6
  48. package/{shadcn → src/components}/select.tsx +39 -41
  49. package/{shadcn → src/components}/separator.tsx +7 -7
  50. package/src/{primitives → components}/sheet.tsx +27 -44
  51. package/{shadcn → src/components}/skeleton.tsx +3 -3
  52. package/src/{primitives → components}/sonner.test.tsx +12 -4
  53. package/src/components/sonner.tsx +67 -0
  54. package/{shadcn → src/components}/table.tsx +17 -44
  55. package/{shadcn → src/components}/tabs.tsx +16 -26
  56. package/{shadcn → src/components}/textarea.tsx +5 -5
  57. package/{shadcn → src/components}/tooltip.tsx +12 -16
  58. package/src/gates/design.test.ts +188 -0
  59. package/src/gates/index.test.ts +11 -0
  60. package/src/gates/index.ts +165 -0
  61. package/src/gates/tokens.test.ts +215 -0
  62. package/src/harness.test.tsx +1 -1
  63. package/src/index.ts +63 -33
  64. package/src/theme/imports.test.ts +160 -0
  65. package/src/{statusTone.test.ts → theme/statusTone.test.ts} +5 -1
  66. package/src/{styles.css → theme/styles.css} +45 -31
  67. package/src/theme/tailwind.css +646 -0
  68. package/src/{tokens.test.ts → theme/tokens.test.ts} +30 -23
  69. package/src/{tokens.ts → theme/tokens.ts} +12 -12
  70. package/components.json +0 -13
  71. package/dist/lib/button.d.ts +0 -1
  72. package/dist/lib/button.js +0 -4
  73. package/dist/lib/cn.d.ts +0 -18
  74. package/dist/lib/cn.js +0 -21
  75. package/dist/lib/menu.d.ts +0 -1
  76. package/dist/lib/menu.js +0 -16
  77. package/dist/lib/progress.d.ts +0 -3
  78. package/dist/lib/progress.js +0 -6
  79. package/dist/lib/select.d.ts +0 -1
  80. package/dist/lib/select.js +0 -3
  81. package/dist/primitives/progress.js +0 -7
  82. package/gates/canonical.test.mjs +0 -71
  83. package/gates/extensions.test.mjs +0 -373
  84. package/gates/index.d.mts +0 -51
  85. package/gates/index.mjs +0 -514
  86. package/gates/tokens.test.mjs +0 -276
  87. package/shadcn/README.md +0 -13
  88. package/shadcn/badge.tsx +0 -49
  89. package/shadcn/button.tsx +0 -67
  90. package/shadcn/combobox.tsx +0 -299
  91. package/shadcn/dialog.tsx +0 -166
  92. package/shadcn/dropdown-menu.tsx +0 -267
  93. package/shadcn/field.tsx +0 -236
  94. package/shadcn/input-group.tsx +0 -154
  95. package/shadcn/progress.tsx +0 -29
  96. package/shadcn/sheet.tsx +0 -145
  97. package/shadcn/sonner.tsx +0 -49
  98. package/src/lib/button.ts +0 -4
  99. package/src/lib/cn.test.ts +0 -33
  100. package/src/lib/cn.ts +0 -23
  101. package/src/lib/menu.ts +0 -16
  102. package/src/lib/progress.ts +0 -6
  103. package/src/lib/select.ts +0 -4
  104. package/src/primitives/alert.tsx +0 -76
  105. package/src/primitives/card.tsx +0 -103
  106. package/src/primitives/input.tsx +0 -19
  107. package/src/primitives/label.tsx +0 -22
  108. package/src/primitives/select.tsx +0 -192
  109. package/src/primitives/separator.tsx +0 -28
  110. package/src/primitives/skeleton.tsx +0 -13
  111. package/src/primitives/sonner.tsx +0 -65
  112. package/src/primitives/table.tsx +0 -114
  113. package/src/primitives/tabs.tsx +0 -88
  114. package/src/primitives/textarea.tsx +0 -18
  115. package/src/primitives/tooltip.tsx +0 -57
  116. /package/dist/{primitives → components}/alert.d.ts +0 -0
  117. /package/dist/{primitives → components}/badge.d.ts +0 -0
  118. /package/dist/{primitives → components}/combobox.d.ts +0 -0
  119. /package/dist/{primitives → components}/dialog.d.ts +0 -0
  120. /package/dist/{primitives → components}/dropdown-menu.d.ts +0 -0
  121. /package/dist/{primitives → components}/field.d.ts +0 -0
  122. /package/dist/{primitives → components}/input-group.d.ts +0 -0
  123. /package/dist/{primitives → components}/input.d.ts +0 -0
  124. /package/dist/{primitives → components}/label.d.ts +0 -0
  125. /package/dist/{primitives → components}/progress.d.ts +0 -0
  126. /package/dist/{primitives → components}/separator.d.ts +0 -0
  127. /package/dist/{primitives → components}/sheet.d.ts +0 -0
  128. /package/dist/{primitives → components}/skeleton.d.ts +0 -0
  129. /package/dist/{primitives → components}/sonner.d.ts +0 -0
  130. /package/dist/{primitives → components}/tabs.d.ts +0 -0
  131. /package/dist/{primitives → components}/textarea.d.ts +0 -0
  132. /package/dist/{primitives → components}/tooltip.d.ts +0 -0
  133. /package/dist/{statusTone.d.ts → theme/statusTone.d.ts} +0 -0
  134. /package/dist/{statusTone.js → theme/statusTone.js} +0 -0
  135. /package/src/{statusTone.ts → theme/statusTone.ts} +0 -0
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * @vitest-environment node
3
3
  *
4
- * The foundation gate: `styles.css` is the shadcn preset's exact generated
5
- * output (`:root`, `.dark`, `@theme inline`, the base layer) plus `brand`,
6
- * the one Robomous extension. `tokens.ts` is the TypeScript mirror a
4
+ * The token contract: `styles.css` is the one home for a colour (`:root`,
5
+ * `.dark`, `@theme inline`, the base layer) — the semantic vocabulary plus
6
+ * `brand`, the one Robomous extension. `tokens.ts` is the mirror a
7
7
  * `<canvas>`/`<svg>` or a test reads a colour off of; this suite parses the
8
8
  * stylesheet structurally and asserts the two agree, declaration for
9
9
  * declaration, and that none of the tokens this rewrite retired have crept
@@ -23,9 +23,14 @@ import { cssVar, DARK_THEME, LIGHT_THEME, THEME } from "./tokens";
23
23
 
24
24
  const STYLESHEET = readFileSync(fileURLToPath(new URL("./styles.css", import.meta.url)), "utf8");
25
25
 
26
- /** Whitespace is presentation; a value that wraps is the same value. */
26
+ /**
27
+ * Whitespace and quote style are presentation: a value that wraps, and a font
28
+ * family spelled in double quotes rather than single, are the same value. Both
29
+ * change under an ordinary formatter run and neither changes what a browser
30
+ * resolves, so neither may fail this suite.
31
+ */
27
32
  function normalize(value: string): string {
28
- return value.replace(/\s+/g, " ").trim();
33
+ return value.replace(/\s+/g, " ").replace(/"/g, "'").trim();
29
34
  }
30
35
 
31
36
  /**
@@ -65,9 +70,9 @@ function declarations(block: string): Map<string, string> {
65
70
  return map;
66
71
  }
67
72
 
68
- // The shadcn standard vocabulary, exactly as the CLI 4.18.0 scratch emitted
69
- // it — not derived from `tokens.ts`, so a mistake in the mirror cannot also
70
- // erase the thing it was supposed to mirror.
73
+ // The semantic vocabulary, written out here rather than derived from
74
+ // `tokens.ts`, so a mistake in the mirror cannot also erase the thing it was
75
+ // supposed to mirror.
71
76
  const CHART_NAMES = ["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"];
72
77
  const SIDEBAR_NAMES = [
73
78
  "sidebar",
@@ -101,10 +106,10 @@ const BASE_SEMANTIC_NAMES = [
101
106
  ];
102
107
  const SEMANTIC_NAMES = [...BASE_SEMANTIC_NAMES, ...CHART_NAMES, ...SIDEBAR_NAMES];
103
108
 
104
- // The one extension this package keeps beyond shadcn's vocabulary.
109
+ // The one name this package keeps beyond the semantic vocabulary.
105
110
  const EXTENSION_NAMES = ["brand"];
106
111
 
107
- const ORANGE_CHART = {
112
+ const NEUTRAL_CHART = {
108
113
  "chart-1": "oklch(0.87 0 0)",
109
114
  "chart-2": "oklch(0.556 0 0)",
110
115
  "chart-3": "oklch(0.439 0 0)",
@@ -115,7 +120,7 @@ const ORANGE_CHART = {
115
120
  describe(":root", () => {
116
121
  const root = declarations(blockBody(STYLESHEET, ":root {"));
117
122
 
118
- it("declares every standard shadcn semantic variable, the five extensions, and --radius, and nothing else", () => {
123
+ it("declares every semantic variable, the one extension, and --radius, and nothing else", () => {
119
124
  expect([...root.keys()].sort()).toEqual(
120
125
  [...SEMANTIC_NAMES, ...EXTENSION_NAMES, "radius"].sort(),
121
126
  );
@@ -134,13 +139,13 @@ describe(":root", () => {
134
139
  expect(lightKeys).toEqual(rootKeys);
135
140
  });
136
141
 
137
- it("pins --radius to the preset's medium step, in both the CSS and THEME", () => {
142
+ it("pins --radius to the medium step, in both the CSS and THEME", () => {
138
143
  expect(root.get("radius")).toBe("0.625rem");
139
144
  expect(THEME.radius).toBe("0.625rem");
140
145
  });
141
146
 
142
147
  it("pins the neutral chart palette exactly", () => {
143
- for (const [name, value] of Object.entries(ORANGE_CHART)) {
148
+ for (const [name, value] of Object.entries(NEUTRAL_CHART)) {
144
149
  expect(root.get(name)).toBe(value);
145
150
  }
146
151
  });
@@ -149,7 +154,7 @@ describe(":root", () => {
149
154
  describe(".dark", () => {
150
155
  const dark = declarations(blockBody(STYLESHEET, ".dark {"));
151
156
 
152
- it("declares every standard shadcn semantic variable and the five extensions, and nothing else (no --radius)", () => {
157
+ it("declares every semantic variable and the one extension, and nothing else (no --radius)", () => {
153
158
  expect([...dark.keys()].sort()).toEqual([...SEMANTIC_NAMES, ...EXTENSION_NAMES].sort());
154
159
  });
155
160
 
@@ -164,7 +169,7 @@ describe(".dark", () => {
164
169
  });
165
170
 
166
171
  it("pins the neutral chart palette exactly, unchanged from light", () => {
167
- for (const [name, value] of Object.entries(ORANGE_CHART)) {
172
+ for (const [name, value] of Object.entries(NEUTRAL_CHART)) {
168
173
  expect(dark.get(name)).toBe(value);
169
174
  }
170
175
  });
@@ -200,8 +205,8 @@ describe("@theme inline", () => {
200
205
  /**
201
206
  * The four `--text-*` custom properties this rewrite retired (Task 2 moved
202
207
  * their consumers onto Tailwind's standard scale: xs/sm/base/2xl). Assembled
203
- * from fragments — the same trick `tests/scripts/design_tokens.test.mjs`'s
204
- * `HEX` uses — so this guard's own source never spells any retired name as a
208
+ * from fragments — the same trick `src/gates/tokens.test.ts`'s `HEX` uses — so
209
+ * this guard's own source never spells any retired name as a
205
210
  * contiguous string and cannot trip the repo-wide sweep that proves the
206
211
  * migration complete everywhere else.
207
212
  */
@@ -231,8 +236,10 @@ describe("structure", () => {
231
236
  const anchors = [
232
237
  '@import "tailwindcss";',
233
238
  '@import "tw-animate-css";',
234
- '@import "shadcn/tailwind.css";',
235
- // One family, so one font import: `b2iH` sets the heading face to the body's
239
+ // The variant and utility layer, ahead of the token blocks: a variant
240
+ // has to exist before a utility can qualify on it.
241
+ '@import "./tailwind.css";',
242
+ // One family, so one font import: the heading face resolves to the body's
236
243
  // rather than naming a second one.
237
244
  '@import "@fontsource-variable/geist";',
238
245
  "@custom-variant dark (&:is(.dark *));",
@@ -249,17 +256,17 @@ describe("structure", () => {
249
256
  it("reaches its own package's classes: @source after the imports", () => {
250
257
  const sourceAt = STYLESHEET.indexOf('@source ".";');
251
258
  const lastImportAt = STYLESHEET.lastIndexOf("@import");
252
- expect(sourceAt, "styles.css has no @source \".\";").toBeGreaterThan(-1);
259
+ expect(sourceAt, 'styles.css has no @source ".";').toBeGreaterThan(-1);
253
260
  expect(sourceAt).toBeGreaterThan(lastImportAt);
254
261
  });
255
262
 
256
- it("applies the base-layer ring/border rule shadcn ships", () => {
263
+ it("applies the base-layer ring/border rule to every element", () => {
257
264
  expect(/\*\s*\{\s*@apply border-border outline-ring\/50;\s*\}/.test(STYLESHEET)).toBe(true);
258
265
  });
259
266
 
260
267
  /**
261
268
  * The `*` rule above names the outline *colour* and nothing else about focus.
262
- * The geometry is the primitives': every focusable one carries Nova's
269
+ * The geometry belongs to the components: every focusable one carries its own
263
270
  * `focus-visible:ring-3 focus-visible:ring-ring/50` (the tab bar adds a 1px
264
271
  * `outline-ring` on top of it), so a stylesheet-level `:focus-visible`
265
272
  * override would now fight the components instead of backing them up.
@@ -268,7 +275,7 @@ describe("structure", () => {
268
275
  * re-adding a blanket rule here is how a single global declaration would
269
276
  * quietly start overriding thirteen components again.
270
277
  */
271
- it("leaves focus geometry to the primitives: no stylesheet-level :focus-visible rule", () => {
278
+ it("leaves focus geometry to the components: no stylesheet-level :focus-visible rule", () => {
272
279
  expect(STYLESHEET).not.toContain(":focus-visible");
273
280
  });
274
281
 
@@ -8,24 +8,24 @@
8
8
  * which parses the stylesheet and asserts the two agree, declaration for
9
9
  * declaration.
10
10
  *
11
- * `LIGHT_THEME`/`DARK_THEME` are the shadcn preset (`b2iH` style
12
- * `nova`, base colour `neutral`, chart palette `neutral`) exactly as the CLI
13
- * 4.19.0 scratch generated it, plus `brand` (Robomous coral identity only).
14
- * Consumer extensions such as VisionSet's `stage` and `origin-*` live in the
15
- * consumer's own token module. Everything else is shadcn's own vocabulary.
11
+ * `LIGHT_THEME`/`DARK_THEME` carry the semantic vocabulary on a neutral base
12
+ * colour and chart palette, plus one name of this package's own: `brand`,
13
+ * Robomous orange, identity only. A consumer's own vocabulary lives in the
14
+ * consumer's stylesheet and token module, never here — DESIGN.md,
15
+ * *Per-consumer extensions*.
16
16
  */
17
17
 
18
18
  export const LIGHT_THEME: Readonly<Record<string, string>> = Object.freeze({
19
19
  background: "oklch(1 0 0)",
20
- foreground: "oklch(0.145 0 0)",
20
+ foreground: "oklch(0.2 0 0)",
21
21
  card: "oklch(1 0 0)",
22
22
  "card-foreground": "oklch(0.145 0 0)",
23
23
  popover: "oklch(1 0 0)",
24
24
  "popover-foreground": "oklch(0.145 0 0)",
25
- primary: "oklch(0.205 0 0)",
25
+ primary: "oklch(0.2 0 0)",
26
26
  "primary-foreground": "oklch(0.985 0 0)",
27
27
  secondary: "oklch(0.97 0 0)",
28
- "secondary-foreground": "oklch(0.205 0 0)",
28
+ "secondary-foreground": "oklch(0.269 0 0)",
29
29
  muted: "oklch(0.97 0 0)",
30
30
  "muted-foreground": "oklch(0.556 0 0)",
31
31
  accent: "oklch(0.97 0 0)",
@@ -48,9 +48,9 @@ export const LIGHT_THEME: Readonly<Record<string, string>> = Object.freeze({
48
48
  "sidebar-border": "oklch(0.922 0 0)",
49
49
  "sidebar-ring": "oklch(0.708 0 0)",
50
50
 
51
- // Robomous coral. Identity only — the wordmark and its styleguide swatch
52
- // — never a functional-UI colour.
53
- brand: "oklch(0.653 0.178 32.3)",
51
+ // Robomous orange (#F5580B). Identity only — the wordmark and its styleguide
52
+ // swatch — never a functional-UI colour.
53
+ brand: "oklch(0.663 0.205 39.9)",
54
54
  });
55
55
 
56
56
  export const DARK_THEME: Readonly<Record<string, string>> = Object.freeze({
@@ -86,7 +86,7 @@ export const DARK_THEME: Readonly<Record<string, string>> = Object.freeze({
86
86
  "sidebar-border": "oklch(1 0 0 / 10%)",
87
87
  "sidebar-ring": "oklch(0.556 0 0)",
88
88
 
89
- brand: "oklch(0.653 0.178 32.3)",
89
+ brand: "oklch(0.663 0.205 39.9)",
90
90
  });
91
91
 
92
92
  /** The two provenance facts a colour string alone cannot carry. */
package/components.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "$schema": "https://ui.shadcn.com/schema.json",
3
- "style": "radix-nova",
4
- "rsc": false,
5
- "tsx": true,
6
- "tailwind": { "config": "", "css": "src/styles.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" },
7
- "iconLibrary": "lucide",
8
- "rtl": false,
9
- "aliases": { "components": "@/components", "utils": "@/lib/cn", "ui": "@/primitives", "lib": "@/lib", "hooks": "@/hooks" },
10
- "menuColor": "default",
11
- "menuAccent": "subtle",
12
- "registries": {}
13
- }
@@ -1 +0,0 @@
1
- export declare const inlineLink = "h-auto p-0";
@@ -1,4 +0,0 @@
1
- // A link button is inline prose, not a boxed control: the canonical variant keeps
2
- // the button's height and padding, so the sites that sit inside a sentence or a
3
- // table cell hand them back.
4
- export const inlineLink = "h-auto p-0";
package/dist/lib/cn.d.ts DELETED
@@ -1,18 +0,0 @@
1
- /**
2
- * `cn` — merge class names, last conflicting utility wins.
3
- *
4
- * `clsx` handles the conditionals; `tailwind-merge` handles the part a naive
5
- * join gets wrong. Without it `cn("px-4", props.className)` with `px-6`
6
- * passed in emits both, and which one applies is decided by the order
7
- * Tailwind happened to write them into the stylesheet — so a caller's
8
- * override works or does not depending on a rule nobody can see. That is why
9
- * the `className` prop on every primitive here is a real extension point
10
- * rather than a suggestion.
11
- *
12
- * The shadcn preset's own vocabulary needs no custom `tailwind-merge`
13
- * configuration — unlike v1's `--text-*` scale, none of its names collide
14
- * with a stock Tailwind class group — so this is the bare merge, the same
15
- * shape the CLI scratch's own `lib/utils.ts` ships.
16
- */
17
- import { type ClassValue } from "clsx";
18
- export declare function cn(...inputs: readonly ClassValue[]): string;
package/dist/lib/cn.js DELETED
@@ -1,21 +0,0 @@
1
- /**
2
- * `cn` — merge class names, last conflicting utility wins.
3
- *
4
- * `clsx` handles the conditionals; `tailwind-merge` handles the part a naive
5
- * join gets wrong. Without it `cn("px-4", props.className)` with `px-6`
6
- * passed in emits both, and which one applies is decided by the order
7
- * Tailwind happened to write them into the stylesheet — so a caller's
8
- * override works or does not depending on a rule nobody can see. That is why
9
- * the `className` prop on every primitive here is a real extension point
10
- * rather than a suggestion.
11
- *
12
- * The shadcn preset's own vocabulary needs no custom `tailwind-merge`
13
- * configuration — unlike v1's `--text-*` scale, none of its names collide
14
- * with a stock Tailwind class group — so this is the bare merge, the same
15
- * shape the CLI scratch's own `lib/utils.ts` ships.
16
- */
17
- import { clsx } from "clsx";
18
- import { twMerge } from "tailwind-merge";
19
- export function cn(...inputs) {
20
- return twMerge(clsx(inputs));
21
- }
@@ -1 +0,0 @@
1
- export declare const menuSurface = "data-closed:animate-none! w-auto";
package/dist/lib/menu.js DELETED
@@ -1,16 +0,0 @@
1
- // What every `DropdownMenuContent` call site adds to the canonical surface, in
2
- // one constant because both halves are the same rule — a menu that behaves like
3
- // a menu (DESIGN.md, Motion).
4
- //
5
- // `data-closed:animate-none!`: a menu surface leaves on the frame it is
6
- // dismissed. While Radix runs an exit animation the dismissable layer stays
7
- // mounted, and a press that should open the next menu is swallowed as the
8
- // dismissal of this one.
9
- //
10
- // `w-auto`: a menu sizes to its items, not to its trigger. Canonical carries
11
- // `w-(--radix-dropdown-menu-trigger-width) min-w-32`, which pins the surface to
12
- // the trigger — behind an icon-sized button that is the 128px floor, and every
13
- // item longer than that wraps (the row actions on ModelsScreen, the Annotate
14
- // picker). `min-w-32` survives as the floor it was meant to be, because
15
- // tailwind-merge replaces only the `w-*` in the same utility group.
16
- export const menuSurface = "data-closed:animate-none! w-auto";
@@ -1,3 +0,0 @@
1
- export declare function progressAria(value: number): {
2
- readonly "aria-valuenow": number;
3
- };
@@ -1,6 +0,0 @@
1
- // Canonical `Progress` reads `value` only to size the indicator and never
2
- // forwards it to Radix's `Root`, so the number a screen reader would announce
3
- // is otherwise never rendered at all — a caller that needs it says so again here.
4
- export function progressAria(value) {
5
- return { "aria-valuenow": value };
6
- }
@@ -1 +0,0 @@
1
- export declare const twoLineTrigger = "data-[size=default]:h-auto min-h-8 *:data-[slot=select-value]:line-clamp-none";
@@ -1,3 +0,0 @@
1
- // A two-line option needs the closed trigger to grow and to stop clamping its
2
- // value; both overrides name canonical's own variants so the merge replaces them.
3
- export const twoLineTrigger = "data-[size=default]:h-auto min-h-8 *:data-[slot=select-value]:line-clamp-none";
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Progress as ProgressPrimitive } from "radix-ui";
3
- import { cn } from "../lib/cn.js";
4
- function Progress({ className, value, ...props }) {
5
- return (_jsx(ProgressPrimitive.Root, { "data-slot": "progress", className: cn("relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted", className), ...props, children: _jsx(ProgressPrimitive.Indicator, { "data-slot": "progress-indicator", className: "size-full flex-1 bg-primary transition-all", style: { transform: `translateX(-${100 - (value || 0)}%)` } }) }));
6
- }
7
- export { Progress };
@@ -1,71 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { existsSync, readFileSync, readdirSync } from "node:fs";
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { test } from "node:test";
6
- import { relativize } from "../scripts/shadcn_relativize.mjs";
7
-
8
- import {
9
- ADAPTER_REMOVED_LINES,
10
- additiveOnly,
11
- checkAdapter,
12
- withoutLines,
13
- } from "./index.mjs";
14
-
15
- const REPO = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
16
- const PRIMITIVES = path.join(REPO, "src/primitives");
17
- const SNAPSHOTS = path.join(REPO, "shadcn");
18
-
19
- test("additiveOnly accepts an added line and refuses a changed one", () => {
20
- assert.equal(additiveOnly("a\nb\n", "a\nx\nb\n").ok, true);
21
- assert.equal(additiveOnly("a\nb\n", "a\nB\n").ok, false);
22
- assert.equal(additiveOnly("a\nb\n", "b\na\n").ok, false);
23
- assert.equal(additiveOnly("a\n\nb\n", "a\nb\n").ok, false);
24
- assert.equal(additiveOnly("a\r\nb \r\n", "a\nb\n").ok, true);
25
- });
26
-
27
- test("checkAdapter refuses an unlisted file carrying the marker", () => {
28
- const result = checkAdapter("unlisted.tsx", "// SHADCN FRAMEWORK ADAPTER\nconst x = 1\n");
29
- assert.equal(result.ok, false);
30
- });
31
-
32
- test("checkAdapter accepts a listed file carrying the marker", () => {
33
- const result = checkAdapter("sonner.tsx", "// SHADCN FRAMEWORK ADAPTER\nconst x = 1\n");
34
- assert.deepEqual(result, { ok: true, isAdapter: true });
35
- });
36
-
37
- test("checkAdapter ignores a file with no marker even if unlisted", () => {
38
- const result = checkAdapter("unlisted.tsx", "const x = 1\n");
39
- assert.deepEqual(result, { ok: true, isAdapter: false });
40
- });
41
-
42
- test("a listed adapter passes when only the two next-themes lines are removed", () => {
43
- const snapshot = 'import { useTheme } from "next-themes"\nconst x = 1\n const { theme = "system" } = useTheme()\nconst y = 2\n';
44
- const actual = "// SHADCN FRAMEWORK ADAPTER\nconst x = 1\nconst y = 2\n";
45
- const result = additiveOnly(withoutLines(relativize(snapshot), ADAPTER_REMOVED_LINES), actual);
46
- assert.equal(result.ok, true);
47
- });
48
-
49
- test("a listed adapter that also drops a different snapshot line still fails", () => {
50
- const snapshot = 'import { useTheme } from "next-themes"\nconst x = 1\n const { theme = "system" } = useTheme()\nconst y = 2\n';
51
- const actual = "// SHADCN FRAMEWORK ADAPTER\nconst y = 2\n"; // "const x = 1" went missing too
52
- const result = additiveOnly(withoutLines(relativize(snapshot), ADAPTER_REMOVED_LINES), actual);
53
- assert.equal(result.ok, false);
54
- });
55
-
56
- const primitives = readdirSync(PRIMITIVES).filter((f) => f.endsWith(".tsx") && !f.endsWith(".test.tsx"));
57
-
58
- for (const file of primitives) {
59
- test(`${file} is shadcn's canonical file plus added lines only`, () => {
60
- const snapshot = path.join(SNAPSHOTS, file);
61
- assert.ok(existsSync(snapshot), `${file} has no snapshot in shadcn/ — install it with pnpm shadcn:add`);
62
- const snapshotText = relativize(readFileSync(snapshot, "utf8"));
63
- const actualText = readFileSync(path.join(PRIMITIVES, file), "utf8");
64
- const adapter = checkAdapter(file, actualText);
65
- assert.ok(adapter.ok, adapter.reason);
66
- const result = adapter.isAdapter
67
- ? additiveOnly(withoutLines(snapshotText, ADAPTER_REMOVED_LINES), actualText)
68
- : additiveOnly(snapshotText, actualText);
69
- assert.ok(result.ok, `${file} diverges from its snapshot at: ${result.missing}`);
70
- });
71
- }