rizzo-css 0.0.62 → 0.0.63

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 (171) hide show
  1. package/README.md +9 -5
  2. package/bin/rizzo-css.js +247 -27
  3. package/dist/rizzo.min.css +5 -3
  4. package/package.json +14 -7
  5. package/scaffold/astro/Footer.astro +8 -0
  6. package/scaffold/astro/Settings.astro +8 -2
  7. package/scaffold/astro/Tabs.astro +2 -2
  8. package/scaffold/react/Accordion.tsx +143 -0
  9. package/scaffold/react/Alert.tsx +90 -0
  10. package/scaffold/react/AlertDialog.tsx +80 -0
  11. package/scaffold/react/AspectRatio.tsx +32 -0
  12. package/scaffold/react/Avatar.tsx +53 -0
  13. package/scaffold/react/BackToTop.tsx +62 -0
  14. package/scaffold/react/Badge.tsx +39 -0
  15. package/scaffold/react/Breadcrumb.tsx +81 -0
  16. package/scaffold/react/Button.tsx +40 -0
  17. package/scaffold/react/ButtonGroup.tsx +24 -0
  18. package/scaffold/react/Card.tsx +26 -0
  19. package/scaffold/react/Checkbox.tsx +40 -0
  20. package/scaffold/react/Collapsible.tsx +58 -0
  21. package/scaffold/react/ContextMenu.tsx +67 -0
  22. package/scaffold/react/CopyToClipboard.tsx +128 -0
  23. package/scaffold/react/Dashboard.tsx +23 -0
  24. package/scaffold/react/Divider.tsx +47 -0
  25. package/scaffold/react/DocsSidebar.tsx +48 -0
  26. package/scaffold/react/Dropdown.tsx +256 -0
  27. package/scaffold/react/Empty.tsx +29 -0
  28. package/scaffold/react/FontSwitcher.tsx +68 -0
  29. package/scaffold/react/Footer.tsx +55 -0
  30. package/scaffold/react/FormGroup.tsx +57 -0
  31. package/scaffold/react/HoverCard.tsx +61 -0
  32. package/scaffold/react/Icons.tsx +22 -0
  33. package/scaffold/react/Input.tsx +69 -0
  34. package/scaffold/react/Kbd.tsx +16 -0
  35. package/scaffold/react/Label.tsx +16 -0
  36. package/scaffold/react/Modal.tsx +149 -0
  37. package/scaffold/react/Navbar.tsx +72 -0
  38. package/scaffold/react/Pagination.tsx +155 -0
  39. package/scaffold/react/Popover.tsx +66 -0
  40. package/scaffold/react/ProgressBar.tsx +66 -0
  41. package/scaffold/react/Radio.tsx +38 -0
  42. package/scaffold/react/ResizableHandle.tsx +24 -0
  43. package/scaffold/react/ResizablePane.tsx +29 -0
  44. package/scaffold/react/ResizablePaneGroup.tsx +29 -0
  45. package/scaffold/react/ScrollArea.tsx +29 -0
  46. package/scaffold/react/Search.tsx +62 -0
  47. package/scaffold/react/Select.tsx +65 -0
  48. package/scaffold/react/Separator.tsx +33 -0
  49. package/scaffold/react/Settings.tsx +60 -0
  50. package/scaffold/react/Sheet.tsx +86 -0
  51. package/scaffold/react/Skeleton.tsx +32 -0
  52. package/scaffold/react/Slider.tsx +66 -0
  53. package/scaffold/react/SoundEffects.tsx +15 -0
  54. package/scaffold/react/Spinner.tsx +36 -0
  55. package/scaffold/react/Switch.tsx +52 -0
  56. package/scaffold/react/Table.tsx +178 -0
  57. package/scaffold/react/Tabs.tsx +143 -0
  58. package/scaffold/react/Textarea.tsx +69 -0
  59. package/scaffold/react/ThemeSwitcher.tsx +89 -0
  60. package/scaffold/react/Toast.tsx +43 -0
  61. package/scaffold/react/Toggle.tsx +45 -0
  62. package/scaffold/react/ToggleGroup.tsx +34 -0
  63. package/scaffold/react/Tooltip.tsx +40 -0
  64. package/scaffold/vanilla/README-RIZZO.md +1 -1
  65. package/scaffold/vanilla/components/accordion.html +30 -0
  66. package/scaffold/vanilla/components/alert-dialog.html +30 -0
  67. package/scaffold/vanilla/components/alert.html +30 -0
  68. package/scaffold/vanilla/components/aspect-ratio.html +30 -0
  69. package/scaffold/vanilla/components/avatar.html +30 -0
  70. package/scaffold/vanilla/components/back-to-top.html +30 -0
  71. package/scaffold/vanilla/components/badge.html +30 -0
  72. package/scaffold/vanilla/components/breadcrumb.html +30 -0
  73. package/scaffold/vanilla/components/button-group.html +30 -0
  74. package/scaffold/vanilla/components/button.html +30 -0
  75. package/scaffold/vanilla/components/cards.html +30 -0
  76. package/scaffold/vanilla/components/collapsible.html +30 -0
  77. package/scaffold/vanilla/components/context-menu.html +30 -0
  78. package/scaffold/vanilla/components/copy-to-clipboard.html +30 -0
  79. package/scaffold/vanilla/components/dashboard.html +30 -0
  80. package/scaffold/vanilla/components/divider.html +30 -0
  81. package/scaffold/vanilla/components/docs-sidebar.html +30 -0
  82. package/scaffold/vanilla/components/dropdown.html +30 -0
  83. package/scaffold/vanilla/components/empty.html +30 -0
  84. package/scaffold/vanilla/components/font-switcher.html +30 -0
  85. package/scaffold/vanilla/components/footer.html +30 -0
  86. package/scaffold/vanilla/components/forms.html +30 -0
  87. package/scaffold/vanilla/components/hover-card.html +30 -0
  88. package/scaffold/vanilla/components/icons.html +30 -0
  89. package/scaffold/vanilla/components/index.html +30 -0
  90. package/scaffold/vanilla/components/kbd.html +30 -0
  91. package/scaffold/vanilla/components/label.html +30 -0
  92. package/scaffold/vanilla/components/modal.html +30 -0
  93. package/scaffold/vanilla/components/navbar.html +30 -0
  94. package/scaffold/vanilla/components/pagination.html +30 -0
  95. package/scaffold/vanilla/components/popover.html +30 -0
  96. package/scaffold/vanilla/components/progress-bar.html +30 -0
  97. package/scaffold/vanilla/components/resizable.html +30 -0
  98. package/scaffold/vanilla/components/scroll-area.html +30 -0
  99. package/scaffold/vanilla/components/search.html +30 -0
  100. package/scaffold/vanilla/components/separator.html +30 -0
  101. package/scaffold/vanilla/components/settings.html +30 -0
  102. package/scaffold/vanilla/components/sheet.html +30 -0
  103. package/scaffold/vanilla/components/skeleton.html +30 -0
  104. package/scaffold/vanilla/components/slider.html +30 -0
  105. package/scaffold/vanilla/components/sound-effects.html +30 -0
  106. package/scaffold/vanilla/components/spinner.html +30 -0
  107. package/scaffold/vanilla/components/switch.html +30 -0
  108. package/scaffold/vanilla/components/table.html +30 -0
  109. package/scaffold/vanilla/components/tabs.html +30 -0
  110. package/scaffold/vanilla/components/theme-switcher.html +30 -0
  111. package/scaffold/vanilla/components/toast.html +30 -0
  112. package/scaffold/vanilla/components/toggle-group.html +30 -0
  113. package/scaffold/vanilla/components/toggle.html +30 -0
  114. package/scaffold/vanilla/components/tooltip.html +30 -0
  115. package/scaffold/vanilla/index.html +30 -0
  116. package/scaffold/vue/Accordion.vue +9 -0
  117. package/scaffold/vue/Alert.vue +9 -0
  118. package/scaffold/vue/AlertDialog.vue +9 -0
  119. package/scaffold/vue/AspectRatio.vue +9 -0
  120. package/scaffold/vue/Avatar.vue +9 -0
  121. package/scaffold/vue/BackToTop.vue +9 -0
  122. package/scaffold/vue/Badge.vue +28 -0
  123. package/scaffold/vue/Breadcrumb.vue +9 -0
  124. package/scaffold/vue/Button.vue +23 -0
  125. package/scaffold/vue/ButtonGroup.vue +9 -0
  126. package/scaffold/vue/Card.vue +21 -0
  127. package/scaffold/vue/Checkbox.vue +31 -0
  128. package/scaffold/vue/Collapsible.vue +9 -0
  129. package/scaffold/vue/ContextMenu.vue +9 -0
  130. package/scaffold/vue/CopyToClipboard.vue +9 -0
  131. package/scaffold/vue/Dashboard.vue +9 -0
  132. package/scaffold/vue/Divider.vue +23 -0
  133. package/scaffold/vue/DocsSidebar.vue +9 -0
  134. package/scaffold/vue/Dropdown.vue +9 -0
  135. package/scaffold/vue/Empty.vue +9 -0
  136. package/scaffold/vue/FontSwitcher.vue +9 -0
  137. package/scaffold/vue/Footer.vue +9 -0
  138. package/scaffold/vue/FormGroup.vue +45 -0
  139. package/scaffold/vue/HoverCard.vue +9 -0
  140. package/scaffold/vue/Icons.vue +9 -0
  141. package/scaffold/vue/Input.vue +59 -0
  142. package/scaffold/vue/Kbd.vue +9 -0
  143. package/scaffold/vue/Label.vue +23 -0
  144. package/scaffold/vue/Modal.vue +9 -0
  145. package/scaffold/vue/Navbar.vue +9 -0
  146. package/scaffold/vue/Pagination.vue +9 -0
  147. package/scaffold/vue/Popover.vue +9 -0
  148. package/scaffold/vue/ProgressBar.vue +9 -0
  149. package/scaffold/vue/Radio.vue +29 -0
  150. package/scaffold/vue/ResizableHandle.vue +9 -0
  151. package/scaffold/vue/ResizablePane.vue +9 -0
  152. package/scaffold/vue/ResizablePaneGroup.vue +9 -0
  153. package/scaffold/vue/ScrollArea.vue +9 -0
  154. package/scaffold/vue/Search.vue +9 -0
  155. package/scaffold/vue/Select.vue +52 -0
  156. package/scaffold/vue/Separator.vue +9 -0
  157. package/scaffold/vue/Settings.vue +9 -0
  158. package/scaffold/vue/Sheet.vue +9 -0
  159. package/scaffold/vue/Skeleton.vue +9 -0
  160. package/scaffold/vue/Slider.vue +9 -0
  161. package/scaffold/vue/SoundEffects.vue +9 -0
  162. package/scaffold/vue/Spinner.vue +21 -0
  163. package/scaffold/vue/Switch.vue +9 -0
  164. package/scaffold/vue/Table.vue +9 -0
  165. package/scaffold/vue/Tabs.vue +9 -0
  166. package/scaffold/vue/Textarea.vue +60 -0
  167. package/scaffold/vue/ThemeSwitcher.vue +9 -0
  168. package/scaffold/vue/Toast.vue +9 -0
  169. package/scaffold/vue/Toggle.vue +9 -0
  170. package/scaffold/vue/ToggleGroup.vue +9 -0
  171. package/scaffold/vue/Tooltip.vue +9 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # rizzo-css
