@pauldvlp/vp-pkg-shadcn 0.4.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.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/pauldvlp/vp-templates/main/assets/cover.webp" alt="@pauldvlp/vp-templates" width="100%" />
3
+ </p>
4
+
5
+ # @pauldvlp/vp-pkg-shadcn
6
+
7
+ A [Vite+](https://viteplus.dev) **package generator** that drops a shared, fully customizable
8
+ **shadcn** UI package into an **existing** monorepo:
9
+
10
+ - `packages/ui` — a shared shadcn design system (Tailwind v4, fonts, `lib/utils`, `components/ui/*`)
11
+
12
+ It's a [Bingo](https://create.bingo) template, so options can be passed on the `vp create` command
13
+ line (anything after `--`) and the **shadcn theme is materialized at create time** from the preset
14
+ you choose. Unlike [`@pauldvlp/vp-react-ts-shadcn`](../vp-react-ts-shadcn) (which scaffolds a whole
15
+ monorepo), this only emits `packages/ui` and leaves the rest of your repo untouched.
16
+
17
+ ## Usage
18
+
19
+ Run it from the root of an existing repo (published under the [`@pauldvlp/create`](../create) manifest):
20
+
21
+ ```bash
22
+ # Interactive (prompts for anything you don't pass)
23
+ vp create @pauldvlp:vp-pkg-shadcn
24
+
25
+ # Non-interactive, fully specified
26
+ vp create @pauldvlp:vp-pkg-shadcn -- \
27
+ --scope @acme --base base --preset vega --iconLibrary lucide --components button,card,dialog
28
+ ```
29
+
30
+ > Only **string/enum** options parse reliably as `vp create -- --flag value`. **Boolean** options
31
+ > (`--cssVariables`, `--rtl`, `--pointer`, `--install`) are best left to the interactive prompt —
32
+ > Bingo's CLI does not accept `--no-x` / `--x=false` cleanly. Omit them and answer the prompt.
33
+
34
+ ### Requirements
35
+
36
+ Your repo must be a **pnpm workspace that globs the directory you pick** (e.g. `packages/*`), so the
37
+ new `<scope>/ui` is linked and the post-scaffold `pnpm --filter <scope>/ui ...` steps resolve. The
38
+ generator does **not** edit your `pnpm-workspace.yaml` or any app — wiring a consumer is up to you
39
+ (see below).
40
+
41
+ ### Where it lands (the `--directory`)
42
+
43
+ The generator emits the package contents at the **root** of its file tree, and Bingo writes them under
44
+ the target directory — which **defaults to `ui`** (so within `vp create`'s monorepo flow it lands at
45
+ `<chosen-parent>/ui`, e.g. `packages/ui`). Pass `--directory <path>` to place it elsewhere. `--scope`
46
+ defaults to the **surrounding monorepo's scope** (read from the nearest `pnpm-workspace.yaml`'s
47
+ `package.json` — e.g. a repo named `acme` → `@acme`), falling back to `@app` outside a workspace.
48
+
49
+ ## Options
50
+
51
+ | Option | Type / values | Default | Notes |
52
+ | --------------- | ---------------------------------------------- | -------------- | --------------------------------------------------------------------------------------- |
53
+ | `--scope` | string | monorepo scope | npm scope for the package → `@scope/ui`. Defaults to the surrounding monorepo's scope (e.g. `@acme`), `@app` outside a workspace. `@` is added if you omit it. |
54
+ | `--base` | `radix` \| `base` | `radix` | shadcn component library (radix-ui or @base-ui). Honored by `shadcn init --base`. |
55
+ | `--preset` | style name or code | `b30557okNu` | A style (`nova`, `vega`, `maia`, `lyra`, `mira`, `luma`, `sera`, `rhea`) **or** a code from ui.shadcn.com. **Owns** color, fonts, radius, baseColor, menu styling. |
56
+ | `--iconLibrary` | `lucide` \| `hugeicons` \| `radix` \| `tabler` | `hugeicons` | Icon library (persists; not part of the preset). |
57
+ | `--cssVariables`| boolean | `true` | CSS variables for theming. |
58
+ | `--rtl` | boolean | `false` | RTL support. |
59
+ | `--pointer` | boolean | `false` | Pointer cursor on interactive elements. |
60
+ | `--components` | comma list | `button,badge` | shadcn components to pre-install. `button` + `badge` are always included. |
61
+ | `--install` | boolean | `true` | Run install + apply the shadcn theme after scaffolding. `false` = files only. |
62
+
63
+ ## How it scaffolds
64
+
65
+ `produce()` emits `packages/ui` with a **minimal** `globals.css` (so Tailwind v4 is detectable),
66
+ resolves the package's `catalog:` specifiers to concrete versions (it can't assume your repo's
67
+ pnpm catalog), bakes `components.json` from your options, then runs:
68
+
69
+ ```bash
70
+ pnpm install
71
+ pnpm --filter <scope>/ui exec shadcn init --base <base> --preset <preset> ... --no-reinstall -y -f
72
+ pnpm --filter <scope>/ui exec shadcn add button badge <extra> -y
73
+ ```
74
+
75
+ shadcn `init` fills the theme tokens into `globals.css` and creates `lib/utils.ts`; `add` writes
76
+ components into `src/components/ui/`. The UI package `exports` (`./components/* → ./src/components/*.tsx`)
77
+ resolves them as `@scope/ui/components/ui/<name>`.
78
+
79
+ ## Consume it from an app
80
+
81
+ This generator only creates the `ui` package — wiring it into a consuming app is three steps:
82
+
83
+ **1. Depend on it.**
84
+
85
+ ```jsonc
86
+ // apps/<your-app>/package.json
87
+ "dependencies": { "@scope/ui": "workspace:*" }
88
+ ```
89
+
90
+ **2. Give the app Tailwind v4.** The app — not the `ui` package — compiles the styles, so it needs the
91
+ Tailwind plugin. Skip this if the app already uses Tailwind v4.
92
+
93
+ ```bash
94
+ pnpm --filter <your-app> add -D @tailwindcss/vite tailwindcss
95
+ ```
96
+
97
+ ```ts
98
+ // apps/<your-app>/vite.config.ts
99
+ import tailwindcss from '@tailwindcss/vite'
100
+ export default defineConfig({ plugins: [/* ...existing */ tailwindcss()] })
101
+ ```
102
+
103
+ > `ui`'s `globals.css` already `@source`s `apps/**/*.{ts,tsx}` (and the `ui` package), so Tailwind
104
+ > scans your app's class names. If your app lives outside `apps/`, add an `@source` for its path.
105
+
106
+ **3. Import the styles once at the app's entry point**, then use components:
107
+
108
+ ```tsx
109
+ // apps/<your-app>/src/main.tsx
110
+ import '@scope/ui/globals.css'
111
+ import { Button } from '@scope/ui/components/ui/button'
112
+ ```
113
+
114
+ ## Re-theme later
115
+
116
+ ```bash
117
+ pnpm --filter @scope/ui exec shadcn init --preset <new-code> --no-reinstall -y -f
118
+ pnpm --filter @scope/ui exec shadcn add <component>
119
+ ```
120
+
121
+ ## Develop the generator
122
+
123
+ ```bash
124
+ pnpm install
125
+ node bin/index.ts --help # list options
126
+ node bin/index.ts --directory /tmp/demo --scope @demo --base base --preset vega
127
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/index.ts
4
+ import fs2 from "node:fs";
5
+ import path3 from "node:path";
6
+ import * as prompts from "@clack/prompts";
7
+
8
+ // ../template-kit/src/index.ts
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ var RENAME = {
12
+ _gitignore: ".gitignore"
13
+ };
14
+ var DEFAULT_PRESET = "b30557okNu";
15
+ var ICON_LIBS = {
16
+ hugeicons: { "@hugeicons/react": "^1.1.9", "@hugeicons/core-free-icons": "^4.2.1" },
17
+ lucide: { "lucide-react": "^0" },
18
+ radix: { "@radix-ui/react-icons": "^1" },
19
+ tabler: { "@tabler/icons-react": "^3" }
20
+ };
21
+ var CATALOG = {
22
+ "@types/node": "^24",
23
+ typescript: "^5",
24
+ vite: "npm:@voidzero-dev/vite-plus-core@latest",
25
+ vitest: "4.1.9",
26
+ "vite-plus": "^0.2.1",
27
+ "babel-plugin-react-compiler": "^1.0.0",
28
+ "@rolldown/plugin-babel": "^0.2.3"
29
+ };
30
+ function toScope(name) {
31
+ const n = name.trim();
32
+ return n.startsWith("@") ? n : `@${n}`;
33
+ }
34
+ function detectMonorepoScope() {
35
+ let dir = process.cwd();
36
+ for (let i = 0; i < 10; i++) {
37
+ const hasWorkspace = fs.existsSync(path.join(dir, "pnpm-workspace.yaml")) || fs.existsSync(path.join(dir, "pnpm-workspace.yml"));
38
+ const pkgPath = path.join(dir, "package.json");
39
+ if (hasWorkspace && fs.existsSync(pkgPath)) {
40
+ try {
41
+ const name = JSON.parse(fs.readFileSync(pkgPath, "utf8")).name;
42
+ if (typeof name === "string" && name) {
43
+ const head = name.startsWith("@") ? name.slice(1).split("/")[0] : name;
44
+ return toScope(head);
45
+ }
46
+ } catch {
47
+ }
48
+ }
49
+ const parent = path.dirname(dir);
50
+ if (parent === dir) break;
51
+ dir = parent;
52
+ }
53
+ return void 0;
54
+ }
55
+ function readTree(dir, transform, base = dir) {
56
+ const out = {};
57
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
58
+ const abs = path.join(dir, entry.name);
59
+ const name = RENAME[entry.name] ?? entry.name;
60
+ if (entry.isDirectory()) {
61
+ out[name] = readTree(abs, transform, base);
62
+ } else {
63
+ const rel = path.relative(base, abs);
64
+ out[name] = transform(rel, fs.readFileSync(abs, "utf8"));
65
+ }
66
+ }
67
+ return out;
68
+ }
69
+ function setPath(tree, relPath, content) {
70
+ const parts = relPath.split("/");
71
+ let node = tree;
72
+ for (let i = 0; i < parts.length - 1; i++) {
73
+ const key = parts[i];
74
+ if (typeof node[key] !== "object") node[key] = {};
75
+ node = node[key];
76
+ }
77
+ node[parts[parts.length - 1]] = content;
78
+ }
79
+ function patchJson(tree, relPath, mutate) {
80
+ const parts = relPath.split("/");
81
+ let node = tree;
82
+ for (let i = 0; i < parts.length - 1; i++) node = node[parts[i]];
83
+ const key = parts[parts.length - 1];
84
+ const json = JSON.parse(node[key]);
85
+ mutate(json);
86
+ node[key] = `${JSON.stringify(json, null, 2)}
87
+ `;
88
+ }
89
+ function resolveCatalogDeps(pkg, catalog = CATALOG) {
90
+ for (const field of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
91
+ const deps = pkg[field];
92
+ if (!deps) continue;
93
+ for (const [name, range] of Object.entries(deps)) {
94
+ if ((range === "catalog:" || range === "catalog:default") && catalog[name]) deps[name] = catalog[name];
95
+ }
96
+ }
97
+ }
98
+ function addIconDeps(pkg, iconLibrary) {
99
+ const iconDeps = ICON_LIBS[iconLibrary] ?? ICON_LIBS.hugeicons;
100
+ pkg.dependencies = { ...pkg.dependencies, ...iconDeps };
101
+ }
102
+ function withRequiredComponents(csv, required = ["button", "badge"]) {
103
+ const requested = csv.split(",").map((c) => c.trim()).filter(Boolean);
104
+ return Array.from(/* @__PURE__ */ new Set([...required, ...requested]));
105
+ }
106
+ function uiComponentsJson(theme) {
107
+ const { scope, base, cssVariables, iconLibrary, rtl } = theme;
108
+ return {
109
+ $schema: "https://ui.shadcn.com/schema.json",
110
+ style: `${base}-nova`,
111
+ rsc: false,
112
+ tsx: true,
113
+ tailwind: { config: "", css: "./src/styles/globals.css", baseColor: "neutral", cssVariables },
114
+ iconLibrary,
115
+ rtl,
116
+ base,
117
+ aliases: {
118
+ components: `${scope}/ui/components`,
119
+ ui: `${scope}/ui/components`,
120
+ lib: `${scope}/ui/lib`,
121
+ utils: `${scope}/ui/lib/utils`,
122
+ hooks: `${scope}/ui/hooks`
123
+ }
124
+ };
125
+ }
126
+ function shadcnInitFlags(opts) {
127
+ return [
128
+ `--base ${opts.base}`,
129
+ `--preset ${opts.preset}`,
130
+ opts.cssVariables ? "--css-variables" : "--no-css-variables",
131
+ opts.rtl ? "--rtl" : "--no-rtl",
132
+ opts.pointer ? "--pointer" : "--no-pointer",
133
+ "--no-reinstall",
134
+ "-y",
135
+ "-f"
136
+ ].join(" ");
137
+ }
138
+
139
+ // bin/index.ts
140
+ import { runTemplateCLI } from "bingo";
141
+
142
+ // src/template.ts
143
+ import path2 from "node:path";
144
+ import { fileURLToPath } from "node:url";
145
+ import { createTemplate } from "bingo";
146
+ import { z } from "zod";
147
+
148
+ // package.json
149
+ var package_default = {
150
+ name: "@pauldvlp/vp-pkg-shadcn",
151
+ version: "0.4.0",
152
+ description: "Add a shared, fully customizable shadcn UI package (packages/ui) into an existing Vite+ monorepo, themeable via shadcn presets.",
153
+ author: "pauldvlp (https://github.com/pauldvlp/vp-templates)",
154
+ homepage: "https://github.com/pauldvlp/vp-templates",
155
+ repository: {
156
+ type: "git",
157
+ url: "git+https://github.com/pauldvlp/vp-templates.git",
158
+ directory: "packages/vp-pkg-shadcn"
159
+ },
160
+ bugs: "https://github.com/pauldvlp/vp-templates/issues",
161
+ keywords: [
162
+ "vite-plus-generator",
163
+ "vite-plus",
164
+ "shadcn",
165
+ "react",
166
+ "template"
167
+ ],
168
+ bin: "./dist/index.js",
169
+ type: "module",
170
+ files: [
171
+ "dist",
172
+ "template"
173
+ ],
174
+ scripts: {
175
+ build: "esbuild bin/index.ts --bundle --outfile=dist/index.js --format=esm --platform=node --target=node22 --packages=external",
176
+ dev: "node bin/index.ts",
177
+ prepack: "pnpm run build"
178
+ },
179
+ dependencies: {
180
+ "@clack/prompts": "^0.11.0",
181
+ bingo: "^0.9.3",
182
+ zod: "^3.25.76"
183
+ },
184
+ devDependencies: {
185
+ "@pauldvlp/template-kit": "workspace:*",
186
+ "@types/node": "^24",
187
+ esbuild: "^0.25.0",
188
+ typescript: "^5"
189
+ },
190
+ engines: {
191
+ node: ">=22.18.0"
192
+ }
193
+ };
194
+
195
+ // src/template.ts
196
+ var TEMPLATE_DIR = path2.join(path2.dirname(fileURLToPath(import.meta.url)), "..", "template");
197
+ var template_default = createTemplate({
198
+ about: {
199
+ name: package_default.name,
200
+ description: package_default.description
201
+ },
202
+ options: {
203
+ scope: z.string().describe("npm scope for the workspace package, e.g. @acme").default("@app"),
204
+ // Unions of literals (not z.enum) so the value is settable on Bingo's CLI: bingo's arg parser
205
+ // handles ZodUnion/ZodLiteral but not ZodEnum (a bare `--base radix` would otherwise mis-parse to
206
+ // `base: true`). Both still render as an interactive `select`.
207
+ base: z.union([z.literal("radix"), z.literal("base")]).describe("shadcn component library base (radix-ui or @base-ui)").default("radix"),
208
+ preset: z.string().describe("shadcn preset: a style name (nova, vega, maia, lyra, mira, luma, sera, rhea) or a code from ui.shadcn.com").default(DEFAULT_PRESET),
209
+ iconLibrary: z.union([z.literal("lucide"), z.literal("hugeicons"), z.literal("radix"), z.literal("tabler")]).describe("Icon library").default("hugeicons"),
210
+ cssVariables: z.boolean().describe("Use CSS variables for theming").default(true),
211
+ rtl: z.boolean().describe("Enable RTL support").default(false),
212
+ pointer: z.boolean().describe("Use pointer cursor on interactive elements").default(false),
213
+ components: z.string().describe("Comma-separated shadcn components to pre-install, e.g. button,card,dialog").default("button,badge"),
214
+ install: z.boolean().describe("Install deps and apply the shadcn theme after scaffolding").default(true)
215
+ },
216
+ // Default the scope to the surrounding monorepo's scope (e.g. `@acme`) so it tracks the repo
217
+ // instead of a fixed `@app`. Falls back to `@app` when run outside a pnpm workspace.
218
+ prepare() {
219
+ const monorepoScope = detectMonorepoScope();
220
+ return {
221
+ scope: () => monorepoScope ?? "@app"
222
+ };
223
+ },
224
+ async produce({ options }) {
225
+ const scope = toScope(options.scope || "app");
226
+ const files = readTree(TEMPLATE_DIR, (_rel, content) => content.split("@app").join(scope));
227
+ patchJson(files, "package.json", (pkg) => {
228
+ resolveCatalogDeps(pkg);
229
+ addIconDeps(pkg, options.iconLibrary);
230
+ });
231
+ setPath(files, "components.json", `${JSON.stringify(uiComponentsJson({ ...options, scope }), null, 2)}
232
+ `);
233
+ const adds = withRequiredComponents(options.components);
234
+ const ui = `${scope}/ui`;
235
+ const initFlags = shadcnInitFlags(options);
236
+ const scripts = options.install ? [
237
+ { commands: ["pnpm install --silent"], phase: 0 },
238
+ { commands: [`pnpm --filter ${ui} exec shadcn init ${initFlags}`], phase: 1 },
239
+ { commands: [`pnpm --filter ${ui} exec shadcn add ${adds.join(" ")} -y`], phase: 2 }
240
+ ] : [];
241
+ return {
242
+ files,
243
+ scripts
244
+ };
245
+ }
246
+ });
247
+
248
+ // bin/index.ts
249
+ var DOCS_URL = "https://github.com/pauldvlp/vp-templates/blob/main/packages/vp-pkg-shadcn/README.md";
250
+ function getArg(argv2, name) {
251
+ for (let i = 0; i < argv2.length; i++) {
252
+ const arg = argv2[i];
253
+ if (arg === `--${name}`) return argv2[i + 1];
254
+ if (arg.startsWith(`--${name}=`)) return arg.slice(name.length + 3);
255
+ }
256
+ return void 0;
257
+ }
258
+ var argv = process.argv.slice(2);
259
+ var isHelp = argv.some((arg) => arg === "--help" || arg === "-h");
260
+ var isInteractive = process.stdout.isTTY && !argv.includes("--no-interactive");
261
+ if (!getArg(argv, "directory") && !isHelp) {
262
+ process.argv.push("--directory", "ui");
263
+ }
264
+ var status = await runTemplateCLI(template_default);
265
+ process.exitCode = status;
266
+ var finalArgv = process.argv.slice(2);
267
+ var targetDir = getArg(finalArgv, "directory");
268
+ if (!isHelp && targetDir && targetDir !== "." && path3.resolve(targetDir) !== process.cwd()) {
269
+ fs2.rmSync(path3.join(targetDir, ".git"), { recursive: true, force: true });
270
+ }
271
+ if (!isHelp && (status === 0 || status === void 0)) {
272
+ const ui = `${toScope(getArg(finalArgv, "scope") || detectMonorepoScope() || "app")}/ui`;
273
+ prompts.note(
274
+ [
275
+ `1. Workspace glob the dir you chose (e.g. packages/*) so ${ui} is linked`,
276
+ `2. Depend on it ${'"' + ui + '": "workspace:*"'} in your app's package.json`,
277
+ `3. Tailwind v4 pnpm --filter <app> add -D @tailwindcss/vite tailwindcss`,
278
+ ` then add tailwindcss() to the app's vite.config plugins`,
279
+ `4. Import the styles import '${ui}/globals.css' in the app entry (e.g. src/main.tsx)`,
280
+ ``,
281
+ `Add components pnpm --filter ${ui} exec shadcn add <name>`,
282
+ `Docs ${DOCS_URL}`
283
+ ].join("\n"),
284
+ `Wire ${ui} into your app`
285
+ );
286
+ if (isInteractive) {
287
+ const ack = await prompts.confirm({ message: "Got it \u2014 continue?", initialValue: true });
288
+ if (prompts.isCancel(ack)) prompts.cancel("Okay \u2014 see the docs link above when you\u2019re ready.");
289
+ }
290
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@pauldvlp/vp-pkg-shadcn",
3
+ "version": "0.4.0",
4
+ "description": "Add a shared, fully customizable shadcn UI package (packages/ui) into an existing Vite+ monorepo, themeable via shadcn presets.",
5
+ "author": "pauldvlp (https://github.com/pauldvlp/vp-templates)",
6
+ "homepage": "https://github.com/pauldvlp/vp-templates",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/pauldvlp/vp-templates.git",
10
+ "directory": "packages/vp-pkg-shadcn"
11
+ },
12
+ "bugs": "https://github.com/pauldvlp/vp-templates/issues",
13
+ "keywords": [
14
+ "vite-plus-generator",
15
+ "vite-plus",
16
+ "shadcn",
17
+ "react",
18
+ "template"
19
+ ],
20
+ "type": "module",
21
+ "files": [
22
+ "dist",
23
+ "template"
24
+ ],
25
+ "dependencies": {
26
+ "@clack/prompts": "^0.11.0",
27
+ "bingo": "^0.9.3",
28
+ "zod": "^3.25.76"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^24",
32
+ "esbuild": "^0.25.0",
33
+ "typescript": "^5",
34
+ "@pauldvlp/template-kit": "0.0.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=22.18.0"
38
+ },
39
+ "scripts": {
40
+ "build": "esbuild bin/index.ts --bundle --outfile=dist/index.js --format=esm --platform=node --target=node22 --packages=external",
41
+ "dev": "node bin/index.ts"
42
+ },
43
+ "bin": {
44
+ "vp-pkg-shadcn": "./dist/index.js"
45
+ }
46
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@app/ui",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ "./globals.css": "./src/styles/globals.css",
8
+ "./lib/*": "./src/lib/*.ts",
9
+ "./components/*": "./src/components/*.tsx",
10
+ "./hooks/*": "./src/hooks/*.ts"
11
+ },
12
+ "scripts": {
13
+ "lint": "vp lint",
14
+ "check": "vp check"
15
+ },
16
+ "dependencies": {
17
+ "@fontsource-variable/outfit": "^5.2.8",
18
+ "@fontsource-variable/space-grotesk": "^5.2.10",
19
+ "class-variance-authority": "^0.7.1",
20
+ "clsx": "^2.1.1",
21
+ "shadcn": "^4.11.0",
22
+ "tailwind-merge": "^3.6.0",
23
+ "tw-animate-css": "^1.4.0"
24
+ },
25
+ "devDependencies": {
26
+ "@tailwindcss/vite": "^4",
27
+ "@types/react": "^19.2.17",
28
+ "@types/react-dom": "^19.2.3",
29
+ "@vitejs/plugin-react": "^6.0.2",
30
+ "react": "^19.2.7",
31
+ "react-dom": "^19.2.7",
32
+ "tailwindcss": "^4",
33
+ "typescript": "~6.0.2",
34
+ "vite": "catalog:",
35
+ "vite-plus": "catalog:"
36
+ },
37
+ "peerDependencies": {
38
+ "react": "^19",
39
+ "react-dom": "^19"
40
+ }
41
+ }
File without changes
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ @import 'tailwindcss';
2
+ @import 'tw-animate-css';
3
+
4
+ @custom-variant dark (&:is(.dark *));
5
+ @source "../../../../apps/**/*.{ts,tsx}";
6
+ @source "../**/*.{ts,tsx}";
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "types": ["vite-plus/client"],
10
+ "skipLibCheck": true,
11
+ "strict": true,
12
+ "verbatimModuleSyntax": true,
13
+ "allowImportingTsExtensions": true,
14
+ "noEmit": true,
15
+ "paths": {
16
+ "@app/ui/*": ["./src/*"]
17
+ }
18
+ },
19
+ "include": ["src"],
20
+ "exclude": ["node_modules", "dist"]
21
+ }
@@ -0,0 +1,31 @@
1
+ import tailwindcss from '@tailwindcss/vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import { defineConfig, lazyPlugins } from 'vite-plus'
4
+
5
+ // https://vite.dev/config/
6
+ export default defineConfig({
7
+ lint: {
8
+ plugins: ['react', 'typescript', 'oxc'],
9
+ rules: {
10
+ 'react/rules-of-hooks': 'error',
11
+ 'react/only-export-components': [
12
+ 'warn',
13
+ {
14
+ allowConstantExport: true
15
+ }
16
+ ],
17
+ 'vite-plus/prefer-vite-plus-imports': 'error'
18
+ },
19
+ options: {
20
+ typeAware: true,
21
+ typeCheck: true
22
+ },
23
+ jsPlugins: [
24
+ {
25
+ name: 'vite-plus',
26
+ specifier: 'vite-plus/oxlint-plugin'
27
+ }
28
+ ]
29
+ },
30
+ plugins: lazyPlugins(() => [react(), tailwindcss()])
31
+ })