@create-ui/cli 0.5.3 → 0.5.5

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Contents
4
4
 
5
- - [Import from the configured icon library](#import-from-the-configured-icon-library)
5
+ - [Icons and assets come from @create-ui/assets](#icons-and-assets-come-from-create-uiassets)
6
6
  - [Icons in Button use the leadingIcon / trailingIcon props](#icons-in-button-use-the-leadingicon--trailingicon-props)
7
7
  - [Icon-only buttons](#icon-only-buttons)
8
8
  - [No sizing classes on icons inside components](#no-sizing-classes-on-icons-inside-components)
@@ -10,11 +10,28 @@
10
10
 
11
11
  ---
12
12
 
13
- ## Import from the configured icon library
13
+ ## Icons and assets come from @create-ui/assets
14
14
 
15
- **Always import icons from the project's configured `iconLibrary`.** Read the `iconLibrary` field from `createui info` (or `components.json`): `lucide` `lucide-react`, `tabler` → `@tabler/icons-react`, etc. The resolved default is `lucide`. Never hardcode an icon package.
15
+ **All icons and marks come from `@create-ui/assets`** — Create UI's own asset library. Registry components already import from it, and the CLI ships those imports as-is. Never reach for `lucide-react`, `@tabler/icons-react`, or any other icon package.
16
16
 
17
- Inside this monorepo, components import their icons from `@create-ui/assets/icons` (RemixIcon `Ri*`, e.g. `RiSearchLine`, `RiArrowRightLine`, `RiCheckLine`). In an end-user project, use whatever `iconLibrary` resolves to.
17
+ **General-purpose UI icons** `@create-ui/assets/icons` (Remix Icon, `Ri*` names). This subpath re-exports [`@remixicon/react`](https://remixicon.com), so the full Remix set is available:
18
+
19
+ ```tsx
20
+ import { RiArrowDownSLine, RiSearchLine, RiCheckLine } from "@create-ui/assets/icons"
21
+ ```
22
+
23
+ **Brand, flag, payment, social, and badge marks** → category subpaths (PascalCase, 900+ typed SVG components):
24
+
25
+ ```tsx
26
+ import { Github } from "@create-ui/assets/social"
27
+ import { Turkey } from "@create-ui/assets/flags"
28
+ import { VisaColor } from "@create-ui/assets/payments"
29
+ import { Docker } from "@create-ui/assets/brands"
30
+ ```
31
+
32
+ Subpaths: `icons` (Remix UI icons), `social`, `flags`, `payments`, `brands`, `banks`, `badges`, `crypto` (Web3 Icons). Marks that ship multiple treatments carry a suffix — pick the variant: `VisaColor` / `VisaBlack` / `VisaWhite`.
33
+
34
+ **Sizing & color differ from UI icons.** Standalone marks have their source dimensions stripped, so set a size explicitly (`className="size-6"` or `width`/`height`), and their brand colors are baked in — don't recolor; use the `Black` / `White` variant for contrast. This is the opposite of `Ri*` icons rendered *inside* Create UI components (`Button`, `DropdownMenuItem`, …), which are auto-sized via CVA — see [No sizing classes on icons inside components](#no-sizing-classes-on-icons-inside-components).
18
35
 
19
36
  ---
20
37
 
@@ -26,22 +43,22 @@ Inside this monorepo, components import their icons from `@create-ui/assets/icon
26
43
 
27
44
  ```tsx
28
45
  <Button>
29
- <SearchIcon className="mr-2 size-4" />
46
+ <RiSearchLine className="mr-2 size-4" />
30
47
  Search
31
48
  </Button>
32
49
 
33
50
  <Button>
34
51
  Next
35
- <ArrowRightIcon className="ml-2 size-4" />
52
+ <RiArrowRightLine className="ml-2 size-4" />
36
53
  </Button>
37
54
  ```
38
55
 
39
56
  **Correct:**
40
57
 
41
58
  ```tsx
42
- <Button leadingIcon={<SearchIcon />}>Search</Button>
59
+ <Button leadingIcon={<RiSearchLine />}>Search</Button>
43
60
 
44
- <Button trailingIcon={<ArrowRightIcon />}>Next</Button>
61
+ <Button trailingIcon={<RiArrowRightLine />}>Next</Button>
45
62
  ```
46
63
 
47
64
  ---
@@ -54,31 +71,31 @@ For a button that shows only an icon, set `iconOnly`, pass the icon via `leading
54
71
 
55
72
  ```tsx
56
73
  <Button>
57
- <SearchIcon className="size-4" />
74
+ <RiSearchLine className="size-4" />
58
75
  </Button>
59
76
  ```
60
77
 
61
78
  **Correct:**
62
79
 
63
80
  ```tsx
64
- <Button iconOnly aria-label="Search" leadingIcon={<SearchIcon />} />
81
+ <Button iconOnly aria-label="Search" leadingIcon={<RiSearchLine />} />
65
82
 
66
- <Button iconOnly aria-label="More options" appearance="ghost" leadingIcon={<MoreIcon />} />
83
+ <Button iconOnly aria-label="More options" appearance="ghost" leadingIcon={<RiMore2Line />} />
67
84
  ```
68
85
 
69
86
  ---
70
87
 
71
88
  ## No sizing classes on icons inside components
72
89
 
73
- Components handle icon sizing via CSS. Don't add `size-4`, `w-4 h-4`, or other sizing classes to icons rendered inside `Button`, `DropdownMenuItem`, `Alert`, `Sidebar*`, or other Create UI components — unless the user explicitly asks for a custom icon size.
90
+ Components handle icon sizing via CSS. Don't add `size-4`, `w-4 h-4`, or other sizing classes to icons rendered inside `Button`, `DropdownMenuItem`, `InlineAlert`, `Toast`, or other Create UI components — unless the user explicitly asks for a custom icon size.
74
91
 
75
92
  **Incorrect:**
76
93
 
77
94
  ```tsx
78
- <Button leadingIcon={<SearchIcon className="size-4" />}>Search</Button>
95
+ <Button leadingIcon={<RiSearchLine className="size-4" />}>Search</Button>
79
96
 
80
97
  <DropdownMenuItem>
81
- <SettingsIcon className="mr-2 size-4" />
98
+ <RiSettings3Line className="mr-2 size-4" />
82
99
  Settings
83
100
  </DropdownMenuItem>
84
101
  ```
@@ -86,10 +103,10 @@ Components handle icon sizing via CSS. Don't add `size-4`, `w-4 h-4`, or other s
86
103
  **Correct:**
87
104
 
88
105
  ```tsx
89
- <Button leadingIcon={<SearchIcon />}>Search</Button>
106
+ <Button leadingIcon={<RiSearchLine />}>Search</Button>
90
107
 
91
108
  <DropdownMenuItem>
92
- <SettingsIcon />
109
+ <RiSettings3Line />
93
110
  Settings
94
111
  </DropdownMenuItem>
95
112
  ```
@@ -98,33 +115,32 @@ Components handle icon sizing via CSS. Don't add `size-4`, `w-4 h-4`, or other s
98
115
 
99
116
  ## Pass icons as component values, not string keys
100
117
 
101
- Use `icon={CheckIcon}`, not a string key into a lookup map.
118
+ Use `icon={RiCheckLine}`, not a string key into a lookup map.
102
119
 
103
120
  **Incorrect:**
104
121
 
105
122
  ```tsx
106
123
  const iconMap = {
107
- check: CheckIcon,
108
- alert: AlertIcon,
124
+ check: RiCheckLine,
125
+ alert: RiAlertLine,
109
126
  }
110
127
 
111
- function StatusBadge({ icon }: { icon: string }) {
128
+ function StatusIcon({ icon }: { icon: string }) {
112
129
  const Icon = iconMap[icon]
113
130
  return <Icon />
114
131
  }
115
132
 
116
- <StatusBadge icon="check" />
133
+ <StatusIcon icon="check" />
117
134
  ```
118
135
 
119
136
  **Correct:**
120
137
 
121
138
  ```tsx
122
- // Import from the project's configured iconLibrary (e.g. lucide-react, @tabler/icons-react).
123
- import { CheckIcon } from "lucide-react"
139
+ import { RiCheckLine } from "@create-ui/assets/icons"
124
140
 
125
- function StatusBadge({ icon: Icon }: { icon: React.ComponentType }) {
141
+ function StatusIcon({ icon: Icon }: { icon: React.ComponentType }) {
126
142
  return <Icon />
127
143
  }
128
144
 
129
- <StatusBadge icon={CheckIcon} />
145
+ <StatusIcon icon={RiCheckLine} />
130
146
  ```
@@ -87,7 +87,7 @@ Create UI's own `Button` implements its `danger` / `success` variants with the r
87
87
 
88
88
  Every primitive exposes its full visual range through typed props. Drive appearance through those props, not through manual `border` / `bg` / `hover:` class overrides.
89
89
 
90
- `Button` has four styling axes (verify any other component by reading its source in `apps/v4/registry/ui/<name>.tsx`):
90
+ `Button` has four styling axes (verify any other component's props from its installed source under the project's `ui` alias — e.g. `components/ui/<name>.tsx` — or with `npx @create-ui/cli view <name>`):
91
91
 
92
92
  - `variant`: `primary` (default), `neutral-solid`, `neutral-light`, `danger`, `success`, `inverse-solid`, `inverse-light`
93
93
  - `appearance`: `solid` (default), `outline`, `ghost`, `soft`
@@ -139,17 +139,13 @@ Use `className` for layout (e.g. `max-w-md`, `mx-auto`, `mt-4`), **not** for ove
139
139
  **Incorrect:**
140
140
 
141
141
  ```tsx
142
- <Card className="bg-sky-100 text-sky-900 font-bold">
143
- <CardContent>Dashboard</CardContent>
144
- </Card>
142
+ <Input className="bg-sky-100 text-sky-900 font-bold" placeholder="Search…" />
145
143
  ```
146
144
 
147
145
  **Correct:**
148
146
 
149
147
  ```tsx
150
- <Card className="mx-auto max-w-md">
151
- <CardContent>Dashboard</CardContent>
152
- </Card>
148
+ <Input className="mx-auto max-w-md" placeholder="Search…" />
153
149
  ```
154
150
 
155
151
  ---
@@ -210,7 +206,7 @@ Semantic tokens already swap with the `.dark` class — don't write parallel `da
210
206
 
211
207
  ## Use cn() for conditional classes
212
208
 
213
- Use `cn()` for conditional or merged class names instead of template-string ternaries. Import it from `@/lib/utils` in a user project (in this monorepo, components import from `@/registry/lib/utils`).
209
+ Use `cn()` for conditional or merged class names instead of template-string ternaries. Import it from `@/lib/utils` (the project's `utils` alias).
214
210
 
215
211
  **Incorrect:**
216
212
 
@@ -250,4 +246,4 @@ Use `outline-primary-700` (or `outline-primary-500`) for primary controls and `o
250
246
 
251
247
  ## No manual z-index on overlay components
252
248
 
253
- `Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, and `HoverCard` manage their own stacking. Never add `z-50` or `z-[999]`.
249
+ `DropdownMenu`, `Tooltip`, `InfoTooltip`, and `CommandDialog` manage their own stacking. Never add `z-50` or `z-[999]`.
@@ -1,2 +1,2 @@
1
- import {a}from'../chunk-VQCXAURP.js';import {W as W$1}from'../chunk-EWAP55CF.js';export{B as transformMenu}from'../chunk-EWAP55CF.js';import'../chunk-Y7WZRQWW.js';import J from'postcss';import M from'postcss-selector-parser';import {z as z$1}from'zod';import {Project,ScriptKind,SyntaxKind,Node}from'ts-morph';var A="cn-",V=z$1.record(z$1.string().startsWith(A),z$1.string());function v(t){let e=J.parse(t),r={};return e.walkRules(n=>{let s=n.selectors??[];if(s.length===0)return;let i=F(n);if(i)for(let g of s){let l=R(g);M(o=>{o.each(a=>{let f=$(a);if(!f)return;let u=f.value;u.startsWith(A)&&(r[u]=r[u]?`${i} ${r[u]}`:i);});}).processSync(l);}}),V.parse(r)}function R(t){return t.replace(/\s*&\s*/g,"").trim()}function F(t){let e=[];for(let r of t.nodes||[])if(r.type==="atrule"&&r.name==="apply"){let n=r.params.trim();n&&e.push(n);}return e.length===0?null:e.join(" ")}function $(t){let e=[];return t.walkClasses(r=>{r.value.startsWith(A)&&e.push(r);}),e.length===0?null:e[e.length-1]}var z=new Set(["cn-menu-target"]);function p(t){return Node.isStringLiteral(t)||Node.isNoSubstitutionTemplateLiteral(t)}var O=async({sourceFile:t,styleMap:e})=>{let r=new Set;return W(t,e,r),w(t,e,r),_(t,e,r),t};function E(t,e,r){let n=t.getLiteralText(),s=y(n);if(s.length===0)return;let i=s.filter(l=>!r.has(l));if(i.length===0){let l=m(n);t.setLiteralValue(l);return}let g=i.map(l=>e[l]).filter(l=>!!l);if(g.length>0){let l=g.join(" "),o=m(d(l,n));t.setLiteralValue(o),i.forEach(a=>r.add(a));}else {let l=m(n);t.setLiteralValue(l);}}function W(t,e,r){t.forEachDescendant(n=>{if(!Node.isCallExpression(n))return;let s=n.getExpression();if(!Node.isIdentifier(s)||s.getText()!=="cva")return;let i=n.getArguments()[0];Node.isStringLiteral(i)&&E(i,e,r);let g=n.getArguments()[1];if(!g||!Node.isObjectLiteralExpression(g))return;let l=g.getProperties().find(a=>Node.isPropertyAssignment(a)&&Node.isIdentifier(a.getNameNode())&&a.getNameNode().getText()==="variants");if(!l||!Node.isPropertyAssignment(l))return;let o=l.getInitializer();!o||!Node.isObjectLiteralExpression(o)||o.getProperties().forEach(a=>{if(!Node.isPropertyAssignment(a))return;let f=a.getInitializer();!f||!Node.isObjectLiteralExpression(f)||f.getProperties().forEach(u=>{if(!Node.isPropertyAssignment(u))return;let x=u.getInitializer();x&&Node.isStringLiteral(x)&&E(x,e,r);});});});}function w(t,e,r){t.forEachDescendant(n=>{if(!Node.isJsxAttribute(n)||n.getNameNode().getText()!=="className")return;let s=n.getInitializer();if(!s)return;let i=D(s);if(i.length===0)return;let g=n.getParent()?.getParent();if(!g||!Node.isJsxOpeningElement(g)&&!Node.isJsxSelfClosingElement(g))return;let l=i.filter(a=>!r.has(a));if(l.length===0){I(s);return}let o=l.map(a=>e[a]).filter(a=>!!a);if(o.length>0){let a=o.join(" ");B(g,a);}else I(s);});}function D(t){let e=[];if(p(t))return y(t.getLiteralText());if(!Node.isJsxExpression(t))return e;let r=t.getExpression();if(!r)return e;if(p(r))return y(r.getLiteralText());if(Node.isCallExpression(r)&&T(r))for(let n of r.getArguments())p(n)&&e.push(...y(n.getLiteralText()));return e}function I(t){if(p(t)){let r=m(t.getLiteralText());t.setLiteralValue(r);return}if(!Node.isJsxExpression(t))return;let e=t.getExpression();if(e){if(p(e)){let r=m(e.getLiteralText());e.setLiteralValue(r);return}if(Node.isCallExpression(e)&&T(e)){for(let r of e.getArguments())if(p(r)){let n=m(r.getLiteralText());r.setLiteralValue(n);}C(e);}}}function y(t){let e=t.matchAll(/\bcn-[\w-]+\b/g);return Array.from(e,r=>r[0])}function m(t){return t.replace(/\bcn-[\w-]+\b/g,e=>z.has(e)?e:"").replace(/\s+/g," ").trim()}function C(t){if(!T(t))return;let e=t.getArguments(),r=e.filter(n=>p(n)?n.getLiteralText().trim()!=="":true);if(r.length!==e.length){let n=r.map(i=>i.getText()),s=t.getParent();s&&Node.isJsxExpression(s)?s.replaceWithText(`{cn(${n.join(", ")})}`):t.replaceWithText(`cn(${n.join(", ")})`);}}function B(t,e){if(!Node.isJsxOpeningElement(t)&&!Node.isJsxSelfClosingElement(t))return;let r=t.getAttributes().find(i=>Node.isJsxAttribute(i)&&i.getNameNode().getText()==="className");if(!r||!Node.isJsxAttribute(r)){t.addAttribute({name:"className",initializer:`{cn(${JSON.stringify(e)})}`});return}let n=r.getInitializer();if(!n){r.setInitializer(`{cn(${JSON.stringify(e)})}`);return}if(p(n)){let i=n.getLiteralText(),g=m(d(e,i));n.setLiteralValue(g);return}if(!Node.isJsxExpression(n))return;let s=n.getExpression();if(!s){r.setInitializer(`{cn(${JSON.stringify(e)})}`);return}if(p(s)){let i=s.getLiteralText(),g=m(d(e,i));s.setLiteralValue(g);return}if(Node.isCallExpression(s)&&T(s)){let i=s.getArguments()[0];if(p(i)){let o=i.getLiteralText(),a=m(d(e,o));i.setLiteralValue(a);for(let f=1;f<s.getArguments().length;f++){let u=s.getArguments()[f];if(p(u)){let x=u.getLiteralText(),S=m(x);S!==x&&u.setLiteralValue(S);}}C(s);return}let g=s.getArguments().map(o=>{if(p(o)){let a=m(o.getLiteralText());return a?JSON.stringify(a):null}return o.getText()}).filter(o=>o!==null),l=[JSON.stringify(e),...g];r.setInitializer(`{cn(${l.join(", ")})}`);return}r.setInitializer(`{cn(${JSON.stringify(e)}, ${s.getText()})}`);}function d(t,e){let r=e.split(/\s+/).filter(Boolean);return [...t.split(/\s+/).filter(Boolean),...r].join(" ").trim()}function T(t){let e=t.getExpression();return Node.isIdentifier(e)&&e.getText()==="cn"}function _(t,e,r){t.forEachDescendant(n=>{if(!Node.isCallExpression(n))return;let s=n.getExpression();if(!(!Node.isIdentifier(s)||s.getText()!=="mergeProps"))for(let i of n.getArguments()){if(!Node.isObjectLiteralExpression(i))continue;let g=i.getProperties().find(o=>Node.isPropertyAssignment(o)&&Node.isIdentifier(o.getNameNode())&&o.getNameNode().getText()==="className");if(!g||!Node.isPropertyAssignment(g))continue;let l=g.getInitializer();if(l&&Node.isCallExpression(l)&&T(l)){let o=k(l);if(o.length===0)continue;let a=o.filter(u=>!r.has(u));if(a.length===0){b(l);continue}let f=a.map(u=>e[u]).filter(u=>!!u);if(f.length>0){let u=f.join(" ");K(l,u,r,a);}else b(l);}}});}function k(t){let e=[];for(let r of t.getArguments())p(r)&&e.push(...y(r.getLiteralText()));return e}function b(t){for(let e of t.getArguments())if(p(e)){let r=m(e.getLiteralText());e.setLiteralValue(r);}C(t);}function K(t,e,r,n){let s=t.getArguments()[0];if(p(s)){let o=s.getLiteralText(),a=m(d(e,o));s.setLiteralValue(a),n.forEach(f=>r.add(f));for(let f=1;f<t.getArguments().length;f++){let u=t.getArguments()[f];if(p(u)){let x=u.getLiteralText(),S=m(x);S!==x&&u.setLiteralValue(S);}}C(t);return}let i=t.getArguments().map(o=>{if(p(o)){let a=m(o.getLiteralText());return a?JSON.stringify(a):null}return o.getText()}).filter(o=>o!==null),g=[JSON.stringify(e),...i];n.forEach(o=>r.add(o)),t.getParent()&&t.replaceWithText(`cn(${g.join(", ")})`);}async function X(t,{styleMap:e,transformers:r=[O]}){let s=new Project({useInMemoryFileSystem:true}).createSourceFile("component.tsx",t,{scriptKind:ScriptKind.TSX,overwrite:true});for(let i of r)await i({sourceFile:s,styleMap:e});return s.getText()}var P="lucide",q=async({sourceFile:t,config:e})=>{if(!e.iconLibrary||!(e.iconLibrary in a))return t;let r=P,n=e.iconLibrary;if(r===n)return t;let s=await W$1(),i=[];for(let g of t.getImportDeclarations()??[])if(g.getModuleSpecifier()?.getText()===`"${a[P].import}"`){for(let l of g.getNamedImports()??[]){let o=l.getName(),a=s[o]?.[n];!a||i.includes(a)||(i.push(a),l.remove(),t.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement).filter(f=>f.getTagNameNode()?.getText()===o).forEach(f=>f.getTagNameNode()?.replaceWithText(a)));}g.getNamedImports()?.length===0&&g.remove();}if(i.length>0){let g=t.addImportDeclaration({moduleSpecifier:a[n]?.import,namedImports:i.map(l=>({name:l}))});H(t)||g.replaceWithText(g.getText().replace(";",""));}return t};function H(t){return t.getImportDeclarations()?.[0]?.getText().endsWith(";")??false}export{v as createStyleMap,q as transformIcons,X as transformStyle};//# sourceMappingURL=index.js.map
1
+ import {a}from'../chunk-VQCXAURP.js';import {W as W$1}from'../chunk-5YX4Z2U3.js';export{B as transformMenu}from'../chunk-5YX4Z2U3.js';import'../chunk-Y7WZRQWW.js';import J from'postcss';import M from'postcss-selector-parser';import {z as z$1}from'zod';import {Project,ScriptKind,SyntaxKind,Node}from'ts-morph';var A="cn-",V=z$1.record(z$1.string().startsWith(A),z$1.string());function v(t){let e=J.parse(t),r={};return e.walkRules(n=>{let s=n.selectors??[];if(s.length===0)return;let i=F(n);if(i)for(let g of s){let l=R(g);M(o=>{o.each(a=>{let f=$(a);if(!f)return;let u=f.value;u.startsWith(A)&&(r[u]=r[u]?`${i} ${r[u]}`:i);});}).processSync(l);}}),V.parse(r)}function R(t){return t.replace(/\s*&\s*/g,"").trim()}function F(t){let e=[];for(let r of t.nodes||[])if(r.type==="atrule"&&r.name==="apply"){let n=r.params.trim();n&&e.push(n);}return e.length===0?null:e.join(" ")}function $(t){let e=[];return t.walkClasses(r=>{r.value.startsWith(A)&&e.push(r);}),e.length===0?null:e[e.length-1]}var z=new Set(["cn-menu-target"]);function p(t){return Node.isStringLiteral(t)||Node.isNoSubstitutionTemplateLiteral(t)}var O=async({sourceFile:t,styleMap:e})=>{let r=new Set;return W(t,e,r),w(t,e,r),_(t,e,r),t};function E(t,e,r){let n=t.getLiteralText(),s=y(n);if(s.length===0)return;let i=s.filter(l=>!r.has(l));if(i.length===0){let l=m(n);t.setLiteralValue(l);return}let g=i.map(l=>e[l]).filter(l=>!!l);if(g.length>0){let l=g.join(" "),o=m(d(l,n));t.setLiteralValue(o),i.forEach(a=>r.add(a));}else {let l=m(n);t.setLiteralValue(l);}}function W(t,e,r){t.forEachDescendant(n=>{if(!Node.isCallExpression(n))return;let s=n.getExpression();if(!Node.isIdentifier(s)||s.getText()!=="cva")return;let i=n.getArguments()[0];Node.isStringLiteral(i)&&E(i,e,r);let g=n.getArguments()[1];if(!g||!Node.isObjectLiteralExpression(g))return;let l=g.getProperties().find(a=>Node.isPropertyAssignment(a)&&Node.isIdentifier(a.getNameNode())&&a.getNameNode().getText()==="variants");if(!l||!Node.isPropertyAssignment(l))return;let o=l.getInitializer();!o||!Node.isObjectLiteralExpression(o)||o.getProperties().forEach(a=>{if(!Node.isPropertyAssignment(a))return;let f=a.getInitializer();!f||!Node.isObjectLiteralExpression(f)||f.getProperties().forEach(u=>{if(!Node.isPropertyAssignment(u))return;let x=u.getInitializer();x&&Node.isStringLiteral(x)&&E(x,e,r);});});});}function w(t,e,r){t.forEachDescendant(n=>{if(!Node.isJsxAttribute(n)||n.getNameNode().getText()!=="className")return;let s=n.getInitializer();if(!s)return;let i=D(s);if(i.length===0)return;let g=n.getParent()?.getParent();if(!g||!Node.isJsxOpeningElement(g)&&!Node.isJsxSelfClosingElement(g))return;let l=i.filter(a=>!r.has(a));if(l.length===0){I(s);return}let o=l.map(a=>e[a]).filter(a=>!!a);if(o.length>0){let a=o.join(" ");B(g,a);}else I(s);});}function D(t){let e=[];if(p(t))return y(t.getLiteralText());if(!Node.isJsxExpression(t))return e;let r=t.getExpression();if(!r)return e;if(p(r))return y(r.getLiteralText());if(Node.isCallExpression(r)&&T(r))for(let n of r.getArguments())p(n)&&e.push(...y(n.getLiteralText()));return e}function I(t){if(p(t)){let r=m(t.getLiteralText());t.setLiteralValue(r);return}if(!Node.isJsxExpression(t))return;let e=t.getExpression();if(e){if(p(e)){let r=m(e.getLiteralText());e.setLiteralValue(r);return}if(Node.isCallExpression(e)&&T(e)){for(let r of e.getArguments())if(p(r)){let n=m(r.getLiteralText());r.setLiteralValue(n);}C(e);}}}function y(t){let e=t.matchAll(/\bcn-[\w-]+\b/g);return Array.from(e,r=>r[0])}function m(t){return t.replace(/\bcn-[\w-]+\b/g,e=>z.has(e)?e:"").replace(/\s+/g," ").trim()}function C(t){if(!T(t))return;let e=t.getArguments(),r=e.filter(n=>p(n)?n.getLiteralText().trim()!=="":true);if(r.length!==e.length){let n=r.map(i=>i.getText()),s=t.getParent();s&&Node.isJsxExpression(s)?s.replaceWithText(`{cn(${n.join(", ")})}`):t.replaceWithText(`cn(${n.join(", ")})`);}}function B(t,e){if(!Node.isJsxOpeningElement(t)&&!Node.isJsxSelfClosingElement(t))return;let r=t.getAttributes().find(i=>Node.isJsxAttribute(i)&&i.getNameNode().getText()==="className");if(!r||!Node.isJsxAttribute(r)){t.addAttribute({name:"className",initializer:`{cn(${JSON.stringify(e)})}`});return}let n=r.getInitializer();if(!n){r.setInitializer(`{cn(${JSON.stringify(e)})}`);return}if(p(n)){let i=n.getLiteralText(),g=m(d(e,i));n.setLiteralValue(g);return}if(!Node.isJsxExpression(n))return;let s=n.getExpression();if(!s){r.setInitializer(`{cn(${JSON.stringify(e)})}`);return}if(p(s)){let i=s.getLiteralText(),g=m(d(e,i));s.setLiteralValue(g);return}if(Node.isCallExpression(s)&&T(s)){let i=s.getArguments()[0];if(p(i)){let o=i.getLiteralText(),a=m(d(e,o));i.setLiteralValue(a);for(let f=1;f<s.getArguments().length;f++){let u=s.getArguments()[f];if(p(u)){let x=u.getLiteralText(),S=m(x);S!==x&&u.setLiteralValue(S);}}C(s);return}let g=s.getArguments().map(o=>{if(p(o)){let a=m(o.getLiteralText());return a?JSON.stringify(a):null}return o.getText()}).filter(o=>o!==null),l=[JSON.stringify(e),...g];r.setInitializer(`{cn(${l.join(", ")})}`);return}r.setInitializer(`{cn(${JSON.stringify(e)}, ${s.getText()})}`);}function d(t,e){let r=e.split(/\s+/).filter(Boolean);return [...t.split(/\s+/).filter(Boolean),...r].join(" ").trim()}function T(t){let e=t.getExpression();return Node.isIdentifier(e)&&e.getText()==="cn"}function _(t,e,r){t.forEachDescendant(n=>{if(!Node.isCallExpression(n))return;let s=n.getExpression();if(!(!Node.isIdentifier(s)||s.getText()!=="mergeProps"))for(let i of n.getArguments()){if(!Node.isObjectLiteralExpression(i))continue;let g=i.getProperties().find(o=>Node.isPropertyAssignment(o)&&Node.isIdentifier(o.getNameNode())&&o.getNameNode().getText()==="className");if(!g||!Node.isPropertyAssignment(g))continue;let l=g.getInitializer();if(l&&Node.isCallExpression(l)&&T(l)){let o=k(l);if(o.length===0)continue;let a=o.filter(u=>!r.has(u));if(a.length===0){b(l);continue}let f=a.map(u=>e[u]).filter(u=>!!u);if(f.length>0){let u=f.join(" ");K(l,u,r,a);}else b(l);}}});}function k(t){let e=[];for(let r of t.getArguments())p(r)&&e.push(...y(r.getLiteralText()));return e}function b(t){for(let e of t.getArguments())if(p(e)){let r=m(e.getLiteralText());e.setLiteralValue(r);}C(t);}function K(t,e,r,n){let s=t.getArguments()[0];if(p(s)){let o=s.getLiteralText(),a=m(d(e,o));s.setLiteralValue(a),n.forEach(f=>r.add(f));for(let f=1;f<t.getArguments().length;f++){let u=t.getArguments()[f];if(p(u)){let x=u.getLiteralText(),S=m(x);S!==x&&u.setLiteralValue(S);}}C(t);return}let i=t.getArguments().map(o=>{if(p(o)){let a=m(o.getLiteralText());return a?JSON.stringify(a):null}return o.getText()}).filter(o=>o!==null),g=[JSON.stringify(e),...i];n.forEach(o=>r.add(o)),t.getParent()&&t.replaceWithText(`cn(${g.join(", ")})`);}async function X(t,{styleMap:e,transformers:r=[O]}){let s=new Project({useInMemoryFileSystem:true}).createSourceFile("component.tsx",t,{scriptKind:ScriptKind.TSX,overwrite:true});for(let i of r)await i({sourceFile:s,styleMap:e});return s.getText()}var P="lucide",q=async({sourceFile:t,config:e})=>{if(!e.iconLibrary||!(e.iconLibrary in a))return t;let r=P,n=e.iconLibrary;if(r===n)return t;let s=await W$1(),i=[];for(let g of t.getImportDeclarations()??[])if(g.getModuleSpecifier()?.getText()===`"${a[P].import}"`){for(let l of g.getNamedImports()??[]){let o=l.getName(),a=s[o]?.[n];!a||i.includes(a)||(i.push(a),l.remove(),t.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement).filter(f=>f.getTagNameNode()?.getText()===o).forEach(f=>f.getTagNameNode()?.replaceWithText(a)));}g.getNamedImports()?.length===0&&g.remove();}if(i.length>0){let g=t.addImportDeclaration({moduleSpecifier:a[n]?.import,namedImports:i.map(l=>({name:l}))});H(t)||g.replaceWithText(g.getText().replace(";",""));}return t};function H(t){return t.getImportDeclarations()?.[0]?.getText().endsWith(";")??false}export{v as createStyleMap,q as transformIcons,X as transformStyle};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@create-ui/cli",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "Add components to your apps.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,213 +0,0 @@
1
- # Contributing to the Create UI Monorepo
2
-
3
- This guide is for contributors working **inside** the Create UI monorepo — adding or editing
4
- registry components, the CLI, or the documentation site. If you only want to consume Create UI in
5
- your own app, see [`cli.md`](./cli.md) instead.
6
-
7
- ## Contents
8
-
9
- - [Monorepo layout](#monorepo-layout)
10
- - [Dev, build & quality commands](#dev-build--quality-commands)
11
- - [Tests](#tests)
12
- - [The registry](#the-registry)
13
- - [Authoring a component](#authoring-a-component)
14
- - [Scaffolding & validation](#scaffolding--validation)
15
- - [Testing the CLI locally](#testing-the-cli-locally)
16
- - [Website: three-layer architecture](#website-three-layer-architecture)
17
- - [Component rules recap](#component-rules-recap)
18
- - [Commit convention](#commit-convention)
19
-
20
- ## Monorepo layout
21
-
22
- Create UI is a **pnpm 9.0.6 + Turbo** monorepo with two workspaces:
23
-
24
- | Workspace | What it is | Stack |
25
- |---|---|---|
26
- | `apps/v4` | Documentation site & component showcase | Next.js 16 (App Router), React 19, Tailwind CSS v4 |
27
- | `packages/createui` | The `createui` CLI published to npm | Commander.js, tsup (ESM-only) |
28
-
29
- The site is also where the **registry** lives (`apps/v4/registry/`). The CLI reads that registry —
30
- in the monorepo it points at the local dev server (`http://localhost:4000/r`).
31
-
32
- ## Dev, build & quality commands
33
-
34
- Run all commands from the repo root. Package manager is **pnpm** — do not use npm or yarn.
35
-
36
- ```bash
37
- # Develop
38
- pnpm dev # everything, in parallel via Turbo
39
- pnpm v4:dev # docs/showcase site only (port 4000)
40
- pnpm createui:dev # CLI only, in watch mode
41
-
42
- # Build
43
- pnpm build # all workspaces
44
- pnpm v4:build # site only
45
- pnpm createui:build # CLI only
46
-
47
- # Quality
48
- pnpm check # lint + typecheck + format:check (run this before opening a PR)
49
- pnpm lint # ESLint
50
- pnpm lint:fix # ESLint with --fix
51
- pnpm typecheck # TypeScript
52
- pnpm format:write # Prettier write
53
- pnpm format:check # Prettier check
54
- ```
55
-
56
- ## Tests
57
-
58
- The test suite needs the v4 dev server running; `pnpm test` handles that for you.
59
-
60
- ```bash
61
- pnpm test # starts the v4 dev server, then runs Vitest
62
- pnpm test:dev # runs Vitest against an already-running server (no startup)
63
- ```
64
-
65
- ## The registry
66
-
67
- Every UI component is defined under `apps/v4/registry/` and served to users through the CLI.
68
-
69
- ```
70
- apps/v4/registry/
71
- ui/ core UI components (button, select, dialog, …)
72
- examples/ demos shown in the docs
73
- blocks/ larger composed blocks
74
- hooks/ custom React hooks
75
- lib/ utilities (e.g. cn())
76
- internal/ internal-only components (not exposed to users)
77
- components/ shared registry components
78
- ```
79
-
80
- Each subdirectory has a `_registry.ts` that exports a metadata array, and every array is aggregated
81
- in `apps/v4/registry/registry.ts`.
82
-
83
- In-repo registry entries **omit `content`** — `pnpm registry:build` injects each file's source when
84
- it generates `apps/v4/public/r/<name>.json`. Real entry shapes:
85
-
86
- ```ts
87
- // apps/v4/registry/ui/_registry.ts
88
- {
89
- name: "button",
90
- type: "registry:ui",
91
- dependencies: ["class-variance-authority", "radix-ui"],
92
- files: [{ path: "ui/button.tsx", type: "registry:ui" }],
93
- }
94
-
95
- {
96
- name: "select",
97
- type: "registry:ui",
98
- registryDependencies: ["field", "dropdown-menu"],
99
- files: [{ path: "ui/select.tsx", type: "registry:ui" }],
100
- }
101
- ```
102
-
103
- The `type` values, file objects (`{ path, type, content?, target? }`), and item fields are defined by
104
- the registry-item schema (`$schema: https://createui.co/schema/registry-item.json`). Use
105
- `dependencies` for npm packages and `registryDependencies` for other registry items the component
106
- needs.
107
-
108
- ## Authoring a component
109
-
110
- 1. Create `apps/v4/registry/ui/<name>.tsx`:
111
- - use **`cva`** for variants and **`cn()`** (from `@/registry/lib/utils`) to merge classes
112
- - put `data-slot="<name>"` on the root element
113
- - support polymorphism with **`asChild`** via the Radix `Slot`
114
- - type props as `React.ComponentProps<"el"> & VariantProps<typeof variants> & { … }`
115
- - use a **named export** (`export { Name }`)
116
- 2. Add an entry to `apps/v4/registry/ui/_registry.ts` (shape above).
117
- 3. Add a demo under `apps/v4/registry/examples/<name>-demo.tsx` and register it in
118
- `apps/v4/registry/examples/_registry.ts`.
119
- 4. Run **`pnpm registry:build`** to rebuild the registry (it also runs `lint:fix` + format and
120
- regenerates the `public/r/*.json` files).
121
-
122
- > Filenames are **kebab-case**; exports are PascalCase named exports. There is **no** `pnpm tokens:build` —
123
- > tokens live in `apps/v4/styles/globals.css` and are edited directly.
124
-
125
- ## Scaffolding & validation
126
-
127
- ```bash
128
- pnpm scaffold <name> # create a component + example + registry entry
129
- pnpm scaffold <name> --existing # generate an example from an existing component (parses CVA)
130
- pnpm scaffold <name> --dry-run # preview output without writing files
131
- pnpm scaffold <name> --force # overwrite existing files
132
-
133
- pnpm validate:registries # validate every _registry.ts against the schema
134
- ```
135
-
136
- ## Testing the CLI locally
137
-
138
- The root `pnpm createui` script runs the **local CLI build** against `http://localhost:4000/r`, so
139
- start the site first:
140
-
141
- ```bash
142
- pnpm v4:dev # serves the local registry at http://localhost:4000/r
143
- pnpm createui add -c ~/path/to/app # run the local CLI against a target app
144
- ```
145
-
146
- `-c` (`--cwd`) points at the project you want to add components to.
147
-
148
- ## Website: three-layer architecture
149
-
150
- Site work follows a strict three-layer model:
151
-
152
- ```
153
- registry/ui/ primitives — SACROSANCT, never edited by site work
154
- ↓ composed by
155
- components/site/ shared composites (reused across ≥2 route groups)
156
- ↓ composed by
157
- app/(group)/_components/ route-local composites (used by one route group)
158
- ```
159
-
160
- A new composite belongs in `components/site/` only if it is reused across **two or more** route
161
- groups; otherwise it lives in the route group's `_components/`. If a primitive is missing, **ask
162
- first** — never edit `registry/ui/` to make a page work.
163
-
164
- The authoritative website guides live in **`mds/website/`** — start at
165
- [`mds/website/BRIEF.md`](../../mds/website/BRIEF.md) (it is written in Turkish). Consult those guides
166
- for any website task; do not duplicate them here.
167
-
168
- ## Component rules recap
169
-
170
- These conventions keep every component consistent (see [`rules/styling.md`](./rules/styling.md),
171
- [`rules/composition.md`](./rules/composition.md), and [`rules/icons.md`](./rules/icons.md) for the
172
- full rules):
173
-
174
- - **`data-slot`** on the root element (and on meaningful sub-parts) for semantic styling hooks.
175
- - **`cn()`** for all class merging — never string-concatenate classes.
176
- - **`cva`** for variant-based styling; hoist the variants object out of the component.
177
- - **Semantic tokens** for color: `bg-primary-base`, `text-error-base`, `bg-weak`, `text-body` —
178
- never `bg-background` / `text-foreground`-style names.
179
- - **Radix UI** primitives for accessibility; polymorphism via **`asChild`** + Radix `Slot` only.
180
- - **Focus is `outline-*`**, never `ring-*` (e.g. `focus-visible:outline-primary-700`).
181
- - Intersection prop types: `React.ComponentProps<"button"> & VariantProps<…> & { … }`.
182
- - **kebab-case** filenames, **named** exports.
183
-
184
- A correct root element looks like:
185
-
186
- ```tsx
187
- // Incorrect — ring focus, non-semantic token, anonymous default export
188
- <button className={`${base} focus-visible:ring-2 bg-primary`}>{children}</button>
189
-
190
- // Correct — data-slot, cn(), outline focus, semantic token
191
- <Comp
192
- data-slot="button"
193
- className={cn(buttonVariants({ variant, appearance, size, className }))}
194
- {...props}
195
- />
196
- ```
197
-
198
- When you reference a component in an example, **read its source** at
199
- `apps/v4/registry/ui/<name>.tsx` first — never guess props. For instance, `Button` takes
200
- `variant` (`primary` | `neutral-solid` | `neutral-light` | `danger` | `success` | `inverse-solid` |
201
- `inverse-light`), `appearance` (`solid` | `outline` | `ghost` | `soft`), `size`, `shape`, `loading`,
202
- `iconOnly`, `leadingIcon`, `trailingIcon`, and `asChild` — there is no `variant="outline"` or
203
- `variant="destructive"`.
204
-
205
- ## Commit convention
206
-
207
- Conventional commits: `category(scope): message`.
208
-
209
- Categories: `feat`, `fix`, `refactor`, `docs`, `build`, `test`, `ci`, `chore`.
210
-
211
- ```
212
- feat(components): add loading prop to the button component
213
- ```