@icones/core 0.0.1

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 (57) hide show
  1. package/README.md +72 -0
  2. package/RUNTIME.md +81 -0
  3. package/UTILITIES.md +30 -0
  4. package/dist/catalog.d.ts +17 -0
  5. package/dist/catalog.js +115 -0
  6. package/dist/controller.d.ts +27 -0
  7. package/dist/controller.js +156 -0
  8. package/dist/data-DtdeiZ5o.d.ts +18 -0
  9. package/dist/data-N59s4mFY.js +189 -0
  10. package/dist/data.d.ts +4 -0
  11. package/dist/data.js +36 -0
  12. package/dist/element-types-C9jOyda4.d.ts +9 -0
  13. package/dist/element-types.d.ts +2 -0
  14. package/dist/element-types.js +0 -0
  15. package/dist/elements-DLSCanEZ.d.ts +16 -0
  16. package/dist/elements.d.ts +3 -0
  17. package/dist/elements.js +29 -0
  18. package/dist/icon-data-HGvJGwoB.d.ts +42 -0
  19. package/dist/icon-data.d.ts +2 -0
  20. package/dist/icon-data.js +95 -0
  21. package/dist/index.d.ts +17 -0
  22. package/dist/index.js +15 -0
  23. package/dist/loaders-DxxA-L6t.d.ts +58 -0
  24. package/dist/loaders.d.ts +2 -0
  25. package/dist/loaders.js +112 -0
  26. package/dist/manifest.d.ts +9 -0
  27. package/dist/manifest.js +87 -0
  28. package/dist/presentation.d.ts +94 -0
  29. package/dist/presentation.js +189 -0
  30. package/dist/registry.d.ts +25 -0
  31. package/dist/registry.js +66 -0
  32. package/dist/resource-types.d.ts +68 -0
  33. package/dist/resource-types.js +0 -0
  34. package/dist/runtime.d.ts +7 -0
  35. package/dist/runtime.js +12 -0
  36. package/dist/set-options-C2BMGh-r.d.ts +11 -0
  37. package/dist/set-options.d.ts +2 -0
  38. package/dist/set-options.js +23 -0
  39. package/dist/sizes-CMxyEIpX.d.ts +10 -0
  40. package/dist/sizes.d.ts +2 -0
  41. package/dist/sizes.js +0 -0
  42. package/dist/slug.d.ts +5 -0
  43. package/dist/slug.js +7 -0
  44. package/dist/sources-CXcG9DjB.d.ts +11 -0
  45. package/dist/store.d.ts +36 -0
  46. package/dist/store.js +265 -0
  47. package/dist/svg-data.d.ts +2 -0
  48. package/dist/svg-data.js +2 -0
  49. package/dist/svg.d.ts +19 -0
  50. package/dist/svg.js +49 -0
  51. package/dist/symbol.d.ts +7 -0
  52. package/dist/symbol.js +22 -0
  53. package/dist/types.d.ts +30 -0
  54. package/dist/types.js +0 -0
  55. package/dist/view-box.d.ts +6 -0
  56. package/dist/view-box.js +9 -0
  57. package/package.json +133 -0
