trix-ui 0.2.2 → 0.2.4

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.
@@ -1,105 +1,105 @@
1
- import path from "node:path";
2
- import { promises as fs } from "node:fs";
3
- import { Command } from "commander";
4
- import { Project } from "ts-morph";
5
- import { registryIndexSchema, registrySchema } from "../schema/index.js";
6
- import { transformIcons, transformMenu, transformRender } from "../utils/index.js";
7
- const DEFAULT_ITEM_SCHEMA = "https://ui.shadcn.com/schema/registry-item.json";
8
- export const buildCommand = new Command("build")
9
- .description("Build registry items into JSON files")
10
- .argument("[registry]", "path to registry.json", "registry.json")
11
- .option("--output <dir>", "output directory", "dist")
12
- .option("--style <name>", "style name")
13
- .option("--icon-library <name>", "icon library")
14
- .option("--menu-color <name>", "menu color")
15
- .option("--schema <url>", "registry item schema URL")
16
- .action(async (registryArg, options) => {
17
- try {
18
- const cwd = process.cwd();
19
- const registryPath = resolvePath(cwd, registryArg);
20
- const { registry, items } = await loadRegistry(registryPath);
21
- const outputDir = resolvePath(cwd, options.output ?? "dist");
22
- const transformConfig = getTransformConfig(items, options);
23
- const project = new Project({ useInMemoryFileSystem: true });
24
- await fs.mkdir(outputDir, { recursive: true });
25
- for (const item of items) {
26
- const payload = await buildRegistryItem(cwd, project, item, transformConfig, options.schema);
27
- const outputPath = path.join(outputDir, `${item.name}.json`);
28
- await fs.writeFile(outputPath, JSON.stringify(payload, null, 2));
29
- }
30
- if (registry) {
31
- const registryOutput = { ...registry, items };
32
- await fs.writeFile(path.join(outputDir, "registry.json"), JSON.stringify(registryOutput, null, 2));
33
- }
34
- }
35
- catch (error) {
36
- console.error(error.message);
37
- process.exit(1);
38
- }
39
- });
40
- function resolvePath(cwd, value) {
41
- return path.isAbsolute(value) ? value : path.resolve(cwd, value);
42
- }
43
- async function loadRegistry(registryPath) {
44
- const raw = await fs.readFile(registryPath, "utf8");
45
- const parsed = JSON.parse(raw);
46
- if (Array.isArray(parsed)) {
47
- return {
48
- items: registryIndexSchema.parse(parsed)
49
- };
50
- }
51
- const registry = registrySchema.parse(parsed);
52
- return {
53
- registry,
54
- items: registry.items
55
- };
56
- }
57
- function getTransformConfig(items, options) {
58
- const config = {
59
- style: options.style,
60
- iconLibrary: options.iconLibrary,
61
- menuColor: options.menuColor
62
- };
63
- const baseItem = items.find((item) => item.type === "registry:base");
64
- if (baseItem?.config) {
65
- config.style ??= baseItem.config.style;
66
- config.iconLibrary ??= baseItem.config.iconLibrary;
67
- config.menuColor ??= baseItem.config.menuColor;
68
- }
69
- return config;
70
- }
71
- async function buildRegistryItem(cwd, project, item, config, schemaOverride) {
72
- const payload = { ...item };
73
- const schemaValue = schemaOverride ?? DEFAULT_ITEM_SCHEMA;
74
- if (!payload.$schema && schemaValue) {
75
- payload.$schema = schemaValue;
76
- }
77
- if (item.files) {
78
- payload.files = await Promise.all(item.files.map(async (file) => {
79
- const sourcePath = resolvePath(cwd, file.path);
80
- const raw = file.content ?? (await fs.readFile(sourcePath, "utf8"));
81
- const content = isSourceFile(file.path)
82
- ? await transformSource(project, file.path, raw, config)
83
- : raw;
84
- return {
85
- ...file,
86
- content
87
- };
88
- }));
89
- }
90
- return payload;
91
- }
92
- async function transformSource(project, filename, raw, config) {
93
- const sourceFile = project.createSourceFile(filename, raw, {
94
- overwrite: true
95
- });
96
- let next = await transformRender({ filename, raw, config, sourceFile });
97
- next = await transformMenu({ filename, raw, config, sourceFile: next });
98
- next = await transformIcons({ filename, raw, config, sourceFile: next });
99
- return next.getFullText();
100
- }
101
- function isSourceFile(filePath) {
102
- const ext = path.extname(filePath).toLowerCase();
103
- return ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".jsx";
104
- }
1
+ import path from "node:path";
2
+ import { promises as fs } from "node:fs";
3
+ import { Command } from "commander";
4
+ import { Project } from "ts-morph";
5
+ import { registryIndexSchema, registrySchema } from "../schema/index.js";
6
+ import { transformIcons, transformMenu, transformRender } from "../utils/index.js";
7
+ const DEFAULT_ITEM_SCHEMA = "https://ui.trix.com/schema/registry-item.json";
8
+ export const buildCommand = new Command("build")
9
+ .description("Build registry items into JSON files")
10
+ .argument("[registry]", "path to registry.json", "registry.json")
11
+ .option("--output <dir>", "output directory", "dist")
12
+ .option("--style <name>", "style name")
13
+ .option("--icon-library <name>", "icon library")
14
+ .option("--menu-color <name>", "menu color")
15
+ .option("--schema <url>", "registry item schema URL")
16
+ .action(async (registryArg, options) => {
17
+ try {
18
+ const cwd = process.cwd();
19
+ const registryPath = resolvePath(cwd, registryArg);
20
+ const { registry, items } = await loadRegistry(registryPath);
21
+ const outputDir = resolvePath(cwd, options.output ?? "dist");
22
+ const transformConfig = getTransformConfig(items, options);
23
+ const project = new Project({ useInMemoryFileSystem: true });
24
+ await fs.mkdir(outputDir, { recursive: true });
25
+ for (const item of items) {
26
+ const payload = await buildRegistryItem(cwd, project, item, transformConfig, options.schema);
27
+ const outputPath = path.join(outputDir, `${item.name}.json`);
28
+ await fs.writeFile(outputPath, JSON.stringify(payload, null, 2));
29
+ }
30
+ if (registry) {
31
+ const registryOutput = { ...registry, items };
32
+ await fs.writeFile(path.join(outputDir, "registry.json"), JSON.stringify(registryOutput, null, 2));
33
+ }
34
+ }
35
+ catch (error) {
36
+ console.error(error.message);
37
+ process.exit(1);
38
+ }
39
+ });
40
+ function resolvePath(cwd, value) {
41
+ return path.isAbsolute(value) ? value : path.resolve(cwd, value);
42
+ }
43
+ async function loadRegistry(registryPath) {
44
+ const raw = await fs.readFile(registryPath, "utf8");
45
+ const parsed = JSON.parse(raw);
46
+ if (Array.isArray(parsed)) {
47
+ return {
48
+ items: registryIndexSchema.parse(parsed)
49
+ };
50
+ }
51
+ const registry = registrySchema.parse(parsed);
52
+ return {
53
+ registry,
54
+ items: registry.items
55
+ };
56
+ }
57
+ function getTransformConfig(items, options) {
58
+ const config = {
59
+ style: options.style,
60
+ iconLibrary: options.iconLibrary,
61
+ menuColor: options.menuColor
62
+ };
63
+ const baseItem = items.find((item) => item.type === "registry:base");
64
+ if (baseItem?.config) {
65
+ config.style ??= baseItem.config.style;
66
+ config.iconLibrary ??= baseItem.config.iconLibrary;
67
+ config.menuColor ??= baseItem.config.menuColor;
68
+ }
69
+ return config;
70
+ }
71
+ async function buildRegistryItem(cwd, project, item, config, schemaOverride) {
72
+ const payload = { ...item };
73
+ const schemaValue = schemaOverride ?? DEFAULT_ITEM_SCHEMA;
74
+ if (!payload.$schema && schemaValue) {
75
+ payload.$schema = schemaValue;
76
+ }
77
+ if (item.files) {
78
+ payload.files = await Promise.all(item.files.map(async (file) => {
79
+ const sourcePath = resolvePath(cwd, file.path);
80
+ const raw = file.content ?? (await fs.readFile(sourcePath, "utf8"));
81
+ const content = isSourceFile(file.path)
82
+ ? await transformSource(project, file.path, raw, config)
83
+ : raw;
84
+ return {
85
+ ...file,
86
+ content
87
+ };
88
+ }));
89
+ }
90
+ return payload;
91
+ }
92
+ async function transformSource(project, filename, raw, config) {
93
+ const sourceFile = project.createSourceFile(filename, raw, {
94
+ overwrite: true
95
+ });
96
+ let next = await transformRender({ filename, raw, config, sourceFile });
97
+ next = await transformMenu({ filename, raw, config, sourceFile: next });
98
+ next = await transformIcons({ filename, raw, config, sourceFile: next });
99
+ return next.getFullText();
100
+ }
101
+ function isSourceFile(filePath) {
102
+ const ext = path.extname(filePath).toLowerCase();
103
+ return ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".jsx";
104
+ }
105
105
  //# sourceMappingURL=build.js.map
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trix-ui",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Lite UI CLI, registry tooling, and templates.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,14 +33,6 @@
33
33
  "tailwind.css",