2
2
 
3
- A modern CSS design system with semantic theming, 14 built-in themes, and accessible components (BEM). **The same CSS and component styles** ship for every option: **Vanilla JS**, Astro, and Svelte. Framework-agnostic: use with any stack or plain HTML.
3
+ A modern CSS design system with semantic theming, 14 built-in themes, and accessible components (BEM). **The same CSS and component styles** ship for every option: **Vanilla JS**, Astro, Svelte, React, and Vue. Framework-agnostic: use with any stack or plain HTML.
4
4
 
5
5
  ## Install
6
6
 
@@ -16,7 +16,7 @@ bun add rizzo-css
16
16
 
17
17
  The package works with **npm**, **pnpm**, **yarn**, and **bun**. After install, run the CLI with your manager’s runner: `npx` (npm/yarn), `pnpm dlx`, or `bunx`.
18
18
 
19
- **Quick start (no install):** `npx rizzo-css init` — choose **framework** (Vanilla, Astro, or Svelte), then **add to existing** or **create new**. Both flows use the **same template choice**: **Landing** (hero/features), **Docs** (sidebar + sample doc), **Dashboard** (sidebar + stats/table), or **Full** (clone of the docs site). Landing/Docs/Dashboard = component picker (all 56 or pick). We **never overwrite your existing files**; any skipped content is in **RIZZO-SETUP.md**. You must add the `<link>` yourself (CLI prints the exact tag). Non-interactive: `npx rizzo-css init --yes --framework vanilla|astro|svelte --template landing|docs|dashboard|full` or `npx rizzo-css add --template landing|docs|dashboard|full`. Optional **rizzo-css.json** and `add --install-package`. All get the **same CSS and component styles**. To use the **official Svelte or Astro create command** plus Rizzo, create the app first, then run `npx rizzo-css add`:
19
+ **Quick start (no install):** `npx rizzo-css init` — choose **framework** (Vanilla, Astro, Svelte, React, or Vue), then **add to existing** or **create new**. Both flows use the **same template choice**: **Landing** (hero/features), **Docs** (sidebar + sample doc), **Dashboard** (sidebar + stats/table), or **Full** (clone of the docs site). Landing/Docs/Dashboard = component picker (all 56 or pick). We **never overwrite your existing files**; any skipped content is in **RIZZO-SETUP.md**. You must add the `<link>` yourself (CLI prints the exact tag). Non-interactive: `npx rizzo-css init --yes --framework vanilla|astro|svelte|react|vue --template landing|docs|dashboard|full` or `npx rizzo-css add --template landing|docs|dashboard|full`. Optional **rizzo-css.json** and `add --install-package`. All get the **same CSS and component styles**. To use the **official Svelte or Astro create command** plus Rizzo, create the app first, then run `npx rizzo-css add`:
20
20
 
