@teacss/preset-icons 0.4.6 → 0.5.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.
- package/README.md +25 -99
- package/dist/browser.js +1 -1
- package/dist/core-BTaY9Bti.js +1 -0
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/dist/merge.d.ts +3 -4
- package/package.json +6 -6
- package/dist/core-DvPxBdOd.js +0 -1
package/README.md
CHANGED
|
@@ -1,31 +1,6 @@
|
|
|
1
1
|
# @teacss/preset-icons
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
`@teacss/preset-icons` is the official opt-in icon preset for application
|
|
8
|
-
authors who want icons compiled from `icon:<collection>-<icon-name>` classes.
|
|
9
|
-
It bundles the Lucide (UI icons), Carbon (IBM's design-system icons), Flagpack
|
|
10
|
-
(country flags), and Cryptocurrency Color (coins and tokens, as `crypto`)
|
|
11
|
-
datasets, emits icons as CSS masks or backgrounds, and exposes
|
|
12
|
-
icon-specific merge metadata for custom runtime mergers. The generated icons require no client-side runtime
|
|
13
|
-
script.
|
|
14
|
-
|
|
15
|
-
Icon data comes from the `@iconify-json/lucide`, `@iconify-json/flagpack`, and
|
|
16
|
-
`@iconify-json/cryptocurrency-color`, and `@iconify-json/carbon` packages this preset depends on, so it installs with the preset and resolves as
|
|
17
|
-
an ordinary module import. Each dataset is imported only when one of its icons
|
|
18
|
-
is used, so a build that never writes `icon:flagpack-*` does not load the flag
|
|
19
|
-
data.
|
|
20
|
-
**Generation never reaches the network**: there is no CDN fetch, no registry
|
|
21
|
-
install, and no filesystem probing for collection packages. A build works
|
|
22
|
-
fully offline.
|
|
23
|
-
|
|
24
|
-
This package owns only the icon vocabulary and its loading behavior:
|
|
25
|
-
`@teacss/core` owns parsing and CSS generation,
|
|
26
|
-
`@teacss/preset-standard` supplies general utilities, themes, conditions, and
|
|
27
|
-
preflights, and `@teacss/preset-articles` supplies long-form content styling.
|
|
28
|
-
None of those other preset vocabularies are bundled here.
|
|
3
|
+
Pure-CSS icon utilities with no client-side runtime.
|
|
29
4
|
|
|
30
5
|
## Usage
|
|
31
6
|
|
|
@@ -35,44 +10,23 @@ None of those other preset vocabularies are bundled here.
|
|
|
35
10
|
@teacss;
|
|
36
11
|
```
|
|
37
12
|
|
|
38
|
-
The `icons` short name works with either the application-facing `teacss`
|
|
39
|
-
package or a direct `@teacss/preset-icons` installation. Nothing else to
|
|
40
|
-
install or configure — the bundled data resolves immediately.
|
|
41
|
-
|
|
42
13
|
```html
|
|
43
14
|
<span class="icon:lucide-sun"></span>
|
|
44
|
-
<span class="icon:
|
|
15
|
+
<span class="icon:carbon-sun"></span>
|
|
45
16
|
<span class="icon:flagpack-nl"></span>
|
|
46
17
|
<span class="icon:crypto-btc"></span>
|
|
47
|
-
<span class="icon:carbon-sun"></span>
|
|
48
18
|
```
|
|
49
19
|
|
|
50
|
-
The
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
`<icon-name>` is the collection's own kebab-case id. Its camelCase spelling
|
|
61
|
-
resolves to the same icon for every bundled id — `icon:carbon-db2Database`,
|
|
62
|
-
`icon:lucide-barChart3`, `icon:lucide-arrowDown01` — and both spellings are
|
|
63
|
-
case-insensitive. Nothing else resolves: a partial or arbitrary re-hyphenation
|
|
64
|
-
such as `icon:lucide-bar-chart3` or `icon:carbon-add--alt` emits no CSS. The
|
|
65
|
-
kebab id stays canonical.
|
|
66
|
-
|
|
67
|
-
`mode: "auto"` chooses a mask for `currentColor` icons and a background image
|
|
68
|
-
for multicolor icons. Lucide and Carbon use `currentColor`, so their icons
|
|
69
|
-
resolve to masks and take their color from the surrounding text; Flagpack flags and `crypto`
|
|
70
|
-
coins carry their own colors, so they resolve to
|
|
71
|
-
background images and ignore text color.
|
|
72
|
-
Override one icon with `?mask`, `?bg`, or `?auto`, for example
|
|
73
|
-
`icon:lucide-sun?bg`.
|
|
74
|
-
|
|
75
|
-
CSS integrations also resolve the raw qualified name through `icon(...)`:
|
|
20
|
+
The grammar is `icon:<collection>-<icon-name>`. The preset bundles Lucide,
|
|
21
|
+
Carbon, Flagpack, and Cryptocurrency Color (named `crypto`) and works offline.
|
|
22
|
+
Datasets load only when a matching icon is used.
|
|
23
|
+
|
|
24
|
+
Names are case-insensitive and accept each collection's canonical kebab-case or
|
|
25
|
+
camelCase form. Arbitrary re-hyphenation emits no CSS. Missing icons do not fall
|
|
26
|
+
back to a shorter collection name.
|
|
27
|
+
|
|
28
|
+
`mode: "auto"` uses masks for `currentColor` icons and background images for
|
|
29
|
+
multicolor icons. Override one icon with `?mask`, `?bg`, or `?auto`.
|
|
76
30
|
|
|
77
31
|
```css
|
|
78
32
|
.logo {
|
|
@@ -80,62 +34,34 @@ CSS integrations also resolve the raw qualified name through `icon(...)`:
|
|
|
80
34
|
}
|
|
81
35
|
```
|
|
82
36
|
|
|
83
|
-
|
|
37
|
+
## Custom collections
|
|
84
38
|
|
|
85
|
-
|
|
86
|
-
data. Add another one
|
|
87
|
-
by handing the preset data it can read locally through `collections` — an
|
|
88
|
-
inline map, a loader function, or a helper such as `FileSystemIconLoader` from
|
|
89
|
-
`@iconify/utils/lib/loader/fs`:
|
|
39
|
+
Pass local data or a loader through `collections`:
|
|
90
40
|
|
|
91
41
|
```ts
|
|
92
42
|
import { icons as tabler } from "@iconify-json/tabler";
|
|
43
|
+
import { presetIcons } from "@teacss/preset-icons";
|
|
93
44
|
|
|
94
45
|
presetIcons({ collections: { tabler: () => tabler } });
|
|
95
46
|
```
|
|
96
47
|
|
|
97
|
-
|
|
98
|
-
nothing. Set `warn: true` to report
|
|
48
|
+
Generation never downloads or installs collections. An unknown collection,
|
|
49
|
+
missing icon, or failed loader emits nothing. Set `warn: true` to report it.
|
|
50
|
+
Programmatic integrations can call `preset.api.resolveIcon(name)`.
|
|
99
51
|
|
|
100
|
-
|
|
101
|
-
nothing, every other icon still generates, and the build does not abort. `warn`
|
|
102
|
-
is the only thing that decides whether it is reported, and the reported line
|
|
103
|
-
carries the thrown message.
|
|
52
|
+
## Runtime merging
|
|
104
53
|
|
|
105
|
-
|
|
106
|
-
resolves a qualified name against the bundled data and the configured
|
|
107
|
-
`collections`.
|
|
108
|
-
|
|
109
|
-
For runtime class merging, the `/merge` entry exports both a lazy icon-only
|
|
110
|
-
`cn` and the self-contained plugin:
|
|
111
|
-
|
|
112
|
-
```sh
|
|
113
|
-
bun add @teacss/classes
|
|
114
|
-
```
|
|
54
|
+
The `/merge` entry exports an icon-only `cn` and `pluginIcon`:
|
|
115
55
|
|
|
116
56
|
```ts
|
|
117
57
|
import { createMerger } from "@teacss/classes";
|
|
118
|
-
import {
|
|
119
|
-
cn as iconCn,
|
|
120
|
-
pluginIcon,
|
|
121
|
-
} from "@teacss/preset-icons/merge";
|
|
58
|
+
import { cn as iconCn, pluginIcon } from "@teacss/preset-icons/merge";
|
|
122
59
|
|
|
123
60
|
const cn = createMerger({ plugins: [pluginIcon] });
|
|
124
|
-
|
|
125
|
-
iconCn("icon:lucide-sun", "icon:not-real-name"); // "icon:not-real-name"
|
|
126
61
|
```
|
|
127
62
|
|
|
128
|
-
The application `cn` from `teacss` already
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
only the canonical lexical grammar, not whether a collection or icon exists.
|
|
132
|
-
Canonical nonexistent resources merge normally; non-canonical `icon:*`
|
|
133
|
-
declarations are opaque, so different raw strings survive and exact duplicates
|
|
134
|
-
keep their last position. The bare keyword `icon` has no canonical value and
|
|
135
|
-
is opaque as well.
|
|
136
|
-
|
|
137
|
-
## Status
|
|
63
|
+
The application `cn` from `teacss` already combines icon and Standard merge
|
|
64
|
+
metadata. Merging validates only the canonical token shape, not whether the icon
|
|
65
|
+
exists.
|
|
138
66
|
|
|
139
|
-
Pre-1.0.
|
|
140
|
-
`@iconify-json/flagpack`, `@iconify-json/cryptocurrency-color`, and
|
|
141
|
-
`@iconify-json/carbon` data.
|
|
67
|
+
Pre-1.0. Output follows the bundled Iconify datasets.
|
package/dist/browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,r as t,t as n}from"./core-
|
|
1
|
+
import{n as e,r as t,t as n}from"./core-BTaY9Bti.js";import r from"./index.js";export{t as BUNDLED_COLLECTIONS,r as default,n as icons,e as presetIcons};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./syntax-DmIPw0tH.js";import{loadIcon as t}from"@iconify/utils";import{encodeSvgForCss as n}from"@iconify/utils/lib/svg/encode-svg-for-css";import{definePreset as r,getEnvFlags as i,warnOnce as a}from"@teacss/core";import{searchForIcon as o}from"@iconify/utils/lib/loader/modern";const s=new Map([[`carbon`,()=>import(`@iconify-json/carbon`).then(e=>e.icons)],[`crypto`,()=>import(`@iconify-json/cryptocurrency-color`).then(e=>e.icons)],[`flagpack`,()=>import(`@iconify-json/flagpack`).then(e=>e.icons)],[`lucide`,()=>import(`@iconify-json/lucide`).then(e=>e.icons)]]),c=[...s.keys()];function l(e){return e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase())}const u=new WeakMap;function d(e){let t=0;for(let n of e)n===`-`&&t++;return t}function f(e,t,n){let r=d(e)-d(t);if(r!==0)return r<0;let i=Number(n(t))-Number(n(e));return i===0?e<t:i<0}function p(e){let t=u.get(e);if(t)return t;let n=new Map,r=t=>Object.hasOwn(e.icons,t);for(let t of[...Object.keys(e.icons),...Object.keys(e.aliases??{})]){let e=l(t).toLowerCase(),i=n.get(e);(i===void 0||f(t,i,r))&&n.set(e,t)}return u.set(e,n),n}async function m(e,t,n){let r=s.get(e);if(!r)return;let i=await r(),a=t.toLowerCase(),c=p(i).get(a),l=[...new Set([t,a,...c==null?[]:[c]])];return await o(i,e,l,n)}const h=c;async function g(e,n,r){return await m(e,n,r)??await t(e,n,r)}function _(e,t){return`${e}\0${t}`}function v(e,t,n){let r=(t,r)=>{n.set(_(e,t),r instanceof Error?r.message:String(r))};return typeof t==`function`?(async e=>{try{return await t(e)}catch(t){r(e,t);return}}):t&&Object.fromEntries(Object.entries(t).map(([e,t])=>[e,typeof t==`function`?async()=>{try{return await t()}catch(t){r(e,t);return}}:t]))}const y=r((t={})=>{let{scale:r=1,mode:o=`auto`,warn:s=!1,collections:c,extraProperties:l={},customizations:u={},layer:d=`icons`,unit:f,processor:p}=t,m=i(),y=new Map,x={addXmlNs:!0,scale:r,customCollections:c?Object.fromEntries(Object.entries(c).map(([e,t])=>[e,v(e,t,y)])):void 0,warn:void 0,customizations:{...u,additionalProps:{...l},trimCustomSvg:!0,async iconCustomizer(e,t,n){await u.iconCustomizer?.(e,t,n),f&&(n.width||=`${r}${f}`,n.height||=`${r}${f}`)}}},S=new Set([...h,...Object.keys(c||{})]),C=async(e,t)=>{let n=b(e,S);if(!n)return;let r=await g(n.collection,n.name,t?{...x,usedProps:t}:x);if(r)return{...n,svg:r};let i=_(n.collection,n.name),a=y.get(i);if(a!==void 0)throw y.delete(i),Error(a)};return{name:`@teacss/preset-icons`,enforce:`pre`,options:t,layers:{[d]:-30},api:{encodeSvgForCss:n,resolveIcon:e=>C(e)},rules:[[e,async e=>{let[t,r,i=o]=e,c={},l;try{l=await C(r,c)}catch(e){s&&!m.isESLint&&a(`failed to load icon "${t}": ${e instanceof Error?e.message:String(e)}`);return}if(!l){s&&!m.isESLint&&a(`failed to load icon "${t}"`);return}let u,d=`url("data:image/svg+xml;utf8,${n(l.svg)}")`;return i===`auto`&&(i=/currentcolor/i.test(l.svg)?`mask`:`bg`),u=i===`mask`?{"--tea-icon":d,display:`inline-block`,"-webkit-mask":`var(--tea-icon) no-repeat`,mask:`var(--tea-icon) no-repeat`,"-webkit-mask-size":`100% 100%`,"mask-size":`100% 100%`,"background-color":`currentColor`,"background-image":`none`,color:`inherit`,...c}:{display:`inline-block`,"-webkit-mask":`none`,mask:`none`,background:`${d} no-repeat`,"background-size":`100% 100%`,"background-color":`transparent`,...c},await p?.(u,{...l,icon:l.name,mode:i}),u},{layer:d}]]}});function b(e,t){let n=e.split(`-`);if(!(n.length<2||n.some(e=>e.length===0)))for(let e=n.length-1;e>=1;e--){let r=n.slice(0,e).join(`-`);if(t.has(r))return{collection:r,name:n.slice(e).join(`-`)}}}export{y as n,c as r,h as t};
|
package/dist/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,r as t,t as n}from"./core-
|
|
1
|
+
import{n as e,r as t,t as n}from"./core-BTaY9Bti.js";export{t as BUNDLED_COLLECTIONS,n as icons,e as presetIcons};
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,r as t,t as n}from"./core-
|
|
1
|
+
import{n as e,r as t,t as n}from"./core-BTaY9Bti.js";var r=e;export{t as BUNDLED_COLLECTIONS,r as default,n as icons,e as presetIcons};
|
package/dist/merge.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Merger, MergerPlugin } from "@teacss/classes";
|
|
2
2
|
//#region src/merge.d.ts
|
|
3
3
|
/** Merger metadata for the canonical `icon:<collection>-<name>` vocabulary. */
|
|
4
|
-
declare const pluginIcon: MergerPlugin;
|
|
4
|
+
export declare const pluginIcon: MergerPlugin;
|
|
5
5
|
/** Lazily initialized merger bound only to the canonical icon vocabulary. */
|
|
6
|
-
declare const cn: Merger;
|
|
7
|
-
//#endregion
|
|
8
|
-
export { cn, pluginIcon };
|
|
6
|
+
export declare const cn: Merger;
|
|
7
|
+
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teacss/preset-icons",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Pure-CSS Iconify icon utilities for TeaCSS — one class per icon, no runtime.",
|
|
5
5
|
"homepage": "https://css.teasim.com",
|
|
6
6
|
"funding": "https://github.com/sponsors/billgo",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"dev": "tsdown --config-loader unrun --watch"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@iconify-json/carbon": "^1.2.
|
|
31
|
+
"@iconify-json/carbon": "^1.2.26",
|
|
32
32
|
"@iconify-json/cryptocurrency-color": "^1.2.4",
|
|
33
33
|
"@iconify-json/flagpack": "^1.2.8",
|
|
34
|
-
"@iconify-json/lucide": "^1.2.
|
|
34
|
+
"@iconify-json/lucide": "^1.2.129",
|
|
35
35
|
"@iconify/types": "^2.0.0",
|
|
36
|
-
"@iconify/utils": "^3.1.
|
|
37
|
-
"@teacss/classes": "0.
|
|
38
|
-
"@teacss/core": "0.
|
|
36
|
+
"@iconify/utils": "^3.1.5",
|
|
37
|
+
"@teacss/classes": "0.5.0",
|
|
38
|
+
"@teacss/core": "0.5.0"
|
|
39
39
|
},
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=22.12.0"
|
package/dist/core-DvPxBdOd.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./syntax-DmIPw0tH.js";import{loadIcon as t}from"@iconify/utils";import{encodeSvgForCss as n}from"@iconify/utils/lib/svg/encode-svg-for-css";import{definePreset as r,getEnvFlags as i,warnOnce as a}from"@teacss/core";import{searchForIcon as o}from"@iconify/utils/lib/loader/modern";const s=new Map([[`carbon`,()=>import(`@iconify-json/carbon`).then(e=>e.icons)],[`crypto`,()=>import(`@iconify-json/cryptocurrency-color`).then(e=>e.icons)],[`flagpack`,()=>import(`@iconify-json/flagpack`).then(e=>e.icons)],[`lucide`,()=>import(`@iconify-json/lucide`).then(e=>e.icons)]]),c=[...s.keys()];function l(e){return e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase())}const u=new WeakMap;function d(e){let t=0;for(let n of e)n===`-`&&t++;return t}function f(e,t,n){let r=d(e)-d(t);if(r!==0)return r<0;let i=Number(n(t))-Number(n(e));return i===0?e<t:i<0}function p(e){let t=u.get(e);if(t)return t;let n=new Map,r=t=>Object.hasOwn(e.icons,t);for(let t of[...Object.keys(e.icons),...Object.keys(e.aliases??{})]){let e=l(t).toLowerCase(),i=n.get(e);(i===void 0||f(t,i,r))&&n.set(e,t)}return u.set(e,n),n}async function m(e,t,n){let r=s.get(e);if(!r)return;let i=await r(),a=t.toLowerCase(),c=p(i).get(a);return await o(i,e,[...new Set([t,a,...c==null?[]:[c]])],n)}const h=c;async function g(e,n,r){return await m(e,n,r)??await t(e,n,r)}function _(e,t){return`${e}\0${t}`}function v(e,t,n){let r=(t,r)=>{n.set(_(e,t),r instanceof Error?r.message:String(r))};return typeof t==`function`?(async e=>{try{return await t(e)}catch(t){r(e,t);return}}):t&&Object.fromEntries(Object.entries(t).map(([e,t])=>[e,typeof t==`function`?async()=>{try{return await t()}catch(t){r(e,t);return}}:t]))}const y=r((t={})=>{let{scale:r=1,mode:o=`auto`,warn:s=!1,collections:c,extraProperties:l={},customizations:u={},layer:d=`icons`,unit:f,processor:p}=t,m=i(),y=new Map,x={addXmlNs:!0,scale:r,customCollections:c?Object.fromEntries(Object.entries(c).map(([e,t])=>[e,v(e,t,y)])):void 0,warn:void 0,customizations:{...u,additionalProps:{...l},trimCustomSvg:!0,async iconCustomizer(e,t,n){await u.iconCustomizer?.(e,t,n),f&&(n.width||=`${r}${f}`,n.height||=`${r}${f}`)}}},S=new Set([...h,...Object.keys(c||{})]),C=async(e,t)=>{let n=b(e,S);if(!n)return;let r=await g(n.collection,n.name,t?{...x,usedProps:t}:x);if(r)return{...n,svg:r};let i=_(n.collection,n.name),a=y.get(i);if(a!==void 0)throw y.delete(i),Error(a)};return{name:`@teacss/preset-icons`,enforce:`pre`,options:t,layers:{[d]:-30},api:{encodeSvgForCss:n,resolveIcon:e=>C(e)},rules:[[e,async e=>{let[t,r,i=o]=e,c={},l;try{l=await C(r,c)}catch(e){s&&!m.isESLint&&a(`failed to load icon "${t}": ${e instanceof Error?e.message:String(e)}`);return}if(!l){s&&!m.isESLint&&a(`failed to load icon "${t}"`);return}let u,d=`url("data:image/svg+xml;utf8,${n(l.svg)}")`;return i===`auto`&&(i=/currentcolor/i.test(l.svg)?`mask`:`bg`),u=i===`mask`?{"--tea-icon":d,display:`inline-block`,"-webkit-mask":`var(--tea-icon) no-repeat`,mask:`var(--tea-icon) no-repeat`,"-webkit-mask-size":`100% 100%`,"mask-size":`100% 100%`,"background-color":`currentColor`,"background-image":`none`,color:`inherit`,...c}:{display:`inline-block`,"-webkit-mask":`none`,mask:`none`,background:`${d} no-repeat`,"background-size":`100% 100%`,"background-color":`transparent`,...c},await p?.(u,{...l,icon:l.name,mode:i}),u},{layer:d}]]}});function b(e,t){let n=e.split(`-`);if(!(n.length<2||n.some(e=>e.length===0)))for(let e=n.length-1;e>=1;e--){let r=n.slice(0,e).join(`-`);if(t.has(r))return{collection:r,name:n.slice(e).join(`-`)}}}export{y as n,c as r,h as t};
|