yummaui 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +14 -5
  2. package/dist/cli.mjs +16 -12
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -39,13 +39,20 @@ pnpm dlx yummaui add button
39
39
  pnpm dlx yummaui add dialog tooltip
40
40
  pnpm dlx yummaui add dialog-sign-in
41
41
  pnpm dlx yummaui add --all
42
+ pnpm dlx yummaui add button --style compact --radius small
42
43
  ```
43
44
 
44
- | Option | |
45
- |---------------|------------------------------------|
46
- | `-a, --all` | Add every component |
47
- | `--overwrite` | Replace files that already exist |
48
- | `-y, --yes` | Skip prompts and take the defaults |
45
+ | Option | |
46
+ |--------------------|---------------------------------------------------|
47
+ | `-a, --all` | Add every component |
48
+ | `--style <name>` | `soft`, `compact` or `squircle` |
49
+ | `--radius <step>` | `none`, `small`, `medium`, `large` or `extra` |
50
+ | `--overwrite` | Replace files that already exist |
51
+ | `-y, --yes` | Skip prompts and take the defaults |
52
+
53
+ A style and radius set as `style` and `radius` in `yummaui.json` apply to
54
+ every `add`; the flags win over them. Each style takes some radius steps and
55
+ refuses the rest, and `add` says why.
49
56
 
50
57
  ### `list [component]`
51
58
 
@@ -81,6 +88,8 @@ The CLI reads a static JSON registry published by the docs site:
81
88
  ```
82
89
  https://yummacss.com/ui/r/index.json every component and block
83
90
  https://yummacss.com/ui/r/<id>.json one component's source and dependencies