21
21
  ```bash
22
22
  npm create svelte@latest my-app && cd my-app && npx rizzo-css add
@@ -42,6 +42,8 @@ You install **the same package** for every framework: `npm install rizzo-css`. N
42
42
  | **Vanilla** | `npm install rizzo-css` or CDN | Link `node_modules/rizzo-css/dist/rizzo.min.css` or use CDN (see below) | None; write HTML with the same BEM classes as the docs |
43
43
  | **Astro** | `npm install rizzo-css` | `import 'rizzo-css'` in layout or link from `public/` | Copy components from `node_modules/rizzo-css/scaffold/astro/` or use `npx rizzo-css add` with components |
44
44
  | **Svelte** | `npm install rizzo-css` | `import 'rizzo-css'` in root layout or link from `static/` | Copy components from `node_modules/rizzo-css/scaffold/svelte/` or use `npx rizzo-css add` with components |
45
+ | **React** | `npm install rizzo-css` | `import 'rizzo-css'` in root or link from `public/` | Copy components from `node_modules/rizzo-css/scaffold/react/` or use `npx rizzo-css add` with components |
46
+ | **Vue** | `npm install rizzo-css` | `import 'rizzo-css'` in main entry or link from `public/` | Copy components from `node_modules/rizzo-css/scaffold/vue/` or use `npx rizzo-css add` with components |
45
47
 
46
48
  **CSS paths (CLI and scaffolds):**
47
49
 
@@ -50,10 +52,12 @@ You install **the same package** for every framework: `npm install rizzo-css`. N
50
52
  | **Vanilla** | `css/rizzo.min.css` (project root) | `css/rizzo.min.css` (relative) |
51
53
  | **Astro** | `public/css/rizzo.min.css` | `/css/rizzo.min.css` (Astro serves `public/` at `/`) |
52
54
  | **Svelte** | `static/css/rizzo.min.css` | `/css/rizzo.min.css` (SvelteKit serves `static/` at `/`) |
55
+ | **React** | `public/css/rizzo.min.css` (or Vite `index.html` link) | `/css/rizzo.min.css` or import in entry |
56
+ | **Vue** | `public/css/rizzo.min.css` (or Vite link) | `/css/rizzo.min.css` or import in main |
53
57
 
54
58
  With `npx rizzo-css add --path <dir>`, the CLI still suggests the correct href for your framework (e.g. Astro/Svelte get a leading `/` path).
55
59
 
56
- Scaffolds in the package: `scaffold/vanilla/` (and `scaffold/vanilla/variants/docs`, `dashboard`, `full`), `scaffold/astro/base/` and `scaffold/astro/variants/` (docs, dashboard, full), `scaffold/svelte/base/` and `scaffold/svelte/variants/`, plus `scaffold/astro/` and `scaffold/svelte/` (all components), and `scaffold/config/` (font pairs for Settings). **Every framework gets the same four templates:** **Landing** | **Docs** | **Dashboard** | **Full**. Landing/Docs/Dashboard = component picker (all or pick). Full = site clone (all components). **We never overwrite your existing files**; skipped content goes in **RIZZO-SETUP.md**. You must add the stylesheet `<link>` yourself (CLI prints the exact tag). Every scaffold includes LICENSE-RIZZO, README-RIZZO.md, and .gitignore; Astro/Svelte include package.json and .env.example.
60
+ Scaffolds in the package: `scaffold/vanilla/` (and variants), `scaffold/astro/`, `scaffold/svelte/`, `scaffold/react/`, `scaffold/vue/` (base + variants; all components), and `scaffold/config/` (font pairs for Settings). **Every framework gets the same four templates:** **Landing** | **Docs** | **Dashboard** | **Full**. Landing/Docs/Dashboard = component picker (all or pick). Full = site clone (all components). **We never overwrite your existing files**; skipped content goes in **RIZZO-SETUP.md**. You must add the stylesheet `<link>` yourself (CLI prints the exact tag). Every scaffold includes LICENSE-RIZZO, README-RIZZO.md, and .gitignore; Astro/Svelte include package.json and .env.example.
57
61
 
58
62
  ## Use
59
63
 
@@ -68,7 +72,7 @@ import 'rizzo-css';
68
72
  **Without a bundler (plain HTML):** Use a CDN. Both unpkg and jsDelivr resolve the package root to the built CSS (via the `unpkg` / `jsdelivr` fields in this package). For reliability or to pin a version, use the explicit path:
69
73
 
70
74
  ```html
71
- <!-- unpkg (pin version: replace @latest with @0.0.62 or any version) -->
75
+ <!-- unpkg (pin version: replace @latest with @0.0.63 or any version) -->
72
76
  <link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />
73
77
 
74
78
  <!-- or jsDelivr -->
@@ -77,7 +81,7 @@ import 'rizzo-css';
77
81
 
78
82
  Short URLs also work: `https://unpkg.com/rizzo-css@latest` and `https://cdn.jsdelivr.net/npm/rizzo-css@latest` (CDNs serve the default file from package.json). To verify after publish: open the URL in a browser or run `curl -I https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css` and expect `200 OK`.
79
83
 