34
34
  "README.md"
35
35
  ],
36
- "scripts": {
37
- "build": "tsc -p tsconfig.json",
38
- "dev": "node --enable-source-maps --import tsx src/index.ts",
39
- "typecheck": "tsc -p tsconfig.json --noEmit",
40
- "pub:beta": "pnpm build && pnpm publish --no-git-checks --access public --tag beta",
41
- "pub:release": "pnpm build && pnpm publish --access public",
42
- "test": "vitest"
43
- },
44
36
  "dependencies": {
45
37
  "@antfu/ni": "^28.2.0",
46
38
  "chalk": "^5.6.2",
@@ -64,5 +56,13 @@
64
56
  "@types/prompts": "^2.4.9",
65
57
  "tsx": "^4.21.0",
66
58
  "typescript": "^5.9.3"
59
+ },
60
+ "scripts": {
61
+ "build": "tsc -p tsconfig.json",
62
+ "dev": "node --enable-source-maps --import tsx src/index.ts",
63
+ "typecheck": "tsc -p tsconfig.json --noEmit",
64
+ "pub:beta": "pnpm build && pnpm publish --no-git-checks --access public --tag beta",
65
+ "pub:release": "pnpm build && pnpm publish --access public",
66
+ "test": "vitest"
67
67
  }
