@iconia/react 0.1.0-dev.00e4942

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wyesoftware
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # @iconia/react
2
+
3
+ CLI and React component library for [iconia.io](https://iconia.io) — manage SVG icon collections and import them as typed React components at build time.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @iconia/react
9
+ # or
10
+ bun add @iconia/react
11
+ # or
12
+ pnpm add @iconia/react
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```bash
18
+ npx @iconia/react init # create iconia.config.ts
19
+ npx @iconia/react add my-icons # add a collection and download icons
20
+ ```
21
+
22
+
23
+ ### Shorter commands after install
24
+
25
+ Once `@iconia/react` is installed in your project you can drop the package name and use `iconia` directly:
26
+
27
+ ```bash
28
+ iconia init
29
+ iconia add my-icons
30
+ iconia sync
31
+ iconia pull
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ `iconia.config.ts` in your project root:
37
+
38
+ ```ts
39
+ import type { IconiaConfig } from "@iconia/react";
40
+
41
+ export default {
42
+ apiKey: process.env.ICONIA_API_KEY,
43
+ collections: ["my-icons", "team-brand"],
44
+ } satisfies IconiaConfig;
45
+ ```
46
+
47
+ Set `ICONIA_API_KEY` to an API key generated in your [iconia.io dashboard](https://iconia.io/settings/api-keys).
48
+
49
+ ---
50
+
51
+ ## CLI commands
52
+
53
+ ### `iconia init`
54
+
55
+ Create a starter `iconia.config.ts` in the current directory.
56
+
57
+ ```bash
58
+ npx @iconia/react init
59
+ ```
60
+
61
+ ---
62
+
63
+ ### `iconia add <slug>`
64
+
65
+ Add a collection to your project: validates it exists on the server, updates `iconia.config.ts`, downloads icons and generates React components.
66
+
67
+ ```bash
68
+ npx @iconia/react add my-icons
69
+ npx @iconia/react add team-brand
70
+ ```
71
+
72
+ ---
73
+
74
+ ### `iconia remove <slug>`
75
+
76
+ Remove a collection: deletes generated files and removes the slug from `iconia.config.ts`.
77
+
78
+ ```bash
79
+ npx @iconia/react remove my-icons
80
+ ```
81
+
82
+ ---
83
+
84
+ ### `iconia pull`
85
+
86
+ Full re-download and regeneration of all (or one) collection. Replaces existing generated files.
87
+
88
+ ```bash
89
+ npx @iconia/react pull # all collections from config
90
+ npx @iconia/react pull --collection my-icons # one collection only
91
+ ```
92
+
93
+ ---
94
+
95
+ ### `iconia sync`
96
+
97
+ Incremental update: compares server fingerprints with the local `.iconia-lock.json` and only regenerates collections that have changes (new icons, updated icons, deleted icons).
98
+
99
+ ```bash
100
+ npx @iconia/react sync # all collections
101
+ npx @iconia/react sync --collection my-icons
102
+ ```
103
+
104
+ Output shows a diff per collection:
105
+
106
+ ```
107
+ my-icons: +3 added (arrow-right, chevron-down, x)
108
+ team-brand: ~1 updated (logo)
109
+ old-set: up to date
110
+ ```
111
+
112
+ ---
113
+
114
+ ### `iconia upload <path>`
115
+
116
+ Upload a single SVG file or an entire folder of SVGs to a collection on iconia.io.
117
+
118
+ ```bash
119
+ npx @iconia/react upload ./icons/arrow.svg --collection my-icons
120
+ npx @iconia/react upload ./icons/ --collection my-icons
121
+ npx @iconia/react upload ./icons/ --collection my-icons --tags ui,navigation
122
+ ```
123
+
124
+ Options:
125
+
126
+ - `-c, --collection <slug>` — target collection **(required)**
127
+ - `--tags <tags>` — comma-separated tags applied to all uploaded icons
128
+
129
+ ---
130
+
131
+ ## Using icons in your project
132
+
133
+ After `pull` or `sync`, import icons directly from the collection:
134
+
135
+ ```tsx
136
+ import { ArrowRight, Home, Settings } from "@iconia/react/my-icons";
137
+
138
+ export function App() {
139
+ return (
140
+ <div>
141
+ <ArrowRight className="size-5" />
142
+ <Home strokeWidth={1.5} />
143
+ <Settings color="gray" />
144
+ </div>
145
+ );
146
+ }
147
+ ```
148
+
149
+ All icons accept standard `SVGProps<SVGSVGElement>` and forward refs.
150
+
151
+ ---
152
+
153
+ ## Lockfile
154
+
155
+ `iconia sync` reads and writes `.iconia-lock.json` in your project root. It stores the fingerprint of every downloaded icon so that `sync` can detect changes without diffing SVG content.
156
+
157
+ Commit this file to version control so your team shares the same sync baseline.
158
+
159
+ ---
160
+
161
+ ## API key
162
+
163
+ Generate an API key at **iconia.io → Settings → API Keys**. The key authenticates CLI requests and scopes them to your collections.
164
+
165
+ ```bash
166
+ export ICONIA_API_KEY=ik_...
167
+ ```
168
+
169
+ Or add it to `.env` and load it via your preferred env tooling (`dotenv`, Vite, Next.js, etc.).
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import{Command as ho}from"commander";import{Command as Ro}from"commander";import N from"fs";import jo from"path";import v from"picocolors";var Uo=`import type { IconiaConfig } from '@iconia/react';
3
+
4
+ const config: IconiaConfig = {
5
+ apiKey: process.env.ICONIA_API_KEY ?? '',
6
+ collections: [],
7
+ };
8
+
9
+ export default config;
10
+ `,X=new Ro("init").description("Create an iconia.config.ts file in the current directory").action(()=>{let o=jo.resolve(process.cwd(),"iconia.config.ts");if(N.existsSync(o)){console.log(v.yellow("iconia.config.ts already exists. Skipping."));return}N.writeFileSync(o,Uo),console.log(v.green("✓ Created iconia.config.ts")),console.log(`
11
+ Next steps:`),console.log(` 1. Set ${v.cyan("ICONIA_API_KEY")} in your environment`),console.log(` 2. Edit ${v.cyan("iconia.config.ts")} to add your collections`),console.log(` 3. Run ${v.cyan("npx iconia pull")} to fetch icons`),console.log(`
12
+ Import icons: ${v.cyan("import { MyIcon } from '@iconia/react/my-collection'")}`)});import{Command as Vo}from"commander";import V from"picocolors";import vo from"ora";import{z as Y}from"zod";import D from"path";var uo=Y.object({apiKey:Y.string().min(1,"apiKey is required"),collections:Y.array(Y.string()).default([])}),Lo="https://api.iconia.io";async function u(){let o=D.resolve(process.cwd(),"iconia.config.ts"),r=D.resolve(process.cwd(),"iconia.config.js"),i;try{let f=await import(o);i=f.default??f}catch{try{let f=await import(r);i=f.default??f}catch{throw Error("Could not find iconia.config.ts or iconia.config.js\nRun `npx @iconia/react init` to create one.")}}let n=uo.safeParse(i);if(!n.success){let f=n.error.issues.map((a)=>` - ${a.path.join(".")}: ${a.message}`).join(`
13
+ `);throw Error(`Invalid iconia config:
14
+ ${f}`)}let c=i.__internal?.endpoint??Lo;return{...n.data,apiUrl:c}}function Z(o){return{Authorization:`ApiKey ${o.apiKey}`,"Content-Type":"application/json"}}async function G(o,r=3){for(let i=0;i<=r;i++){let n=await o();if(n.status!==429||i===r)return n;let t=parseInt(n.headers.get("Retry-After")??"60",10);process.stderr.write(`
15
+ ⏳ Rate limited — waiting ${t}s before retry ${i+1}/${r}...
16
+ `),await new Promise((c)=>{let f=()=>{clearTimeout(a),process.exit(130)},a=setTimeout(()=>{process.removeListener("SIGINT",f),c()},t*1000);process.once("SIGINT",f)})}return o()}async function l(o){let r=await G(()=>fetch(new URL("/v1/collections",o.apiUrl).toString(),{headers:Z(o)}));if(!r.ok){let n={};try{n=await r.json()}catch{}throw Error(`API error ${r.status}: ${n.error??r.statusText}`)}return(await r.json()).collections}async function P(o,r){let i=new URL("/v1/collections/icons",o.apiUrl);i.searchParams.set("collections",r.join(","));let n=await G(()=>fetch(i.toString(),{headers:Z(o)}));if(!n.ok){let c={};try{c=await n.json()}catch{}throw Error(`API error ${n.status}: ${c.error??n.statusText}`)}return(await n.json()).icons}async function x(o,r){let i=await G(()=>fetch(new URL("/v1/icons",o.apiUrl).toString(),{method:"POST",headers:Z(o),body:JSON.stringify(r)}));if(!i.ok){let n={};try{n=await i.json()}catch{}throw Error(n.error??i.statusText)}return!0}import _ from"fs";import O from"path";import{fileURLToPath as Eo}from"url";import po from"picocolors";import{optimize as _o}from"svgo";function Co(o){return _o(o,{plugins:["removeDoctype","removeXMLProcInst","removeComments","removeMetadata","removeTitle","removeDesc"]}).data.replace(/<svg([^>]*)>/i,(i,n)=>`<svg${n.replace(/\s+(width|height)=['"][^'"]*['"]/gi,"")}>`)}function g(o){let r={},i=/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g,n;while((n=i.exec(o))!==null){let t=n[1].replace(/^xlink:/,"").replace(/-([a-z])/g,(c,f)=>f.toUpperCase());r[t]=n[2]??n[3]??""}return r}function oo(o){let r=[],i=0;while(i<o.length){let n=o.indexOf("<",i);if(n===-1)break;let t=o[n+1];if(t==="/"||t==="!"||t==="?"){let I=o.indexOf(">",n);i=I===-1?o.length:I+1;continue}let c=n+1,f=!1,a="";while(c<o.length){let I=o[c];if(f){if(I===a)f=!1}else if(I==='"'||I==="'")f=!0,a=I;else if(I===">")break;c++}if(c>=o.length)break;let $=o.slice(n+1,c),m=$.trimEnd().endsWith("/"),e=m?$.slice(0,$.lastIndexOf("/")).trim():$.trim(),y=e.search(/\s/),w=y===-1?e:e.slice(0,y);if(!w){i=c+1;continue}let j=y===-1?"":e.slice(y+1),p=g(j);if(i=c+1,m)r.push([w,p]);else{let I=`<${w}`,K=`</${w}>`,F=1,R=i;while(F>0&&R<o.length){let U=o.indexOf(I,R),s=o.indexOf(K,R);if(s===-1)break;if(U!==-1&&U<s)F++,R=U+I.length;else if(F--,F===0){let Io=o.slice(i,s),k=oo(Io),Fo=k.length>0?[w,p,k]:[w,p];r.push(Fo),i=s+K.length}else R=s+K.length}if(F>0)r.push([w,p])}}return r}function ro(o){let r=Co(o),i=r.match(/<svg([^>]*)>/i),n=g(i?.[1]??"");delete n.xmlns,delete n.xmlnsXlink;let{viewBox:t}=n,c=t?{viewBox:t}:{},a=r.match(/<svg[^>]*>([\s\S]*)<\/svg>/i)?.[1]?.trim()??"";return{iconNode:oo(a),svgAttrs:c}}function b(o){return o.replace(/[-_\s]+(.)/g,(r,i)=>i.toUpperCase()).replace(/^(.)/,(r,i)=>i.toUpperCase())}function io(o){if(o.length===0)return"";let r=["import { forwardRef, createElement } from 'react';","","const _r = (n) => n.map(([t, a, c], i) => createElement(t, { key: i, ...a }, ...(c ? _r(c) : [])));",""];for(let{name:i,iconNode:n,svgAttrs:t}of o){let c=b(i),f={viewBox:"0 0 24 24",...t},a=JSON.stringify(n),$=JSON.stringify(f);r.push(`export const ${c} = /*#__PURE__*/forwardRef(({ children, ...props }, ref) =>`,` createElement('svg', { ref, xmlns: 'http://www.w3.org/2000/svg', ...${$}, ...props },`,` ..._r(${a}),`," children"," )",");",`${c}.displayName = '${c}';`,"")}return r.join(`
17
+ `)}function no(o){let r=["import type { ForwardRefExoticComponent, SVGProps, RefAttributes } from 'react';","","type IconComponent = ForwardRefExoticComponent<SVGProps<SVGSVGElement> & RefAttributes<SVGSVGElement>>;",""];for(let i of o)r.push(`export declare const ${b(i)}: IconComponent;`);return r.push(""),r.join(`
18
+ `)}function M(){return O.resolve(O.dirname(Eo(import.meta.url)),"..")}function z(o,r){let i=[];for(let t of r)try{let{iconNode:c,svgAttrs:f}=ro(t.svgContent);i.push({name:t.name,iconNode:c,svgAttrs:f})}catch(c){console.warn(po.yellow(` ⚠ Skipped ${t.name}: ${c.message}`))}if(i.length===0)return 0;let n=M();return _.writeFileSync(O.join(n,`${o}.js`),io(i),"utf-8"),_.writeFileSync(O.join(n,`${o}.d.ts`),no(i.map((t)=>t.name)),"utf-8"),i.length}function H(){let o=O.join(M(),"..","package.json");try{let r=JSON.parse(_.readFileSync(o,"utf-8")),i=r.exports??{};if(i["./*"]?.import?.startsWith("./dist/"))return;r.exports={".":i["."]??{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/index.cjs"},"./*":{import:"./dist/*.js",types:"./dist/*.d.ts"}},_.writeFileSync(o,JSON.stringify(r,null,2)+`
19
+ `,"utf-8")}catch{}}function to(o){let r=M(),i=O.join(r,`${o}.js`),n=O.join(r,`${o}.d.ts`);if(_.existsSync(i))_.unlinkSync(i);if(_.existsSync(n))_.unlinkSync(n)}import co from"fs";import Ko from"path";var Oo=".iconia-lock.json";function fo(){return Ko.resolve(process.cwd(),Oo)}function C(){try{let o=co.readFileSync(fo(),"utf-8");return JSON.parse(o)}catch{return{version:1,collections:{}}}}function E(o){co.writeFileSync(fo(),JSON.stringify(o,null,2),"utf-8")}function J(o,r,i){return{...o,collections:{...o.collections,[r]:{icons:Object.fromEntries(i.map((n)=>[n.slug,n.fingerprint]))}}}}function ao(o,r){let{[r]:i,...n}=o.collections;return{...o,collections:n}}var mo=new Vo("pull").description("Fetch icons and regenerate all collection files (replaces existing)").option("-c, --collection <slug>","Pull only this collection").action(async(o)=>{let r=vo("Loading config...").start(),i;try{i=await u()}catch(m){r.fail(V.red(m.message)),process.exit(1)}let n=o.collection?[o.collection]:i.collections;if(n.length===0){r.warn(V.yellow("No collections in config. Add one with `iconia add <slug>`."));return}if(o.collection&&!i.collections.includes(o.collection))r.fail(V.red(`Collection '${o.collection}' is not in your config.`)),process.exit(1);r.text=`Fetching icons for ${n.join(", ")}...`;let t;try{t=await P(i,n)}catch(m){r.fail(V.red(`Failed to fetch icons: ${m.message}`)),process.exit(1)}if(t.length===0){r.warn(V.yellow("No icons found."));return}r.text=`Generating ${t.length} icon${t.length!==1?"s":""}...`;let c=new Map;for(let m of t){let e=c.get(m.collectionSlug)??[];e.push(m),c.set(m.collectionSlug,e)}let f=C(),a=0,$=[];for(let[m,e]of c){let y=z(m,e);if(y===0)continue;a+=y,$.push(m),f=J(f,m,e.map((w)=>({slug:w.slug,fingerprint:w.fingerprint})))}if(E(f),H(),r.succeed(V.green(`Generated ${a} icon${a!==1?"s":""} across ${$.length} collection${$.length!==1?"s":""}`)),$.length>0){let m=$[0]??"",e=b(c.get(m)?.[0]?.name??"MyIcon");console.log(`
20
+ Import icons:
21
+ ${V.cyan(`import { ${e} } from '@iconia/react/${m}'`)}`)}});import{Command as Po}from"commander";import L from"picocolors";import bo from"ora";import A from"fs";import yo from"path";function T(){let o=yo.resolve(process.cwd(),"iconia.config.ts"),r=yo.resolve(process.cwd(),"iconia.config.js");if(A.existsSync(o))return o;if(A.existsSync(r))return r;return null}function h(o){let n=A.readFileSync(o,"utf-8").match(/collections:\s*\[([\s\S]*?)\]/)?.[1];if(!n)return null;let t=[],c=/['"]([^'"]+)['"]/g,f;while((f=c.exec(n))!==null){let a=f[1];if(a)t.push(a)}return t}function Q(o,r){let i=A.readFileSync(o,"utf-8"),n=r.length===0?"[]":`[
22
+ ${r.map((c)=>` '${c}'`).join(`,
23
+ `)},
24
+ ]`,t=i.replace(/collections:\s*\[[\s\S]*?\]/,`collections: ${n}`);if(t===i)return!1;return A.writeFileSync(o,t,"utf-8"),!0}var eo=new Po("add").description("Add a collection to your project (updates config and downloads icons)").argument("<slug>","Collection slug").action(async(o)=>{let r=bo("Loading config...").start(),i;try{i=await u()}catch(a){r.fail(L.red(a.message)),process.exit(1)}if(i.collections.includes(o))r.info(L.yellow(`Collection '${o}' is already in your config. Running pull...`));else{r.text="Verifying collection...";let a;try{a=await l(i)}catch(j){r.fail(L.red(`Failed to fetch collections: ${j.message}`)),process.exit(1)}if(!a.find((j)=>j.slug===o))r.fail(L.red(`Collection '${o}' not found. Available: ${a.map((j)=>j.slug).join(", ")||"none"}`)),process.exit(1);let m=T();if(!m)r.fail(L.red("Config file not found. Run `npx @iconia/react init` first.")),process.exit(1);let y=[...h(m)??i.collections,o];if(!Q(m,y))r.warn(L.yellow(`Could not update config automatically. Add '${o}' to collections in iconia.config.ts manually.`));else r.text=`Added '${o}' to config. Fetching icons...`}r.text=`Fetching icons for '${o}'...`;let n;try{n=await P(i,[o])}catch(a){r.fail(L.red(`Failed to fetch icons: ${a.message}`)),process.exit(1)}if(n.length===0){r.warn(L.yellow(`No icons in collection '${o}'.`));return}r.text=`Generating ${n.length} icon${n.length!==1?"s":""}...`;let t=z(o,n),c=C();c=J(c,o,n.map((a)=>({slug:a.slug,fingerprint:a.fingerprint}))),E(c),r.succeed(L.green(`Added '${o}' — ${t} icon${t!==1?"s":""} generated`));let f=b(n[0]?.name??"Icon");console.log(`
25
+ Import icons:
26
+ ${L.cyan(`import { ${f} } from '@iconia/react/${o}'`)}`)});import{Command as zo}from"commander";import W from"picocolors";var wo=new zo("remove").description("Remove a collection from your project (updates config and deletes generated files)").argument("<slug>","Collection slug").action(async(o)=>{let r;try{r=await u()}catch(n){console.error(W.red(n.message)),process.exit(1)}if(!r.collections.includes(o))console.warn(W.yellow(`Collection '${o}' is not in your config.`));else{let n=T();if(n){let c=(h(n)??r.collections).filter((a)=>a!==o);if(!Q(n,c))console.warn(W.yellow(`Could not update config automatically. Remove '${o}' from collections in iconia.config.ts manually.`))}}to(o);let i=C();i=ao(i,o),E(i),console.log(W.green(`✓ Removed collection '${o}'`))});import{Command as Jo}from"commander";import d from"picocolors";import So from"ora";var $o=new Jo("sync").description("Sync icons: add new, update changed, remove deleted — without full re-fetch").option("-c, --collection <slug>","Sync only this collection").action(async(o)=>{let r=So("Loading config...").start(),i;try{i=await u()}catch(y){r.fail(d.red(y.message)),process.exit(1)}let n=o.collection?[o.collection]:i.collections;if(n.length===0){r.warn(d.yellow("No collections in config. Add one with `iconia add <slug>`."));return}if(o.collection&&!i.collections.includes(o.collection))r.fail(d.red(`Collection '${o.collection}' is not in your config.`)),process.exit(1);r.text=`Fetching icons for ${n.join(", ")}...`;let t;try{t=await P(i,n)}catch(y){r.fail(d.red(`Failed to fetch icons: ${y.message}`)),process.exit(1)}let c=new Map;for(let y of t){let w=c.get(y.collectionSlug)??[];w.push(y),c.set(y.collectionSlug,w)}let f=C(),a=0,$=0,m=0,e=0;for(let y of n){let w=c.get(y)??[],j=f.collections[y]?.icons??{},p=new Map(w.map((s)=>[s.slug,s])),I=new Set(Object.keys(j)),K=new Set(p.keys()),F=[...K].filter((s)=>!I.has(s)),R=[...I].filter((s)=>!K.has(s)),U=[...K].filter((s)=>I.has(s)&&j[s]!==p.get(s).fingerprint);if(F.length===0&&R.length===0&&U.length===0){console.log(d.dim(` ${y}: up to date`));continue}if(F.length>0)console.log(d.green(` ${y}: +${F.length} added`)+d.dim(` (${F.slice(0,5).join(", ")}${F.length>5?"…":""})`));if(U.length>0)console.log(d.blue(` ${y}: ~${U.length} updated`)+d.dim(` (${U.slice(0,5).join(", ")}${U.length>5?"…":""})`));if(R.length>0)console.log(d.red(` ${y}: -${R.length} removed`)+d.dim(` (${R.slice(0,5).join(", ")}${R.length>5?"…":""})`));if(w.length>0)z(y,w);f=J(f,y,w.map((s)=>({slug:s.slug,fingerprint:s.fingerprint}))),a+=F.length,$+=U.length,m+=R.length,e++}if(E(f),e>0)H();if(e===0)r.succeed(d.green("Everything is up to date."));else r.succeed(d.green(`Sync complete: ${a} added, ${$} updated, ${m} removed across ${e} collection${e!==1?"s":""}`))});import{Command as qo}from"commander";import B from"fs";import q from"path";import S from"picocolors";import Ao from"ora";function Yo(o){return q.basename(o,q.extname(o)).toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function Ho(o){return o.split("-").map((r)=>r.charAt(0).toUpperCase()+r.slice(1)).join(" ")}function To(o){let r=B.statSync(o);if(r.isFile()){if(!o.endsWith(".svg"))throw Error(`File '${o}' is not an SVG.`);return[o]}if(r.isDirectory())return B.readdirSync(o).filter((i)=>i.endsWith(".svg")).map((i)=>q.join(o,i));throw Error(`'${o}' is not a file or directory.`)}var so=new qo("upload").description("Upload SVG file(s) to an Iconia collection").argument("<path>","SVG file or directory of SVGs").requiredOption("-c, --collection <slug>","Target collection slug").option("--tags <tags>","Comma-separated tags to apply to all uploaded icons").action(async(o,r)=>{let i=Ao("Loading config...").start(),n;try{n=await u()}catch(m){i.fail(S.red(m.message)),process.exit(1)}let t;try{t=To(q.resolve(process.cwd(),o))}catch(m){i.fail(S.red(m.message)),process.exit(1)}if(t.length===0){i.warn(S.yellow("No SVG files found."));return}let c=r.tags?r.tags.split(",").map((m)=>m.trim()).filter(Boolean):[];i.text=`Uploading ${t.length} file${t.length!==1?"s":""} to '${r.collection}'...`;let f=0,a=0,$=[];for(let m of t){let e=Yo(m);if(!e){$.push(`${q.basename(m)}: could not derive a valid slug`),a++;continue}let y=B.readFileSync(m,"utf-8");try{await x(n,{collectionSlug:r.collection,name:Ho(e),slug:e,svgContent:y,tags:c}),f++,i.text=`Uploading... (${f}/${t.length})`}catch(w){$.push(`${q.basename(m)}: ${w.message}`),a++}}if(a===0)i.succeed(S.green(`Uploaded ${f} icon${f!==1?"s":""} to '${r.collection}'`));else{i.warn(S.yellow(`Uploaded ${f}, failed ${a}`));for(let m of $)console.log(S.dim(` ✗ ${m}`))}});process.on("SIGINT",()=>process.exit(130));var Qo=new ho("iconia").version("0.1.0").description("CLI for fetching and generating React icon components from Iconia").addCommand(X).addCommand(eo).addCommand(wo).addCommand(mo).addCommand($o).addCommand(so);Qo.parse(process.argv);
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ var{defineProperty:m,getOwnPropertyNames:a,getOwnPropertyDescriptor:d}=Object,y=Object.prototype.hasOwnProperty;function G(e){return this[e]}var S=(e)=>{var o=(c??=new WeakMap).get(e),t;if(o)return o;if(o=m({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function"){for(var n of a(e))if(!y.call(o,n))m(o,n,{get:G.bind(e,n),enumerable:!(t=d(e,n))||t.enumerable})}return c.set(e,o),o},c;var V=(e)=>e;function I(e,o){this[e]=V.bind(null,o)}var g=(e,o)=>{for(var t in o)m(e,t,{get:o[t],enumerable:!0,configurable:!0,set:I.bind(o,t)})};var E={};g(E,{createIconiaIcon:()=>l});module.exports=S(E);var r=require("react");function i(e){return e.map(([o,t,n],p)=>r.createElement(o,{key:p,...t},...n?i(n):[]))}function l(e,o,t={}){let n=r.forwardRef(({children:p,...s},f)=>r.createElement("svg",{ref:f,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",...t,...s},...i(o),p));return n.displayName=e,n}
@@ -0,0 +1,22 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ import { ForwardRefExoticComponent, RefAttributes, SVGProps } from 'react';
4
+ import { z } from 'zod';
5
+
6
+ export type IconNodeElement = [
7
+ tagName: string,
8
+ attrs: Record<string, string>,
9
+ children?: IconNodeElement[]
10
+ ];
11
+ export type IconNode = IconNodeElement[];
12
+ declare const configSchema: z.ZodObject<{
13
+ apiKey: z.ZodString;
14
+ collections: z.ZodDefault<z.ZodArray<z.ZodString>>;
15
+ }, z.core.$strip>;
16
+ export type IconiaConfig = z.infer<typeof configSchema> & {
17
+ apiUrl?: string;
18
+ };
19
+ export type IconComponent = ForwardRefExoticComponent<SVGProps<SVGSVGElement> & RefAttributes<SVGSVGElement>>;
20
+ export declare function createIconiaIcon(displayName: string, iconNode: IconNode, svgAttrs?: Record<string, string>): IconComponent;
21
+
22
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{forwardRef as s,createElement as p}from"react";function m(o){return o.map(([t,n,e],r)=>p(t,{key:r,...n},...e?m(e):[]))}function a(o,t,n={}){let e=s(({children:r,...c},i)=>p("svg",{ref:i,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",...n,...c},...m(t),r));return e.displayName=o,e}export{a as createIconiaIcon};
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@iconia/react",
3
+ "version": "0.1.0-dev.00e4942",
4
+ "description": "Fetch and generate React icon components from your Iconia collections",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./*": {
16
+ "import": "./dist/*.js",
17
+ "types": "./dist/*.d.ts"
18
+ }
19
+ },
20
+ "peerDependencies": {
21
+ "react": ">=18"
22
+ },
23
+ "bin": {
24
+ "iconia": "./dist/cli/index.js"
25
+ },
26
+ "scripts": {
27
+ "build": "bun build.ts",
28
+ "typecheck": "tsc --noEmit"
29
+ },
30
+ "dependencies": {
31
+ "commander": "14.0.3",
32
+ "ora": "9.3.0",
33
+ "picocolors": "1.1.1",
34
+ "prettier": "3.8.1",
35
+ "svgo": "4.0.1",
36
+ "zod": "4.3.6"
37
+ },
38
+ "devDependencies": {
39
+ "@types/bun": "1.3.11",
40
+ "@types/node": "25.5.2",
41
+ "@types/react": "19.2.14",
42
+ "bun-plugin-dts": "0.4.0",
43
+ "typescript": "6.0.2"
44
+ },
45
+ "files": [
46
+ "dist"
47
+ ],
48
+ "keywords": [
49
+ "react",
50
+ "nodejs",
51
+ "svg",
52
+ "cli",
53
+ "typescript",
54
+ "icons",
55
+ "bun"
56
+ ],
57
+ "license": "MIT",
58
+ "author": "Wyesoftware",
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/iconia-io/iconia-react.git"
62
+ },
63
+ "bugs": {
64
+ "url": "https://github.com/iconia-io/iconia-react/issues"
65
+ },
66
+ "homepage": "https://github.com/iconia-io/iconia-react#readme"
67
+ }