80
- Use the same class names and HTML structure as in the [component docs](https://rizzo-css.vercel.app/docs/components). **Vanilla JS**, Astro, and Svelte all use the same CSS and BEM markup; choose **Full** to add framework component files via the component picker. Each scaffold has README-RIZZO.md; every install includes LICENSE-RIZZO. The **Navbar** in every scaffold uses **flat links** (Docs, Components, Blocks, Themes, Colors), default Cat logo in the brand link (optional `logo` prop for a custom image), Search, and Settings. The **Vanilla** Full template includes the same navbar (from shared snippet), Settings panel, and toast; **Astro** and **Svelte** Full scaffolds include theme persistence and toast (`showToast`, `removeToast`, `removeAllToasts`).
84
+ Use the same class names and HTML structure as in the [component docs](https://rizzo-css.vercel.app/docs/components). **Vanilla JS**, Astro, Svelte, React, and Vue all use the same CSS and BEM markup; choose **Full** to add framework component files via the component picker. Each scaffold has README-RIZZO.md; every install includes LICENSE-RIZZO. The **Navbar** in every scaffold uses **flat links** (Docs, Components, Blocks, Themes, Colors), default Cat logo in the brand link (optional `logo` prop for a custom image), Search, and Settings. The **Vanilla** Full template includes the same navbar (from shared snippet), Settings panel, and toast; **Astro** and **Svelte** Full scaffolds include theme persistence and toast (`showToast`, `removeToast`, `removeAllToasts`).
81
85
 
82
86
  ## Themes
83
87
 
package/bin/rizzo-css.js CHANGED
@@ -18,7 +18,7 @@ const CLI_BANNER = ` /\\___/\\
18
18
  |_| \\_\\___/____/____\\___/ \\____|____/____/
19
19
 
20
20
 
21
- Design system · Vanilla · Astro · Svelte`;
21
+ Design system · Vanilla · Astro · Svelte · React · Vue`;
22
22
 
23
23
  /** Rainbow theme colors for "RIZZOCSS" block (from our themes: red → orange → yellow → green → blue → purple → pink). */
24
24
  const BANNER_RAINBOW = [
@@ -79,7 +79,7 @@ const RIZZO_SNIPPET_FILE = 'RIZZO-SNIPPET.txt';
79
79
  const RIZZO_SETUP_FILE = 'RIZZO-SETUP.md';
80
80
 
81
81
  const COMMANDS = ['init', 'add', 'theme', 'doctor', 'help'];
82
- const FRAMEWORKS = ['vanilla', 'astro', 'svelte'];
82
+ const FRAMEWORKS = ['vanilla', 'astro', 'svelte', 'react', 'vue'];
83
83
  /** Supported package managers: detection, install/add commands, and --package-manager override. */
84
84
  const VALID_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
85
85
 
@@ -95,7 +95,7 @@ const TEMPLATES = [
95
95
  /** Build RIZZO-SETUP.md content: instructions + snippets. Never overwrites; use for landing or when files were skipped. */
96
96
  function buildRizzoSetupMd(framework, opts) {
97
97
  const { linkTag, linkHref, theme, defaultDark, defaultLight, skippedFiles = [], exampleMinimalPage } = opts;
98
- const fw = framework === 'vanilla' ? 'Vanilla' : framework === 'astro' ? 'Astro' : 'Svelte';
98
+ const fw = framework === 'vanilla' ? 'Vanilla' : framework === 'astro' ? 'Astro' : framework === 'svelte' ? 'Svelte' : framework === 'react' ? 'React' : 'Vue';
99
99
  let md = `# Rizzo CSS setup
100
100
 
101
101
  This file was generated by \`npx rizzo-css init\` or \`npx rizzo-css add\`. Use it to integrate Rizzo CSS into your project. **We never overwrite your existing files** — add the snippets below where needed.
@@ -213,6 +213,8 @@ const ASTRO_COMPONENTS = [
213
213
  'Label', 'Kbd', 'Collapsible', 'AlertDialog', 'AspectRatio', 'ButtonGroup', 'Empty', 'Separator',
214
214
  'Slider', 'Sheet', 'Popover', 'Toggle', 'ToggleGroup', 'ScrollArea', 'HoverCard', 'ContextMenu', 'ResizablePaneGroup', 'ResizablePane', 'ResizableHandle',
215
215
  ];
216
+ const REACT_COMPONENTS = [...ASTRO_COMPONENTS];
217
+ const VUE_COMPONENTS = [...ASTRO_COMPONENTS];
216
218
 
217
219
  // Base set for Manual: all interactive components we ship (so manual has a full working set). Full includes everything (same list).
218
220
  const RECOMMENDED_COMPONENTS = [
@@ -233,6 +235,8 @@ const VANILLA_JS_COMPONENTS = ['Modal', 'Dropdown', 'Tabs', 'Toast', 'ThemeSwitc
233
235
  const COMPONENT_DEPS = {
234
236
  astro: { Settings: ['ThemeSwitcher', 'FontSwitcher', 'SoundEffects'], Toast: ['Alert'], Navbar: ['Search', 'Settings'] },
235
237
  svelte: { Settings: ['ThemeSwitcher', 'FontSwitcher', 'SoundEffects'], Toast: ['Alert'], Navbar: ['Search', 'Settings'] },
238
+ react: { Settings: ['ThemeSwitcher', 'FontSwitcher', 'SoundEffects'], Toast: ['Alert'], Navbar: ['Search', 'Settings'] },
239
+ vue: { Settings: ['ThemeSwitcher', 'FontSwitcher', 'SoundEffects'], Toast: ['Alert'], Navbar: ['Search', 'Settings'] },
236
240
  };
237
241
 
238
242
  function getComponentDeps(framework, componentName) {
@@ -303,6 +307,8 @@ const C = {
303
307
  vanilla: '\u001b[38;5;226m', // Vanilla JS yellow
304
308
  astro: '\u001b[38;5;208m', // Astro orange #ff5d01
305
309
  svelte: '\u001b[38;5;202m', // Svelte orange #ff3e00
310
+ react: '\u001b[38;5;39m', // React blue
311
+ vue: '\u001b[38;5;42m', // Vue green
306
312
  };
307
313
 
308
314
  const CIRCLE_EMPTY = '\u25CB '; // ○
@@ -1072,7 +1078,7 @@ function multiSelectMenu(options, title, initialSelected) {
1072
1078
  function printHelp() {
1073
1079
  console.log(getBanner());
1074
1080
  console.log(`
1075
- rizzo-css CLI — Add Rizzo CSS to your project (Vanilla, Astro, Svelte)
1081
+ rizzo-css CLI — Add Rizzo CSS to your project (Vanilla, Astro, Svelte, React, Vue)
1076
1082
 
1077
1083
  Available commands: init, add, theme, doctor, help
1078
1084
 
@@ -1098,7 +1104,7 @@ Commands:
1098
1104
  Options (init):
1099
1105
  --yes Non-interactive: scaffold new in cwd with defaults (framework: astro, template: landing)
1100
1106
  --path <dir> Project directory (relative to cwd or absolute). Scaffold and run install there. With --yes; interactive: "Enter path" option.
1101
- --framework <fw> vanilla | astro | svelte (with --yes; otherwise first prompt)
1107
+ --framework <fw> vanilla | astro | svelte | react | vue (same 56 components each)
1102
1108
  --template <t> create new: css-only | landing | docs | dashboard | full (default: landing). add: same options.
1103
1109
  --package-manager <pm> npm | pnpm | yarn | bun (with --yes, or skip PM prompt when interactive)
1104
1110
  --install After scaffolding, run package manager install in project directory (no prompt)
@@ -1110,7 +1116,7 @@ Options (init):
1110
1116
  Options (add) — run from your existing project root; you will choose a template then select components (or CSS only):
1111
1117
  --template <t> css-only | landing | docs | dashboard | full (CSS only = stylesheet only; others = component picker)
1112
1118
  --path <dir> Target directory for rizzo.min.css (overrides config and framework default)
1113
- --framework <fw> vanilla | astro | svelte (overrides config and detection)
1119
+ --framework <fw> vanilla | astro | svelte | react | vue (overrides config and detection)
1114
1120
  --dry-run Preview which files would be written without writing; show RIZZO-SETUP.md snippet for skipped files
1115
1121
  --package-manager <pm> npm | pnpm | yarn | bun (override detection for install/print commands)
1116
1122
  --install-package After copying CSS, run package manager add rizzo-css
@@ -1162,6 +1168,9 @@ Component dependencies (Full template):
1162
1168
  Some components require others to work. The component picker adds required ones automatically.
1163
1169
  Full list of available components and what relies on what: npx rizzo-css help components
1164
1170
 
1171
+ Frameworks:
1172
+ Scaffolds (init/add): Vanilla, Astro, Svelte, React, Vue. Same 56 components in each framework’s syntax; same CSS and BEM. Docs: https://rizzo-css.vercel.app/docs/react and Vue.
1173
+
1165
1174
  Docs: https://rizzo-css.vercel.app
1166
1175
  `);
1167
1176
  }
@@ -1177,7 +1186,7 @@ function printHelpComponents() {
1177
1186
  console.log(`
1178
1187
  Components — full list and what relies on what
1179
1188
 
1180
- Available to pick (Astro & Svelte; same list):
1189
+ Available to pick (Astro, Svelte, React, Vue; same list):
1181
1190
  ` + line1 + (line2 ? ',\n ' + line2 : '') + (line3 ? ',\n ' + line3 : '') + `
1182
1191
 
1183
1192
  Dependencies (when you pick the component on the left, the right is added automatically):
@@ -1191,6 +1200,8 @@ Icons: copied whenever you add any component.
1191
1200
  Where components are copied:
1192
1201
  Astro → src/components/rizzo/ (import from there)
1193
1202
  Svelte → src/lib/rizzo/ (import from '$lib/rizzo')
1203
+ React → src/components/rizzo/ (import from there or @/components/rizzo)
1204
+ Vue → src/components/rizzo/ (import from there or @/components/rizzo)
1194
1205
  Vanilla → components/ (HTML) (for interactivity add js/main.js; use --vanilla-js on add)
1195
1206
 
1196
1207
  Core = all components above; dependencies are included so everything works.
@@ -1223,7 +1234,7 @@ function cmdDoctor() {
1223
1234
  const fw = config.framework || 'vanilla';
1224
1235
  const paths = getFrameworkCssPaths(fw);
1225
1236
  const targetDir = (config.targetDir || paths.targetDir);
1226
- const cssPath = fw === 'astro' ? join(cwd, 'public', 'css', 'rizzo.min.css') : fw === 'svelte' ? join(cwd, 'static', 'css', 'rizzo.min.css') : join(cwd, targetDir, 'rizzo.min.css');
1237
+ const cssPath = (fw === 'astro' || fw === 'react' || fw === 'vue') ? join(cwd, 'public', 'css', 'rizzo.min.css') : fw === 'svelte' ? join(cwd, 'static', 'css', 'rizzo.min.css') : join(cwd, targetDir, 'rizzo.min.css');
1227
1238
  if (!existsSync(cssPath)) {
1228
1239
  console.log(' ✗ CSS not found at ' + cssPath);
1229
1240
  ok = false;
@@ -1243,7 +1254,7 @@ function cmdDoctor() {
1243
1254
  ok = false;
1244
1255
  }
1245
1256
  }
1246
- const fontsDir = fw === 'astro' ? join(cwd, 'public', 'assets', 'fonts') : fw === 'svelte' ? join(cwd, 'static', 'assets', 'fonts') : join(cwd, targetDir, 'fonts');
1257
+ const fontsDir = (fw === 'astro' || fw === 'react' || fw === 'vue') ? join(cwd, 'public', 'assets', 'fonts') : fw === 'svelte' ? join(cwd, 'static', 'assets', 'fonts') : join(cwd, targetDir, 'fonts');
1247
1258
  if (!existsSync(fontsDir)) {
1248
1259
  console.log(' ? Fonts path not found: ' + pathRelative(cwd, fontsDir) + ' (CSS may reference ../assets/fonts/ or ./fonts/; add fonts if you use theme typography)');
1249
1260
  } else {
@@ -1259,7 +1270,7 @@ function cmdDoctor() {
1259
1270
  console.log(' ? Could not read fonts dir: ' + pathRelative(cwd, fontsDir));
1260
1271
  }
1261
1272
  }
1262
- const sfxDir = fw === 'astro' ? join(cwd, 'public', 'assets', 'sfx') : fw === 'svelte' ? join(cwd, 'static', 'assets', 'sfx') : join(cwd, 'assets', 'sfx');
1273
+ const sfxDir = (fw === 'astro' || fw === 'react' || fw === 'vue') ? join(cwd, 'public', 'assets', 'sfx') : fw === 'svelte' ? join(cwd, 'static', 'assets', 'sfx') : join(cwd, 'assets', 'sfx');
1263
1274
  if (!existsSync(sfxDir)) {
1264
1275
  console.log(' ? Sound effects path not found: ' + pathRelative(cwd, sfxDir) + ' (optional; needed if you use Settings or SoundEffects with click sounds)');
1265
1276
  } else {
@@ -1272,7 +1283,7 @@ function cmdDoctor() {
1272
1283
  console.log(' ? Could not read sfx dir: ' + pathRelative(cwd, sfxDir));
1273
1284
  }
1274
1285
  }
1275
- const layoutPaths = fw === 'svelte' ? ['src/app.html'] : fw === 'astro' ? ['src/layouts/Layout.astro', 'src/layouts/BaseLayout.astro'] : [];
1286
+ const layoutPaths = fw === 'svelte' ? ['src/app.html'] : fw === 'astro' ? ['src/layouts/Layout.astro', 'src/layouts/BaseLayout.astro'] : fw === 'react' ? ['index.html', 'src/main.tsx', 'src/main.jsx', 'src/App.tsx', 'src/App.jsx'] : fw === 'vue' ? ['index.html', 'src/main.ts', 'src/main.js', 'src/App.vue'] : [];
1276
1287
  for (const lp of layoutPaths) {
1277
1288
  const full = join(cwd, lp);
1278
1289
  if (existsSync(full)) {
@@ -1367,16 +1378,27 @@ async function promptComponentChoice(componentList, framework, initialSelection)
1367
1378
  );
1368
1379
  }
1369
1380
 
1370
- /** Detect framework from cwd: "svelte" | "astro" | null. */
1381
+ /** Detect framework from cwd: "svelte" | "astro" | "react" | "vue" | null. */
1371
1382
  function detectFramework(cwd) {
1372
1383
  if (existsSync(join(cwd, 'svelte.config.js')) || existsSync(join(cwd, 'svelte.config.ts'))) return 'svelte';
1373
1384
  if (existsSync(join(cwd, 'astro.config.mjs')) || existsSync(join(cwd, 'astro.config.mts')) || existsSync(join(cwd, 'astro.config.js'))) return 'astro';
1385
+ if (existsSync(join(cwd, 'vite.config.js')) || existsSync(join(cwd, 'vite.config.ts'))) {
1386
+ try {
1387
+ const pkg = readFileSync(join(cwd, 'package.json'), 'utf8');
1388
+ const json = JSON.parse(pkg);
1389
+ const deps = { ...json.dependencies, ...(json.devDependencies || {}) };
1390
+ if (deps['vue']) return 'vue';
1391
+ if (deps['react'] || deps['react-dom']) return 'react';
1392
+ } catch (_) { /* ignore */ }
1393
+ }
1374
1394
  try {
1375
1395
  const pkg = readFileSync(join(cwd, 'package.json'), 'utf8');
1376
1396
  const json = JSON.parse(pkg);
1377
1397
  const deps = { ...json.dependencies, ...(json.devDependencies || {}) };
1378
1398
  if (deps['@sveltejs/kit'] || deps['svelte']) return 'svelte';
1379
1399
  if (deps['astro']) return 'astro';
1400
+ if (deps['vue']) return 'vue';
1401
+ if (deps['react'] || deps['react-dom']) return 'react';
1380
1402
  } catch (_) { /* ignore */ }
1381
1403
  return null;
1382
1404
  }
@@ -1394,6 +1416,12 @@ function getFrameworkCssPaths(framework) {
1394
1416
  if (framework === 'astro') {
1395
1417
  return { targetDir: 'public/css', linkHref: '/css/rizzo.min.css', fontsDir: 'public/assets/fonts', assetsRoot: 'public' };
1396
1418
  }
1419
+ if (framework === 'react') {
1420
+ return { targetDir: 'public/css', linkHref: '/css/rizzo.min.css', fontsDir: 'public/assets/fonts', assetsRoot: 'public' };
1421
+ }
1422
+ if (framework === 'vue') {
1423
+ return { targetDir: 'public/css', linkHref: '/css/rizzo.min.css', fontsDir: 'public/assets/fonts', assetsRoot: 'public' };
1424
+ }
1397
1425
  return { targetDir: 'css', linkHref: 'css/rizzo.min.css', fontsDir: 'css/fonts', assetsRoot: '' };
1398
1426
  }
1399
1427
 
@@ -1403,7 +1431,7 @@ function getFrameworkCssPaths(framework) {
1403
1431
  */
1404
1432
  function getLinkHrefForTargetDir(framework, targetDir) {
1405
1433
  const file = 'rizzo.min.css';
1406
- if (framework === 'astro' && targetDir) {
1434
+ if ((framework === 'astro' || framework === 'react' || framework === 'vue') && targetDir) {
1407
1435
  const path = targetDir.replace(/^public\/?/, '').replace(/\/+$/, '') || 'css';
1408
1436
  return '/' + (path ? path + '/' : '') + file;
1409
1437
  }
@@ -1475,6 +1503,14 @@ function getScaffoldAstroDir() {
1475
1503
  return join(getPackageRoot(), 'scaffold', 'astro');
1476
1504
  }
1477
1505
 
1506
+ function getScaffoldReactDir() {
1507
+ return join(getPackageRoot(), 'scaffold', 'react');
1508
+ }
1509
+
1510
+ function getScaffoldVueDir() {
1511
+ return join(getPackageRoot(), 'scaffold', 'vue');
1512
+ }
1513
+
1478
1514
  function getScaffoldUtilsDir() {
1479
1515
  return join(getPackageRoot(), 'scaffold', 'utils');
1480
1516
  }
@@ -1634,6 +1670,17 @@ function copyRizzoIcons(projectDir, framework, opts) {
1634
1670
  }
1635
1671
  mkdirSync(targetDir, { recursive: true });
1636
1672
  copyDirRecursive(iconsSrc, targetDir);
1673
+ } else if (framework === 'react' || framework === 'vue') {
1674
+ const scaffoldDir = framework === 'react' ? getScaffoldReactDir() : getScaffoldVueDir();
1675
+ const iconsSrc = join(scaffoldDir, 'icons');
1676
+ if (!existsSync(iconsSrc)) return;
1677
+ const targetDir = join(projectDir, 'src', 'components', 'rizzo', 'icons');
1678
+ if (plan) {
1679
+ collectIconPaths(iconsSrc, targetDir);
1680
+ return;
1681
+ }
1682
+ mkdirSync(targetDir, { recursive: true });
1683
+ copyDirRecursive(iconsSrc, targetDir);
1637
1684
  } else if (framework === 'vanilla') {
1638
1685
  const iconsSrc = getScaffoldVanillaIconsDir();
1639
1686
  if (!existsSync(iconsSrc)) return;
@@ -1906,6 +1953,139 @@ function copyAstroComponents(projectDir, selectedNames, opts) {
1906
1953
  }
1907
1954
  }
1908
1955
 
1956
+ function copyReactComponents(projectDir, selectedNames, opts) {
1957
+ const scaffoldDir = getScaffoldReactDir();
1958
+ if (!existsSync(scaffoldDir)) {
1959
+ console.log('\n React component templates not in this package; use CSS only or see docs.');
1960
+ return;
1961
+ }
1962
+ const files = readdirSync(scaffoldDir).filter((f) => f.endsWith('.tsx') || f.endsWith('.jsx'));
1963
+ const available = files.map((f) => f.replace(/\.(tsx|jsx)$/, ''));
1964
+ const toCopy = selectedNames.filter((n) => n !== 'Icons' && available.includes(n));
1965
+ const copyIconsOnly = selectedNames.includes('Icons') && toCopy.length === 0;
1966
+ if (toCopy.length === 0 && !copyIconsOnly) {
1967
+ console.log('\n No matching React components in scaffold; use CSS only or see docs.');
1968
+ return;
1969
+ }
1970
+ const targetDir = join(projectDir, 'src', 'components', 'rizzo');
1971
+ const plan = opts && opts.dryRun && opts.plan ? opts.plan : null;
1972
+ if (plan) {
1973
+ toCopy.forEach((name) => {
1974
+ const f = files.find((file) => file.replace(/\.(tsx|jsx)$/, '') === name);
1975
+ const ext = f ? (f.endsWith('.tsx') ? '.tsx' : '.jsx') : '.tsx';
1976
+ plan.wouldWrite.push(pathRelative(projectDir, join(targetDir, name + ext)));
1977
+ });
1978
+ const iconsSrc = join(scaffoldDir, 'icons');
1979
+ if (existsSync(iconsSrc) && (toCopy.length > 0 || copyIconsOnly)) {
1980
+ (function collect(s, d) {
1981
+ readdirSync(s, { withFileTypes: true }).forEach((e) => {
1982
+ const destPath = join(d, e.name);
1983
+ if (e.isDirectory()) collect(join(s, e.name), destPath);
1984
+ else plan.wouldWrite.push(pathRelative(projectDir, destPath));
1985
+ });
1986
+ })(iconsSrc, join(targetDir, 'icons'));
1987
+ }
1988
+ if (toCopy.length > 0) plan.wouldWrite.push(pathRelative(projectDir, join(targetDir, 'index.ts')));
1989
+ return;
1990
+ }
1991
+ mkdirSync(targetDir, { recursive: true });
1992
+ const exports = [];
1993
+ const extUsed = {};
1994
+ for (const name of toCopy) {
1995
+ const tsxPath = join(scaffoldDir, name + '.tsx');
1996
+ const jsxPath = join(scaffoldDir, name + '.jsx');
1997
+ const src = existsSync(tsxPath) ? tsxPath : existsSync(jsxPath) ? jsxPath : null;
1998
+ if (src) {
1999
+ const ext = src.endsWith('.tsx') ? '.tsx' : '.jsx';
2000
+ copyFileSync(src, join(targetDir, name + ext));
2001
+ exports.push(`export { default as ${name} } from './${name}${ext}';`);
2002
+ extUsed[name] = ext;
2003
+ }
2004
+ }
2005
+ const iconsSrc = join(scaffoldDir, 'icons');
2006
+ if (existsSync(iconsSrc) && (toCopy.length > 0 || copyIconsOnly)) copyDirRecursive(iconsSrc, join(targetDir, 'icons'));
2007
+ if (toCopy.includes('Settings')) {
2008
+ const configDir = getScaffoldConfigDir();
2009
+ const fontsSrc = join(configDir, 'fonts.ts');
2010
+ if (existsSync(fontsSrc)) {
2011
+ const projectConfigDir = join(projectDir, 'src', 'components', 'config');
2012
+ mkdirSync(projectConfigDir, { recursive: true });
2013
+ copyFileSync(fontsSrc, join(projectConfigDir, 'fonts.ts'));
2014
+ }
2015
+ }
2016
+ if (exports.length > 0 || copyIconsOnly) {
2017
+ if (exports.length > 0) {
2018
+ const indexContent = `/** Rizzo CSS React components — selected via npx rizzo-css add */\n${exports.join('\n')}\n`;
2019
+ writeFileSync(join(targetDir, 'index.ts'), indexContent, 'utf8');
2020
+ }
2021
+ const msg = copyIconsOnly ? 'Icons' : exports.length + ' React components' + (existsSync(iconsSrc) ? ' + icons' : '');
2022
+ console.log('\n ✓ ' + msg + ' copied to ' + targetDir);
2023
+ console.log(' Import in your app: import { Button, Badge, ... } from \'../components/rizzo\' or \'@/components/rizzo\';\n');
2024
+ }
2025
+ }
2026
+
2027
+ function copyVueComponents(projectDir, selectedNames, opts) {
2028
+ const scaffoldDir = getScaffoldVueDir();
2029
+ if (!existsSync(scaffoldDir)) {
2030
+ console.log('\n Vue component templates not in this package; use CSS only or see docs.');
2031
+ return;
2032
+ }
2033
+ const files = readdirSync(scaffoldDir).filter((f) => f.endsWith('.vue'));
2034
+ const available = files.map((f) => f.replace('.vue', ''));
2035
+ const toCopy = selectedNames.filter((n) => n !== 'Icons' && available.includes(n));
2036
+ const copyIconsOnly = selectedNames.includes('Icons') && toCopy.length === 0;
2037
+ if (toCopy.length === 0 && !copyIconsOnly) {
2038
+ console.log('\n No matching Vue components in scaffold; use CSS only or see docs.');
2039
+ return;
2040
+ }
2041
+ const targetDir = join(projectDir, 'src', 'components', 'rizzo');
2042
+ const plan = opts && opts.dryRun && opts.plan ? opts.plan : null;
2043
+ if (plan) {
2044
+ toCopy.forEach((name) => { plan.wouldWrite.push(pathRelative(projectDir, join(targetDir, name + '.vue'))); });
2045
+ const iconsSrc = join(scaffoldDir, 'icons');
2046
+ if (existsSync(iconsSrc) && (toCopy.length > 0 || copyIconsOnly)) {
2047
+ (function collect(s, d) {
2048
+ readdirSync(s, { withFileTypes: true }).forEach((e) => {
2049
+ const destPath = join(d, e.name);
2050
+ if (e.isDirectory()) collect(join(s, e.name), destPath);
2051
+ else plan.wouldWrite.push(pathRelative(projectDir, destPath));
2052
+ });
2053
+ })(iconsSrc, join(targetDir, 'icons'));
2054
+ }
2055
+ if (toCopy.length > 0) plan.wouldWrite.push(pathRelative(projectDir, join(targetDir, 'index.ts')));
2056
+ return;
2057
+ }
2058
+ mkdirSync(targetDir, { recursive: true });
2059
+ const exports = [];
2060
+ for (const name of toCopy) {
2061
+ const src = join(scaffoldDir, name + '.vue');
2062
+ if (existsSync(src)) {
2063
+ copyFileSync(src, join(targetDir, name + '.vue'));
2064
+ exports.push(`export { default as ${name} } from './${name}.vue';`);
2065
+ }
2066
+ }
2067
+ const iconsSrc = join(scaffoldDir, 'icons');
2068
+ if (existsSync(iconsSrc) && (toCopy.length > 0 || copyIconsOnly)) copyDirRecursive(iconsSrc, join(targetDir, 'icons'));
2069
+ if (toCopy.includes('Settings')) {
2070
+ const configDir = getScaffoldConfigDir();
2071
+ const fontsSrc = join(configDir, 'fonts.ts');
2072
+ if (existsSync(fontsSrc)) {
2073
+ const projectConfigDir = join(projectDir, 'src', 'components', 'config');
2074
+ mkdirSync(projectConfigDir, { recursive: true });
2075
+ copyFileSync(fontsSrc, join(projectConfigDir, 'fonts.ts'));
2076
+ }
2077
+ }
2078
+ if (exports.length > 0 || copyIconsOnly) {
2079
+ if (exports.length > 0) {
2080
+ const indexContent = `/** Rizzo CSS Vue components — selected via npx rizzo-css add */\n${exports.join('\n')}\n`;
2081
+ writeFileSync(join(targetDir, 'index.ts'), indexContent, 'utf8');
2082
+ }
2083
+ const msg = copyIconsOnly ? 'Icons' : exports.length + ' Vue components' + (existsSync(iconsSrc) ? ' + icons' : '');
2084
+ console.log('\n ✓ ' + msg + ' copied to ' + targetDir);
2085
+ console.log(' Import in your app: import { Button, Badge, ... } from \'@/components/rizzo\' or relative path;\n');
2086
+ }
2087
+ }
2088
+
1909
2089
  /** Add Rizzo CSS to an existing project. Same variation as create new: Landing | Docs | Dashboard. We never overwrite existing files (including config files). frameworkOverride: when set (from init), skip framework prompt. options: { config?, targetDir?, template? } — template is variation: landing|docs|dashboard (or full→landing). */
1910
2090
  async function runAddToExisting(frameworkOverride, options) {
1911
2091
  const cwd = process.cwd();
@@ -1918,6 +2098,8 @@ async function runAddToExisting(frameworkOverride, options) {
1918
2098
  { value: 'vanilla', label: 'Vanilla JS (HTML + CSS)', color: C.vanilla },
1919
2099
  { value: 'astro', label: 'Astro', color: C.astro },
1920
2100
  { value: 'svelte', label: 'Svelte', color: C.svelte },
2101
+ { value: 'react', label: 'React', color: C.react },
2102
+ { value: 'vue', label: 'Vue', color: C.vue },
1921
2103
  ];
1922
2104
  let frameworkPrompt = '? Framework';
1923
2105
  if (detected) {
@@ -1932,7 +2114,7 @@ async function runAddToExisting(frameworkOverride, options) {
1932
2114
  selectedVariation = await promptTemplate();
1933
2115
  }
1934
2116
 
1935
- const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : framework === 'vanilla' ? Object.keys(VANILLA_COMPONENT_SLUGS) : [];
2117
+ const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : framework === 'react' ? REACT_COMPONENTS : framework === 'vue' ? VUE_COMPONENTS : framework === 'vanilla' ? Object.keys(VANILLA_COMPONENT_SLUGS) : [];
1936
2118
  const preselected = options.preselectedComponents && options.preselectedComponents.length > 0 ? options.preselectedComponents : null;
1937
2119
  let selectedComponents;
1938
2120
  if (selectedVariation === 'css-only') {
@@ -1992,7 +2174,7 @@ async function runAddToExisting(frameworkOverride, options) {
1992
2174
  const paths = getFrameworkCssPaths(framework);
1993
2175
  const targetDirRaw = (options && options.targetDir) || (config && config.targetDir) || paths.targetDir;
1994
2176
  let cssTarget;
1995
- if (framework === 'astro') {
2177
+ if (framework === 'astro' || framework === 'react' || framework === 'vue') {
1996
2178
  cssTarget = join(cwd, 'public', 'css', 'rizzo.min.css');
1997
2179
  } else if (framework === 'svelte') {
1998
2180
  cssTarget = join(cwd, 'static', 'css', 'rizzo.min.css');
@@ -2077,7 +2259,7 @@ async function runAddToExisting(frameworkOverride, options) {
2077
2259
  }
2078
2260
 
2079
2261
  if (options._overwriteCss) {
2080
- if (framework === 'astro') {
2262
+ if (framework === 'astro' || framework === 'react' || framework === 'vue') {
2081
2263
  copyRizzoCssAndFontsForAstro(cwd, cssSource, copyOpts);
2082
2264
  } else if (framework === 'svelte') {
2083
2265
  copyRizzoCssAndFontsForSvelte(cwd, cssSource, copyOpts);
@@ -2105,6 +2287,14 @@ async function runAddToExisting(frameworkOverride, options) {
2105
2287
  const expanded = expandWithDeps('astro', selectedComponents);
2106
2288
  logAddedDeps(selectedComponents, expanded, 'astro');
2107
2289
  copyAstroComponents(cwd, expanded, copyOpts);
2290
+ } else if (framework === 'react' && selectedComponents.length > 0) {
2291
+ const expanded = expandWithDeps('react', selectedComponents);
2292
+ logAddedDeps(selectedComponents, expanded, 'react');
2293
+ copyReactComponents(cwd, expanded, copyOpts);
2294
+ } else if (framework === 'vue' && selectedComponents.length > 0) {
2295
+ const expanded = expandWithDeps('vue', selectedComponents);
2296
+ logAddedDeps(selectedComponents, expanded, 'vue');
2297
+ copyVueComponents(cwd, expanded, copyOpts);
2108
2298
  } else if (framework === 'vanilla' && selectedComponents.length > 0) {
2109
2299
  const linkHrefForVanilla = (options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref;
2110
2300
  const vanillaRepl = { '{{LINK_HREF}}': linkHrefForVanilla, '{{DATA_THEME}}': theme };
@@ -2135,7 +2325,7 @@ async function runAddToExisting(frameworkOverride, options) {
2135
2325
  if (options.dryRun && needsJs && !existsSync(vanillaJsPath) && options.plan) options.plan.wouldWrite.push('js/main.js');
2136
2326
  }
2137
2327
 
2138
- const linkHref = (framework === 'astro' || framework === 'svelte') ? paths.linkHref : ((options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref);
2328
+ const linkHref = (framework === 'astro' || framework === 'svelte' || framework === 'react' || framework === 'vue') ? paths.linkHref : ((options && options.targetDir) ? getLinkHrefForTargetDir(framework, options.targetDir) : paths.linkHref);
2139
2329
  const pmFromOption = options && options.packageManager && VALID_PACKAGE_MANAGERS.includes(options.packageManager);
2140
2330
  const pm = pmFromOption
2141
2331
  ? getPackageManagerCommands({ agent: options.packageManager, command: options.packageManager })
@@ -2143,7 +2333,7 @@ async function runAddToExisting(frameworkOverride, options) {
2143
2333
  ? getPackageManagerCommands({ agent: config.packageManager, command: config.packageManager })
2144
2334
  : resolvePackageManager(cwd);
2145
2335
  const cliExample = pm.dlx('rizzo-css theme');
2146
- const configTargetDir = framework === 'astro' ? 'public/css' : framework === 'svelte' ? 'static/css' : targetDirRaw;
2336
+ const configTargetDir = (framework === 'astro' || framework === 'react' || framework === 'vue') ? 'public/css' : framework === 'svelte' ? 'static/css' : targetDirRaw;
2147
2337
  const configPath = join(cwd, RIZZO_CONFIG_FILE);
2148
2338
  const hadConfig = existsSync(configPath);
2149
2339
  if (options.dryRun) {
@@ -2169,7 +2359,7 @@ async function runAddToExisting(frameworkOverride, options) {
2169
2359
  copyPackageLicense(cwd);
2170
2360
  const writeSnippet = options.writeSnippet !== false;
2171
2361
  if (writeSnippet) {
2172
- const where = framework === 'svelte' ? 'Root layout (e.g. src/app.html)' : framework === 'astro' ? 'Layout (e.g. src/layouts/Layout.astro)' : 'HTML or layout';
2362
+ const where = framework === 'svelte' ? 'Root layout (e.g. src/app.html)' : framework === 'astro' ? 'Layout (e.g. src/layouts/Layout.astro)' : (framework === 'react' || framework === 'vue') ? 'index.html or root component' : 'HTML or layout';
2173
2363
  const snippetBody = [
2174
2364
  'Add to ' + where + ':',
2175
2365
  '',
@@ -2211,6 +2401,11 @@ async function runAddToExisting(frameworkOverride, options) {
2211
2401
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
2212
2402
  console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
2213
2403
  console.log(' Components: src/components/rizzo — import from there.');
2404
+ } else if (framework === 'react' || framework === 'vue') {
2405
+ console.log('\nIn index.html or root component, add:');
2406
+ console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
2407
+ console.log(' data-theme="' + theme + '" on <html> (themes: ' + cliExample + ')');
2408
+ console.log(' Components: src/components/rizzo — import from there or @/components/rizzo.');
2214
2409
  } else {
2215
2410
  console.log('\nIn your HTML or layout, add:');
2216
2411
  console.log(' <link rel="stylesheet" href="' + linkHref + '" />');
@@ -2222,7 +2417,7 @@ async function runAddToExisting(frameworkOverride, options) {
2222
2417
  }
2223
2418
  const addCmd = pm.add('rizzo-css');
2224
2419
  console.log('\n To add the rizzo-css package to this project (optional): ' + addCmd);
2225
- const shouldPromptAdd = (framework === 'astro' || framework === 'svelte') && options.noInstall !== true && options.installPackage !== true && process.stdin.isTTY;
2420
+ const shouldPromptAdd = (framework === 'astro' || framework === 'svelte' || framework === 'react' || framework === 'vue') && options.noInstall !== true && options.installPackage !== true && process.stdin.isTTY;
2226
2421
  if (shouldPromptAdd) {
2227
2422
  console.log('\n Add rizzo-css to your package.json so you can import components from the package.');
2228
2423
  const answer = await question(' Run ' + addCmd + '? (Y/n) ');
@@ -2279,6 +2474,8 @@ async function cmdInit(argv) {
2279
2474
  fullAllComponents = true;
2280
2475
  if (framework === 'svelte') selectedComponents = [...SVELTE_COMPONENTS];
2281
2476
  else if (framework === 'astro') selectedComponents = [...ASTRO_COMPONENTS];
2477
+ else if (framework === 'react') selectedComponents = [...REACT_COMPONENTS];
2478
+ else if (framework === 'vue') selectedComponents = [...VUE_COMPONENTS];
2282
2479
  else selectedComponents = Object.keys(VANILLA_COMPONENT_SLUGS);
2283
2480
  }
2284
2481
  const projectDir = customProjectPath ? pathResolve(cwd, customProjectPath) : cwd;
@@ -2296,6 +2493,8 @@ async function cmdInit(argv) {
2296
2493
  { value: 'vanilla', label: 'Vanilla JS (HTML + CSS + same styles & components)', color: C.vanilla },
2297
2494
  { value: 'astro', label: 'Astro', color: C.astro },
2298
2495
  { value: 'svelte', label: 'Svelte', color: C.svelte },
2496
+ { value: 'react', label: 'React', color: C.react },
2497
+ { value: 'vue', label: 'Vue', color: C.vue },
2299
2498
  ],
2300
2499
  '? Framework — all get the same CSS and component styles'
2301
2500
  );
@@ -2341,7 +2540,7 @@ async function cmdInit(argv) {
2341
2540
  fullAllComponents = false;
2342
2541
  } else if (selectedVariation === 'full' && hasFullVariant(framework)) {
2343
2542
  fullAllComponents = true;
2344
- selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : framework === 'astro' ? [...ASTRO_COMPONENTS] : Object.keys(VANILLA_COMPONENT_SLUGS);
2543
+ selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : framework === 'astro' ? [...ASTRO_COMPONENTS] : framework === 'react' ? [...REACT_COMPONENTS] : framework === 'vue' ? [...VUE_COMPONENTS] : Object.keys(VANILLA_COMPONENT_SLUGS);
2345
2544
  } else {
2346
2545
  const addChoice = await selectMenu(
2347
2546
  [
@@ -2352,9 +2551,9 @@ async function cmdInit(argv) {
2352
2551
  );
2353
2552
  fullAllComponents = (addChoice === 'all');
2354
2553
  if (fullAllComponents) {
2355
- selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : framework === 'astro' ? [...ASTRO_COMPONENTS] : Object.keys(VANILLA_COMPONENT_SLUGS);
2554
+ selectedComponents = framework === 'svelte' ? [...SVELTE_COMPONENTS] : framework === 'astro' ? [...ASTRO_COMPONENTS] : framework === 'react' ? [...REACT_COMPONENTS] : framework === 'vue' ? [...VUE_COMPONENTS] : Object.keys(VANILLA_COMPONENT_SLUGS);
2356
2555
  } else {
2357
- const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : Object.keys(VANILLA_COMPONENT_SLUGS);
2556
+ const componentList = framework === 'svelte' ? SVELTE_COMPONENTS : framework === 'astro' ? ASTRO_COMPONENTS : framework === 'react' ? REACT_COMPONENTS : framework === 'vue' ? VUE_COMPONENTS : Object.keys(VANILLA_COMPONENT_SLUGS);
2358
2557
  const recommended = RECOMMENDED_COMPONENTS.filter((c) => componentList.includes(c));
2359
2558
  selectedComponents = await promptComponentChoice(componentList, framework, recommended);
2360
2559
  }
@@ -2419,7 +2618,7 @@ async function cmdInit(argv) {
2419
2618
 
2420
2619
  // Full gets all required dependencies so everything works; manual gets deps when user picks (see prompt labels).
2421
2620
  let componentsToCopy = selectedComponents;
2422
- if ((framework === 'astro' || framework === 'svelte') && selectedComponents.length > 0) {
2621
+ if ((framework === 'astro' || framework === 'svelte' || framework === 'react' || framework === 'vue') && selectedComponents.length > 0) {
2423
2622
  componentsToCopy = expandWithDeps(framework, selectedComponents);
2424
2623
  logAddedDeps(selectedComponents, componentsToCopy, framework);
2425
2624
  }
@@ -2698,8 +2897,8 @@ async function cmdInit(argv) {
2698
2897
  copyPackageLicense(projectDir);
2699
2898
  copyVanillaGitignore(projectDir);
2700
2899
  } else {
2701
- // Add-to-existing (landing) or Vanilla create new with picked components: CSS, fonts, icons, sfx (framework-appropriate)
2702
- if (framework === 'astro') {
2900
+ // Add-to-existing (landing) or Vanilla/React/Vue create new with picked components: CSS, fonts, icons, sfx (framework-appropriate)
2901
+ if (framework === 'astro' || framework === 'react' || framework === 'vue') {
2703
2902
  copyRizzoCssAndFontsForAstro(projectDir, cssSource);
2704
2903
  cssTarget = join(projectDir, 'public', 'css', 'rizzo.min.css');
2705
2904
  } else if (framework === 'svelte') {
@@ -2719,7 +2918,7 @@ async function cmdInit(argv) {
2719
2918
  if (statSync(cssTarget).size < 5000) {
2720
2919
  console.warn('\nWarning: rizzo.min.css is very small. From repo root run: pnpm build:css');
2721
2920
  }
2722
- const linkHrefForSetup = framework === 'vanilla' ? 'css/rizzo.min.css' : '/css/rizzo.min.css';
2921
+ const linkHrefForSetup = (framework === 'vanilla') ? 'css/rizzo.min.css' : '/css/rizzo.min.css';
2723
2922
  const setupMdContent = buildRizzoSetupMd(framework, {
2724
2923
  linkHref: linkHrefForSetup,
2725
2924
  theme,
@@ -2744,10 +2943,19 @@ async function cmdInit(argv) {
2744
2943
  mkdirSync(join(projectDir, 'static'), { recursive: true });
2745
2944
  indexPath = svelteIndex;
2746
2945
  writeFileSync(svelteIndex, landingHtmlForAdd, 'utf8');
2946
+ } else if ((framework === 'react' || framework === 'vue') && !existsSync(join(projectDir, 'public', 'index.html'))) {
2947
+ mkdirSync(join(projectDir, 'public'), { recursive: true });
2948
+ indexPath = join(projectDir, 'public', 'index.html');
2949
+ writeFileSync(indexPath, landingHtmlForAdd, 'utf8');
2747
2950
  }
2748
2951
  writeFileSync(join(projectDir, RIZZO_SETUP_FILE), setupMdContent, 'utf8');
2749
2952
  copyPackageLicense(projectDir);
2750
2953
  if (framework === 'vanilla') copyVanillaGitignore(projectDir);
2954
+ if ((framework === 'react' || framework === 'vue') && componentsToCopy.length > 0) {
2955
+ copyRizzoIcons(projectDir, framework);
2956
+ if (framework === 'react') copyReactComponents(projectDir, componentsToCopy);
2957
+ else copyVueComponents(projectDir, componentsToCopy);
2958
+ }
2751
2959
  } else if (framework === 'vanilla' && selectedTemplate === 'full' && !fullAllComponents) {
2752
2960
  indexPath = join(projectDir, 'index.html');
2753
2961
  if (!existsSync(indexPath)) {
@@ -2786,6 +2994,18 @@ async function cmdInit(argv) {
2786
2994
  else writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'static/index.html', content: landingHtml }] }), 'utf8');
2787
2995
  writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
2788
2996
  copyPackageLicense(projectDir);
2997
+ } else if (framework === 'react' || framework === 'vue') {
2998
+ indexPath = join(projectDir, 'public', 'index.html');
2999
+ mkdirSync(join(projectDir, 'public'), { recursive: true });
3000
+ if (!existsSync(indexPath)) writeFileSync(indexPath, landingHtml, 'utf8');
3001
+ else writeFileSync(join(projectDir, RIZZO_SETUP_FILE), buildRizzoSetupMd(framework, { linkHref: '/css/rizzo.min.css', theme, defaultDark, defaultLight, skippedFiles: [{ relativePath: 'public/index.html', content: landingHtml }] }), 'utf8');
3002
+ writeFileSync(join(projectDir, SCAFFOLD_README_FILENAME), FALLBACK_MINIMAL_README, 'utf8');
3003
+ if (componentsToCopy.length > 0) {
3004
+ copyRizzoIcons(projectDir, framework);
3005
+ if (framework === 'react') copyReactComponents(projectDir, componentsToCopy);
3006
+ else copyVueComponents(projectDir, componentsToCopy);
3007
+ }
3008
+ copyPackageLicense(projectDir);
2789
3009
  } else {
2790
3010
  copyPackageLicense(projectDir);
2791
3011
  }