68
- }
68
+ }
@@ -1,181 +1,204 @@
1
- {
2
- "version": 1,
3
- "components": [
4
- {
5
- "name": "avatar",
6
- "description": "Avatar with image, fallback, and grouping helpers.",
7
- "files": [
8
- {
9
- "source": "components/ui/avatar.tsx",
10
- "target": "{{components}}/avatar.tsx"
11
- }
12
- ],
13
- "dependencies": {
14
- "npm": ["@radix-ui/react-avatar", "clsx", "tailwind-merge"]
15
- }
16
- },
17
- {
18
- "name": "badge",
19
- "description": "Badge with variants.",
20
- "files": [
21
- {
22
- "source": "components/ui/badge.tsx",
23
- "target": "{{components}}/badge.tsx"
24
- }
25
- ],
26
- "dependencies": {
27
- "npm": ["clsx", "tailwind-merge"]
28
- }
29
- },
30
- {
31
- "name": "button",
32
- "description": "Button with variants and focus ring.",
33
- "files": [
34
- {
35
- "source": "components/ui/button.tsx",
36
- "target": "{{components}}/button.tsx"
37
- }
38
- ],
39
- "dependencies": {
40
- "npm": ["clsx", "tailwind-merge"]
41
- }
42
- },
43
- {
44
- "name": "card",
45
- "description": "Card container with header/content/footer.",
46
- "files": [
47
- {
48
- "source": "components/ui/card.tsx",
49
- "target": "{{components}}/card.tsx"
50
- }
51
- ],
52
- "dependencies": {
53
- "npm": ["clsx", "tailwind-merge"]
54
- }
55
- },
56
- {
57
- "name": "input",
58
- "description": "Text input with consistent focus styles.",
59
- "files": [
60
- {
61
- "source": "components/ui/input.tsx",
62
- "target": "{{components}}/input.tsx"
63
- }
64
- ],
65
- "dependencies": {
66
- "npm": ["clsx", "tailwind-merge"]
67
- }
68
- },
69
- {
70
- "name": "label",
71
- "description": "Label with accessible focus and disabled styles.",
72
- "files": [
73
- {
74
- "source": "components/ui/label.tsx",
75
- "target": "{{components}}/label.tsx"
76
- }
77
- ],
78
- "dependencies": {
79
- "npm": ["@radix-ui/react-label", "clsx", "tailwind-merge"]
80
- }
81
- },
82
- {
83
- "name": "tabs",
84
- "description": "Tabs using Radix primitives.",
85
- "files": [
86
- {
87
- "source": "components/ui/tabs.tsx",
88
- "target": "{{components}}/tabs.tsx"
89
- }
90
- ],
91
- "dependencies": {
92
- "npm": ["@radix-ui/react-tabs", "clsx", "tailwind-merge"]
93
- }
94
- },
95
- {
96
- "name": "textarea",
97
- "description": "Textarea with consistent focus styles.",
98
- "files": [
99
- {
100
- "source": "components/ui/textarea.tsx",
101
- "target": "{{components}}/textarea.tsx"
102
- }
103
- ],
104
- "dependencies": {
105
- "npm": ["clsx", "tailwind-merge"]
106
- }
107
- }
108
- ],
109
- "sections": [
110
- {
111
- "name": "modern-hero",
112
- "description": "Animated hero with grid, particles, and CTA buttons.",
113
- "files": [
114
- {
115
- "source": "sections/modern-hero.tsx",
116
- "target": "{{sections}}/modern-hero.tsx"
117
- }
118
- ],
119
- "dependencies": {
120
- "local": ["button"]
121
- }
122
- }
123
- ],
124
- "wrappers": [
125
- {
126
- "name": "interactive-wrap",
127
- "description": "Interactive wrapper with hover glow and magnetic press.",
128
- "files": [
129
- {
130
- "source": "wrappers/Interative-wrapper.tsx",
131
- "target": "{{wrappers}}/interactive-wrap.tsx"
132
- }
133
- ],
134
- "dependencies": {
135
- "npm": ["@radix-ui/react-slot", "clsx", "tailwind-merge"]
136
- }
137
- }
138
- ],
139
- "composites": [
140
- {
141
- "name": "feature-collection-card",
142
- "description": "Card for spotlighting a featured collection.",
143
- "files": [
144
- {
145
- "source": "composites/feature-collection-card.tsx",
146
- "target": "{{composites}}/feature-collection-card.tsx"
147
- }
148
- ],
149
- "dependencies": {
150
- "npm": ["clsx", "tailwind-merge"]
151
- }
152
- },
153
- {
154
- "name": "music-player-card",
155
- "description": "Premium music player card with transport controls.",
156
- "files": [
157
- {
158
- "source": "composites/music-player-card.tsx",
159
- "target": "{{composites}}/music-player-card.tsx"
160
- }
161
- ],
162
- "dependencies": {
163
- "npm": ["lucide-react", "clsx", "tailwind-merge"]
164
- }
165
- },
166
- {
167
- "name": "user-profile-card",
168
- "description": "Profile card with avatar, tags, and action button.",
169
- "files": [
170
- {
171
- "source": "composites/user-profile-card.tsx",
172
- "target": "{{composites}}/user-profile-card.tsx"
173
- }
174
- ],
175
- "dependencies": {
176
- "local": ["badge", "button", "card"],
177
- "npm": ["lucide-react", "clsx", "tailwind-merge"]
178
- }
179
- }
180
- ]
1
+ {
2
+ "version": 1,
3
+ "components": [
4
+ {
5
+ "name": "avatar",
6
+ "description": "Avatar with image, fallback, and grouping helpers.",
7
+ "files": [
8
+ {
9
+ "source": "components/ui/avatar.tsx",
10
+ "target": "{{components}}/avatar.tsx"
11
+ }
12
+ ],
13
+ "dependencies": {
14
+ "npm": ["@radix-ui/react-avatar", "clsx", "tailwind-merge"]
15
+ }
16
+ },
17
+ {
18
+ "name": "badge",
19
+ "description": "Badge with variants.",
20
+ "files": [
21
+ {
22
+ "source": "components/ui/badge.tsx",
23
+ "target": "{{components}}/badge.tsx"
24
+ }
25
+ ],
26
+ "dependencies": {
27
+ "npm": ["clsx", "tailwind-merge"]
28
+ }
29
+ },
30
+ {
31
+ "name": "button",
32
+ "description": "Button with variants and focus ring.",
33
+ "files": [
34
+ {
35
+ "source": "components/ui/button.tsx",
36
+ "target": "{{components}}/button.tsx"
37
+ }
38
+ ],
39
+ "dependencies": {
40
+ "npm": ["clsx", "tailwind-merge"]
41
+ }
42
+ },
43
+ {
44
+ "name": "card",
45
+ "description": "Card container with header/content/footer.",
46
+ "files": [
47
+ {
48
+ "source": "components/ui/card.tsx",
49
+ "target": "{{components}}/card.tsx"
50
+ }
51
+ ],
52
+ "dependencies": {
53
+ "npm": ["clsx", "tailwind-merge"]
54
+ }
55
+ },
56
+ {
57
+ "name": "input",
58
+ "description": "Text input with consistent focus styles.",
59
+ "files": [
60
+ {
61
+ "source": "components/ui/input.tsx",
62
+ "target": "{{components}}/input.tsx"
63
+ }
64
+ ],
65
+ "dependencies": {
66
+ "npm": ["clsx", "tailwind-merge"]
67
+ }
68
+ },
69
+ {
70
+ "name": "label",
71
+ "description": "Label with accessible focus and disabled styles.",
72
+ "files": [
73
+ {
74
+ "source": "components/ui/label.tsx",
75
+ "target": "{{components}}/label.tsx"
76
+ }
77
+ ],
78
+ "dependencies": {
79
+ "npm": ["@radix-ui/react-label", "clsx", "tailwind-merge"]
80
+ }
81
+ },
82
+ {
83
+ "name": "tabs",
84
+ "description": "Tabs using Radix primitives.",
85
+ "files": [
86
+ {
87
+ "source": "components/ui/tabs.tsx",
88
+ "target": "{{components}}/tabs.tsx"
89
+ }
90
+ ],
91
+ "dependencies": {
92
+ "npm": ["@radix-ui/react-tabs", "clsx", "tailwind-merge"]
93
+ }
94
+ },
95
+ {
96
+ "name": "textarea",
97
+ "description": "Textarea with consistent focus styles.",
98
+ "files": [
99
+ {
100
+ "source": "components/ui/textarea.tsx",
101
+ "target": "{{components}}/textarea.tsx"
102
+ }
103
+ ],
104
+ "dependencies": {
105
+ "npm": ["clsx", "tailwind-merge"]
106
+ }
107
+ }
108
+ ],
109
+ "sections": [
110
+ {
111
+ "name": "signature-hero",
112
+ "description": "Premium editorial hero with layered panels, glow accents, and CTAs.",
113
+ "files": [
114
+ {
115
+ "source": "sections/signature-hero.tsx",
116
+ "target": "{{sections}}/signature-hero.tsx"
117
+ }
118
+ ]
119
+ }
120
+ ],
121
+ "wrappers": [
122
+ {
123
+ "name": "interactive-wrap",
124
+ "description": "Interactive wrapper with hover glow and magnetic press.",
125
+ "files": [
126
+ {
127
+ "source": "wrappers/Interative-wrapper.tsx",
128
+ "target": "{{wrappers}}/interactive-wrap.tsx"
129
+ }
130
+ ],
131
+ "dependencies": {
132
+ "npm": ["@radix-ui/react-slot", "clsx", "tailwind-merge"]
133
+ }
134
+ },
135
+ {
136
+ "name": "reveal-wrap",
137
+ "description": "Scroll reveal wrapper with motion-safe transitions.",
138
+ "files": [
139
+ {
140
+ "source": "wrappers/reveal-wrap.tsx",
141
+ "target": "{{wrappers}}/reveal-wrap.tsx"
142
+ }
143
+ ],
144
+ "dependencies": {
145
+ "npm": ["clsx", "tailwind-merge"]
146
+ }
147
+ },
148
+ {
149
+ "name": "progress-wrap",
150
+ "description": "Scroll progress wrapper with render-prop state.",
151
+ "files": [
152
+ {
153
+ "source": "wrappers/progress-wrapper.tsx",
154
+ "target": "{{wrappers}}/progress-wrap.tsx"
155
+ }
156
+ ],
157
+ "dependencies": {
158
+ "npm": ["clsx", "tailwind-merge"]
159
+ }
160
+ }
161
+ ],
162
+ "composites": [
163
+ {
164
+ "name": "feature-collection-card",
165
+ "description": "Card for spotlighting a featured collection.",
166
+ "files": [
167
+ {
168
+ "source": "composites/feature-collection-card.tsx",
169
+ "target": "{{composites}}/feature-collection-card.tsx"
170
+ }
171
+ ],
172
+ "dependencies": {
173
+ "npm": ["clsx", "tailwind-merge"]
174
+ }
175
+ },
176
+ {
177
+ "name": "music-player-card",
178
+ "description": "Premium music player card with transport controls.",
179
+ "files": [
180
+ {
181
+ "source": "composites/music-player-card.tsx",
182
+ "target": "{{composites}}/music-player-card.tsx"
183
+ }
184
+ ],
185
+ "dependencies": {
186
+ "npm": ["lucide-react", "clsx", "tailwind-merge"]
187
+ }
188
+ },
189
+ {
190
+ "name": "user-profile-card",
191
+ "description": "Profile card with avatar, tags, and action button.",
192
+ "files": [
193
+ {
194
+ "source": "composites/user-profile-card.tsx",
195
+ "target": "{{composites}}/user-profile-card.tsx"
196
+ }
197
+ ],
198
+ "dependencies": {
199
+ "local": ["badge", "button", "card"],
200
+ "npm": ["lucide-react", "clsx", "tailwind-merge"]
201
+ }
202
+ }
203
+ ]
181
204
  }