@@ -0,0 +1,12 @@
1
+ import { defaultIconLoader } from "./loaders.js";
2
+ //#region src/runtime/compiled.ts
3
+ const iconLoader = defaultIconLoader;
4
+ const compiledIcons = /* @__PURE__ */ new Map();
5
+ function registerStatic(name, icon) {
6
+ compiledIcons.set(name, icon);
7
+ }
8
+ function resolve(name) {
9
+ return compiledIcons.get(name);
10
+ }
11
+ //#endregion
12
+ export { iconLoader, registerStatic, resolve };
@@ -0,0 +1,11 @@
1
+ //#region src/options/set-options.d.ts
2
+ type IconSetMap<Value> = Readonly<Partial<Record<string, Value>>>;
3
+ type IconSetOptions<Value> = Value | IconSetMap<Value>;
4
+ declare function ownValue<Value>(values: IconSetMap<Value> | undefined, key: string | undefined): Value | undefined;
5
+ /** The default discriminator is for primitive values; object values supply their own. */
6
+ declare function isSetMap<Value>(value: IconSetOptions<Value>): value is IconSetMap<Value>;
7
+ declare function resolveSetOption<Value>(value: IconSetOptions<Value> | undefined, set: string | undefined, isMap?: (value: IconSetOptions<Value>) => value is Readonly<Partial<Record<string, Value>>>): Value | undefined;
8
+ /** Child maps merge by set; a shared value replaces the inherited map. */
9
+ declare function mergeSetOptions<Value>(parent: IconSetOptions<Value> | undefined, next: IconSetOptions<Value> | undefined, isMap?: (value: IconSetOptions<Value>) => value is Readonly<Partial<Record<string, Value>>>): IconSetOptions<Value> | undefined;
10
+ //#endregion
11
+ export { ownValue as a, mergeSetOptions as i, IconSetOptions as n, resolveSetOption as o, isSetMap as r, IconSetMap as t };
@@ -0,0 +1,2 @@
1
+ import { a as ownValue, i as mergeSetOptions, n as IconSetOptions, o as resolveSetOption, r as isSetMap, t as IconSetMap } from "./set-options-C2BMGh-r.js";
2
+ export { IconSetMap, IconSetOptions, isSetMap, mergeSetOptions, ownValue, resolveSetOption };
@@ -0,0 +1,23 @@
1
+ //#region src/options/set-options.ts
2
+ function ownValue(values, key) {
3
+ return values && key !== void 0 && Object.hasOwn(values, key) ? values[key] : void 0;
4
+ }
5
+ /** The default discriminator is for primitive values; object values supply their own. */
6
+ function isSetMap(value) {
7
+ return typeof value === "object" && value !== null;
8
+ }
9
+ function resolveSetOption(value, set, isMap = isSetMap) {
10
+ if (value === void 0 || !isMap(value)) return value;
11
+ return ownValue(value, set) ?? ownValue(value, "default");
12
+ }
13
+ /** Child maps merge by set; a shared value replaces the inherited map. */
14
+ function mergeSetOptions(parent, next, isMap = isSetMap) {
15
+ if (next === void 0) return parent;
16
+ if (!isMap(next)) return next;
17
+ return {
18
+ ...parent !== void 0 && isMap(parent) ? parent : { default: parent },
19
+ ...Object.fromEntries(Object.entries(next).filter(([, value]) => value !== void 0))
20
+ };
21
+ }
22
+ //#endregion
23
+ export { isSetMap, mergeSetOptions, ownValue, resolveSetOption };
@@ -0,0 +1,10 @@
1
+ //#region src/options/sizes.d.ts
2
+ type DefaultSizeName = "xs" | "sm" | "md" | "lg" | "xl";
3
+ type CustomSizeName<CustomSize extends object> = keyof CustomSize & string;
4
+ type EnabledCustomSizeName<CustomSize extends object> = { [Key in CustomSizeName<CustomSize>]: CustomSize[Key] extends true ? Key : never; }[CustomSizeName<CustomSize>];
5
+ type DisabledDefaultSizeName<CustomSize extends object> = { [Key in DefaultSizeName]: Key extends keyof CustomSize ? CustomSize[Key] extends false ? Key : never : never; }[DefaultSizeName];
6
+ type ResolveSizeName<CustomSize extends object> = Exclude<DefaultSizeName, DisabledDefaultSizeName<CustomSize>> | EnabledCustomSizeName<CustomSize>;
7
+ type CSSLengthUnit = "%" | "cap" | "ch" | "cm" | "dvb" | "dvh" | "dvi" | "dvmax" | "dvmin" | "dvw" | "em" | "ex" | "ic" | "in" | "lh" | "lvb" | "lvh" | "lvi" | "lvmax" | "lvmin" | "lvw" | "mm" | "pc" | "pt" | "px" | "Q" | "rcap" | "rch" | "rem" | "rex" | "ric" | "rlh" | "svb" | "svh" | "svi" | "svmax" | "svmin" | "svw" | "vb" | "vh" | "vi" | "vmax" | "vmin" | "vw";
8
+ type CSSSize = "0" | "auto" | "inherit" | "initial" | "revert" | "revert-layer" | "unset" | `${number}${CSSLengthUnit}` | `calc(${string})` | `clamp(${string})` | `max(${string})` | `min(${string})` | `var(${string})`;
9
+ //#endregion
10
+ export { DefaultSizeName as n, ResolveSizeName as r, CSSSize as t };
@@ -0,0 +1,2 @@
1
+ import { n as DefaultSizeName, r as ResolveSizeName, t as CSSSize } from "./sizes-CMxyEIpX.js";
2
+ export { CSSSize, DefaultSizeName, ResolveSizeName };
package/dist/sizes.js ADDED
File without changes
package/dist/slug.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ //#region src/resources/slug.d.ts
2
+ /** Normalize an ASCII slug; the caller decides how to handle an empty result. */
3
+ declare function toAsciiSlug(value: string): string;
4
+ //#endregion
5
+ export { toAsciiSlug };
package/dist/slug.js ADDED
@@ -0,0 +1,7 @@
1
+ //#region src/resources/slug.ts
2
+ /** Normalize an ASCII slug; the caller decides how to handle an empty result. */
3
+ function toAsciiSlug(value) {
4
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
5
+ }
6
+ //#endregion
7
+ export { toAsciiSlug };
@@ -0,0 +1,11 @@
1
+ import { i as IconSet, n as IconData } from "./icon-data-HGvJGwoB.js";
2
+ import { Data, IconLoaderResult, ParsedIconName } from "./types.js";
3
+ //#region src/runtime/sources.d.ts
4
+ /** Resolve an icon name from a full icon set payload when prefix/provider match. */
5
+ declare function resolveIconSetData(data: IconSet, name: string): IconData | null;
6
+ /** Parse user icon refs and keep provider-aware prefix/name fields. */
7
+ declare function parseIconName(value: string): ParsedIconName | null;
8
+ /** Convert loaded results from loaders into a canonical runtime data shape. */
9
+ declare function toData(value: IconLoaderResult, name: string): Data | null;
10
+ //#endregion
11
+ export { resolveIconSetData as n, toData as r, parseIconName as t };
@@ -0,0 +1,36 @@
1
+ import { Data, IconLoadState, IconLoader, IconSources } from "./types.js";
2
+ import { r as IconApiConfig } from "./loaders-DxxA-L6t.js";
3
+ import { r as toData } from "./sources-CXcG9DjB.js";
4
+ //#region src/runtime/store.d.ts
5
+ type IconStoreOptions = {
6
+ sources?: IconSources | readonly IconSources[];
7
+ api?: IconApiConfig;
8
+ parent?: IconStore;
9
+ /** Serialized per-request data for hydration. Also subject to maxEntries. */
10
+ initialData?: Readonly<Record<string, Data>>;
11
+ /** LRU capacity. Active entries and the current snapshot may temporarily exceed it. */
12
+ maxEntries?: number;
13
+ ttl?: number;
14
+ missingTtl?: number;
15
+ concurrency?: number;
16
+ timeout?: number;
17
+ };
18
+ type LoadOptions = {
19
+ force?: boolean;
20
+ loader?: IconLoader;
21
+ };
22
+ type IconStore = {
23
+ sources: readonly IconSources[];
24
+ api: IconApiConfig | undefined;
25
+ getState(name: string): IconLoadState;
26
+ load(name: string, options?: LoadOptions): Promise<Data | null>;
27
+ retry(name: string): Promise<Data | null>;
28
+ invalidate(name?: string | ((name: string) => boolean)): void;
29
+ preload(names: readonly string[]): Promise<void>;
30
+ snapshot(): Record<string, Data>;
31
+ subscribe(name: string, listener: () => void): () => void;
32
+ };
33
+ /** One store per SSR request or client application. Snapshot reads never run loaders. */
34
+ declare function createIconStore(options?: IconStoreOptions): IconStore;
35
+ //#endregion
36
+ export { IconStore, IconStoreOptions, createIconStore, toData };
package/dist/store.js ADDED
@@ -0,0 +1,265 @@
1
+ import { parseIconName, toData } from "./data.js";
2
+ import { createIconApiLoader, isSymbolApi, mergeIconApi, resolveIconApi } from "./loaders.js";
3
+ import { resolveIconSymbol } from "./symbol.js";
4
+ //#region src/runtime/store.ts
5
+ const idle = { status: "idle" };
6
+ const deferred = Symbol("deferred source");
7
+ /** One store per SSR request or client application. Snapshot reads never run loaders. */
8
+ function createIconStore(options = {}) {
9
+ for (const key of [
10
+ "maxEntries",
11
+ "concurrency",
12
+ "timeout",
13
+ "ttl",
14
+ "missingTtl"
15
+ ]) {
16
+ const value = options[key];
17
+ if (value === void 0) continue;
18
+ const minimum = key === "ttl" || key === "missingTtl" ? 0 : 1;
19
+ if (!Number.isFinite(value) || value < minimum || (key === "maxEntries" || key === "concurrency") && !Number.isInteger(value)) throw new RangeError(`Invalid icon store ${key}: ${value}`);
20
+ }
21
+ const local = options.sources ? Array.isArray(options.sources) ? options.sources : [options.sources] : [];
22
+ const inherited = options.parent;
23
+ const delegate = options.api === void 0 ? inherited : void 0;
24
+ const sources = [...local, ...inherited?.sources ?? []];
25
+ const activeSources = delegate ? local : sources;
26
+ const api = mergeIconApi(inherited?.api, options.api);
27
+ const loaders = /* @__PURE__ */ new Map();
28
+ const loader = (name, parsed, request) => {
29
+ const selected = resolveIconApi(api, name);
30
+ let selectedLoader = loaders.get(selected);
31
+ if (!selectedLoader) {
32
+ selectedLoader = createIconApiLoader(isSymbolApi(selected) ? false : selected);
33
+ loaders.set(selected, selectedLoader);
34
+ }
35
+ return selectedLoader(name, parsed, request);
36
+ };
37
+ const reference = (name) => {
38
+ const selected = resolveIconApi(api, name);
39
+ return isSymbolApi(selected) ? resolveIconSymbol(selected, name) : null;
40
+ };
41
+ const maxEntries = Math.max(1, options.maxEntries ?? 512);
42
+ const concurrency = Math.max(1, options.concurrency ?? 8);
43
+ const states = /* @__PURE__ */ new Map();
44
+ const requests = /* @__PURE__ */ new Map();
45
+ const listeners = /* @__PURE__ */ new Map();
46
+ const queue = [];
47
+ let running = 0;
48
+ for (const [name, data] of Object.entries(options.initialData ?? {})) {
49
+ const resolved = toData(data, name);
50
+ if (resolved) cache(name, {
51
+ status: "loaded",
52
+ data: resolved
53
+ }, options.ttl ?? 3e5);
54
+ }
55
+ /** Drop unreferenced cache entries when the in-memory budget is exceeded. */
56
+ function trim(current) {
57
+ for (const name of states.keys()) {
58
+ if (states.size <= maxEntries) break;
59
+ if (name !== current && !listeners.has(name) && !requests.has(name)) states.delete(name);
60
+ }
61
+ }
62
+ /** Record state and expiration for stable reads during a render tick. */
63
+ function cache(name, state, ttl = Infinity) {
64
+ states.delete(name);
65
+ states.set(name, {
66
+ state,
67
+ expires: Date.now() + ttl
68
+ });
69
+ trim(name);
70
+ return state;
71
+ }
72
+ function publish(name, state, ttl = Infinity) {
73
+ cache(name, state, ttl);
74
+ listeners.get(name)?.forEach((listener) => listener());
75
+ }
76
+ /** Read one source entry by full name or by set fallback when name is namespaced. */
77
+ function sourceValue(source, name) {
78
+ const parsed = parseIconName(name);
79
+ const key = Object.hasOwn(source, name) ? name : name.includes(":") ? parsed?.prefix ?? "" : "";
80
+ return Object.hasOwn(source, key) ? source[key] : void 0;
81
+ }
82
+ /** Probe all active sources and return deferred marker when async callbacks appear. */
83
+ function probe(name) {
84
+ for (const source of activeSources) {
85
+ if (typeof source === "function") return deferred;
86
+ const value = sourceValue(source, name);
87
+ if (typeof value === "function") return deferred;
88
+ const data = toData(value, name);
89
+ if (data) return data;
90
+ }
91
+ return null;
92
+ }
93
+ /** Resolve current state from cache/probe/delegate/reference without mutating listeners. */
94
+ function getState(name) {
95
+ const cached = states.get(name);
96
+ if (cached) {
97
+ states.delete(name);
98
+ states.set(name, cached);
99
+ return cached.state;
100
+ }
101
+ let data;
102
+ try {
103
+ data = probe(name);
104
+ } catch (cause) {
105
+ return cache(name, {
106
+ status: "error",
107
+ error: cause instanceof Error ? cause : new Error(String(cause))
108
+ }, 0);
109
+ }
110
+ if (data === deferred) return idle;
111
+ if (!data) {
112
+ if (delegate) return delegate.getState(name);
113
+ const symbol = reference(name);
114
+ if (!symbol) return idle;
115
+ return cache(name, {
116
+ status: "referenced",
117
+ ...symbol
118
+ });
119
+ }
120
+ return cache(name, {
121
+ status: "loaded",
122
+ data
123
+ });
124
+ }
125
+ /** Resolve icon data from active sources in order, supporting sync and async sources. */
126
+ async function resolveSources(name, signal) {
127
+ for (const source of activeSources) {
128
+ signal.throwIfAborted();
129
+ const value = typeof source === "function" ? await source(name, parseIconName(name), { signal }) : sourceValue(source, name);
130
+ const data = toData(typeof value === "function" ? await value() : value, name);
131
+ if (data) return data;
132
+ }
133
+ return null;
134
+ }
135
+ /** Clear cache, requests and subscribers for one key or a predicate match set. */
136
+ function invalidate(name) {
137
+ const names = typeof name !== "string" ? /* @__PURE__ */ new Set([
138
+ ...states.keys(),
139
+ ...requests.keys(),
140
+ ...listeners.keys()
141
+ ]) : /* @__PURE__ */ new Set([name]);
142
+ for (const key of names) {
143
+ if (typeof name === "function" && !name(key)) continue;
144
+ const request = requests.get(key);
145
+ requests.delete(key);
146
+ request?.controller.abort();
147
+ states.delete(key);
148
+ listeners.get(key)?.forEach((listener) => listener());
149
+ }
150
+ }
151
+ function load(name, loadOptions = {}) {
152
+ if (loadOptions.force) invalidate(name);
153
+ const pending = requests.get(name);
154
+ if (pending) return pending.promise;
155
+ const state = getState(name);
156
+ if (state.href && !loadOptions.loader) return Promise.resolve(null);
157
+ const cached = states.get(name);
158
+ if (delegate && !cached && probe(name) === null && !loadOptions.loader) return delegate.load(name, loadOptions);
159
+ if (!loadOptions.force && (!cached || cached.expires > Date.now())) {
160
+ if (state.data) return Promise.resolve(state.data);
161
+ if (state.status === "missing") return Promise.resolve(null);
162
+ }
163
+ if (delegate && state.status !== "error" && probe(name) === null && !loadOptions.loader) return delegate.load(name, loadOptions);
164
+ const controller = new AbortController();
165
+ const request = {
166
+ controller,
167
+ promise: null
168
+ };
169
+ requests.set(name, request);
170
+ request.promise = new Promise((resolve, reject) => {
171
+ let started = false;
172
+ const run = () => {
173
+ if (controller.signal.aborted) return;
174
+ started = true;
175
+ running++;
176
+ const timer = setTimeout(() => controller.abort(/* @__PURE__ */ new Error(`Icon request timed out: ${name}`)), options.timeout ?? 15e3);
177
+ const abort = () => reject(controller.signal.reason);
178
+ controller.signal.addEventListener("abort", abort, { once: true });
179
+ (async () => {
180
+ try {
181
+ const data = await resolveSources(name, controller.signal);
182
+ controller.signal.throwIfAborted();
183
+ resolve(data ?? (delegate && !loadOptions.loader ? await delegate.load(name, loadOptions) : toData(await (loadOptions.loader ?? loader)(name, parseIconName(name), { signal: controller.signal }), name)));
184
+ } catch (error) {
185
+ reject(error);
186
+ }
187
+ })();
188
+ request.promise.finally(() => {
189
+ clearTimeout(timer);
190
+ controller.signal.removeEventListener("abort", abort);
191
+ running--;
192
+ queue.shift()?.();
193
+ }).catch(() => {});
194
+ };
195
+ controller.signal.addEventListener("abort", () => {
196
+ if (started) return;
197
+ const index = queue.indexOf(run);
198
+ if (index >= 0) queue.splice(index, 1);
199
+ reject(controller.signal.reason);
200
+ }, { once: true });
201
+ queueMicrotask(() => {
202
+ if (controller.signal.aborted) return;
203
+ if (running < concurrency) run();
204
+ else queue.push(run);
205
+ });
206
+ }).then((data) => {
207
+ const symbol = !data && !loadOptions.loader ? reference(name) : null;
208
+ if (requests.get(name) === request) publish(name, data ? {
209
+ status: "loaded",
210
+ data
211
+ } : symbol ? {
212
+ status: "referenced",
213
+ ...symbol
214
+ } : { status: "missing" }, data ? options.ttl ?? 3e5 : options.missingTtl ?? 3e4);
215
+ return data;
216
+ }).catch((cause) => {
217
+ const error = cause instanceof Error ? cause : new Error(String(cause));
218
+ if (requests.get(name) === request) publish(name, {
219
+ status: "error",
220
+ error
221
+ }, 0);
222
+ throw error;
223
+ }).finally(() => {
224
+ if (requests.get(name) === request) requests.delete(name);
225
+ trim();
226
+ });
227
+ publish(name, { status: "loading" });
228
+ return request.promise;
229
+ }
230
+ return {
231
+ sources,
232
+ api,
233
+ getState,
234
+ load,
235
+ retry: (name) => load(name, { force: true }),
236
+ invalidate,
237
+ async preload(names) {
238
+ await Promise.all(names.map((name) => load(name)));
239
+ },
240
+ snapshot() {
241
+ const parentData = Object.entries(delegate?.snapshot() ?? {}).filter(([name]) => {
242
+ try {
243
+ return probe(name) === null;
244
+ } catch {
245
+ return false;
246
+ }
247
+ });
248
+ return Object.fromEntries([...parentData, ...[...states].flatMap(([name, { state }]) => state.data ? [[name, state.data]] : [])]);
249
+ },
250
+ subscribe(name, listener) {
251
+ const subscribers = listeners.get(name) ?? /* @__PURE__ */ new Set();
252
+ listeners.set(name, subscribers);
253
+ subscribers.add(listener);
254
+ const unsubscribeParent = delegate?.subscribe(name, listener);
255
+ return () => {
256
+ unsubscribeParent?.();
257
+ subscribers.delete(listener);
258
+ if (!subscribers.size) listeners.delete(name);
259
+ trim();
260
+ };
261
+ }
262
+ };
263
+ }
264
+ //#endregion
265
+ export { createIconStore, toData };
@@ -0,0 +1,2 @@
1
+ import { n as elementDataToIcon, r as renderSvgData, t as createSvgSymbolDocument } from "./data-DtdeiZ5o.js";
2
+ export { createSvgSymbolDocument, elementDataToIcon, renderSvgData };
@@ -0,0 +1,2 @@
1
+ import { n as elementDataToIcon, r as renderSvgData, t as createSvgSymbolDocument } from "./data-N59s4mFY.js";
2
+ export { createSvgSymbolDocument, elementDataToIcon, renderSvgData };
package/dist/svg.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { n as IconData } from "./icon-data-HGvJGwoB.js";
2
+ //#region src/svg/index.d.ts
3
+ /** Built-in drawing coordinates. Rendered pixel dimensions are controlled by size. */
4
+ declare const iconViewBoxes: Readonly<{
5
+ readonly default: "0 0 24 24";
6
+ readonly flagSquare: "0 0 512 512";
7
+ readonly flagLandscape: "0 0 640 480";
8
+ }>;
9
+ declare function getIconViewBox(name?: string): "0 0 24 24" | "0 0 512 512" | "0 0 640 480";
10
+ /** Only named Flag assets follow the filename contract; direct Data stays untouched. */
11
+ declare function withIconViewBox(data: IconData, name?: string): IconData;
12
+ /** Component CSS contract; low-level rewriting is shared with build tools. */
13
+ declare function configurableStrokeBody(body: string, variable?: string): string;
14
+ /** Let inherited configuration override widths inside inline and external SVG. */
15
+ declare function rewriteStrokeWidths(body: string, variable: string): string;
16
+ /** Rewrite SVG IDs and references using a caller-provided instance prefix. */
17
+ declare function replaceSvgIds(body: string, prefix: string): string;
18
+ //#endregion
19
+ export { configurableStrokeBody, getIconViewBox, iconViewBoxes, replaceSvgIds, rewriteStrokeWidths, withIconViewBox };
package/dist/svg.js ADDED
@@ -0,0 +1,49 @@
1
+ //#region src/svg/index.ts
2
+ /** Built-in drawing coordinates. Rendered pixel dimensions are controlled by size. */
3
+ const iconViewBoxes = Object.freeze({
4
+ default: "0 0 24 24",
5
+ flagSquare: "0 0 512 512",
6
+ flagLandscape: "0 0 640 480"
7
+ });
8
+ function getIconViewBox(name) {
9
+ if (!name?.startsWith("flag:")) return iconViewBoxes.default;
10
+ return /-(circle|square)$/.test(name) ? iconViewBoxes.flagSquare : iconViewBoxes.flagLandscape;
11
+ }
12
+ /** Only named Flag assets follow the filename contract; direct Data stays untouched. */
13
+ function withIconViewBox(data, name) {
14
+ const viewBox = getIconViewBox(name);
15
+ if (viewBox === iconViewBoxes.default) return data;
16
+ const [, , width, height] = viewBox.split(" ").map(Number);
17
+ return {
18
+ ...data,
19
+ left: 0,
20
+ top: 0,
21
+ width,
22
+ height
23
+ };
24
+ }
25
+ /** Component CSS contract; low-level rewriting is shared with build tools. */
26
+ function configurableStrokeBody(body, variable = "--icones-stroke-width") {
27
+ return rewriteStrokeWidths(body, variable);
28
+ }
29
+ /** Let inherited configuration override widths inside inline and external SVG. */
30
+ function rewriteStrokeWidths(body, variable) {
31
+ const strokes = [...body.matchAll(/\bstroke\s*=\s*(["'])(.*?)\1/gi)].map((match) => match[2]);
32
+ const styledStrokes = [...body.matchAll(/(?:^|[;"'])\s*stroke\s*:\s*([^;"']+)/gi)].map((match) => match[1]);
33
+ if ([...strokes, ...styledStrokes].some((stroke) => !/^(currentcolor|none|inherit)$/i.test(stroke.trim()))) return body;
34
+ return body.replace(/\bstroke-width\s*=\s*(["'])(.*?)\1/g, (_match, quote, width) => `stroke-width=${quote}${strokeValue(width, variable)}${quote}`).replace(/\bstyle\s*=\s*(["'])(.*?)\1/g, (_match, quote, style) => `style=${quote}${style.replace(/(^|;)\s*stroke-width\s*:\s*([^;]+)/g, (_declaration, separator, width) => `${separator}stroke-width:${strokeValue(width, variable)}`)}${quote}`);
35
+ }
36
+ function strokeValue(width, variable) {
37
+ return width.includes(variable) ? width : `var(${variable}, ${width.trim()})`;
38
+ }
39
+ /** Rewrite SVG IDs and references using a caller-provided instance prefix. */
40
+ function replaceSvgIds(body, prefix) {
41
+ const ids = new Set([...body.matchAll(/\bid\s*=\s*(["'])(.*?)\1/g)].map((match) => match[2]));
42
+ for (const id of ids) {
43
+ const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
44
+ body = body.replace(new RegExp(`([#;"'])${escaped}([)"']|\\.[a-z])`, "g"), (_match, before, after) => before + prefix + id + after);
45
+ }
46
+ return body;
47
+ }
48
+ //#endregion
49
+ export { configurableStrokeBody, getIconViewBox, iconViewBoxes, replaceSvgIds, rewriteStrokeWidths, withIconViewBox };
@@ -0,0 +1,7 @@
1
+ import { RuntimeIcon } from "./types.js";
2
+ import { c as IconSymbolApiOptions } from "./loaders-DxxA-L6t.js";
3
+ //#region src/runtime/symbol.d.ts
4
+ /** URL resolution only: never fetches or evaluates a data source. Safe during SSR. */
5
+ declare function resolveIconSymbol(api: IconSymbolApiOptions, name: string): RuntimeIcon | null;
6
+ //#endregion
7
+ export { resolveIconSymbol };
package/dist/symbol.js ADDED
@@ -0,0 +1,22 @@
1
+ import { parseViewBox } from "./view-box.js";
2
+ import { parseIconName } from "./data.js";
3
+ import { getIconViewBox } from "./svg.js";
4
+ //#region src/runtime/symbol.ts
5
+ /** URL resolution only: never fetches or evaluates a data source. Safe during SSR. */
6
+ function resolveIconSymbol(api, name) {
7
+ const parsed = parseIconName(name);
8
+ if (!api.url && (!name.includes(":") || !parsed || parsed.provider)) return null;
9
+ const base = (api.baseUrl ?? "/icons").replace(/\/+$/, "");
10
+ const href = String(api.url ? api.url(name, parsed) : `${base}/${encodeURIComponent(parsed.prefix)}/${encodeURIComponent(parsed.name)}.svg#icon`);
11
+ const url = new URL(href, "https://icones.invalid/");
12
+ if (!/^https?:$/.test(url.protocol) || !url.hash || url.hash === "#") throw new TypeError("Symbol URL must use HTTP(S) or a relative path and include a fragment ID.");
13
+ const viewBox = api.viewBox ?? getIconViewBox(name);
14
+ const dimensions = parseViewBox(viewBox);
15
+ if (!dimensions) throw new TypeError("Invalid symbol viewBox.");
16
+ return {
17
+ href,
18
+ viewBox: dimensions.join(" ")
19
+ };
20
+ }
21
+ //#endregion
22
+ export { resolveIconSymbol };
@@ -0,0 +1,30 @@
1
+ import { i as ElementNode, n as ElementChild, r as ElementData, t as ElementAttributes } from "./element-types-C9jOyda4.js";
2
+ import { i as IconSet, n as IconData } from "./icon-data-HGvJGwoB.js";
3
+ import { IconName, IconName as IconName$1, IconNamesBySet, IconSetName } from "@icones/names";
4
+ //#region src/runtime/types.d.ts
5
+ type Data = IconData | ElementData;
6
+ type Name = IconName$1 | (string & {});
7
+ type RuntimeIcon = {
8
+ data?: Data;
9
+ href?: string;
10
+ viewBox?: string;
11
+ fill?: string;
12
+ };
13
+ type ParsedIconName = {
14
+ provider: string;
15
+ prefix: string;
16
+ name: string;
17
+ };
18
+ type IconLoaderResult = Data | IconSet | null | undefined;
19
+ type IconLoader = (name: string, parsedName: ParsedIconName | null, request?: {
20
+ signal: AbortSignal;
21
+ }) => IconLoaderResult | Promise<IconLoaderResult>;
22
+ type IconLoadStatus = "idle" | "loading" | "loaded" | "referenced" | "missing" | "error";
23
+ type IconLoadState = RuntimeIcon & {
24
+ status: IconLoadStatus;
25
+ error?: Error;
26
+ };
27
+ type IconSource = string | Data;
28
+ type IconSources = Readonly<Record<string, Data | IconSet | (() => IconLoaderResult | Promise<IconLoaderResult>)>> | IconLoader;
29
+ //#endregion
30
+ export { Data, type ElementAttributes, type ElementChild, type ElementData, type ElementNode, type IconData, IconLoadState, IconLoadStatus, IconLoader, IconLoaderResult, type IconName, type IconNamesBySet, type IconSet, type IconSetName, IconSource, IconSources, Name, ParsedIconName, RuntimeIcon };
package/dist/types.js ADDED
File without changes
@@ -0,0 +1,6 @@
1
+ //#region src/svg/view-box.d.ts
2
+ type ViewBox = [left: number, top: number, width: number, height: number];
3
+ /** Parse finite SVG coordinates with positive dimensions. Callers supply error context. */
4
+ declare function parseViewBox(value: string): ViewBox | null;
5
+ //#endregion
6
+ export { ViewBox, parseViewBox };
@@ -0,0 +1,9 @@
1
+ //#region src/svg/view-box.ts
2
+ /** Parse finite SVG coordinates with positive dimensions. Callers supply error context. */
3
+ function parseViewBox(value) {
4
+ const dimensions = value.trim().split(/[\s,]+/).map(Number);
5
+ if (dimensions.length !== 4 || !dimensions.every(Number.isFinite) || dimensions[2] <= 0 || dimensions[3] <= 0) return null;
6
+ return dimensions;
7
+ }
8
+ //#endregion
9
+ export { parseViewBox };