UNPKG

untitledui

Version:

The Untitled UI CLI tool helps you quickly scaffold projects with Untitled UI React and add components and page examples to your existing projects with an interactive interface in seconds.

81 lines (77 loc) 41.4 kB
#!/usr/bin/env node import{Command as p3}from"commander";import o0 from"async-retry";import N from"chalk";import{Command as I3}from"commander";import{execa as b0}from"execa";import*as F from"fs";import Z0 from"ora";import N3 from"os";import*as w from"path";import Q0 from"prompts";import{Project as A3}from"ts-morph";import f0 from"node-fetch";import{Readable as J3,pipeline as K3}from"stream";import{x as U3}from"tar";import{promisify as V3}from"util";var L3=V3(K3);async function m0(W,Q){try{let z=await b3(Q);await L3(z,U3({cwd:W,strip:1}))}catch(z){throw new Error(`Failed to download or extract repository from API: ${z instanceof Error?z.message:z}`)}}async function b3(W){let Q=`https://www.untitledui.com/react/api/download-repo?template=${W.template}`;try{let z=await f0(Q,{method:"GET",headers:{"Content-Type":"application/json",Accept:"application/octet-stream"}});if(z.status===403||z.status===404)throw new Error("Repository not found");if(!z.ok)throw new Error(`Failed to download from API. Status: ${z.status} ${z.statusText}`);if(!z.body)throw new Error("Response body is empty");return J3.from(z.body)}catch(z){throw new Error(`Error downloading tarball: ${z instanceof Error?z.message:z}`)}}async function B0(W){let Q=`https://www.untitledui.com/react/api/validate-key?key=${W}`;try{return(await f0(Q)).status===200}catch{return!1}}import M3 from"node-fetch";var c0={invalid_key:"Invalid key provided",no_components_found:"No components found",no_components_provided:"No components provided"};async function J0(W,Q,z){let $=Q.map((q)=>{if(q.includes("modals/"))if(q.includes("-modal"))return q;else return q+"-modal";return q});try{let q=await M3("https://www.untitledui.com/react/api/components",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({type:W,components:$,key:z})});if(!q.ok)console.log(c0?.[q.statusText]||c0.no_components_found),process.exit(1);return await q.json()}catch(q){return null}}import N0 from"node-fetch";var p={invalid_key:"Invalid key provided",no_components_found:"No components found",no_components_provided:"No components provided"};async function l0(W,Q=""){let z=`https://www.untitledui.com/react/api/components/list?key=${Q}&type=${W}`;try{let X=await N0(z),$=await X.json();if(!X.ok)console.log(p?.[X.statusText]||p.no_components_found),process.exit(1);if(!$?.components?.length)return null;return $}catch(X){return console.error(X),null}}async function a0(W,Q="",z){let X=`https://www.untitledui.com/react/api/components/list?key=${Q}&type=${W}&subfolders=${z.join(",")}`;try{let $=await N0(X);if(!$.ok)console.log(p?.[$.statusText]||p.no_components_found),process.exit(1);let q=await $.json();if(!q?.components?.length)return null;return q}catch($){return console.error($),null}}async function s0(W=""){let Q=`https://www.untitledui.com/react/api/components/list?key=${W}`;try{let z=await N0(Q);if(!z.ok)console.log(p?.[z.statusText]||p.no_components_found),process.exit(1);let X=await z.json();if(!X?.types?.length)return null;return X}catch(z){return console.error(z),null}}import n0 from"fast-glob";import*as y0 from"fs";import*as A0 from"path";import{Project as H1}from"ts-morph";import{loadConfig as R3}from"tsconfig-paths";import B1 from"prettier";import V0 from"fast-glob";import*as K0 from"fs";import*as U0 from"path";import{loadConfig as H3}from"tsconfig-paths";var d=["**/node_modules/**",".next","public","dist","build"],r0={"next-app":"Next.js (App)","next-pages":"Next.js (Pages)",vite:"Vite",other:"Other"};async function o(W){let Q=K0.existsSync(U0.resolve(W,"src")),z=K0.existsSync(U0.resolve(W,`${Q?"src/":""}app`)),[X,$,q,b]=await Promise.all([V0.glob("**/{next,vite,astro}.config.*|gatsby-config.*",{cwd:W,deep:2,ignore:d}),j3(W),G3(W),v3(W)]),H={framework:"other",isTsx:$,tailwindFile:q||null,aliasPrefix:b,isSrcDir:Q,isUsingAppDir:z};if(X.find((L)=>L.startsWith("next.config."))?.length)return H.framework=z?"next-app":"next-pages",H;else if(X.find((L)=>L.startsWith("vite.config."))?.length)return H.framework="vite",H;else if(X?.length||K0.existsSync(U0.resolve(W,"package.json")))return H.framework="other",H;return null}async function j3(W){return(await V0.glob("tsconfig.*",{cwd:W,deep:2,ignore:d})).length>0}async function G3(W){let Q=await V0.glob("tailwind.config.*",{cwd:W,deep:2,ignore:d});if(!Q.length)return null;return Q[0]}async function v3(W){let Q=await H3(W);if(Q?.resultType==="failed"||!Object.keys(Q.paths).length)return null;let z={};for(let[X,$]of Object.entries(Q.paths)){let q=X.replace(/\/\*$/,"/");if($.some((b)=>b.includes("/app/*")))z.appPrefix=q;else if($.some((b)=>b.includes("/components/*")))z.componentsPrefix=q;else if($.some((b)=>b.includes("/utils/*")))z.utilsPrefix=q;else if($.some((b)=>b.includes("/styles/*")))z.stylesPrefix=q;else if($.some((b)=>b.includes("./*")||b.includes("/src/*")))z.srcPrefix=q}return z||null}function t(W){let Q=R3(W),z=n0.sync(["tailwind.config.*","**/globals.css","**/{layout,_app,main}.tsx","package.json"],{cwd:W,deep:4,absolute:!0,onlyFiles:!0,ignore:d}),X={tailwindFile:z.find(($)=>$.includes("tailwind.config.")),cssFile:z.find(($)=>$.includes("globals.css")),layoutFile:z.find(($)=>$.includes("layout")),appFile:z.find(($)=>$.includes("_app")),mainFile:z.find(($)=>$.includes("main")),packageJson:z.find(($)=>$.includes("package.json")),tsConfig:Q?.resultType==="success"?Q?.configFileAbsolutePath:void 0};if(Q.resultType==="failed")throw new Error(`Failed to load tsconfig.json. ${Q.message??""}`.trim());return X}function e(W,Q,z={},X=""){if(W.includes("components")){if(z?.componentsPrefix)return W.replace(/@\/components\//,A0.posix.join(z?.componentsPrefix,Q?Q.replace(/components\//,""):"","/"));if(Q){let $=z?.srcPrefix?A0.posix.join(z?.srcPrefix,Q,"/"):X;return W.replace(/@\/components\//,$)}}if(W.includes("app")&&z?.appPrefix)return W.replace(/^@\/app\//,z?.appPrefix);if(W.includes("utils")&&z?.utilsPrefix)return W.replace(/^@\/utils\//,z?.utilsPrefix);if(W.includes("styles")&&z?.stylesPrefix)return W.replace(/^@\/styles\//,z?.stylesPrefix);if(z?.srcPrefix)return W.replace(/^@\//,z?.srcPrefix);return W}function i0(W){let Q=n0.sync(["vite.config.*"],{cwd:W,absolute:!0,onlyFiles:!0,ignore:d})?.[0];if(!Q)return!1;try{let z=y0.readFileSync(Q,"utf-8");return u3(z)}catch{return!1}}function u3(W){let Q=W.replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,"");if(!["tailwindcss","@tailwindcss/vite","tailwind("].some((q)=>Q.includes(q)))return!1;return["plugins:","postcss:","css:"].some((q)=>Q.includes(q))}function C(){if("bun/1.2.15 npm/? node/v22.6.0 darwin arm64".startsWith("yarn"))return"yarn";if("bun/1.2.15 npm/? node/v22.6.0 darwin arm64".startsWith("pnpm"))return"pnpm";if("bun/1.2.15 npm/? node/v22.6.0 darwin arm64".startsWith("bun"))return"bun";return"npm"}function z0(){switch(C()){case"yarn":return"yarn";case"pnpm":return"pnpx";case"bun":return"bunx";default:return"npx"}}function p0(){switch(C()){case"yarn":return"yarn dev";case"pnpm":return"pnpm dev";case"bun":return"bun dev";default:return"npm run dev"}}function L0(W){return W.replace(/^[ \t]*\/\/\s*(TODO:|collapse-(start|end)).*\r?\n?|[ \t]*{\s*\/\*\s*(TODO:|collapse-(start|end)).*?\*\/\s*}\r?\n?/gm,"")}var y3=w.join(N3.homedir(),".untitledui"),c=w.join(y3,"config.json"),B={components:[],path:"",type:void 0,license:""};if(F.existsSync(c)){let W=JSON.parse(F.readFileSync(c,"utf-8"));B.license=W.license}var $0=(W)=>{if(W.aborted)process.stdout.write("\x1B[?25h"),process.stdout.write(` `),process.exit(1)},t0=new I3().name("add").description("add a component to your project").argument("[components...]","the components to add").option("-a, --all","add all available components",!1).option("-o, --overwrite","overwrite existing files.",!1).option("-p, --path <path>","the path to add the component to.").option("-d, --dir <directory>","the directory where the project is located.").option("-t, --type <base|marketing|shared-assets|application|foundations>","the type of the component to add.").action(async(W,Q)=>{if(W)B.components=W;if(Q)B.all=Q.all,B.dir=Q.dir,B.path=Q.path,B.overwrite=Q.overwrite,B.license=Q.license||B.license;try{await E0(B)}catch(z){console.error(N.red(z))}});async function E0(W){if(W)B={...B,...W};let Q=Z0().start(),z=w.posix.join(process.cwd(),B.dir||"");if(!F.existsSync(w.resolve(z,"package.json")))Q.warn("This command should be run in a project directory."),process.exit(1);let $=await o(z);if(B.license){if(!await B0(B.license))Q.fail("Invalid license key"),process.exit(1);if(!F.existsSync(c)){let K=w.dirname(c);F.mkdirSync(K,{recursive:!0}),F.writeFileSync(c,JSON.stringify({license:B.license},null,2))}if(JSON.parse(F.readFileSync(c,"utf-8")).license!==B.license)F.writeFileSync(c,JSON.stringify({license:B.license},null,2),"utf-8")}Q.stop();let q=[];if(B.components.length){let Y=await J0(B.type,B.components,B.license);if(Y&&Y.pro&&Y.pro.length>0){if(console.log(),Y.pro.length===1){let Z=Y.pro[0]?.split("/")[1]||Y.pro[0];console.log(N.yellow(`\uD83D\uDD12 The ${N.cyan(Z)} component requires PRO access.`))}else console.log(N.yellow("\uD83D\uDD12 The following components require PRO access:")),Y.pro.forEach((Z)=>{let K=Z?.split("/")[1]||Z;console.log(` • ${N.cyan(K)}`)});console.log(),console.log("To access PRO components:"),console.log(` ${N.green("→")} If you've already purchased: ${N.cyan(`${z0()} untitledui@latest login`)}`),console.log(` ${N.green("→")} To purchase PRO components: ${N.cyan("https://www.untitledui.com/buy/react")}`),console.log(),process.exit(1)}if(!Y?.components.length)console.log("No components found"),process.exit(1);q.push(...Y.components)}if(!B?.type&&!B?.components.length){let Y=await s0(B.license);if(!Y)console.log("No component types found"),process.exit(1);let Z=await Q0({type:"select",name:"type",onState:$0,message:`What type of ${N.cyan("component")} are you adding?`,choices:Y?.types.map((K)=>({title:K,value:K}))});B.type=Z.type}if(!B?.path){let Y=await Q0({type:"text",name:"path",onState:$0,message:`Where would you like to add the ${N.cyan("components")}?`,initial:"components"});B.path=Y.path}if(!B?.components.length){let Y=await l0(B?.type,B.license);if(!Y)console.log("No components found"),process.exit(1);let Z=await Q0({type:"multiselect",name:"components",onState:$0,message:`Which ${N.cyan("components")} would you like to add?`,choices:Y?.components?.map((V)=>({title:V?.name+(V?.count?` (${V?.count} variants)`:"")||"example",value:V||"example",selected:B.components.includes(V.name)})),instructions:!1,hint:"- Space to select. Return to submit"});if(!Z.components||!Z.components.length)console.log("No option selected. Exiting..."),process.exit(1);let K=Z.components.filter((V)=>V?.type==="file").map((V)=>V.name),R=Z.components.filter((V)=>V?.type==="dir").map((V)=>V.name),x=[];if(R.length){let V=await a0(B?.type,B.license,R);if(V&&V.components.length)for(let D of V.components){let[k,u]=Object.entries(D)[0]||[],I=await Q0({type:"select",name:"component",onState:$0,message:`Which ${N.cyan("variant")} from ${N.cyan(k)} would you like to add?`,choices:u?.map((P)=>({title:P?.name.replace(/-modal/g,"")||"example",value:P?.name||"example",selected:B.components.includes(P.name)})),instructions:!1,hint:"- Space to select. Return to submit"});if(!I.component)console.log("No variant selected for "+N.cyan(k));x.push(k+"/"+I.component)}else console.log("No variants found")}B.components=[...x,...K]}if(!B.components?.length)Q.warn("No components selected. Exiting."),process.exit(1);let b=t(z),H=new Set,L=new Set,y=new Set,S=new A3({tsConfigFilePath:b?.tsConfig});if(Q.start(),B.type&&B.components.length){let Y=await J0(B.type,B.components,B.license);if(!Y?.components.length)console.log("No components found"),process.exit(1);q.push(...Y.components)}let E=new Set;if(q.forEach((Y)=>{Y?.components?.forEach((Z)=>{E.add({name:Z.name,path:Z.path})})}),Q.stop(),E.size){let Y=Array.from(E).filter((Z)=>!F.existsSync(w.posix.join(z,`${$?.isSrcDir?"src":""}`,Z?.path?.replace(/components\//,B.path+"/"))));if(Y?.length){let Z=await Q0({type:"multiselect",name:"baseComponents",onState:$0,message:"Select which base components you want to add",choices:Y.map((K)=>({title:K?.name,value:K?.name,selected:!0})),instructions:!1,hint:"- Space to select. Return to submit"});if(B.baseComponents=Z.baseComponents,!Y.length&&!Z.baseComponents?.length)Q.warn("No components selected")}}if(Q.start(),B?.baseComponents?.length){let Y=await J0("",B.baseComponents,B.license);if(!Y||!Y?.components.length)console.log("No base components found");else q.push(...Y.components)}if(Q.stop(),q.forEach((Y)=>{let Z=Z0(`Adding ${Y.name}...`).start(),K=Y.files;Y?.dependencies?.forEach((R)=>L.add(R)),Y?.devDependencies?.forEach((R)=>y.add(R));try{if(K?.forEach(async({path:R,code:x})=>{let V=w.posix.join(z,`${$?.isSrcDir?"src":""}`,R.replace(/components\//,B.path+"/")),D=$?.framework==="vite"?x.replace(`"use client"; `,""):x,k=L0(D),u=w.dirname(V);if(F.existsSync(V)&&!B.overwrite){if(F.readFileSync(V,"utf-8")!==k)H.add({code:k,path:V})}else{F.mkdirSync(u,{recursive:!0}),F.writeFileSync(V,k);let I=w.relative(w.posix.join(z,`${$?.isSrcDir?"src":""}`),V).split("/").length,P=I===1?"./":"../".repeat(I-1),O=S.addSourceFileAtPath(w.resolve(V));O.getImportDeclarations().forEach((i)=>{let g=i.getModuleSpecifierValue();i.setModuleSpecifier(e(g,B.path,$?.aliasPrefix,P))}),await O.save()}}),H.size)Z.warn(`Some files of ${N.yellow(Y.name)} already exist`);else Z.succeed(`${N.green(Y.name)} is added successfully`)}catch(R){Z.fail(` Failed to add the component ${N.red(Y.name)}`),console.error(N.red(R)),process.exit(1)}}),H.size&&!B?.overwrite)if(console.log(` Following files already exist in the directory.`),H.forEach((Z)=>{console.log(N.green(`- ${w.relative(z,Z.path)}`))}),(await Q0({type:"confirm",name:"overwrite",message:"Do you want to overwrite the existing files?",initial:!0})).overwrite){let Z=Z0("Overwriting files").start();H.forEach((K)=>{let R=w.relative(w.resolve(z,`${$?.isSrcDir?"src":""}`,B.path),K.path).split("/").length,x=R===1?"./":"../".repeat(R-1),V=S.addSourceFileAtPath(w.resolve(K.path));V.replaceWithText(K.code),V.getImportDeclarations().forEach((D)=>{let k=D.getModuleSpecifierValue();D.setModuleSpecifier(e(k,B.path,$?.aliasPrefix,x))}),V.saveSync()}),Z.succeed("Files are overwritten")}else console.log(`Use ${N.cyan("--overwrite")} or ${N.cyan("-o")} to overwrite existing files, or refer to the documentation ${N.cyan("https://www.untitled.com/docs")} for manual installation. The rest of the files are added.`);let U=C();if(L?.size){let Y=Z0("Installing component dependencies").start();await o0(()=>b0(U,[U==="npm"?"install":"add",...L],{cwd:z}).catch(async(Z)=>{if(Z.message.includes("peer"))Y.warn("Component dependencies conflict detected. Retrying with --legacy-peer-deps..."),Y.start("Installing component dependencies with --legacy-peer-deps flag"),await b0(U,[U==="npm"?"install":"add",...L,"--legacy-peer-deps"],{cwd:z})}),{retries:1}),Y.succeed("Component dependencies are installed")}if(y?.size){let Y=Z0("Installing component devDependencies").start();await o0(()=>b0(U,[U==="npm"?"install":"add","-D",...y],{cwd:z}).catch(async(Z)=>{if(Z.message.includes("peer"))Y.warn("Component devDependencies conflict detected. Retrying with --legacy-peer-deps..."),Y.start("Installing component devDependencies with --legacy-peer-deps flag"),await b0(U,[U==="npm"?"install":"add","-D",...y,"--legacy-peer-deps"],{cwd:z})}),{retries:1}),Y.succeed("Component devDependencies are installed")}if(B.message)console.log(B.message);process.exit(0)}import w0 from"chalk";import{Command as w3}from"commander";import*as f from"fs";import T3 from"http";import S3 from"open";import x3 from"ora";import C3 from"os";import*as S0 from"path";import{URL as F3}from"url";import*as M0 from"fs";import*as l from"path";import{fileURLToPath as E3}from"url";var _3=E3(import.meta.url),_0=l.dirname(_3);function D3(){let W=[l.join(_0,"..","templates","auth-template.html"),l.join(_0,"templates","auth-template.html"),l.join(process.cwd(),"node_modules","untitledui","templates","auth-template.html"),l.join(_0,"..","..","templates","auth-template.html")];for(let Q of W)if(M0.existsSync(Q))return Q;throw new Error("Auth template file not found. Please ensure the CLI package is properly installed.")}function e0(){try{let W=D3();return M0.readFileSync(W,"utf-8")}catch(W){return console.warn("Warning: Using fallback auth template. Some styling may be missing."),`<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{{TITLE}}</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif; min-height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #ffffff; margin: 0; padding: 20px; } .container { text-align: center; max-width: 400px; } .title { font-size: 24px; font-weight: 600; color: #181d27; margin-bottom: 16px; } .description { font-size: 16px; color: #535862; line-height: 1.4; } @media (prefers-color-scheme: dark) { body { background-color: #0c0e12; } .title { color: #fafafa; } .description { color: #94979c; } } </style> </head> <body> <div class="container"> <h1 class="title">{{HEADING}}</h1> <p class="description">{{DESCRIPTION}}</p> {{AUTO_CLOSE_SCRIPT}} </div> </body> </html>`}}function z3(){return e0().replace("{{TITLE}}","Authentication successful").replace("{{HEADING}}","Authentication successful").replace("{{DESCRIPTION}}","You can now close this tab and return to your terminal.").replace("{{AUTO_CLOSE_SCRIPT}}","<script>setTimeout(() => window.close(), 10000);</script>")}function H0(W){return e0().replace("{{TITLE}}","Authentication failed").replace("{{HEADING}}","Authentication failed").replace("{{DESCRIPTION}}",W).replace("{{AUTO_CLOSE_SCRIPT}}","")}var T0=S0.join(C3.homedir(),".untitledui"),D0=S0.join(T0,"config.json"),Q3=new w3().name("login").description("authenticate with Untitled UI to access PRO components").action(async()=>{let W=x3("Starting authentication...").start();try{await k3(W),W.succeed("Authentication completed successfully!"),console.log(w0.green(` ✨ You can now access PRO components with the CLI!`)),process.exit(0)}catch(Q){W.fail(`Authentication failed: ${Q instanceof Error?Q.message:Q}`),process.exit(1)}});async function k3(W){return new Promise((Q,z)=>{let X=T3.createServer(($,q)=>{let b=new F3($.url,"http://localhost");if(b.pathname==="/callback"){let H=b.searchParams.get("apiKey"),L=b.searchParams.get("error");if(L){q.writeHead(400,{"Content-Type":"text/html"}),q.end(H0(decodeURIComponent(L))),X.close(),z(new Error(decodeURIComponent(L)));return}if(!H){q.writeHead(400,{"Content-Type":"text/html"}),q.end(H0("No Access Token received")),X.close(),z(new Error("No Access Token received"));return}try{P3(H),q.writeHead(200,{"Content-Type":"text/html"}),q.end(z3()),X.close(),Q()}catch(y){q.writeHead(500,{"Content-Type":"text/html"}),q.end(H0("Failed to save authentication data")),X.close(),z(y)}}else q.writeHead(404),q.end("Not found")});X.listen(0,"localhost",()=>{let b=`https://www.untitledui.com/react/api/cli-auth?port=${X.address().port}`;W.text="Opening browser for authentication...",S3(b).catch((H)=>{console.log(w0.yellow(` Failed to open browser automatically: ${H.message}`)),console.log(w0.cyan(`Please manually open: ${b} `))}),W.text="Waiting for authentication in browser..."}),setTimeout(()=>{X.close(),z(new Error("Authentication timeout. Please try again."))},300000)})}function P3(W){if(!f.existsSync(T0))f.mkdirSync(T0,{recursive:!0});let Q={};if(f.existsSync(D0))try{Q=JSON.parse(f.readFileSync(D0,"utf-8"))}catch{Q={}}Q.license=W,f.writeFileSync(D0,JSON.stringify(Q,null,2),"utf-8")}import g0 from"async-retry";import M from"chalk";import{Command as l3}from"commander";import{execa as I0}from"execa";import*as T from"fs";import X0 from"ora";import a3 from"os";import*as G from"path";import r from"prompts";import{Project as s3}from"ts-morph";import O3 from"node-fetch";async function j0(W,Q){try{let X=await O3("https://www.untitledui.com/react/api/components/example",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({example:W,key:Q})});if(!X.ok){if(X.status===401||X.status===403)return{type:"error",status:X.status,message:"PRO access required"};return console.error(`API error: ${X.status} - ${X.statusText}`),null}return await X.json()}catch(X){return console.error(X?.message||"Error fetching example data."),null}}import q0 from"async-retry";import A from"chalk";import{Command as g3}from"commander";import{execa as a}from"execa";import R0 from"fast-glob";import _ from"fs";import W0 from"ora";import d3 from"os";import*as v from"path";import u0 from"prompts";import{Project as h3}from"ts-morph";import{fileURLToPath as f3}from"url";import*as G0 from"fs";import*as W3 from"path";function x0(W,Q){let z=W3.join(W,"package.json");if(!G0.existsSync(z))return Q;let X=JSON.parse(G0.readFileSync(z,"utf-8")),$={...X.dependencies,...X.devDependencies},q=[];for(let b of Q){let H=$[b];if(!H){q.push(b);continue}if(b==="tailwindcss"){let L=H.match(/\d+/);if((L?parseInt(L[0],10):0)<4)q.push(b)}}return q}import C0 from"chalk";import*as m from"fs";import*as v0 from"path";function F0(W){if(!m.existsSync(v0.resolve(W)))console.log(C0.red(`Error: CSS file not found at ${W}`)),process.exit(1);let Q=m.readFileSync(v0.resolve(W),"utf-8"),z=/(--color-[a-zA-Z-]+-\d{1,3}):\s*(rgb\([^)]+\))/g,X={},$;while(($=z.exec(Q))!==null)if($[1]&&$[2])X[$[1]]=$[2];return X}function k0(W,Q,z){let X=v0.resolve(z);if(!m.existsSync(X)){console.log(C0.red(`Error: CSS file not found at ${X}`));return}let $=m.readFileSync(X,"utf-8"),q=F0(z),b={},H={};for(let[y,S]of Object.entries(q))if(y.startsWith(`--color-${W}-`)){let E=y.replace(`--color-${W}-`,"");b[E]=y}else if(y.startsWith(`--color-${Q}-`)){let E=y.replace(`--color-${Q}-`,"");H[E]=S}let L=!1;for(let[y,S]of Object.entries(b))if(H[y]){let E=H[y],U=new RegExp(`(${S}):\\s*rgb\\([^)]*\\);?`,"g");if(U.test($))$=$.replace(U,`$1: ${E};`),L=!0;else console.log(C0.yellow(`No match found for ${S}`))}if(L)m.writeFileSync(X,$,"utf-8")}var m3=f3(import.meta.url),Y3=v.dirname(m3),c3=v.join(d3.homedir(),".untitledui"),s=v.join(c3,"config.json"),$3="vite",q3="nextjs",Z3={[q3]:"Next.js",[$3]:"Vite"},h="",j={color:"",template:"",framework:void 0};if(_.existsSync(s)){let W=JSON.parse(_.readFileSync(s,"utf-8"));j.license=W.license}var P0=(W)=>{if(W.aborted)process.stdout.write("\x1B[?25h"),process.stdout.write(` `),process.exit(1)},X3=new g3().name("init").description("initialize a new project or adjust an existing one").argument("[directory]").usage("[directory] [options]").helpOption("-h, --help","display this help message.").option("--vite","initialize a Vite project.",!1).option("--nextjs","initialize a Next.js project.",!1).option("-o, --overwrite","overwrite existing files.",!1).option("--colors-list","show the colors list.",!1).option("-c, --color <color-name>","specify a color for the project.").action(async(W,Q)=>{if(W)h=W;if(Q){if(j.color=Q.color,j.template=Q.template,j.overwrite=Q.overwrite,j.colorsList=Q.colorsList,j.license=Q.license||j.license,j.vite=Q.vite,j.nextjs=Q.nextjs,Q.vite)j.framework=$3;if(Q.nextjs)j.framework=q3}try{await O0(Q),process.exit(0)}catch(z){console.error(A.red(z)),process.exit(1)}});async function O0(W,Q=null){let z=process.cwd(),X=_.existsSync(v.resolve(z,"package.json")),$=v.resolve(v.join(Y3,"../config/styles","theme.css")),q=F0($??""),b=Array.from(new Set(Object.keys(q).map((U)=>U?.split("--color-")?.[1]?.replace(/-\d{1,3}/,"")))),H=W0().start(),L=await o(z),y=X?R0.sync(["**/**/theme.css"],{cwd:z,absolute:!0,onlyFiles:!0,ignore:d}):[],S=y?.[0]&&_.readFileSync(y[0],"utf-8").match(/(--color-brand+-\d{1,3}):\s*(rgb\([^)]+\))/g)?.[1]||void 0;if(j.license){if(!_.existsSync(s)){let Y=v.dirname(s);_.mkdirSync(Y,{recursive:!0}),_.writeFileSync(s,JSON.stringify({license:j.license},null,2))}if(JSON.parse(_.readFileSync(s,"utf-8")).license!==j.license)_.writeFileSync(s,JSON.stringify({license:j.license},null,2))}if(!X){if(H.stop(),!h){let U=await u0({onState:P0,type:"text",name:"path",message:"What is your project named?",initial:"untitled-ui"});if(typeof U.path==="string")h=U.path.trim()}if(Q)Q.projectPath=h;if(_.existsSync(v.resolve(v.posix.join(z,h))))H.fail(A.red("Directory already exists!")),process.exit(1);if(j.vite&&j.nextjs||!j.framework){let U=await u0({type:"select",name:"framework",onState:P0,message:`Which ${A.cyan("framework")} would you like to use?`,choices:Object.entries(Z3).map(([Y,Z])=>({title:Z,value:Y}))});j.framework=U.framework}H.succeed("Framework is selected: "+A.green(Z3[j.framework]))}else if(L?.framework==="other")H.fail("Unsupported project framework"),console.log(`Please refer to the documentation ${A.cyan("https://www.untitled.com/docs")} for supported frameworks or proceed with manual installation.`),process.exit(1);else if(L?.framework.startsWith("next")||L?.framework.startsWith("vite"))if(!Q&&!S)H.succeed(A.yellow(`Detected ${r0[L.framework]} project, proceeding with the setup...`));else H.stop();if(j.colorsList||!j.color&&!S){let U=await u0({type:"select",name:"color",onState:P0,initial:W.color??"",message:`Which ${A.cyan("color")} would you like to use as the ${A.cyanBright("brand")} color?`,choices:b.map((Y)=>({title:Y,value:Y}))});j.color=U.color}let E=v.posix.join(z,h||"");if(h&&!X){let U=v.resolve(h);console.log(` Creating a new project in ${A.blue(h)}`);let Y=W0("Downloading and extracting the repository...").start();try{_.mkdirSync(U,{recursive:!0}),await q0(()=>m0(U,{template:j.framework}),{retries:2}),Y.succeed("Files are downloaded and extracted successfully!");let Z=W0({text:"Installing dependencies..."}).start(),K=R0.sync(["**/styles/theme.css"],{cwd:U,absolute:!0,onlyFiles:!0})[0];if(k0("brand",j.color||"",K??""),await q0(()=>a(C(),["install"],{cwd:E}).catch(async(R)=>{if(R.message.includes("peer"))Z.warn("Dependency conflict detected. Retrying with --legacy-peer-deps..."),Z.start("Installing dependencies with --legacy-peer-deps flag"),await a(C(),["install","--legacy-peer-deps"],{cwd:E})}),{retries:1}),await q0(()=>a("git",["init"],{cwd:E}),{retries:1}),Z.succeed("Dependencies are installed"),!Q)console.log(` Your project is ready, to get started run the following commands: cd ${A.cyan(h)} ${A.cyan(p0())}`)}catch(Z){if(Y.fail(A.red(` Failed to download and extract the repository`)),Z instanceof Error)console.error(Z.message);else console.error(` `);_.rmdirSync(U,{recursive:!0}),process.exit(1)}}else{let U=W0(),Y=new Set,Z=t(z),K=v.resolve(v.join(Y3,"../config")),R=R0.sync(["**"],{cwd:K,onlyFiles:!0,ignore:d}),x=x0(z,["tailwindcss","tailwindcss-animate","@tailwindcss/typography","tailwindcss-react-aria-components"]),V=x0(z,["@tailwindcss/postcss","postcss"]);if(!Q&&!S)U.start("Copying files to the project directory");if(R.forEach((u)=>{let I=u.includes("postcss.config"),P=v.posix.join(v.posix.join(K),u),O=v.posix.join(z,I?u:`${L?.isSrcDir?"src":""}/${u}`);if(_.existsSync(O)){if(j?.overwrite)_.copyFileSync(P,O);else{let i=_.readFileSync(O,"utf-8"),g=_.readFileSync(P,"utf-8");if(i!==g){if(u.endsWith("theme.css")&&S)return;Y.add({targetFile:O,sourceFile:P})}}return}_.mkdirSync(v.dirname(O),{recursive:!0}),_.writeFileSync(O,""),_.copyFileSync(P,O)}),U.stop(),Y.size&&!j?.overwrite)if(console.log(` `),U.fail("Following files already exist in the directory."),Y.forEach((I)=>{console.log(`- ${A.green(I.targetFile)}`)}),(await u0({type:"confirm",name:"overwrite",message:"Do you want to overwrite the existing files?",initial:!0})).overwrite){let I=W0("Overwriting files").start();Y.forEach((P)=>{_.copyFileSync(P.sourceFile,P.targetFile)}),I.succeed("Files are overwritten")}else console.log(`Use ${A.cyan("--overwrite")} or ${A.cyan("-o")} to overwrite existing files, or refer to the documentation ${A.cyan("https://www.untitled.com/docs")} for manual installation. The rest of the files are added.`);if(Z?.tailwindFile)console.log(` Tailwind config file exists in the project directory. You can add it to your globals.css as follows:`),console.log(` ${A.cyan(`@config "../${L?.isSrcDir?"../":""}${v.relative(z,Z.tailwindFile)}";`)} `);if(L?.framework==="vite"){if(!i0(z))console.log(` Tailwind CSS is not configured in your Vite project. Please refer to the documentation ${A.cyan("https://www.untitled.com/react/integrations/vite")} for manual installation. `)}let D=Z?.layoutFile||Z?.appFile||L?.framework==="vite"&&Z?.mainFile||"";if(!D)console.log(`Import following files to your main file: `),R.forEach((u)=>{console.log(A.cyan(u))});else{let I=new h3({tsConfigFilePath:v.resolve(Z?.tsConfig||"")}).addSourceFileAtPath(v.resolve(D)),P="globals.css";I.getImportDeclarations().filter((g)=>g.getModuleSpecifierValue().includes("globals.css")).forEach((g)=>g.remove());let O=v.relative(v.resolve(z,`${L?.isSrcDir?"src":""}`),D).split("/").length,i=L?.aliasPrefix?.stylesPrefix||L?.aliasPrefix?.srcPrefix||(O===1?"./":"../".repeat(O-1));I.addImportDeclarations(R.filter((g)=>g.includes("globals.css")).map((g)=>({moduleSpecifier:`${i}${L?.aliasPrefix?.stylesPrefix?g?.split("styles/")[1]:g}`}))),I.saveSync()}let k=R0.sync(["**/styles/theme.css"],{cwd:z,absolute:!0,onlyFiles:!0,ignore:d});if(!k?.length)return U.fail(`Failed to copy ${A.cyan("theme.css")} file. Ensure that the ${A.cyan("theme.css")} file exists in the project directory under ${A.yellow("styles/")} folder.`);if((j.color||!S)&&k0("brand",j.color||"brand",k[0]??""),x.length||V.length){let u=W0().start("Installing dependencies");x.length&&await q0(()=>a(C(),[C()==="npm"?"install":"add",...x],{cwd:E}).catch(async(I)=>{if(I.message.includes("peer"))u.warn("Dependency conflict detected. Retrying with --legacy-peer-deps..."),u.start("Installing dependencies with --legacy-peer-deps flag"),await a(C(),[C()==="npm"?"install":"add",...x,"--legacy-peer-deps"],{cwd:E})}),{retries:1}),V.length&&await q0(()=>a(C(),[C()==="npm"?"install":"add","-D",...V],{cwd:E}).catch(async(I)=>{if(I.message.includes("peer"))u.warn("DevDependency conflict detected. Retrying with --legacy-peer-deps..."),u.start("Installing dependencies with --legacy-peer-deps flag"),await a(C(),[C()==="npm"?"install":"add","-D",...V,"--legacy-peer-deps"],{cwd:E})}),{retries:1}),u.succeed("Dependencies are installed")}if(!Q&&!S)U.succeed(A.green("Project setup is completed!"));if(Q&&X){H.stop(),U.stop();return}else console.log(` Your project is ready, you can now start adding components.`)}}var r3=G.join(a3.homedir(),".untitledui"),n=G.join(r3,"config.json"),J={path:"",example:"",license:"",components:[]},d0={};if(T.existsSync(n)){let W=JSON.parse(T.readFileSync(n,"utf-8"));J.license=W.license}var Y0=(W)=>{if(W.aborted)process.stdout.write("\x1B[?25h"),process.stdout.write(` `),process.exit(1)},B3=new l3().name("example").description("add an example to the project").argument("[example]","the example to add").option("-o, --overwrite","overwrite existing files.",!1).option("-p, --path <path>","the path to add the component to.").option("-e, --example-path <example-path>","the path to add the example file to.").action(async(W,Q)=>{if(W)J.example=W;if(Q)J.path=Q.path,J.overwrite=Q.overwrite,J.examplePath=Q.examplePath,J.license=Q.license||J.license;try{await O0(Q,d0),await n3(J)}catch(z){console.error(M.red(z))}});async function n3(W){let Q=X0().start(),z=G.posix.join(process.cwd(),d0?.projectPath||"");if(!T.existsSync(G.posix.join(G.resolve(z,"package.json"))))Q.warn("This command should be run in a project directory."),process.exit(1);let $=await o(z);if(J.license){if(!await B0(J.license))Q.fail("Invalid license key"),process.exit(1);if(!T.existsSync(n)){let K=G.dirname(n);T.mkdirSync(K,{recursive:!0}),T.writeFileSync(n,JSON.stringify({license:J.license},null,2))}if(JSON.parse(T.readFileSync(n,"utf-8")).license!==J.license)T.writeFileSync(n,JSON.stringify({license:J.license},null,2),"utf-8")}if(Q.stop(),!J.example){let Y=await r({type:"select",name:"example",onState:Y0,message:"Select which type of example you want to add",choices:[{title:"Application",value:"application"},{title:"Marketing",value:"marketing"}]});J.example=Y.example}let q=null;if(J.example){let Y=await j0(J.example,J.license);if(Y?.type==="error"&&(Y.status===401||Y.status===403))console.log(),console.log(M.yellow(`\uD83D\uDD12 The ${M.cyan(J.example)} example requires PRO access.`)),console.log(),console.log("To access PRO examples:"),console.log(` ${M.green("→")} If you've already purchased: ${M.cyan(`${z0()} untitledui@latest login`)}`),console.log(` ${M.green("→")} To purchase PRO examples: ${M.cyan("https://www.untitledui.com/buy/react")}`),console.log(),process.exit(1);if(Y?.type==="directory"){let Z=await r({type:"select",name:"example",onState:Y0,message:`Select a folder or file in "${J.example}"`,choices:Y.results.map((K)=>({title:K,value:K}))});if(!Z.example)return;if(J.example=Z.example,Y=await j0(Z.example,J.license),Y?.type==="error"&&(Y.status===401||Y.status===403))console.log(),console.log(M.yellow(`\uD83D\uDD12 The ${M.cyan(Z.example)} example requires PRO access.`)),console.log(),console.log("To access PRO examples:"),console.log(` ${M.green("→")} If you've already purchased: ${M.cyan(`${z0()} untitledui@latest login`)}`),console.log(` ${M.green("→")} To purchase PRO examples: ${M.cyan("https://www.untitledui.com/buy/react")}`),console.log(),process.exit(1)}if(Y?.type==="json-files"){let Z=await r({type:"select",name:"example",onState:Y0,message:`Select which example you want to add from "${J.example}"`,choices:Y.results.map((K)=>({title:K,value:`${J.example}/${K}`}))});if(!Z.example)return;if(J.example=Z.example,Y=await j0(Z.example,J.license),Y?.type==="error"&&(Y.status===401||Y.status===403))console.log(),console.log(M.yellow(`\uD83D\uDD12 The ${M.cyan(Z.example)} example requires PRO access.`)),console.log(),console.log("To access PRO examples:"),console.log(` ${M.green("→")} If you've already purchased: ${M.cyan(`${z0()} untitledui@latest login`)}`),console.log(` ${M.green("→")} To purchase PRO examples: ${M.cyan("https://www.untitledui.com/buy/react")}`),console.log(),process.exit(1)}if(Y?.type==="json-file")q=Y.content}if(!q)Q.fail("No example found"),process.exit(1);if(!J?.examplePath){let Y=$?.isUsingAppDir?"app":"pages",Z=$?.isSrcDir?G.posix.join("src",Y):Y,K=await r({type:"text",name:"examplePath",onState:Y0,message:`Where would you like to add the ${M.cyan(J?.example)} example?`,initial:Z});J.examplePath=K.examplePath}else if(!T.existsSync(G.posix.join(z,J.examplePath)))T.mkdirSync(G.posix.join(z,J.examplePath),{recursive:!0}),console.log(M.green(`Created directory ${J.examplePath}`));if(!J?.path){let Y=await r({type:"text",name:"path",onState:Y0,message:`Where would you like to add the ${M.cyan("components")}?`,initial:"components"});J.path=Y.path}let b=q.components.filter((Y)=>!T.existsSync(G.posix.join(z,`${$?.isSrcDir?"src":""}`,Y?.path?.replace(/components\//,J.path+"/"))));if(b?.length){let Y=await r({type:"multiselect",name:"components",onState:Y0,message:`Select which components you want to add from ${M.cyan(q.name)} example`,choices:b.map((Z)=>({title:Z?.name,value:Z?.name,selected:!0})),instructions:!1,hint:"- Space to select. Return to submit"});if(J.components=Y.components,!b.length&&!Y.components?.length)Q.warn("No components selected")}let H=t(z),L=new Set,y=new s3({tsConfigFilePath:H?.tsConfig}),S=X0(`Adding ${J?.example}...`).start(),E="";try{if(q.files?.forEach(async({path:Y,code:Z})=>{let K=G.posix.join(z,`${$?.isSrcDir?"src":""}`,Y.replace(/components\//,J.path+"/")),R=$?.framework==="vite"?Z.replace(`"use client"; `,""):Z,x=L0(R);if(Y.includes("examples")){let D=G.basename(Y);K=G.posix.join(z,J?.examplePath??"",D),E=G.posix.join(J?.examplePath??"",D)}let V=G.dirname(K);if(T.existsSync(K)&&!J.overwrite){if(T.readFileSync(K,"utf-8")!==x)L.add({code:x,path:K})}else{T.mkdirSync(V,{recursive:!0}),T.writeFileSync(K,x);let D=G.relative(G.posix.join(z,`${$?.isSrcDir?"src":""}`),K).split("/").length,k=D===1?"./":"../".repeat(D-1),u=y.addSourceFileAtPath(G.resolve(K));u.getImportDeclarations().forEach((I)=>{let P=I.getModuleSpecifierValue();I.setModuleSpecifier(e(P,J.path,$?.aliasPrefix,k))}),await u.save()}}),L.size)S.warn(`Some files of ${M.yellow(J?.example)} already exist`);else S.succeed(`${M.green(J?.example)} is added successfully`)}catch(Y){S.fail(` Failed to add the component ${M.red(J?.example)}`),console.error(M.red(Y)),process.exit(1)}if(L.size&&!J?.overwrite)if(console.log(` Following files already exist in the directory.`),L.forEach((Z)=>{console.log(M.green(`- ${G.relative(z,Z.path)}`))}),(await r({type:"confirm",name:"overwrite",message:"Do you want to overwrite the existing files?",initial:!0})).overwrite){let Z=X0("Overwriting files").start();L.forEach((K)=>{let R=G.relative(G.resolve(z,`${$?.isSrcDir?"src":""}`,J.path),K.path).split("/").length,x=R===1?"./":"../".repeat(R-1),V=y.addSourceFileAtPath(G.resolve(K.path));V.replaceWithText(K.code),V.getImportDeclarations().forEach((D)=>{let k=D.getModuleSpecifierValue();D.setModuleSpecifier(e(k,J.path,$?.aliasPrefix,x))}),V.saveSync()}),Z.succeed("Files are overwritten")}else console.log(`Use ${M.cyan("--overwrite")} or ${M.cyan("-o")} to overwrite existing files, or refer to the documentation ${M.cyan("https://www.untitled.com/docs")} for manual installation. The rest of the files are added.`);let U=C();if(q?.dependencies?.length){let Y=X0("Installing example dependencies").start();await g0(()=>I0(U,[U==="npm"?"install":"add",...q.dependencies],{cwd:z}).catch(async(Z)=>{if(Z.message.includes("peer"))Y.warn("Dependency conflict detected. Retrying with --legacy-peer-deps..."),Y.start("Installing dependencies with --legacy-peer-deps flag"),await I0(U,[U==="npm"?"install":"add",...q.dependencies,"--legacy-peer-deps"],{cwd:z})}),{retries:1}),Y.succeed("Example dependencies are installed")}if(q?.devDependencies?.length){let Y=X0("Installing example devDependencies").start();await g0(()=>I0(U,[U==="npm"?"install":"add","-D",...q.devDependencies],{cwd:z}).catch(async(Z)=>{if(Z.message.includes("peer"))Y.warn("DevDependency conflict detected. Retrying with --legacy-peer-deps..."),Y.start("Installing devDependencies with --legacy-peer-deps flag"),await I0(U,[U==="npm"?"install":"add","-D",...q.devDependencies,"--legacy-peer-deps"],{cwd:z})}),{retries:1}),Y.succeed("Example devDependencies are installed")}if(J?.components?.length)await g0(()=>E0({components:J.components,dir:d0?.projectPath||"",path:J.path,message:` \uD83C\uDF89 Example ${M.green(J.example)} has been added to ${M.green(E)}`}),{retries:1});console.log(` \uD83C\uDF89 Example ${M.green(J.example)} has been added to ${M.green(E)}`),process.exit(0)}var h0={name:"untitledui",version:"0.1.43",main:"dist/index.mjs",description:"The Untitled UI CLI tool helps you quickly scaffold projects with Untitled UI React and add components and page examples to your existing projects with an interactive interface in seconds.",type:"module",publishConfig:{access:"public"},scripts:{test:'echo "Error: no test specified" && exit 1',dev:"bun build --entrypoints ./index.ts --entry-naming=[name].mjs --outdir=dist --target=node --minify --packages=external --env=inline --define=process.env.API_URL=http://localhost:3000/react/api --watch",build:"bun build --entrypoints ./index.ts --entry-naming=[name].mjs --outdir=dist --target=node --minify --packages=external --env=inline --define=process.env.API_URL=https://www.untitledui.com/react/api","publish:npm":"bun run build && npm publish --access public",start:"node dist/index.mjs"},bugs:{url:"https://github.com/untitleduico/react/issues"},homepage:"https://github.com/untitleduico/react#readme",keywords:["untitledui","untitled-ui","untitledui","untitledui-cli","untitledui-react","untitledui-components","untitledui-examples","untitledui-vite","untitledui-nextjs","cli","tailwindcss","nextjs","react","components","examples","vite"],files:["dist","config","templates","README.md"],author:{name:"Untitled UI",url:"https://www.untitledui.com/react"},contributors:[{name:"Dilshod Turobov",url:"https://x.com/deebovv"},{name:"Jordan Hughes",url:"https://x.com/jordanphughes"}],license:"MIT",bin:{untitledui:"dist/index.mjs"},exports:"./dist/index.mjs",dependencies:{"async-retry":"^1.3.3",chalk:"^5.4.1",commander:"^13.1.0",execa:"^7.0.0","fast-glob":"^3.3.3","node-fetch":"^3.3.2",open:"^10.1.0",ora:"^8.2.0",prettier:"^3.5.3",prompts:"^2.4.2",tar:"^7.4.3","ts-morph":"^25.0.1","tsconfig-paths":"^4.2.0","update-check":"^1.5.4"},devDependencies:{"@types/async-retry":"^1.4.9","@types/prompts":"^2.4.9","@types/tar":"^6.1.13","type-fest":"^4.37.0",typescript:"^5.8.2"}};process.on("SIGINT",()=>process.exit(0));process.on("SIGTERM",()=>process.exit(0));async function o3(){let W=new p3().name(h0.name).version(h0.version);W.addCommand(X3).addCommand(t0).addCommand(B3).addCommand(Q3),W.parse()}o3();