91
+ https://yummacss.com/ui/r/styles.json the styles and the radius steps each takes
92
+ https://yummacss.com/ui/r/<style>-<radius>/<id>.json the same, rewritten for a style
84
93
  ```
85
94
 
86
95
  ## License
package/dist/cli.mjs CHANGED
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import e from"picocolors";import{spawnSync as t}from"node:child_process";import{existsSync as n,mkdirSync as r,readFileSync as i,readdirSync as a,rmSync as o,writeFileSync as s}from"node:fs";import{dirname as c,join as l,relative as u,resolve as d,sep as f}from"node:path";import*as p from"@clack/prompts";var m=`0.2.1`;const h=`https://yummacss.com/ui/r`;var g=class extends Error{};async function _(e){let t;try{t=await fetch(e,{headers:{accept:`application/json`}})}catch(t){throw new g(`Could not reach the registry at ${e}. Are you online?`,{cause:t})}if(t.status===404)throw new g(`Not found: ${e}`);if(!t.ok)throw new g(`Registry returned ${t.status} for ${e}`);try{return await t.json()}catch(t){throw new g(`Registry sent invalid JSON from ${e}`,{cause:t})}}function v(e){return _(`${e}/index.json`)}function ee(e,t){return _(`${e}/${t}.json`)}const y=`yummaui.json`,b={"pnpm-lock.yaml":`pnpm`,"bun.lockb":`bun`,"bun.lock":`bun`,"yarn.lock":`yarn`,"package-lock.json":`npm`};function x(e=process.cwd()){let t=d(e);for(;;){if(n(l(t,`package.json`)))return t;let e=c(t);if(e===t)return null;t=e}}function S(e){try{return JSON.parse(i(l(e,`package.json`),`utf8`))}catch{return{}}}function C(e){for(let[t,r]of Object.entries(b))if(n(l(e,t)))return r;let t=S(e).packageManager;if(typeof t==`string`){let e=t.split(`@`)[0];if(e===`pnpm`||e===`npm`||e===`yarn`||e===`bun`)return e}return`npm`}function w(e){let t=S(e),r={...t.dependencies,...t.devDependencies};return r.next?[`app`,`src/app`].some(t=>n(l(e,t)))?`Next.js (App Router)`:`Next.js (Pages Router)`:r.astro?`Astro`:r[`react-router`]||r[`@remix-run/react`]?`React Router`:r.vite?`Vite`:null}function T(e){for(let t of[`tsconfig.json`,`jsconfig.json`]){let r=l(e,t);if(n(r))try{let e=i(r,`utf8`).replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|\s)\/\/.*$/gm,`$1`);if(JSON.parse(e)?.compilerOptions?.paths?.[`@/*`])return`@`}catch{}}return null}function E(e){return l(e,y)}function D(e){let t=E(e);if(!n(t))return null;try{let e=JSON.parse(i(t,`utf8`));return{componentsDir:e.componentsDir??`components/ui`,alias:e.alias??null,registry:e.registry??h}}catch{return null}}function O(e,t){s(E(e),`${JSON.stringify(t,null,` `)}\n`)}function k(e,t){let n=S(e),r=new Set([...Object.keys(n.dependencies??{}),...Object.keys(n.devDependencies??{}),...Object.keys(n.peerDependencies??{})]);return t.filter(e=>!r.has(e.name))}function A(e,t){return{command:e,args:e===`npm`?[`install`,...t]:[`add`,...t]}}function j(e=x()){switch(e?C(e):`npm`){case`pnpm`:return`pnpm dlx yummaui`;case`yarn`:return`yarn dlx yummaui`;case`bun`:return`bunx yummaui`;default:return`npx yummaui`}}function M(e){let t=[],n={all:!1,overwrite:!1,yes:!1};for(let r=0;r<e.length;r++){let i=e[r];i===`--all`||i===`-a`?n.all=!0:i===`--overwrite`?n.overwrite=!0:i===`--yes`||i===`-y`?n.yes=!0:i.startsWith(`-`)||t.push(i)}return{names:t,options:n}}function N(e,t,n){return n===`base`?`${t}.tsx`:`${e}.tsx`}function P(e,t,n={}){let r=[];n.all&&r.push(...e.components.map(e=>e.base));for(let n of t){let t=e.components.find(e=>e.component===n);if(t){r.push(t.base);continue}let i=e.blocks.find(e=>e.id===n);if(i){r.push(i.id);continue}return{unknown:n}}return{ids:[...new Set(r)]}}async function F(i){let{names:a,options:o}=M(i),d=x();if(!d)return p.log.error(`No package.json found. Run this inside a project.`),1;let f=d,m=D(f);if(!m)return p.log.error(`No ${y} found. Run ${e.cyan(`${j(f)} init`)} first.`),1;let{registry:h,componentsDir:_}=m;if(a.length===0&&!o.all)return p.log.error(`Nothing to add. Try: ${j(f)} add button`),1;p.intro(e.bgCyan(e.black(` Yumma UI `)));let b,S=p.spinner();S.start(`Fetching registry`);try{b=await v(m.registry)}catch(e){return S.stop(`Registry unavailable`,1),p.log.error(e instanceof g?e.message:String(e)),1}S.stop(`${b.components.length} components, ${b.blocks.length} blocks available`);let w=P(b,a,{all:o.all});if(`unknown`in w)return p.log.error(`Unknown component or block ${e.bold(w.unknown)}.`),w.unknown===`all`?p.log.info(`Every component is ${e.cyan(`--all`)}.`):L(b,w.unknown),1;let T=w.ids,E=[],O=new Map,F=new Set;async function I(e,t){if(F.has(e))return!0;F.add(e);let i;try{i=await ee(h,e)}catch(e){return p.log.error(e instanceof g?e.message:String(e)),!1}for(let e of i.registryDependencies)if(!await I(e,!1))return!1;let a=l(f,_,N(i.id,i.component,i.variant)),d=u(f,a).replace(/\\/g,`/`);if(n(a)&&!o.overwrite){if(!t||o.yes)return p.log.warn(`Skipped ${d} (already exists)`),!0;let e=await p.confirm({message:`${d} already exists. Overwrite?`,initialValue:!1});if(p.isCancel(e))return p.cancel(`Cancelled.`),!1;if(!e)return p.log.warn(`Skipped ${d}`),!0}let m=i.files[0];if(!m)return p.log.error(`${e} has no files.`),!1;r(c(a),{recursive:!0}),s(a,m.content),E.push(d);for(let e of i.dependencies)O.set(e.name,e.version);return!0}for(let e of T)if(!await I(e,!0))return 1;if(E.length===0)return p.outro(`Nothing written.`),0;p.log.success(`Added\n${E.map(e=>` ${e}`).join(`
3
- `)}`);let R=k(f,[...O].map(([e,t])=>({name:e,version:t}))),z=[...O.keys()].filter(e=>!R.some(t=>t.name===e));if(O.size>0){let t=[...z.map(t=>` ${e.green(`✔`)} ${t} ${e.dim(`already installed`)}`),...R.map(t=>` ${e.yellow(`+`)} ${t.name}@${t.version}`)];p.log.info(`Dependencies\n${t.join(`
4
- `)}`)}if(R.length>0){let n=C(f),r=R.map(e=>`${e.name}@${e.version}`),i=o.yes;if(!i){let t=await p.confirm({message:`Install ${R.length} missing package${R.length>1?`s`:``} with ${e.bold(n)}?`});if(p.isCancel(t))return p.cancel(`Cancelled.`),1;i=t}if(i){let{command:e,args:i}=A(n,r),a=t(e,i,{cwd:f,stdio:`inherit`,shell:process.platform===`win32`});if(a.status!==0)return p.log.error(`${e} exited with ${a.status??`an error`}.`),1}else p.log.info(`Install manually:\n ${C(f)} add ${r.join(` `)}`)}return p.outro(`Done.`),0}function I(e,t){let n=Array.from({length:t.length+1},(e,t)=>t);for(let r=1;r<=e.length;r++){let i=[r];for(let a=1;a<=t.length;a++){let o=e[r-1]===t[a-1]?0:1;i[a]=Math.min(i[a-1]+1,n[a]+1,n[a-1]+o)}n=i}return n[t.length]}function L(e,t){let n=[...e.components.map(e=>e.component),...e.blocks.map(e=>e.id)].map(e=>({name:e,score:e.includes(t)||t.includes(e)?0:I(e,t)})).filter(e=>e.score<=2).sort((e,t)=>e.score-t.score).slice(0,5).map(e=>e.name);n.length?p.log.info(`Did you mean: ${n.join(`, `)}`):p.log.info(`Run ${j()} list to see everything.`)}async function R(t){let n=t.includes(`--force`),r=x();if(!r)return p.log.error(`No package.json found. Run this inside a project.`),1;if(p.intro(e.bgCyan(e.black(` Yumma UI `))),D(r)&&!n)return p.log.warn(`${y} already exists. Use --force to overwrite.`),p.outro(`Nothing to do.`),0;let i=w(r),a=C(r),o=T(r);p.log.step([i?`Detected ${e.bold(i)}`:`No framework detected`,`Detected ${e.bold(a)}`].join(`
5
- `));let s=await p.text({message:`Where should components go?`,placeholder:`components/ui`,defaultValue:`components/ui`});if(p.isCancel(s))return z();let c=!1;if(o){let t=await p.confirm({message:`Use the ${e.bold(`"${o}/"`)} import alias?`});if(p.isCancel(t))return z();c=t}return O(r,{componentsDir:String(s),alias:c&&o?`${o}/${s}`:null,registry:h}),p.log.success(`Wrote ${e.bold(E(r))}`),p.outro(`Next: ${e.cyan(`${j(r)} add button`)}`),0}function z(){return p.cancel(`Cancelled.`),1}async function B(t){let n=t.find(e=>!e.startsWith(`-`)),r=x(),i=r&&D(r)?.registry||h,a;try{a=await v(i)}catch(t){return console.error(e.red(t instanceof g?t.message:String(t))),1}if(n){let t=a.components.find(e=>e.component===n);if(!t)return console.error(e.red(`Unknown component ${n}.`)),1;let i=a.blocks.filter(e=>e.component===n);if(console.log(`\n${e.bold(t.title)} ${e.dim(t.component)}\n`),console.log(` ${e.dim(`${j(r)} add ${t.component}`)}\n`),console.log(` ${e.dim(`Every variation is a prop. Read its API at`)} ${e.cyan(`https://yummacss.com/ui/components/${t.component}`)}\n`),i.length){console.log(` ${e.bold(`${i.length} block${i.length>1?`s`:``} built on it`)}`);for(let t of i)console.log(` ${t.id.padEnd(26)}${e.dim(`add ${t.id}`)}`);console.log()}return 0}console.log(`\n${e.bold(`${a.components.length} components`)}\n`);let o=a.components.map(e=>e.component);for(let e=0;e<o.length;e+=2)console.log(` ${(o[e]??``).padEnd(24)}${o[e+1]??``}`);console.log(`\n${e.bold(`${a.blocks.length} blocks`)}\n`);let s=a.blocks.map(e=>e.id);for(let e=0;e<s.length;e+=2)console.log(` ${(s[e]??``).padEnd(30)}${s[e+1]??``}`);return console.log(`\n ${e.dim(`${j(r)} list <component>`)} to see its blocks\n`),0}const V=[`.astro`,`.cjs`,`.cts`,`.js`,`.jsx`,`.md`,`.mdx`,`.mjs`,`.mts`,`.svelte`,`.ts`,`.tsx`,`.vue`],H=new Set([`node_modules`,`.git`]),U=[/\bfrom\s*["']([^"'\n]+)["']/g,/\bimport\s*\(\s*["']([^"'\n]+)["']/g,/\brequire\s*\(\s*["']([^"'\n]+)["']/g,/\bimport\s+["']([^"'\n]+)["']/g];function W(e){let t=new Set;for(let n of U){n.lastIndex=0;for(let r of e.matchAll(n))r[1]&&t.add(r[1])}return[...t]}const G=/\b(?:from|import\s*\(|require\s*\()\s*`/;function K(e){return G.test(e)}function q(e){let t=e.split(f).join(`/`).replace(/^\.\//,``);for(let e of V)if(t.endsWith(e))return t.slice(0,-e.length);return t}function J(e,t,n){let r=d(n.root,n.componentsDir);if(n.alias){let t=`${n.alias}/`;if(e===n.alias)return`index`;if(e.startsWith(t)){let n=e.slice(t.length);return n?q(n):`index`}}if(!e.startsWith(`.`))return null;let i=u(r,d(c(t),e));return i?i===`..`||i.startsWith(`..${f}`)?null:q(i):`index`}function Y(e,t){return q(u(d(t.root,t.componentsDir),e))}function X(e,t,n=[]){let r;try{r=a(e,{withFileTypes:!0})}catch{return n}for(let i of r){let r=l(e,i.name);if(i.isDirectory()){if(H.has(i.name)||r===t)continue;X(r,t,n)}else if(i.isFile()){let e=i.name.lastIndexOf(`.`);e>0&&V.includes(i.name.slice(e))&&n.push(r)}}return n}function Z(e){let t=new Set;for(let n of e.components)t.add(`${n.component}.tsx`);for(let n of e.blocks)t.add(`${n.id}.tsx`);return t}function Q(e,t){let n=d(e.root,e.componentsDir),r=X(n,``),a=X(e.root,n),o=new Map,s=new Set,c=new Map,l=[];for(let n of r){let r=Y(n,e);n.endsWith(`.tsx`)&&!r.includes(`/`)&&t.has(`${r}.tsx`)?o.set(r,n):s.add(r);let a=i(n,`utf8`);K(a)&&l.push(n);let u=new Set;for(let t of W(a)){let r=J(t,n,e);r&&u.add(r)}c.set(r,u)}for(let t of a){let n=i(t,`utf8`);K(n)&&l.push(t);for(let r of W(n)){let n=J(r,t,e);n&&s.add(n)}}let u=new Set,f=[...s];for(;f.length>0;){let e=f.pop();if(!u.has(e)){u.add(e);for(let t of c.get(e)??[])u.has(t)||f.push(t)}}let p=[];for(let[e,t]of o)u.has(e)||p.push(t);return{unused:p.sort(),kept:o.size-p.length,foreign:r.length-o.size,scanned:r.length+a.length,computed:l}}function te(e){return{write:e.includes(`--write`),yes:e.includes(`--yes`)||e.includes(`-y`)}}async function ne(t){let n=te(t),r=x();if(!r)return p.log.error(`No package.json found. Run this inside a project.`),1;let i=D(r);if(!i)return p.log.error(`No ${y} found. Run ${e.cyan(`${j(r)} init`)} first.`),1;p.intro(e.bgCyan(e.black(` Yumma UI `)));let a,s=p.spinner();s.start(`Fetching registry`);try{a=await v(i.registry)}catch(e){return s.stop(`Registry unavailable`,1),p.log.error(e instanceof g?e.message:String(e)),1}s.stop(`Reading the project`);let c=Q({root:r,componentsDir:i.componentsDir,alias:i.alias},Z(a)),l=e=>u(r,e).replace(/\\/g,`/`);if(c.computed.length>0&&p.log.warn(`Imports built at runtime in ${c.computed.length} file${c.computed.length>1?`s`:``}; anything they name is invisible here:\n${c.computed.slice(0,5).map(e=>` ${l(e)}`).join(`
2
+ import e from"picocolors";import{spawnSync as t}from"node:child_process";import{existsSync as n,mkdirSync as r,readFileSync as i,readdirSync as a,rmSync as o,writeFileSync as s}from"node:fs";import{dirname as c,join as l,relative as u,resolve as d,sep as f}from"node:path";import*as p from"@clack/prompts";var m=`0.4.0`;const h=`https://yummacss.com/ui/r`;var g=class extends Error{};async function _(e){let t;try{t=await fetch(e,{headers:{accept:`application/json`}})}catch(t){throw new g(`Could not reach the registry at ${e}. Are you online?`,{cause:t})}if(t.status===404)throw new g(`Not found: ${e}`);if(!t.ok)throw new g(`Registry returned ${t.status} for ${e}`);try{return await t.json()}catch(t){throw new g(`Registry sent invalid JSON from ${e}`,{cause:t})}}function v(e){return _(`${e}/index.json`)}function ee(e,t){return _(`${e}/${t}.json`)}function te(e){return _(`${e}/styles.json`)}function ne(e,t,n){let r=t??e.default,i=e.styles[r];if(!i)return{error:`There is no ${r} style. Try one of: ${Object.keys(e.styles).join(`, `)}.`};let a=n??i.radius;return i.allow.includes(a)?{folder:`${r}-${a}`}:{error:`${i.refused[a]??`${i.name} does not take ${a}.`} ${i.name} takes: ${i.allow.join(`, `)}.`}}const y=`yummaui.json`,b={"pnpm-lock.yaml":`pnpm`,"bun.lockb":`bun`,"bun.lock":`bun`,"yarn.lock":`yarn`,"package-lock.json":`npm`};function x(e=process.cwd()){let t=d(e);for(;;){if(n(l(t,`package.json`)))return t;let e=c(t);if(e===t)return null;t=e}}function S(e){try{return JSON.parse(i(l(e,`package.json`),`utf8`))}catch{return{}}}function C(e){for(let[t,r]of Object.entries(b))if(n(l(e,t)))return r;let t=S(e).packageManager;if(typeof t==`string`){let e=t.split(`@`)[0];if(e===`pnpm`||e===`npm`||e===`yarn`||e===`bun`)return e}return`npm`}function w(e){let t=S(e),r={...t.dependencies,...t.devDependencies};return r.next?[`app`,`src/app`].some(t=>n(l(e,t)))?`Next.js (App Router)`:`Next.js (Pages Router)`:r.astro?`Astro`:r[`react-router`]||r[`@remix-run/react`]?`React Router`:r.vite?`Vite`:null}function T(e){for(let t of[`tsconfig.json`,`jsconfig.json`]){let r=l(e,t);if(n(r))try{let e=i(r,`utf8`).replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|\s)\/\/.*$/gm,`$1`);if(JSON.parse(e)?.compilerOptions?.paths?.[`@/*`])return`@`}catch{}}return null}function E(e){return l(e,y)}function D(e){let t=E(e);if(!n(t))return null;try{let e=JSON.parse(i(t,`utf8`));return{componentsDir:e.componentsDir??`components/ui`,alias:e.alias??null,registry:e.registry??h,...e.style?{style:e.style}:{},...e.radius?{radius:e.radius}:{}}}catch{return null}}function O(e,t){s(E(e),`${JSON.stringify(t,null,` `)}\n`)}function k(e,t){let n=S(e),r=new Set([...Object.keys(n.dependencies??{}),...Object.keys(n.devDependencies??{}),...Object.keys(n.peerDependencies??{})]);return t.filter(e=>!r.has(e.name))}function A(e,t){return{command:e,args:e===`npm`?[`install`,...t]:[`add`,...t]}}function j(e=x()){switch(e?C(e):`npm`){case`pnpm`:return`pnpm dlx yummaui`;case`yarn`:return`yarn dlx yummaui`;case`bun`:return`bunx yummaui`;default:return`npx yummaui`}}const M=`yumma.config.mjs`;function N(e){return e?e.startsWith(`Next.js`)?`@yummacss/postcss`:`@yummacss/vite`:null}function P(e){let t=S(e),r=new Set([...Object.keys(t.dependencies??{}),...Object.keys(t.devDependencies??{})]),i=N(w(e));return{core:r.has(`yummacss`),plugin:i?{name:i,installed:r.has(i)}:null,config:n(l(e,M))}}function F(e){let t=[];return e.core||t.push(`yummacss`),e.plugin&&!e.plugin.installed&&t.push(e.plugin.name),e.config||t.push(M),t}function I(t){let n=F(P(t));if(n.length===0)return;let r=n.map(t=>` ${e.yellow(`+`)} ${t}`);p.log.warn([`Yumma CSS is not set up here, so these components render unstyled.`,...r,``,` ${e.cyan(`https://yummacss.com/docs/installation`)}`].join(`
3
+ `))}function L(e){let t=[],n={all:!1,overwrite:!1,yes:!1,style:null,radius:null};for(let r=0;r<e.length;r++){let i=e[r],[a,o]=i.split(`=`,2);if(a===`--style`||a===`--radius`){let t=o??e[++r]??null;a===`--style`?n.style=t:n.radius=t}else i===`--all`||i===`-a`?n.all=!0:i===`--overwrite`?n.overwrite=!0:i===`--yes`||i===`-y`?n.yes=!0:i.startsWith(`-`)||t.push(i)}return{names:t,options:n}}function R(e,t,n){return n===`base`?`${t}.tsx`:`${e}.tsx`}function z(e,t,n={}){let r=[];n.all&&r.push(...e.components.map(e=>e.base));for(let n of t){let t=e.components.find(e=>e.component===n);if(t){r.push(t.base);continue}let i=e.blocks.find(e=>e.id===n);if(i){r.push(i.id);continue}return{unknown:n}}return{ids:[...new Set(r)]}}async function B(i){let{names:a,options:o}=L(i),d=x();if(!d)return p.log.error(`No package.json found. Run this inside a project.`),1;let f=d,m=D(f);if(!m)return p.log.error(`No ${y} found. Run ${e.cyan(`${j(f)} init`)} first.`),1;let{componentsDir:h}=m,_=m.registry;if(a.length===0&&!o.all)return p.log.error(`Nothing to add. Try: ${j(f)} add button`),1;p.intro(e.bgCyan(e.black(` Yumma UI `)));let b,S=p.spinner();S.start(`Fetching registry`);try{b=await v(m.registry)}catch(e){return S.stop(`Registry unavailable`,1),p.log.error(e instanceof g?e.message:String(e)),1}S.stop(`${b.components.length} components, ${b.blocks.length} blocks available`);let w=o.style??m.style??null,T=o.radius??m.radius??null;if(w||T)try{let t=ne(await te(m.registry),w,T);if(`error`in t)return p.log.error(t.error),1;_=`${m.registry}/${t.folder}`,p.log.info(`Style ${e.bold(t.folder)}`)}catch(e){return p.log.error(e instanceof g?e.message:String(e)),1}let E=z(b,a,{all:o.all});if(`unknown`in E)return p.log.error(`Unknown component or block ${e.bold(E.unknown)}.`),E.unknown===`all`?p.log.info(`Every component is ${e.cyan(`--all`)}.`):H(b,E.unknown),1;let O=E.ids,M=[],N=new Map,P=new Set;async function F(e,t){if(P.has(e))return!0;P.add(e);let i;try{i=await ee(_,e)}catch(e){return p.log.error(e instanceof g?e.message:String(e)),!1}for(let e of i.registryDependencies)if(!await F(e,!1))return!1;let a=l(f,h,R(i.id,i.component,i.variant)),d=u(f,a).replace(/\\/g,`/`);if(n(a)&&!o.overwrite){if(!t||o.yes)return p.log.warn(`Skipped ${d} (already exists)`),!0;let e=await p.confirm({message:`${d} already exists. Overwrite?`,initialValue:!1});if(p.isCancel(e))return p.cancel(`Cancelled.`),!1;if(!e)return p.log.warn(`Skipped ${d}`),!0}let m=i.files[0];if(!m)return p.log.error(`${e} has no files.`),!1;r(c(a),{recursive:!0}),s(a,m.content),M.push(d);for(let e of i.dependencies)N.set(e.name,e.version);return!0}for(let e of O)if(!await F(e,!0))return 1;if(M.length===0)return p.outro(`Nothing written.`),0;p.log.success(`Added\n${M.map(e=>` ${e}`).join(`
4
+ `)}`);let B=k(f,[...N].map(([e,t])=>({name:e,version:t}))),V=[...N.keys()].filter(e=>!B.some(t=>t.name===e));if(N.size>0){let t=[...V.map(t=>` ${e.green(`✔`)} ${t} ${e.dim(`already installed`)}`),...B.map(t=>` ${e.yellow(`+`)} ${t.name}@${t.version}`)];p.log.info(`Dependencies\n${t.join(`
5
+ `)}`)}if(B.length>0){let n=C(f),r=B.map(e=>`${e.name}@${e.version}`),i=o.yes;if(!i){let t=await p.confirm({message:`Install ${B.length} missing package${B.length>1?`s`:``} with ${e.bold(n)}?`});if(p.isCancel(t))return p.cancel(`Cancelled.`),1;i=t}if(i){let{command:e,args:i}=A(n,r),a=t(e,i,{cwd:f,stdio:`inherit`,shell:process.platform===`win32`});if(a.status!==0)return p.log.error(`${e} exited with ${a.status??`an error`}.`),1}else p.log.info(`Install manually:\n ${C(f)} add ${r.join(` `)}`)}return I(f),p.outro(`Done.`),0}function V(e,t){let n=Array.from({length:t.length+1},(e,t)=>t);for(let r=1;r<=e.length;r++){let i=[r];for(let a=1;a<=t.length;a++){let o=e[r-1]===t[a-1]?0:1;i[a]=Math.min(i[a-1]+1,n[a]+1,n[a-1]+o)}n=i}return n[t.length]}function H(e,t){let n=[...e.components.map(e=>e.component),...e.blocks.map(e=>e.id)].map(e=>({name:e,score:e.includes(t)||t.includes(e)?0:V(e,t)})).filter(e=>e.score<=2).sort((e,t)=>e.score-t.score).slice(0,5).map(e=>e.name);n.length?p.log.info(`Did you mean: ${n.join(`, `)}`):p.log.info(`Run ${j()} list to see everything.`)}async function U(t){let n=t.includes(`--force`),r=x();if(!r)return p.log.error(`No package.json found. Run this inside a project.`),1;if(p.intro(e.bgCyan(e.black(` Yumma UI `))),D(r)&&!n)return p.log.warn(`${y} already exists. Use --force to overwrite.`),p.outro(`Nothing to do.`),0;let i=w(r),a=C(r),o=T(r);p.log.step([i?`Detected ${e.bold(i)}`:`No framework detected`,`Detected ${e.bold(a)}`].join(`
6
+ `));let s=await p.text({message:`Where should components go?`,placeholder:`components/ui`,defaultValue:`components/ui`});if(p.isCancel(s))return W();let c=!1;if(o){let t=await p.confirm({message:`Use the ${e.bold(`"${o}/"`)} import alias?`});if(p.isCancel(t))return W();c=t}return O(r,{componentsDir:String(s),alias:c&&o?`${o}/${s}`:null,registry:h}),p.log.success(`Wrote ${e.bold(E(r))}`),I(r),p.outro(`Next: ${e.cyan(`${j(r)} add button`)}`),0}function W(){return p.cancel(`Cancelled.`),1}async function G(t){let n=t.find(e=>!e.startsWith(`-`)),r=x(),i=r&&D(r)?.registry||h,a;try{a=await v(i)}catch(t){return console.error(e.red(t instanceof g?t.message:String(t))),1}if(n){let t=a.components.find(e=>e.component===n);if(!t)return console.error(e.red(`Unknown component ${n}.`)),1;let i=a.blocks.filter(e=>e.component===n);if(console.log(`\n${e.bold(t.title)} ${e.dim(t.component)}\n`),console.log(` ${e.dim(`${j(r)} add ${t.component}`)}\n`),console.log(` ${e.dim(`Every variation is a prop. Read its API at`)} ${e.cyan(`https://yummacss.com/ui/components/${t.component}`)}\n`),i.length){console.log(` ${e.bold(`${i.length} block${i.length>1?`s`:``} built on it`)}`);for(let t of i)console.log(` ${t.id.padEnd(26)}${e.dim(`add ${t.id}`)}`);console.log()}return 0}console.log(`\n${e.bold(`${a.components.length} components`)}\n`);let o=a.components.map(e=>e.component);for(let e=0;e<o.length;e+=2)console.log(` ${(o[e]??``).padEnd(24)}${o[e+1]??``}`);console.log(`\n${e.bold(`${a.blocks.length} blocks`)}\n`);let s=a.blocks.map(e=>e.id);for(let e=0;e<s.length;e+=2)console.log(` ${(s[e]??``).padEnd(30)}${s[e+1]??``}`);return console.log(`\n ${e.dim(`${j(r)} list <component>`)} to see its blocks\n`),0}const K=[`.astro`,`.cjs`,`.cts`,`.js`,`.jsx`,`.md`,`.mdx`,`.mjs`,`.mts`,`.svelte`,`.ts`,`.tsx`,`.vue`],q=new Set([`node_modules`,`.git`]),re=[/\bfrom\s*["']([^"'\n]+)["']/g,/\bimport\s*\(\s*["']([^"'\n]+)["']/g,/\brequire\s*\(\s*["']([^"'\n]+)["']/g,/\bimport\s+["']([^"'\n]+)["']/g];function J(e){let t=new Set;for(let n of re){n.lastIndex=0;for(let r of e.matchAll(n))r[1]&&t.add(r[1])}return[...t]}const ie=/\b(?:from|import\s*\(|require\s*\()\s*`/;function Y(e){return ie.test(e)}function X(e){let t=e.split(f).join(`/`).replace(/^\.\//,``);for(let e of K)if(t.endsWith(e))return t.slice(0,-e.length);return t}function Z(e,t,n){let r=d(n.root,n.componentsDir);if(n.alias){let t=`${n.alias}/`;if(e===n.alias)return`index`;if(e.startsWith(t)){let n=e.slice(t.length);return n?X(n):`index`}}if(!e.startsWith(`.`))return null;let i=u(r,d(c(t),e));return i?i===`..`||i.startsWith(`..${f}`)?null:X(i):`index`}function ae(e,t){return X(u(d(t.root,t.componentsDir),e))}function Q(e,t,n=[]){let r;try{r=a(e,{withFileTypes:!0})}catch{return n}for(let i of r){let r=l(e,i.name);if(i.isDirectory()){if(q.has(i.name)||r===t)continue;Q(r,t,n)}else if(i.isFile()){let e=i.name.lastIndexOf(`.`);e>0&&K.includes(i.name.slice(e))&&n.push(r)}}return n}function oe(e){let t=new Set;for(let n of e.components)t.add(`${n.component}.tsx`);for(let n of e.blocks)t.add(`${n.id}.tsx`);return t}function se(e,t){let n=d(e.root,e.componentsDir),r=Q(n,``),a=Q(e.root,n),o=new Map,s=new Set,c=new Map,l=[];for(let n of r){let r=ae(n,e);n.endsWith(`.tsx`)&&!r.includes(`/`)&&t.has(`${r}.tsx`)?o.set(r,n):s.add(r);let a=i(n,`utf8`);Y(a)&&l.push(n);let u=new Set;for(let t of J(a)){let r=Z(t,n,e);r&&u.add(r)}c.set(r,u)}for(let t of a){let n=i(t,`utf8`);Y(n)&&l.push(t);for(let r of J(n)){let n=Z(r,t,e);n&&s.add(n)}}let u=new Set,f=[...s];for(;f.length>0;){let e=f.pop();if(!u.has(e)){u.add(e);for(let t of c.get(e)??[])u.has(t)||f.push(t)}}let p=[];for(let[e,t]of o)u.has(e)||p.push(t);return{unused:p.sort(),kept:o.size-p.length,foreign:r.length-o.size,scanned:r.length+a.length,computed:l}}function ce(e){return{write:e.includes(`--write`),yes:e.includes(`--yes`)||e.includes(`-y`)}}async function le(t){let n=ce(t),r=x();if(!r)return p.log.error(`No package.json found. Run this inside a project.`),1;let i=D(r);if(!i)return p.log.error(`No ${y} found. Run ${e.cyan(`${j(r)} init`)} first.`),1;p.intro(e.bgCyan(e.black(` Yumma UI `)));let a,s=p.spinner();s.start(`Fetching registry`);try{a=await v(i.registry)}catch(e){return s.stop(`Registry unavailable`,1),p.log.error(e instanceof g?e.message:String(e)),1}s.stop(`Reading the project`);let c=se({root:r,componentsDir:i.componentsDir,alias:i.alias},oe(a)),l=e=>u(r,e).replace(/\\/g,`/`);if(c.computed.length>0&&p.log.warn(`Imports built at runtime in ${c.computed.length} file${c.computed.length>1?`s`:``}; anything they name is invisible here:\n${c.computed.slice(0,5).map(e=>` ${l(e)}`).join(`
6
7
  `)}`),c.unused.length===0)return p.log.info(`${c.kept} installed, all reachable. ${c.scanned} files scanned.`),p.outro(`Nothing to prune.`),0;if(p.log.info(`Unreachable from outside ${e.bold(i.componentsDir)}\n${c.unused.map(t=>` ${e.yellow(l(t))}`).join(`
7
- `)}`),p.log.step(`${c.unused.length} unused, ${c.kept} in use`+(c.foreign>0?`, ${c.foreign} not ours`:``)),!n.write)return p.outro(`Delete them with ${e.cyan(`${j(r)} prune --write`)}`),0;if(!n.yes){let e=await p.confirm({message:`Delete ${c.unused.length} file${c.unused.length>1?`s`:``}?`,initialValue:!1});if(p.isCancel(e))return p.cancel(`Cancelled.`),1;if(!e)return p.outro(`Nothing deleted.`),0}for(let e of c.unused)o(e,{force:!0});return p.log.success(`Deleted ${c.unused.length}`),p.outro(`Done.`),0}const $=`
8
+ `)}`),p.log.step(`${c.unused.length} unused, ${c.kept} in use`+(c.foreign>0?`, ${c.foreign} not ours`:``)),!n.write)return p.outro(`Delete them with ${e.cyan(`${j(r)} prune --write`)}`),0;if(!n.yes){let e=await p.confirm({message:`Delete ${c.unused.length} file${c.unused.length>1?`s`:``}?`,initialValue:!1});if(p.isCancel(e))return p.cancel(`Cancelled.`),1;if(!e)return p.outro(`Nothing deleted.`),0}for(let e of c.unused)o(e,{force:!0});return p.log.success(`Deleted ${c.unused.length}`),p.outro(`Done.`),0}const $=()=>{let t=j();return`
8
9
  ${e.bold(`yummaui`)} ${e.dim(`v${m}`)}
9
10
 
10
11
  Copies Yumma UI components into your project. Never a dependency.
11
12
 
12
13
  ${e.bold(`Usage`)}
13
- npx yummaui <command> [options]
14
+ ${t} <command> [options]
14
15
 
15
16
  ${e.bold(`Commands`)}
16
17
  init Set up yummaui.json in this project
@@ -20,6 +21,8 @@ ${e.bold(`Commands`)}
20
21
 
21
22
  ${e.bold(`Options`)}
22
23
  -a, --all Add every component
24
+ --style <name> add: soft, compact or squircle
25
+ --radius <step> add: none, small, medium, large or extra
23
26
  --overwrite Replace files that already exist
24
27
  --write prune: delete, instead of only listing
25
28
  -y, --yes Skip prompts, take the defaults
@@ -27,9 +30,10 @@ ${e.bold(`Options`)}
27
30
  --version Show the version
28
31
 
29
32
  ${e.bold(`Examples`)}
30
- npx yummaui add button
31
- npx yummaui add dialog tooltip
32
- npx yummaui add --all
33
- npx yummaui list button
34
- npx yummaui prune
35
- `;async function re(){let t=process.argv.slice(2),n=t[0];if(!n||n===`-h`||n===`--help`)return console.log($),0;if(n===`--version`||n===`-V`)return console.log(m),0;let r=t.slice(1);switch(n){case`init`:return R(r);case`add`:return F(r);case`list`:case`ls`:return B(r);case`prune`:return ne(r);default:return console.error(e.red(`Unknown command "${n}".`)),console.log($),1}}re().then(e=>{process.exitCode=e}).catch(t=>{console.error(e.red(t instanceof Error?t.message:String(t))),process.exitCode=1});export{};
33
+ ${t} add button
34
+ ${t} add dialog tooltip
35
+ ${t} add button --style compact --radius small
36
+ ${t} add --all
37
+ ${t} list button
38
+ ${t} prune
39
+ `};async function ue(){let t=process.argv.slice(2),n=t[0];if(!n||n===`-h`||n===`--help`)return console.log($()),0;if(n===`--version`||n===`-V`)return console.log(m),0;let r=t.slice(1);switch(n){case`init`:return U(r);case`add`:return B(r);case`list`:case`ls`:return G(r);case`prune`:return le(r);default:return console.error(e.red(`Unknown command "${n}".`)),console.log($()),1}}ue().then(e=>{process.exitCode=e}).catch(t=>{console.error(e.red(t instanceof Error?t.message:String(t))),process.exitCode=1});export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yummaui",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Add Yumma UI components to your project.",
5
5
  "keywords": [
6
6
  "yummacss",
@@ -12,7 +12,7 @@
12
12
  "homepage": "https://yummacss.com/ui",
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+https://github.com/yummacss/ui.git"
15
+ "url": "git+https://github.com/yummacss/yummaui.git"
16
16
  },
17
17
  "license": "MIT",
18
18
  "author": "Renildo Pereira",