iconly 2.0.1-dev.0 → 3.0.0-dev.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 CHANGED
@@ -3,43 +3,45 @@
3
3
 
4
4
  <h1>iconly</h1>
5
5
 
6
- <p><sup>Iconly is designed to load and cache SVG icons in the browser, using IndexedDB to store the data. It retrieves the icons from a given SVG file, stores them in IndexedDB, and inserts them into the DOM for easy access and use.</sup></p>
6
+ <p><sup>A lightweight utility to load and cache SVG icons in the browser, using IndexedDB to store the data. It retrieves icons from a given SVG file, stores them in IndexedDB, and inserts them into the DOM for easy access and use.</sup></p>
7
7
 
8
8
  [![npm](https://img.shields.io/npm/v/iconly.svg?colorB=brightgreen)](https://www.npmjs.com/package/iconly)
9
9
  [![GitHub package version](https://img.shields.io/github/package-json/v/ux-ui-pro/iconly.svg)](https://github.com/ux-ui-pro/iconly)
10
10
  [![NPM Downloads](https://img.shields.io/npm/dm/iconly.svg?style=flat)](https://www.npmjs.org/package/iconly)
11
11
 
12
- <sup>1.5kB gzipped</sup>
12
+ <sup>~2kB gzipped</sup>
13
13
 
14
14
  <a href="https://codepen.io/ux-ui/pen/zYmyqWR">Demo</a>
15
15
 
16
16
  </div>
17
17
  <br>
18
18
 
19
- &#10148; **Install**
20
-
19
+ # Install
21
20
  ```console
22
- $ yarn add iconly
21
+ $ npm install iconly
23
22
  ```
24
23
  <br>
25
24
 
26
- &#10148; **Import**
27
-
25
+ # Import
28
26
  ```javascript
29
- import Iconly from 'iconly';
27
+ import { createIconly } from 'iconly';
30
28
  ```
31
29
  <br>
32
30
 
33
- &#10148; **Usage**
34
-
31
+ # Usage
35
32
  ```javascript
36
- const iconly = new Iconly({
33
+ const iconLoader = createIconly({
37
34
  file: './sprite.svg',
38
35
  version: '1.0',
39
36
  debug: true,
37
+ storage: 'indexeddb',
40
38
  });
41
39
 
42
- iconly.init().then(() => console.log('Iconly is initialized and icons are loaded.'));
40
+ const result = await iconLoader.init();
41
+
42
+ if (!result.ok) {
43
+ console.error(result.error);
44
+ }
43
45
  ```
44
46
 
45
47
  ```HTML
@@ -58,16 +60,28 @@ iconly.init().then(() => console.log('Iconly is initialized and icons are loaded
58
60
  ```
59
61
  <br>
60
62
 
61
- &#10148; **Options**
62
-
63
- | Option | Type | Default | Description |
64
- |:-----------:|:-----------------------:|:---------------:|:--------------------------------------------------------------------------------------------------------|
65
- | `file` | `string` | `'./icons.svg'` | The URL of the SVG file containing the icons. |
66
- | `version` | `string` | `'1.0'` | The version of the icon set. |
67
- | `debug` | `boolean` | `false` | If `true`, debug information and errors will be logged to the console. |
68
- | `container` | `string \| HTMLElement` | `document.body` | The container element where the icons will be injected. Can be a CSS selector string or an HTMLElement. |
63
+ # Options
64
+ | Option | Type | Default | Description |
65
+ |:------------------:|:---------------------------------------:|:---------------:|:----------------------------------------------------------------|
66
+ | `file` | `string` | `'./icons.svg'` | The URL of the SVG file containing the icons. |
67
+ | `version` | `string` | `'1.0'` | The version of the icon set. |
68
+ | `debug` | `boolean` | `false` | If `true`, debug callbacks and logger debug output are enabled. |
69
+ | `container` | `string \| HTMLElement` | `document.body` | The container element where the icons will be injected. |
70
+ | `storage` | `'indexeddb' \| 'memory' \| 'session'` | `'indexeddb'` | Storage strategy used for caching icon data. |
71
+ | `dbName` | `string` | `'iconlyDB'` | IndexedDB database name (only for `indexeddb`). |
72
+ | `storeName` | `string` | `'icons'` | IndexedDB store name (only for `indexeddb`). |
73
+ | `sessionKeyPrefix` | `string` | `'iconly'` | Prefix for SessionStorage keys (only for `session`). |
74
+ | `logger` | `{ debug?, error? }` | `undefined` | Optional logger implementation for debug/error output. |
75
+ | `onError` | `(error) => void` | `undefined` | Optional callback invoked on errors. |
76
+ | `onDebug` | `(...args) => void` | `undefined` | Optional callback invoked for debug messages. |
69
77
  <br>
70
78
 
71
- &#10148; **License**
79
+ # Error handling
80
+ - `init()` never throws; it returns a `Result` with `ok: false` and `error` details.
81
+ - When `debug` is `false`, debug messages are suppressed (no `onDebug` calls and no `logger.debug`).
82
+ - Errors still trigger `onError` and `logger.error` (if provided), even when `debug` is `false`.
83
+ - You can cancel a fetch by calling `iconLoader.abort()`, which results in a `fetch_aborted` error code.
84
+
85
+ # License
72
86
 
73
- iconly is released under MIT license
87
+ MIT
package/dist/core.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { IconlyConfig, IconlyInstance } from './types';
2
+ export declare const createIconly: (config?: IconlyConfig) => IconlyInstance;
3
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAe,cAAc,EAAuB,MAAM,SAAS,CAAC;AAY9F,eAAO,MAAM,YAAY,GAAI,SAAQ,YAAiB,KAAG,cAgIxD,CAAC"}
package/dist/dom.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Result } from './types';
2
+ export declare const insertSvg: (container: HTMLElement, data: string) => Result<void>;
3
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,eAAO,MAAM,SAAS,GAAI,WAAW,WAAW,EAAE,MAAM,MAAM,KAAG,MAAM,CAAC,IAAI,CAqC3E,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { IconlyError, IconlyErrorCode } from './types';
2
+ export declare const createIconlyError: (code: IconlyErrorCode, message: string, cause?: unknown) => IconlyError;
3
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE5D,eAAO,MAAM,iBAAiB,GAC5B,MAAM,eAAe,EACrB,SAAS,MAAM,EACf,QAAQ,OAAO,KACd,WAID,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Result } from './types';
2
+ export declare const fetchSvg: (file: string, signal?: AbortSignal) => Promise<Result<string>>;
3
+ //# sourceMappingURL=fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,eAAO,MAAM,QAAQ,GAAU,MAAM,MAAM,EAAE,SAAS,WAAW,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAkBzF,CAAC"}
package/dist/index.cjs.js CHANGED
@@ -1 +1,2 @@
1
- "use strict";var g=Object.defineProperty;var h=(d,r,e)=>r in d?g(d,r,{enumerable:!0,configurable:!0,writable:!0,value:e}):d[r]=e;var l=(d,r,e)=>h(d,typeof r!="symbol"?r+"":r,e);const a=class a{constructor(r={}){l(this,"options");l(this,"container");const e={file:"./icons.svg",version:"1.0",debug:!1,container:document.body??document.documentElement,...r};let n;if(typeof e.container=="string"){const i=document.querySelector(e.container);if(!(i&&i instanceof HTMLElement))throw new Error(`Invalid container selector: "${e.container}"`);n=i}else n=e.container;this.container=n,this.options={file:e.file,version:e.version,debug:e.debug},a.dbInstance||(a.dbInstance=this.openDB("iconlyDB",1))}async openDB(r,e){if(!("indexedDB"in window))throw this.logError("This browser does not support IndexedDB"),new Error("IndexedDB not supported");return await new Promise((n,i)=>{const o=indexedDB.open(r,e);o.onerror=()=>{const s=this.createErrorMessage(o.error,"IndexedDB error");i(new Error(s))},o.onupgradeneeded=s=>{const t=s.target.result;t.objectStoreNames.contains("icons")||t.createObjectStore("icons",{keyPath:"version"})},o.onsuccess=()=>{n(o.result)}})}getIconStore(r,e){return r.transaction("icons",e).objectStore("icons")}static async fetchData(r){const e=await fetch(r);if(!e.ok)throw new Error(`Failed to fetch icons from "${r}"`);return e.text()}insert(r){let e=document.getElementById("iconset");e||(e=document.createElement("div"),e.id="iconset",e.setAttribute("aria-hidden","true"),e.style.cssText="width: 0; height: 0; position: absolute; left: -9999px;",this.container.appendChild(e));const n=new DOMParser().parseFromString(r,"image/svg+xml"),i=n.querySelector("parsererror");if(i)return void this.logError("SVG parsing error:",i.textContent??"");e.innerHTML="";const o=n.documentElement;if(o){const s=document.importNode(o,!0);e.appendChild(s)}else this.logError("No valid SVG content found to insert.")}async init(){try{let r=await a.fetchData(this.options.file);const e=await a.dbInstance;if(!e)throw new Error("Failed to open IndexedDB");const n=this.getIconStore(e,"readwrite"),i=await new Promise((o,s)=>{const t=n.get(this.options.version);t.onsuccess=()=>{o(t.result)},t.onerror=()=>{const c=this.createErrorMessage(t.error,"Error getting record from store");s(new Error(c))}});i?r=i.data:await new Promise((o,s)=>{const t=n.put({version:this.options.version,data:r});t.onsuccess=()=>o(),t.onerror=()=>{const c=this.createErrorMessage(t.error,"Error putting record into store");s(new Error(c))}}),await new Promise((o,s)=>{const t=n.transaction;t.oncomplete=()=>o(),t.onerror=()=>{const c=this.createErrorMessage(t.error,"Transaction error");s(new Error(c))},t.onabort=()=>{const c=this.createErrorMessage(t.error,"Transaction aborted");s(new Error(c))}}),this.insert(r),this.logDebug("Iconly has successfully initialized.")}catch(r){const e=r instanceof Error?r:new Error(String(r));this.logError("Error initializing Iconly:",e.message)}}createErrorMessage(r,e){return r&&(r instanceof DOMException||r instanceof Error)&&r.message||e}logDebug(...r){this.options.debug}logError(...r){}};l(a,"dbInstance",null);let u=a;module.exports=u;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=(e,t,r)=>({code:e,message:t,cause:r}),f=e=>({ok:!0,value:e}),d=e=>({ok:!1,error:e}),S=(e,t)=>{let r=document.getElementById("iconset");r||(r=document.createElement("div"),r.id="iconset",r.setAttribute("aria-hidden","true"),r.style.cssText="width: 0; height: 0; position: absolute; left: -9999px;",e.appendChild(r));const b=new DOMParser().parseFromString(t,"image/svg+xml"),g=b.querySelector("parsererror");if(g)return d(c("parse_error",`SVG parsing error: ${g.textContent??"Unknown error"}`));r.innerHTML="";const u=b.documentElement;if(!u)return d(c("parse_error","No valid SVG content found."));const m=document.importNode(u,!0);return r.appendChild(m),f(void 0)},x=async(e,t)=>{try{const r=await fetch(e,{signal:t});if(!r.ok)return d(c("fetch_failed",`Failed to fetch icons from "${e}".`));const i=await r.text();return f(i)}catch(r){return r instanceof DOMException&&r.name==="AbortError"?d(c("fetch_aborted","Fetch request was aborted.",r)):d(c("fetch_failed","Failed to fetch icons.",r))}},h=(e={})=>{const t=e.dbName??"iconlyDB",r=e.storeName??"icons";let i=null;const b=async()=>{if(i)return i;if(typeof indexedDB>"u")throw c("indexeddb_not_supported","IndexedDB is not supported.");return i=new Promise((l,n)=>{const o=indexedDB.open(t,1);o.onerror=()=>{n(c("indexeddb_open_failed","Failed to open IndexedDB connection.",o.error))},o.onupgradeneeded=s=>{const a=s.target.result;a.objectStoreNames.contains(r)||a.createObjectStore(r,{keyPath:"version"})},o.onsuccess=()=>l(o.result)}),i},g=(l,n)=>l.transaction(r,n).objectStore(r),u=(l,n,o)=>l&&typeof l=="object"&&"code"in l&&"message"in l?l:c(n,o,l);return{get:async l=>{try{const n=await b(),o=g(n,"readonly");return await new Promise(s=>{const a=o.get(l);a.onsuccess=()=>s(f(a.result)),a.onerror=()=>s(d(c("indexeddb_request_failed","Failed to read from IndexedDB.",a.error)))})}catch(n){return d(u(n,"indexeddb_open_failed","Failed to open IndexedDB."))}},set:async l=>{try{const n=await b(),o=g(n,"readwrite");return await new Promise(s=>{const a=o.put(l);a.onsuccess=()=>s(f(void 0)),a.onerror=()=>s(d(c("indexeddb_request_failed","Failed to write to IndexedDB.",a.error)))})}catch(n){return d(c("indexeddb_open_failed","Failed to open IndexedDB.",n))}}}},_=()=>{const e=new Map;return{get:async i=>e.has(i)?f({version:i,data:e.get(i)??""}):f(void 0),set:async i=>(e.set(i.version,i.data),f(void 0))}},D=(e={})=>{const t=e.keyPrefix??"iconly",r=()=>typeof window>"u"||!window.sessionStorage?d(c("storage_unavailable","SessionStorage is not available.")):f(window.sessionStorage);return{get:async g=>{const u=r();if(!u.ok)return u;try{const m=u.value.getItem(`${t}:${g}`);if(!m)return f(void 0);const y=JSON.parse(m);return f(y)}catch(m){return d(c("storage_read_failed","Failed to read from SessionStorage.",m))}},set:async g=>{const u=r();if(!u.ok)return u;try{return u.value.setItem(`${t}:${g.version}`,JSON.stringify(g)),f(void 0)}catch(m){return d(c("storage_write_failed","Failed to write to SessionStorage.",m))}}}},I=(e,t)=>!e||e==="indexeddb"?h({dbName:t.dbName,storeName:t.storeName}):e==="memory"?_():e==="session"?D({keyPrefix:t.sessionKeyPrefix}):e,N=(e={})=>{const t={file:e.file??"./icons.svg",version:e.version??"1.0",debug:e.debug??!1,container:e.container,logger:e.logger,onError:e.onError,onDebug:e.onDebug},r=I(e.storage,{dbName:e.dbName,storeName:e.storeName,sessionKeyPrefix:e.sessionKeyPrefix});let i=null;const b=()=>{i==null||i.abort()},g=()=>{if(typeof document>"u")return d(c("container_invalid","Document is not available in this environment."));if(typeof t.container=="string"){const o=document.querySelector(t.container);return!o||!(o instanceof HTMLElement)?d(c("container_invalid",`Invalid container selector: "${t.container}".`)):f(o)}if(t.container instanceof HTMLElement)return f(t.container);const n=document.body??document.documentElement;return n?f(n):d(c("container_invalid","No valid container element found."))},u=(...n)=>{var o,s,a;t.debug&&((o=t.onDebug)==null||o.call(t,...n),(a=(s=t.logger)==null?void 0:s.debug)==null||a.call(s,"[Iconly debug]",...n))},m=n=>{var o,s,a;(o=t.onError)==null||o.call(t,n),(a=(s=t.logger)==null?void 0:s.error)==null||a.call(s,"[Iconly error]",n)},y=n=>(m(n),d(n));return{init:async()=>{var v;const n=g();if(!n.ok)return y(n.error);const o=await r.get(t.version);if(!o.ok)return y(o.error);let s=(v=o.value)==null?void 0:v.data;if(s)u("Using cached icon set",t.version);else{i=new AbortController;const p=await x(t.file,i.signal);if(!p.ok)return y(p.error);s=p.value;const w=await r.set({version:t.version,data:s});if(!w.ok)return y(w.error)}const a=S(n.value,s);return a.ok?(u("Iconly has successfully initialized."),f(void 0)):y(a.error)},abort:b}};exports.createIconly=N;
2
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/errors.ts","../src/result.ts","../src/dom.ts","../src/fetcher.ts","../src/storage/indexeddb.ts","../src/storage/memory.ts","../src/storage/session.ts","../src/storage/index.ts","../src/core.ts"],"sourcesContent":["import type { IconlyError, IconlyErrorCode } from './types';\n\nexport const createIconlyError = (\n code: IconlyErrorCode,\n message: string,\n cause?: unknown,\n): IconlyError => ({\n code,\n message,\n cause,\n});\n","import type { IconlyError, Result } from './types';\n\nexport const ok = <T>(value: T): Result<T> => ({ ok: true, value });\n\nexport const err = <T = never>(error: IconlyError): Result<T> => ({ ok: false, error });\n","import { createIconlyError } from './errors';\nimport { err, ok } from './result';\nimport type { Result } from './types';\n\nexport const insertSvg = (container: HTMLElement, data: string): Result<void> => {\n let iconSetDiv = document.getElementById('iconset');\n\n if (!iconSetDiv) {\n iconSetDiv = document.createElement('div');\n iconSetDiv.id = 'iconset';\n iconSetDiv.setAttribute('aria-hidden', 'true');\n iconSetDiv.style.cssText = 'width: 0; height: 0; position: absolute; left: -9999px;';\n container.appendChild(iconSetDiv);\n }\n\n const parser = new DOMParser();\n const svgDoc = parser.parseFromString(data, 'image/svg+xml');\n const parserError = svgDoc.querySelector('parsererror');\n\n if (parserError) {\n return err(\n createIconlyError(\n 'parse_error',\n `SVG parsing error: ${parserError.textContent ?? 'Unknown error'}`,\n ),\n );\n }\n\n iconSetDiv.innerHTML = '';\n\n const svgEl = svgDoc.documentElement;\n\n if (!svgEl) {\n return err(createIconlyError('parse_error', 'No valid SVG content found.'));\n }\n\n const imported = document.importNode(svgEl, true);\n\n iconSetDiv.appendChild(imported);\n\n return ok(undefined);\n};\n","import { createIconlyError } from './errors';\nimport { err, ok } from './result';\nimport type { Result } from './types';\n\nexport const fetchSvg = async (file: string, signal?: AbortSignal): Promise<Result<string>> => {\n try {\n const response = await fetch(file, { signal });\n\n if (!response.ok) {\n return err(createIconlyError('fetch_failed', `Failed to fetch icons from \"${file}\".`));\n }\n\n const data = await response.text();\n\n return ok(data);\n } catch (error: unknown) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n return err(createIconlyError('fetch_aborted', 'Fetch request was aborted.', error));\n }\n\n return err(createIconlyError('fetch_failed', 'Failed to fetch icons.', error));\n }\n};\n","import { createIconlyError } from '../errors';\nimport { err, ok } from '../result';\nimport type { IconlyError, IconRecord, IconStorage, Result } from '../types';\n\ninterface IndexedDbOptions {\n dbName?: string;\n storeName?: string;\n}\n\nexport const createIndexedDbStorage = (options: IndexedDbOptions = {}): IconStorage => {\n const dbName = options.dbName ?? 'iconlyDB';\n const storeName = options.storeName ?? 'icons';\n\n let dbPromise: Promise<IDBDatabase> | null = null;\n\n const openDb = async (): Promise<IDBDatabase> => {\n if (dbPromise) {\n return dbPromise;\n }\n\n if (typeof indexedDB === 'undefined') {\n throw createIconlyError('indexeddb_not_supported', 'IndexedDB is not supported.');\n }\n\n dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDB.open(dbName, 1);\n\n request.onerror = (): void => {\n reject(\n createIconlyError(\n 'indexeddb_open_failed',\n 'Failed to open IndexedDB connection.',\n request.error,\n ),\n );\n };\n\n request.onupgradeneeded = (event): void => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName, { keyPath: 'version' });\n }\n };\n\n request.onsuccess = (): void => resolve(request.result);\n });\n\n return dbPromise;\n };\n\n const getStore = (db: IDBDatabase, mode: IDBTransactionMode): IDBObjectStore =>\n db.transaction(storeName, mode).objectStore(storeName);\n\n const toIconlyError = (\n error: unknown,\n fallbackCode: IconlyError['code'],\n message: string,\n ): IconlyError => {\n if (error && typeof error === 'object' && 'code' in error && 'message' in error) {\n return error as IconlyError;\n }\n\n return createIconlyError(fallbackCode, message, error);\n };\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n try {\n const db = await openDb();\n const store = getStore(db, 'readonly');\n\n return await new Promise<Result<IconRecord | undefined>>((resolve) => {\n const request = store.get(version);\n\n request.onsuccess = (): void => resolve(ok(request.result as IconRecord | undefined));\n request.onerror = (): void =>\n resolve(\n err(\n createIconlyError(\n 'indexeddb_request_failed',\n 'Failed to read from IndexedDB.',\n request.error,\n ),\n ),\n );\n });\n } catch (error: unknown) {\n return err(toIconlyError(error, 'indexeddb_open_failed', 'Failed to open IndexedDB.'));\n }\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n try {\n const db = await openDb();\n const store = getStore(db, 'readwrite');\n\n return await new Promise<Result<void>>((resolve) => {\n const request = store.put(record);\n\n request.onsuccess = (): void => resolve(ok(undefined));\n request.onerror = (): void =>\n resolve(\n err(\n createIconlyError(\n 'indexeddb_request_failed',\n 'Failed to write to IndexedDB.',\n request.error,\n ),\n ),\n );\n });\n } catch (error: unknown) {\n return err(createIconlyError('indexeddb_open_failed', 'Failed to open IndexedDB.', error));\n }\n };\n\n return { get, set };\n};\n","import { ok } from '../result';\nimport type { IconRecord, IconStorage, Result } from '../types';\n\nexport const createMemoryStorage = (): IconStorage => {\n const store = new Map<string, string>();\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n if (!store.has(version)) {\n return ok(undefined);\n }\n\n return ok({ version, data: store.get(version) ?? '' });\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n store.set(record.version, record.data);\n\n return ok(undefined);\n };\n\n return { get, set };\n};\n","import { createIconlyError } from '../errors';\nimport { err, ok } from '../result';\nimport type { IconRecord, IconStorage, Result } from '../types';\n\ninterface SessionStorageOptions {\n keyPrefix?: string;\n}\n\nexport const createSessionStorage = (options: SessionStorageOptions = {}): IconStorage => {\n const keyPrefix = options.keyPrefix ?? 'iconly';\n\n const resolveStorage = (): Result<Storage> => {\n if (typeof window === 'undefined' || !window.sessionStorage) {\n return err(createIconlyError('storage_unavailable', 'SessionStorage is not available.'));\n }\n\n return ok(window.sessionStorage);\n };\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n const storageResult = resolveStorage();\n\n if (!storageResult.ok) {\n return storageResult;\n }\n\n try {\n const raw = storageResult.value.getItem(`${keyPrefix}:${version}`);\n\n if (!raw) {\n return ok(undefined);\n }\n\n const parsed = JSON.parse(raw) as IconRecord;\n\n return ok(parsed);\n } catch (error: unknown) {\n return err(\n createIconlyError('storage_read_failed', 'Failed to read from SessionStorage.', error),\n );\n }\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n const storageResult = resolveStorage();\n\n if (!storageResult.ok) {\n return storageResult;\n }\n\n try {\n storageResult.value.setItem(`${keyPrefix}:${record.version}`, JSON.stringify(record));\n\n return ok(undefined);\n } catch (error: unknown) {\n return err(\n createIconlyError('storage_write_failed', 'Failed to write to SessionStorage.', error),\n );\n }\n };\n\n return { get, set };\n};\n","import type { IconStorage, StorageStrategy } from '../types';\nimport { createIndexedDbStorage } from './indexeddb';\nimport { createMemoryStorage } from './memory';\nimport { createSessionStorage } from './session';\n\nexport interface StorageFactoryOptions {\n dbName?: string;\n storeName?: string;\n sessionKeyPrefix?: string;\n}\n\nexport const resolveStorage = (\n strategy: StorageStrategy | undefined,\n options: StorageFactoryOptions,\n): IconStorage => {\n if (!strategy || strategy === 'indexeddb') {\n return createIndexedDbStorage({\n dbName: options.dbName,\n storeName: options.storeName,\n });\n }\n\n if (strategy === 'memory') {\n return createMemoryStorage();\n }\n\n if (strategy === 'session') {\n return createSessionStorage({ keyPrefix: options.sessionKeyPrefix });\n }\n\n return strategy;\n};\n","import { insertSvg } from './dom';\nimport { createIconlyError } from './errors';\nimport { fetchSvg } from './fetcher';\nimport { err, ok } from './result';\nimport { resolveStorage } from './storage';\nimport type { IconlyConfig, IconlyError, IconlyInstance, IconStorage, Result } from './types';\n\ninterface ResolvedIconlyConfig {\n file: string;\n version: string;\n debug: boolean;\n container?: string | HTMLElement;\n logger?: IconlyConfig['logger'];\n onError?: IconlyConfig['onError'];\n onDebug?: IconlyConfig['onDebug'];\n}\n\nexport const createIconly = (config: IconlyConfig = {}): IconlyInstance => {\n const resolved: ResolvedIconlyConfig = {\n file: config.file ?? './icons.svg',\n version: config.version ?? '1.0',\n debug: config.debug ?? false,\n container: config.container,\n logger: config.logger,\n onError: config.onError,\n onDebug: config.onDebug,\n };\n\n const storage: IconStorage = resolveStorage(config.storage, {\n dbName: config.dbName,\n storeName: config.storeName,\n sessionKeyPrefix: config.sessionKeyPrefix,\n });\n\n let controller: AbortController | null = null;\n\n const abort = (): void => {\n controller?.abort();\n };\n\n const resolveContainer = (): Result<HTMLElement> => {\n if (typeof document === 'undefined') {\n return err(\n createIconlyError('container_invalid', 'Document is not available in this environment.'),\n );\n }\n\n if (typeof resolved.container === 'string') {\n const found = document.querySelector(resolved.container);\n\n if (!found || !(found instanceof HTMLElement)) {\n return err(\n createIconlyError(\n 'container_invalid',\n `Invalid container selector: \"${resolved.container}\".`,\n ),\n );\n }\n\n return ok(found);\n }\n\n if (resolved.container instanceof HTMLElement) {\n return ok(resolved.container);\n }\n\n const fallback = document.body ?? document.documentElement;\n\n if (!fallback) {\n return err(createIconlyError('container_invalid', 'No valid container element found.'));\n }\n\n return ok(fallback);\n };\n\n const logDebug = (...messages: unknown[]): void => {\n if (!resolved.debug) {\n return;\n }\n\n resolved.onDebug?.(...messages);\n resolved.logger?.debug?.('[Iconly debug]', ...messages);\n };\n\n const logError = (error: IconlyError): void => {\n resolved.onError?.(error);\n resolved.logger?.error?.('[Iconly error]', error);\n };\n\n const fail = (error: IconlyError): Result<void> => {\n logError(error);\n\n return err(error);\n };\n\n const init = async (): Promise<Result<void>> => {\n const containerResult = resolveContainer();\n\n if (!containerResult.ok) {\n return fail(containerResult.error);\n }\n\n const cacheResult = await storage.get(resolved.version);\n\n if (!cacheResult.ok) {\n return fail(cacheResult.error);\n }\n\n let data = cacheResult.value?.data;\n\n if (!data) {\n controller = new AbortController();\n\n const fetchResult = await fetchSvg(resolved.file, controller.signal);\n\n if (!fetchResult.ok) {\n return fail(fetchResult.error);\n }\n\n data = fetchResult.value;\n\n const storeResult = await storage.set({\n version: resolved.version,\n data,\n });\n\n if (!storeResult.ok) {\n return fail(storeResult.error);\n }\n } else {\n logDebug('Using cached icon set', resolved.version);\n }\n\n const insertResult = insertSvg(containerResult.value, data);\n\n if (!insertResult.ok) {\n return fail(insertResult.error);\n }\n\n logDebug('Iconly has successfully initialized.');\n\n return ok(undefined);\n };\n\n return { init, abort };\n};\n"],"names":["createIconlyError","code","message","cause","ok","value","err","error","insertSvg","container","data","iconSetDiv","svgDoc","parserError","svgEl","imported","fetchSvg","file","signal","response","createIndexedDbStorage","options","dbName","storeName","dbPromise","openDb","resolve","reject","request","event","db","getStore","mode","toIconlyError","fallbackCode","version","store","record","createMemoryStorage","createSessionStorage","keyPrefix","resolveStorage","storageResult","raw","parsed","strategy","createIconly","config","resolved","storage","controller","abort","resolveContainer","found","fallback","logDebug","messages","_a","_c","_b","logError","fail","containerResult","cacheResult","fetchResult","storeResult","insertResult"],"mappings":"gFAEO,MAAMA,EAAoB,CAC/BC,EACAC,EACAC,KACiB,CACjB,KAAAF,EACA,QAAAC,EACA,MAAAC,CACF,GCRaC,EAASC,IAAyB,CAAE,GAAI,GAAM,MAAAA,CAAA,GAE9CC,EAAkBC,IAAmC,CAAE,GAAI,GAAO,MAAAA,CAAA,GCAlEC,EAAY,CAACC,EAAwBC,IAA+B,CAC/E,IAAIC,EAAa,SAAS,eAAe,SAAS,EAE7CA,IACHA,EAAa,SAAS,cAAc,KAAK,EACzCA,EAAW,GAAK,UAChBA,EAAW,aAAa,cAAe,MAAM,EAC7CA,EAAW,MAAM,QAAU,0DAC3BF,EAAU,YAAYE,CAAU,GAIlC,MAAMC,EADS,IAAI,UAAA,EACG,gBAAgBF,EAAM,eAAe,EACrDG,EAAcD,EAAO,cAAc,aAAa,EAEtD,GAAIC,EACF,OAAOP,EACLN,EACE,cACA,sBAAsBa,EAAY,aAAe,eAAe,EAAA,CAClE,EAIJF,EAAW,UAAY,GAEvB,MAAMG,EAAQF,EAAO,gBAErB,GAAI,CAACE,EACH,OAAOR,EAAIN,EAAkB,cAAe,6BAA6B,CAAC,EAG5E,MAAMe,EAAW,SAAS,WAAWD,EAAO,EAAI,EAEhD,OAAAH,EAAW,YAAYI,CAAQ,EAExBX,EAAG,MAAS,CACrB,ECrCaY,EAAW,MAAOC,EAAcC,IAAkD,CAC7F,GAAI,CACF,MAAMC,EAAW,MAAM,MAAMF,EAAM,CAAE,OAAAC,EAAQ,EAE7C,GAAI,CAACC,EAAS,GACZ,OAAOb,EAAIN,EAAkB,eAAgB,+BAA+BiB,CAAI,IAAI,CAAC,EAGvF,MAAMP,EAAO,MAAMS,EAAS,KAAA,EAE5B,OAAOf,EAAGM,CAAI,CAChB,OAASH,EAAgB,CACvB,OAAIA,aAAiB,cAAgBA,EAAM,OAAS,aAC3CD,EAAIN,EAAkB,gBAAiB,6BAA8BO,CAAK,CAAC,EAG7ED,EAAIN,EAAkB,eAAgB,yBAA0BO,CAAK,CAAC,CAC/E,CACF,ECbaa,EAAyB,CAACC,EAA4B,KAAoB,CACrF,MAAMC,EAASD,EAAQ,QAAU,WAC3BE,EAAYF,EAAQ,WAAa,QAEvC,IAAIG,EAAyC,KAE7C,MAAMC,EAAS,SAAkC,CAC/C,GAAID,EACF,OAAOA,EAGT,GAAI,OAAO,UAAc,IACvB,MAAMxB,EAAkB,0BAA2B,6BAA6B,EAGlF,OAAAwB,EAAY,IAAI,QAAqB,CAACE,EAASC,IAAW,CACxD,MAAMC,EAAU,UAAU,KAAKN,EAAQ,CAAC,EAExCM,EAAQ,QAAU,IAAY,CAC5BD,EACE3B,EACE,wBACA,uCACA4B,EAAQ,KAAA,CACV,CAEJ,EAEAA,EAAQ,gBAAmBC,GAAgB,CACzC,MAAMC,EAAMD,EAAM,OAA4B,OAEzCC,EAAG,iBAAiB,SAASP,CAAS,GACzCO,EAAG,kBAAkBP,EAAW,CAAE,QAAS,UAAW,CAE1D,EAEAK,EAAQ,UAAY,IAAYF,EAAQE,EAAQ,MAAM,CACxD,CAAC,EAEMJ,CACT,EAEMO,EAAW,CAACD,EAAiBE,IACjCF,EAAG,YAAYP,EAAWS,CAAI,EAAE,YAAYT,CAAS,EAEjDU,EAAgB,CACpB1B,EACA2B,EACAhC,IAEIK,GAAS,OAAOA,GAAU,UAAY,SAAUA,GAAS,YAAaA,EACjEA,EAGFP,EAAkBkC,EAAchC,EAASK,CAAK,EAqDvD,MAAO,CAAE,IAlDG,MAAO4B,GAA6D,CAC9E,GAAI,CACF,MAAML,EAAK,MAAML,EAAA,EACXW,EAAQL,EAASD,EAAI,UAAU,EAErC,OAAO,MAAM,IAAI,QAAyCJ,GAAY,CACpE,MAAME,EAAUQ,EAAM,IAAID,CAAO,EAEjCP,EAAQ,UAAY,IAAYF,EAAQtB,EAAGwB,EAAQ,MAAgC,CAAC,EACpFA,EAAQ,QAAU,IAChBF,EACEpB,EACEN,EACE,2BACA,iCACA4B,EAAQ,KAAA,CACV,CACF,CAEN,CAAC,CACH,OAASrB,EAAgB,CACvB,OAAOD,EAAI2B,EAAc1B,EAAO,wBAAyB,2BAA2B,CAAC,CACvF,CACF,EA2Bc,IAzBF,MAAO8B,GAA8C,CAC/D,GAAI,CACF,MAAMP,EAAK,MAAML,EAAA,EACXW,EAAQL,EAASD,EAAI,WAAW,EAEtC,OAAO,MAAM,IAAI,QAAuBJ,GAAY,CAClD,MAAME,EAAUQ,EAAM,IAAIC,CAAM,EAEhCT,EAAQ,UAAY,IAAYF,EAAQtB,EAAG,MAAS,CAAC,EACrDwB,EAAQ,QAAU,IAChBF,EACEpB,EACEN,EACE,2BACA,gCACA4B,EAAQ,KAAA,CACV,CACF,CAEN,CAAC,CACH,OAASrB,EAAgB,CACvB,OAAOD,EAAIN,EAAkB,wBAAyB,4BAA6BO,CAAK,CAAC,CAC3F,CACF,CAEc,CAChB,EClHa+B,EAAsB,IAAmB,CACpD,MAAMF,MAAY,IAgBlB,MAAO,CAAE,IAdG,MAAOD,GACZC,EAAM,IAAID,CAAO,EAIf/B,EAAG,CAAE,QAAA+B,EAAS,KAAMC,EAAM,IAAID,CAAO,GAAK,GAAI,EAH5C/B,EAAG,MAAS,EAYT,IANF,MAAOiC,IACjBD,EAAM,IAAIC,EAAO,QAASA,EAAO,IAAI,EAE9BjC,EAAG,MAAS,EAGP,CAChB,ECbamC,EAAuB,CAAClB,EAAiC,KAAoB,CACxF,MAAMmB,EAAYnB,EAAQ,WAAa,SAEjCoB,EAAiB,IACjB,OAAO,OAAW,KAAe,CAAC,OAAO,eACpCnC,EAAIN,EAAkB,sBAAuB,kCAAkC,CAAC,EAGlFI,EAAG,OAAO,cAAc,EA6CjC,MAAO,CAAE,IA1CG,MAAO+B,GAA6D,CAC9E,MAAMO,EAAgBD,EAAA,EAEtB,GAAI,CAACC,EAAc,GACjB,OAAOA,EAGT,GAAI,CACF,MAAMC,EAAMD,EAAc,MAAM,QAAQ,GAAGF,CAAS,IAAIL,CAAO,EAAE,EAEjE,GAAI,CAACQ,EACH,OAAOvC,EAAG,MAAS,EAGrB,MAAMwC,EAAS,KAAK,MAAMD,CAAG,EAE7B,OAAOvC,EAAGwC,CAAM,CAClB,OAASrC,EAAgB,CACvB,OAAOD,EACLN,EAAkB,sBAAuB,sCAAuCO,CAAK,CAAA,CAEzF,CACF,EAoBc,IAlBF,MAAO8B,GAA8C,CAC/D,MAAMK,EAAgBD,EAAA,EAEtB,GAAI,CAACC,EAAc,GACjB,OAAOA,EAGT,GAAI,CACF,OAAAA,EAAc,MAAM,QAAQ,GAAGF,CAAS,IAAIH,EAAO,OAAO,GAAI,KAAK,UAAUA,CAAM,CAAC,EAE7EjC,EAAG,MAAS,CACrB,OAASG,EAAgB,CACvB,OAAOD,EACLN,EAAkB,uBAAwB,qCAAsCO,CAAK,CAAA,CAEzF,CACF,CAEc,CAChB,ECnDakC,EAAiB,CAC5BI,EACAxB,IAEI,CAACwB,GAAYA,IAAa,YACrBzB,EAAuB,CAC5B,OAAQC,EAAQ,OAChB,UAAWA,EAAQ,SAAA,CACpB,EAGCwB,IAAa,SACRP,EAAA,EAGLO,IAAa,UACRN,EAAqB,CAAE,UAAWlB,EAAQ,iBAAkB,EAG9DwB,ECbIC,EAAe,CAACC,EAAuB,KAAuB,CACzE,MAAMC,EAAiC,CACrC,KAAMD,EAAO,MAAQ,cACrB,QAASA,EAAO,SAAW,MAC3B,MAAOA,EAAO,OAAS,GACvB,UAAWA,EAAO,UAClB,OAAQA,EAAO,OACf,QAASA,EAAO,QAChB,QAASA,EAAO,OAAA,EAGZE,EAAuBR,EAAeM,EAAO,QAAS,CAC1D,OAAQA,EAAO,OACf,UAAWA,EAAO,UAClB,iBAAkBA,EAAO,gBAAA,CAC1B,EAED,IAAIG,EAAqC,KAEzC,MAAMC,EAAQ,IAAY,CACxBD,GAAA,MAAAA,EAAY,OACd,EAEME,EAAmB,IAA2B,CAClD,GAAI,OAAO,SAAa,IACtB,OAAO9C,EACLN,EAAkB,oBAAqB,gDAAgD,CAAA,EAI3F,GAAI,OAAOgD,EAAS,WAAc,SAAU,CAC1C,MAAMK,EAAQ,SAAS,cAAcL,EAAS,SAAS,EAEvD,MAAI,CAACK,GAAS,EAAEA,aAAiB,aACxB/C,EACLN,EACE,oBACA,gCAAgCgD,EAAS,SAAS,IAAA,CACpD,EAIG5C,EAAGiD,CAAK,CACjB,CAEA,GAAIL,EAAS,qBAAqB,YAChC,OAAO5C,EAAG4C,EAAS,SAAS,EAG9B,MAAMM,EAAW,SAAS,MAAQ,SAAS,gBAE3C,OAAKA,EAIElD,EAAGkD,CAAQ,EAHThD,EAAIN,EAAkB,oBAAqB,mCAAmC,CAAC,CAI1F,EAEMuD,EAAW,IAAIC,IAA8B,WAC5CR,EAAS,SAIdS,EAAAT,EAAS,UAAT,MAAAS,EAAA,KAAAT,EAAmB,GAAGQ,IACtBE,GAAAC,EAAAX,EAAS,SAAT,YAAAW,EAAiB,QAAjB,MAAAD,EAAA,KAAAC,EAAyB,iBAAkB,GAAGH,GAChD,EAEMI,EAAYrD,GAA6B,YAC7CkD,EAAAT,EAAS,UAAT,MAAAS,EAAA,KAAAT,EAAmBzC,IACnBmD,GAAAC,EAAAX,EAAS,SAAT,YAAAW,EAAiB,QAAjB,MAAAD,EAAA,KAAAC,EAAyB,iBAAkBpD,EAC7C,EAEMsD,EAAQtD,IACZqD,EAASrD,CAAK,EAEPD,EAAIC,CAAK,GAoDlB,MAAO,CAAE,KAjDI,SAAmC,OAC9C,MAAMuD,EAAkBV,EAAA,EAExB,GAAI,CAACU,EAAgB,GACnB,OAAOD,EAAKC,EAAgB,KAAK,EAGnC,MAAMC,EAAc,MAAMd,EAAQ,IAAID,EAAS,OAAO,EAEtD,GAAI,CAACe,EAAY,GACf,OAAOF,EAAKE,EAAY,KAAK,EAG/B,IAAIrD,GAAO+C,EAAAM,EAAY,QAAZ,YAAAN,EAAmB,KAE9B,GAAK/C,EAoBH6C,EAAS,wBAAyBP,EAAS,OAAO,MApBzC,CACTE,EAAa,IAAI,gBAEjB,MAAMc,EAAc,MAAMhD,EAASgC,EAAS,KAAME,EAAW,MAAM,EAEnE,GAAI,CAACc,EAAY,GACf,OAAOH,EAAKG,EAAY,KAAK,EAG/BtD,EAAOsD,EAAY,MAEnB,MAAMC,EAAc,MAAMhB,EAAQ,IAAI,CACpC,QAASD,EAAS,QAClB,KAAAtC,CAAA,CACD,EAED,GAAI,CAACuD,EAAY,GACf,OAAOJ,EAAKI,EAAY,KAAK,CAEjC,CAIA,MAAMC,EAAe1D,EAAUsD,EAAgB,MAAOpD,CAAI,EAE1D,OAAKwD,EAAa,IAIlBX,EAAS,sCAAsC,EAExCnD,EAAG,MAAS,GALVyD,EAAKK,EAAa,KAAK,CAMlC,EAEe,MAAAf,CAAA,CACjB"}
package/dist/index.d.ts CHANGED
@@ -1,25 +1,3 @@
1
- export interface IconlyOptions {
2
- file?: string;
3
- version?: string;
4
- debug?: boolean;
5
- container?: string | HTMLElement;
6
- }
7
- export interface IconRecord {
8
- version: string;
9
- data: string;
10
- }
11
- declare class Iconly {
12
- private static dbInstance;
13
- private readonly options;
14
- private readonly container;
15
- constructor(options?: IconlyOptions);
16
- private openDB;
17
- private getIconStore;
18
- private static fetchData;
19
- private insert;
20
- init(): Promise<void>;
21
- private createErrorMessage;
22
- private logDebug;
23
- private logError;
24
- }
25
- export default Iconly;
1
+ export { createIconly } from './core';
2
+ export type { IconlyConfig, IconlyError, IconlyErrorCode, IconlyInstance, IconRecord, IconStorage, Logger, Result, StorageStrategy, } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,YAAY,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,cAAc,EACd,UAAU,EACV,WAAW,EACX,MAAM,EACN,MAAM,EACN,eAAe,GAChB,MAAM,SAAS,CAAC"}
package/dist/index.es.js CHANGED
@@ -1,100 +1,201 @@
1
- var g = Object.defineProperty;
2
- var h = (d, r, e) => r in d ? g(d, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : d[r] = e;
3
- var l = (d, r, e) => h(d, typeof r != "symbol" ? r + "" : r, e);
4
- const a = class a {
5
- constructor(r = {}) {
6
- l(this, "options");
7
- l(this, "container");
8
- const e = { file: "./icons.svg", version: "1.0", debug: !1, container: document.body ?? document.documentElement, ...r };
9
- let n;
10
- if (typeof e.container == "string") {
11
- const i = document.querySelector(e.container);
12
- if (!(i && i instanceof HTMLElement)) throw new Error(`Invalid container selector: "${e.container}"`);
13
- n = i;
14
- } else n = e.container;
15
- this.container = n, this.options = { file: e.file, version: e.version, debug: e.debug }, a.dbInstance || (a.dbInstance = this.openDB("iconlyDB", 1));
1
+ const c = (e, t, r) => ({
2
+ code: e,
3
+ message: t,
4
+ cause: r
5
+ }), f = (e) => ({ ok: !0, value: e }), d = (e) => ({ ok: !1, error: e }), x = (e, t) => {
6
+ let r = document.getElementById("iconset");
7
+ r || (r = document.createElement("div"), r.id = "iconset", r.setAttribute("aria-hidden", "true"), r.style.cssText = "width: 0; height: 0; position: absolute; left: -9999px;", e.appendChild(r));
8
+ const b = new DOMParser().parseFromString(t, "image/svg+xml"), g = b.querySelector("parsererror");
9
+ if (g)
10
+ return d(
11
+ c(
12
+ "parse_error",
13
+ `SVG parsing error: ${g.textContent ?? "Unknown error"}`
14
+ )
15
+ );
16
+ r.innerHTML = "";
17
+ const u = b.documentElement;
18
+ if (!u)
19
+ return d(c("parse_error", "No valid SVG content found."));
20
+ const m = document.importNode(u, !0);
21
+ return r.appendChild(m), f(void 0);
22
+ }, S = async (e, t) => {
23
+ try {
24
+ const r = await fetch(e, { signal: t });
25
+ if (!r.ok)
26
+ return d(c("fetch_failed", `Failed to fetch icons from "${e}".`));
27
+ const i = await r.text();
28
+ return f(i);
29
+ } catch (r) {
30
+ return r instanceof DOMException && r.name === "AbortError" ? d(c("fetch_aborted", "Fetch request was aborted.", r)) : d(c("fetch_failed", "Failed to fetch icons.", r));
16
31
  }
17
- async openDB(r, e) {
18
- if (!("indexedDB" in window)) throw this.logError("This browser does not support IndexedDB"), new Error("IndexedDB not supported");
19
- return await new Promise((n, i) => {
20
- const o = indexedDB.open(r, e);
32
+ }, h = (e = {}) => {
33
+ const t = e.dbName ?? "iconlyDB", r = e.storeName ?? "icons";
34
+ let i = null;
35
+ const b = async () => {
36
+ if (i)
37
+ return i;
38
+ if (typeof indexedDB > "u")
39
+ throw c("indexeddb_not_supported", "IndexedDB is not supported.");
40
+ return i = new Promise((l, n) => {
41
+ const o = indexedDB.open(t, 1);
21
42
  o.onerror = () => {
22
- const s = this.createErrorMessage(o.error, "IndexedDB error");
23
- i(new Error(s));
43
+ n(
44
+ c(
45
+ "indexeddb_open_failed",
46
+ "Failed to open IndexedDB connection.",
47
+ o.error
48
+ )
49
+ );
24
50
  }, o.onupgradeneeded = (s) => {
25
- const t = s.target.result;
26
- t.objectStoreNames.contains("icons") || t.createObjectStore("icons", { keyPath: "version" });
27
- }, o.onsuccess = () => {
28
- n(o.result);
29
- };
30
- });
31
- }
32
- getIconStore(r, e) {
33
- return r.transaction("icons", e).objectStore("icons");
34
- }
35
- static async fetchData(r) {
36
- const e = await fetch(r);
37
- if (!e.ok) throw new Error(`Failed to fetch icons from "${r}"`);
38
- return e.text();
39
- }
40
- insert(r) {
41
- let e = document.getElementById("iconset");
42
- e || (e = document.createElement("div"), e.id = "iconset", e.setAttribute("aria-hidden", "true"), e.style.cssText = "width: 0; height: 0; position: absolute; left: -9999px;", this.container.appendChild(e));
43
- const n = new DOMParser().parseFromString(r, "image/svg+xml"), i = n.querySelector("parsererror");
44
- if (i) return void this.logError("SVG parsing error:", i.textContent ?? "");
45
- e.innerHTML = "";
46
- const o = n.documentElement;
47
- if (o) {
48
- const s = document.importNode(o, !0);
49
- e.appendChild(s);
50
- } else this.logError("No valid SVG content found to insert.");
51
- }
52
- async init() {
51
+ const a = s.target.result;
52
+ a.objectStoreNames.contains(r) || a.createObjectStore(r, { keyPath: "version" });
53
+ }, o.onsuccess = () => l(o.result);
54
+ }), i;
55
+ }, g = (l, n) => l.transaction(r, n).objectStore(r), u = (l, n, o) => l && typeof l == "object" && "code" in l && "message" in l ? l : c(n, o, l);
56
+ return { get: async (l) => {
53
57
  try {
54
- let r = await a.fetchData(this.options.file);
55
- const e = await a.dbInstance;
56
- if (!e) throw new Error("Failed to open IndexedDB");
57
- const n = this.getIconStore(e, "readwrite"), i = await new Promise((o, s) => {
58
- const t = n.get(this.options.version);
59
- t.onsuccess = () => {
60
- o(t.result);
61
- }, t.onerror = () => {
62
- const c = this.createErrorMessage(t.error, "Error getting record from store");
63
- s(new Error(c));
64
- };
58
+ const n = await b(), o = g(n, "readonly");
59
+ return await new Promise((s) => {
60
+ const a = o.get(l);
61
+ a.onsuccess = () => s(f(a.result)), a.onerror = () => s(
62
+ d(
63
+ c(
64
+ "indexeddb_request_failed",
65
+ "Failed to read from IndexedDB.",
66
+ a.error
67
+ )
68
+ )
69
+ );
65
70
  });
66
- i ? r = i.data : await new Promise((o, s) => {
67
- const t = n.put({ version: this.options.version, data: r });
68
- t.onsuccess = () => o(), t.onerror = () => {
69
- const c = this.createErrorMessage(t.error, "Error putting record into store");
70
- s(new Error(c));
71
- };
72
- }), await new Promise((o, s) => {
73
- const t = n.transaction;
74
- t.oncomplete = () => o(), t.onerror = () => {
75
- const c = this.createErrorMessage(t.error, "Transaction error");
76
- s(new Error(c));
77
- }, t.onabort = () => {
78
- const c = this.createErrorMessage(t.error, "Transaction aborted");
79
- s(new Error(c));
80
- };
81
- }), this.insert(r), this.logDebug("Iconly has successfully initialized.");
82
- } catch (r) {
83
- const e = r instanceof Error ? r : new Error(String(r));
84
- this.logError("Error initializing Iconly:", e.message);
71
+ } catch (n) {
72
+ return d(u(n, "indexeddb_open_failed", "Failed to open IndexedDB."));
85
73
  }
86
- }
87
- createErrorMessage(r, e) {
88
- return r && (r instanceof DOMException || r instanceof Error) && r.message || e;
89
- }
90
- logDebug(...r) {
91
- this.options.debug;
92
- }
93
- logError(...r) {
94
- }
74
+ }, set: async (l) => {
75
+ try {
76
+ const n = await b(), o = g(n, "readwrite");
77
+ return await new Promise((s) => {
78
+ const a = o.put(l);
79
+ a.onsuccess = () => s(f(void 0)), a.onerror = () => s(
80
+ d(
81
+ c(
82
+ "indexeddb_request_failed",
83
+ "Failed to write to IndexedDB.",
84
+ a.error
85
+ )
86
+ )
87
+ );
88
+ });
89
+ } catch (n) {
90
+ return d(c("indexeddb_open_failed", "Failed to open IndexedDB.", n));
91
+ }
92
+ } };
93
+ }, _ = () => {
94
+ const e = /* @__PURE__ */ new Map();
95
+ return { get: async (i) => e.has(i) ? f({ version: i, data: e.get(i) ?? "" }) : f(void 0), set: async (i) => (e.set(i.version, i.data), f(void 0)) };
96
+ }, D = (e = {}) => {
97
+ const t = e.keyPrefix ?? "iconly", r = () => typeof window > "u" || !window.sessionStorage ? d(c("storage_unavailable", "SessionStorage is not available.")) : f(window.sessionStorage);
98
+ return { get: async (g) => {
99
+ const u = r();
100
+ if (!u.ok)
101
+ return u;
102
+ try {
103
+ const m = u.value.getItem(`${t}:${g}`);
104
+ if (!m)
105
+ return f(void 0);
106
+ const y = JSON.parse(m);
107
+ return f(y);
108
+ } catch (m) {
109
+ return d(
110
+ c("storage_read_failed", "Failed to read from SessionStorage.", m)
111
+ );
112
+ }
113
+ }, set: async (g) => {
114
+ const u = r();
115
+ if (!u.ok)
116
+ return u;
117
+ try {
118
+ return u.value.setItem(`${t}:${g.version}`, JSON.stringify(g)), f(void 0);
119
+ } catch (m) {
120
+ return d(
121
+ c("storage_write_failed", "Failed to write to SessionStorage.", m)
122
+ );
123
+ }
124
+ } };
125
+ }, N = (e, t) => !e || e === "indexeddb" ? h({
126
+ dbName: t.dbName,
127
+ storeName: t.storeName
128
+ }) : e === "memory" ? _() : e === "session" ? D({ keyPrefix: t.sessionKeyPrefix }) : e, k = (e = {}) => {
129
+ const t = {
130
+ file: e.file ?? "./icons.svg",
131
+ version: e.version ?? "1.0",
132
+ debug: e.debug ?? !1,
133
+ container: e.container,
134
+ logger: e.logger,
135
+ onError: e.onError,
136
+ onDebug: e.onDebug
137
+ }, r = N(e.storage, {
138
+ dbName: e.dbName,
139
+ storeName: e.storeName,
140
+ sessionKeyPrefix: e.sessionKeyPrefix
141
+ });
142
+ let i = null;
143
+ const b = () => {
144
+ i == null || i.abort();
145
+ }, g = () => {
146
+ if (typeof document > "u")
147
+ return d(
148
+ c("container_invalid", "Document is not available in this environment.")
149
+ );
150
+ if (typeof t.container == "string") {
151
+ const o = document.querySelector(t.container);
152
+ return !o || !(o instanceof HTMLElement) ? d(
153
+ c(
154
+ "container_invalid",
155
+ `Invalid container selector: "${t.container}".`
156
+ )
157
+ ) : f(o);
158
+ }
159
+ if (t.container instanceof HTMLElement)
160
+ return f(t.container);
161
+ const n = document.body ?? document.documentElement;
162
+ return n ? f(n) : d(c("container_invalid", "No valid container element found."));
163
+ }, u = (...n) => {
164
+ var o, s, a;
165
+ t.debug && ((o = t.onDebug) == null || o.call(t, ...n), (a = (s = t.logger) == null ? void 0 : s.debug) == null || a.call(s, "[Iconly debug]", ...n));
166
+ }, m = (n) => {
167
+ var o, s, a;
168
+ (o = t.onError) == null || o.call(t, n), (a = (s = t.logger) == null ? void 0 : s.error) == null || a.call(s, "[Iconly error]", n);
169
+ }, y = (n) => (m(n), d(n));
170
+ return { init: async () => {
171
+ var v;
172
+ const n = g();
173
+ if (!n.ok)
174
+ return y(n.error);
175
+ const o = await r.get(t.version);
176
+ if (!o.ok)
177
+ return y(o.error);
178
+ let s = (v = o.value) == null ? void 0 : v.data;
179
+ if (s)
180
+ u("Using cached icon set", t.version);
181
+ else {
182
+ i = new AbortController();
183
+ const p = await S(t.file, i.signal);
184
+ if (!p.ok)
185
+ return y(p.error);
186
+ s = p.value;
187
+ const w = await r.set({
188
+ version: t.version,
189
+ data: s
190
+ });
191
+ if (!w.ok)
192
+ return y(w.error);
193
+ }
194
+ const a = x(n.value, s);
195
+ return a.ok ? (u("Iconly has successfully initialized."), f(void 0)) : y(a.error);
196
+ }, abort: b };
95
197
  };
96
- l(a, "dbInstance", null);
97
- let u = a;
98
198
  export {
99
- u as default
199
+ k as createIconly
100
200
  };
201
+ //# sourceMappingURL=index.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.es.js","sources":["../src/errors.ts","../src/result.ts","../src/dom.ts","../src/fetcher.ts","../src/storage/indexeddb.ts","../src/storage/memory.ts","../src/storage/session.ts","../src/storage/index.ts","../src/core.ts"],"sourcesContent":["import type { IconlyError, IconlyErrorCode } from './types';\n\nexport const createIconlyError = (\n code: IconlyErrorCode,\n message: string,\n cause?: unknown,\n): IconlyError => ({\n code,\n message,\n cause,\n});\n","import type { IconlyError, Result } from './types';\n\nexport const ok = <T>(value: T): Result<T> => ({ ok: true, value });\n\nexport const err = <T = never>(error: IconlyError): Result<T> => ({ ok: false, error });\n","import { createIconlyError } from './errors';\nimport { err, ok } from './result';\nimport type { Result } from './types';\n\nexport const insertSvg = (container: HTMLElement, data: string): Result<void> => {\n let iconSetDiv = document.getElementById('iconset');\n\n if (!iconSetDiv) {\n iconSetDiv = document.createElement('div');\n iconSetDiv.id = 'iconset';\n iconSetDiv.setAttribute('aria-hidden', 'true');\n iconSetDiv.style.cssText = 'width: 0; height: 0; position: absolute; left: -9999px;';\n container.appendChild(iconSetDiv);\n }\n\n const parser = new DOMParser();\n const svgDoc = parser.parseFromString(data, 'image/svg+xml');\n const parserError = svgDoc.querySelector('parsererror');\n\n if (parserError) {\n return err(\n createIconlyError(\n 'parse_error',\n `SVG parsing error: ${parserError.textContent ?? 'Unknown error'}`,\n ),\n );\n }\n\n iconSetDiv.innerHTML = '';\n\n const svgEl = svgDoc.documentElement;\n\n if (!svgEl) {\n return err(createIconlyError('parse_error', 'No valid SVG content found.'));\n }\n\n const imported = document.importNode(svgEl, true);\n\n iconSetDiv.appendChild(imported);\n\n return ok(undefined);\n};\n","import { createIconlyError } from './errors';\nimport { err, ok } from './result';\nimport type { Result } from './types';\n\nexport const fetchSvg = async (file: string, signal?: AbortSignal): Promise<Result<string>> => {\n try {\n const response = await fetch(file, { signal });\n\n if (!response.ok) {\n return err(createIconlyError('fetch_failed', `Failed to fetch icons from \"${file}\".`));\n }\n\n const data = await response.text();\n\n return ok(data);\n } catch (error: unknown) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n return err(createIconlyError('fetch_aborted', 'Fetch request was aborted.', error));\n }\n\n return err(createIconlyError('fetch_failed', 'Failed to fetch icons.', error));\n }\n};\n","import { createIconlyError } from '../errors';\nimport { err, ok } from '../result';\nimport type { IconlyError, IconRecord, IconStorage, Result } from '../types';\n\ninterface IndexedDbOptions {\n dbName?: string;\n storeName?: string;\n}\n\nexport const createIndexedDbStorage = (options: IndexedDbOptions = {}): IconStorage => {\n const dbName = options.dbName ?? 'iconlyDB';\n const storeName = options.storeName ?? 'icons';\n\n let dbPromise: Promise<IDBDatabase> | null = null;\n\n const openDb = async (): Promise<IDBDatabase> => {\n if (dbPromise) {\n return dbPromise;\n }\n\n if (typeof indexedDB === 'undefined') {\n throw createIconlyError('indexeddb_not_supported', 'IndexedDB is not supported.');\n }\n\n dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDB.open(dbName, 1);\n\n request.onerror = (): void => {\n reject(\n createIconlyError(\n 'indexeddb_open_failed',\n 'Failed to open IndexedDB connection.',\n request.error,\n ),\n );\n };\n\n request.onupgradeneeded = (event): void => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName, { keyPath: 'version' });\n }\n };\n\n request.onsuccess = (): void => resolve(request.result);\n });\n\n return dbPromise;\n };\n\n const getStore = (db: IDBDatabase, mode: IDBTransactionMode): IDBObjectStore =>\n db.transaction(storeName, mode).objectStore(storeName);\n\n const toIconlyError = (\n error: unknown,\n fallbackCode: IconlyError['code'],\n message: string,\n ): IconlyError => {\n if (error && typeof error === 'object' && 'code' in error && 'message' in error) {\n return error as IconlyError;\n }\n\n return createIconlyError(fallbackCode, message, error);\n };\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n try {\n const db = await openDb();\n const store = getStore(db, 'readonly');\n\n return await new Promise<Result<IconRecord | undefined>>((resolve) => {\n const request = store.get(version);\n\n request.onsuccess = (): void => resolve(ok(request.result as IconRecord | undefined));\n request.onerror = (): void =>\n resolve(\n err(\n createIconlyError(\n 'indexeddb_request_failed',\n 'Failed to read from IndexedDB.',\n request.error,\n ),\n ),\n );\n });\n } catch (error: unknown) {\n return err(toIconlyError(error, 'indexeddb_open_failed', 'Failed to open IndexedDB.'));\n }\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n try {\n const db = await openDb();\n const store = getStore(db, 'readwrite');\n\n return await new Promise<Result<void>>((resolve) => {\n const request = store.put(record);\n\n request.onsuccess = (): void => resolve(ok(undefined));\n request.onerror = (): void =>\n resolve(\n err(\n createIconlyError(\n 'indexeddb_request_failed',\n 'Failed to write to IndexedDB.',\n request.error,\n ),\n ),\n );\n });\n } catch (error: unknown) {\n return err(createIconlyError('indexeddb_open_failed', 'Failed to open IndexedDB.', error));\n }\n };\n\n return { get, set };\n};\n","import { ok } from '../result';\nimport type { IconRecord, IconStorage, Result } from '../types';\n\nexport const createMemoryStorage = (): IconStorage => {\n const store = new Map<string, string>();\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n if (!store.has(version)) {\n return ok(undefined);\n }\n\n return ok({ version, data: store.get(version) ?? '' });\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n store.set(record.version, record.data);\n\n return ok(undefined);\n };\n\n return { get, set };\n};\n","import { createIconlyError } from '../errors';\nimport { err, ok } from '../result';\nimport type { IconRecord, IconStorage, Result } from '../types';\n\ninterface SessionStorageOptions {\n keyPrefix?: string;\n}\n\nexport const createSessionStorage = (options: SessionStorageOptions = {}): IconStorage => {\n const keyPrefix = options.keyPrefix ?? 'iconly';\n\n const resolveStorage = (): Result<Storage> => {\n if (typeof window === 'undefined' || !window.sessionStorage) {\n return err(createIconlyError('storage_unavailable', 'SessionStorage is not available.'));\n }\n\n return ok(window.sessionStorage);\n };\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n const storageResult = resolveStorage();\n\n if (!storageResult.ok) {\n return storageResult;\n }\n\n try {\n const raw = storageResult.value.getItem(`${keyPrefix}:${version}`);\n\n if (!raw) {\n return ok(undefined);\n }\n\n const parsed = JSON.parse(raw) as IconRecord;\n\n return ok(parsed);\n } catch (error: unknown) {\n return err(\n createIconlyError('storage_read_failed', 'Failed to read from SessionStorage.', error),\n );\n }\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n const storageResult = resolveStorage();\n\n if (!storageResult.ok) {\n return storageResult;\n }\n\n try {\n storageResult.value.setItem(`${keyPrefix}:${record.version}`, JSON.stringify(record));\n\n return ok(undefined);\n } catch (error: unknown) {\n return err(\n createIconlyError('storage_write_failed', 'Failed to write to SessionStorage.', error),\n );\n }\n };\n\n return { get, set };\n};\n","import type { IconStorage, StorageStrategy } from '../types';\nimport { createIndexedDbStorage } from './indexeddb';\nimport { createMemoryStorage } from './memory';\nimport { createSessionStorage } from './session';\n\nexport interface StorageFactoryOptions {\n dbName?: string;\n storeName?: string;\n sessionKeyPrefix?: string;\n}\n\nexport const resolveStorage = (\n strategy: StorageStrategy | undefined,\n options: StorageFactoryOptions,\n): IconStorage => {\n if (!strategy || strategy === 'indexeddb') {\n return createIndexedDbStorage({\n dbName: options.dbName,\n storeName: options.storeName,\n });\n }\n\n if (strategy === 'memory') {\n return createMemoryStorage();\n }\n\n if (strategy === 'session') {\n return createSessionStorage({ keyPrefix: options.sessionKeyPrefix });\n }\n\n return strategy;\n};\n","import { insertSvg } from './dom';\nimport { createIconlyError } from './errors';\nimport { fetchSvg } from './fetcher';\nimport { err, ok } from './result';\nimport { resolveStorage } from './storage';\nimport type { IconlyConfig, IconlyError, IconlyInstance, IconStorage, Result } from './types';\n\ninterface ResolvedIconlyConfig {\n file: string;\n version: string;\n debug: boolean;\n container?: string | HTMLElement;\n logger?: IconlyConfig['logger'];\n onError?: IconlyConfig['onError'];\n onDebug?: IconlyConfig['onDebug'];\n}\n\nexport const createIconly = (config: IconlyConfig = {}): IconlyInstance => {\n const resolved: ResolvedIconlyConfig = {\n file: config.file ?? './icons.svg',\n version: config.version ?? '1.0',\n debug: config.debug ?? false,\n container: config.container,\n logger: config.logger,\n onError: config.onError,\n onDebug: config.onDebug,\n };\n\n const storage: IconStorage = resolveStorage(config.storage, {\n dbName: config.dbName,\n storeName: config.storeName,\n sessionKeyPrefix: config.sessionKeyPrefix,\n });\n\n let controller: AbortController | null = null;\n\n const abort = (): void => {\n controller?.abort();\n };\n\n const resolveContainer = (): Result<HTMLElement> => {\n if (typeof document === 'undefined') {\n return err(\n createIconlyError('container_invalid', 'Document is not available in this environment.'),\n );\n }\n\n if (typeof resolved.container === 'string') {\n const found = document.querySelector(resolved.container);\n\n if (!found || !(found instanceof HTMLElement)) {\n return err(\n createIconlyError(\n 'container_invalid',\n `Invalid container selector: \"${resolved.container}\".`,\n ),\n );\n }\n\n return ok(found);\n }\n\n if (resolved.container instanceof HTMLElement) {\n return ok(resolved.container);\n }\n\n const fallback = document.body ?? document.documentElement;\n\n if (!fallback) {\n return err(createIconlyError('container_invalid', 'No valid container element found.'));\n }\n\n return ok(fallback);\n };\n\n const logDebug = (...messages: unknown[]): void => {\n if (!resolved.debug) {\n return;\n }\n\n resolved.onDebug?.(...messages);\n resolved.logger?.debug?.('[Iconly debug]', ...messages);\n };\n\n const logError = (error: IconlyError): void => {\n resolved.onError?.(error);\n resolved.logger?.error?.('[Iconly error]', error);\n };\n\n const fail = (error: IconlyError): Result<void> => {\n logError(error);\n\n return err(error);\n };\n\n const init = async (): Promise<Result<void>> => {\n const containerResult = resolveContainer();\n\n if (!containerResult.ok) {\n return fail(containerResult.error);\n }\n\n const cacheResult = await storage.get(resolved.version);\n\n if (!cacheResult.ok) {\n return fail(cacheResult.error);\n }\n\n let data = cacheResult.value?.data;\n\n if (!data) {\n controller = new AbortController();\n\n const fetchResult = await fetchSvg(resolved.file, controller.signal);\n\n if (!fetchResult.ok) {\n return fail(fetchResult.error);\n }\n\n data = fetchResult.value;\n\n const storeResult = await storage.set({\n version: resolved.version,\n data,\n });\n\n if (!storeResult.ok) {\n return fail(storeResult.error);\n }\n } else {\n logDebug('Using cached icon set', resolved.version);\n }\n\n const insertResult = insertSvg(containerResult.value, data);\n\n if (!insertResult.ok) {\n return fail(insertResult.error);\n }\n\n logDebug('Iconly has successfully initialized.');\n\n return ok(undefined);\n };\n\n return { init, abort };\n};\n"],"names":["createIconlyError","code","message","cause","ok","value","err","error","insertSvg","container","data","iconSetDiv","svgDoc","parserError","svgEl","imported","fetchSvg","file","signal","response","createIndexedDbStorage","options","dbName","storeName","dbPromise","openDb","resolve","reject","request","event","db","getStore","mode","toIconlyError","fallbackCode","version","store","record","createMemoryStorage","createSessionStorage","keyPrefix","resolveStorage","storageResult","raw","parsed","strategy","createIconly","config","resolved","storage","controller","abort","resolveContainer","found","fallback","logDebug","messages","_a","_b","_c","logError","fail","containerResult","cacheResult","fetchResult","storeResult","insertResult"],"mappings":"AAEO,MAAMA,IAAoB,CAC/BC,GACAC,GACAC,OACiB;AAAA,EACjB,MAAAF;AAAA,EACA,SAAAC;AAAA,EACA,OAAAC;AACF,ICRaC,IAAK,CAAIC,OAAyB,EAAE,IAAI,IAAM,OAAAA,EAAA,IAE9CC,IAAM,CAAYC,OAAmC,EAAE,IAAI,IAAO,OAAAA,EAAA,ICAlEC,IAAY,CAACC,GAAwBC,MAA+B;AAC/E,MAAIC,IAAa,SAAS,eAAe,SAAS;AAElD,EAAKA,MACHA,IAAa,SAAS,cAAc,KAAK,GACzCA,EAAW,KAAK,WAChBA,EAAW,aAAa,eAAe,MAAM,GAC7CA,EAAW,MAAM,UAAU,2DAC3BF,EAAU,YAAYE,CAAU;AAIlC,QAAMC,IADS,IAAI,UAAA,EACG,gBAAgBF,GAAM,eAAe,GACrDG,IAAcD,EAAO,cAAc,aAAa;AAEtD,MAAIC;AACF,WAAOP;AAAA,MACLN;AAAA,QACE;AAAA,QACA,sBAAsBa,EAAY,eAAe,eAAe;AAAA,MAAA;AAAA,IAClE;AAIJ,EAAAF,EAAW,YAAY;AAEvB,QAAMG,IAAQF,EAAO;AAErB,MAAI,CAACE;AACH,WAAOR,EAAIN,EAAkB,eAAe,6BAA6B,CAAC;AAG5E,QAAMe,IAAW,SAAS,WAAWD,GAAO,EAAI;AAEhD,SAAAH,EAAW,YAAYI,CAAQ,GAExBX,EAAG,MAAS;AACrB,GCrCaY,IAAW,OAAOC,GAAcC,MAAkD;AAC7F,MAAI;AACF,UAAMC,IAAW,MAAM,MAAMF,GAAM,EAAE,QAAAC,GAAQ;AAE7C,QAAI,CAACC,EAAS;AACZ,aAAOb,EAAIN,EAAkB,gBAAgB,+BAA+BiB,CAAI,IAAI,CAAC;AAGvF,UAAMP,IAAO,MAAMS,EAAS,KAAA;AAE5B,WAAOf,EAAGM,CAAI;AAAA,EAChB,SAASH,GAAgB;AACvB,WAAIA,aAAiB,gBAAgBA,EAAM,SAAS,eAC3CD,EAAIN,EAAkB,iBAAiB,8BAA8BO,CAAK,CAAC,IAG7ED,EAAIN,EAAkB,gBAAgB,0BAA0BO,CAAK,CAAC;AAAA,EAC/E;AACF,GCbaa,IAAyB,CAACC,IAA4B,OAAoB;AACrF,QAAMC,IAASD,EAAQ,UAAU,YAC3BE,IAAYF,EAAQ,aAAa;AAEvC,MAAIG,IAAyC;AAE7C,QAAMC,IAAS,YAAkC;AAC/C,QAAID;AACF,aAAOA;AAGT,QAAI,OAAO,YAAc;AACvB,YAAMxB,EAAkB,2BAA2B,6BAA6B;AAGlF,WAAAwB,IAAY,IAAI,QAAqB,CAACE,GAASC,MAAW;AACxD,YAAMC,IAAU,UAAU,KAAKN,GAAQ,CAAC;AAExC,MAAAM,EAAQ,UAAU,MAAY;AAC5B,QAAAD;AAAA,UACE3B;AAAA,YACE;AAAA,YACA;AAAA,YACA4B,EAAQ;AAAA,UAAA;AAAA,QACV;AAAA,MAEJ,GAEAA,EAAQ,kBAAkB,CAACC,MAAgB;AACzC,cAAMC,IAAMD,EAAM,OAA4B;AAE9C,QAAKC,EAAG,iBAAiB,SAASP,CAAS,KACzCO,EAAG,kBAAkBP,GAAW,EAAE,SAAS,WAAW;AAAA,MAE1D,GAEAK,EAAQ,YAAY,MAAYF,EAAQE,EAAQ,MAAM;AAAA,IACxD,CAAC,GAEMJ;AAAA,EACT,GAEMO,IAAW,CAACD,GAAiBE,MACjCF,EAAG,YAAYP,GAAWS,CAAI,EAAE,YAAYT,CAAS,GAEjDU,IAAgB,CACpB1B,GACA2B,GACAhC,MAEIK,KAAS,OAAOA,KAAU,YAAY,UAAUA,KAAS,aAAaA,IACjEA,IAGFP,EAAkBkC,GAAchC,GAASK,CAAK;AAqDvD,SAAO,EAAE,KAlDG,OAAO4B,MAA6D;AAC9E,QAAI;AACF,YAAML,IAAK,MAAML,EAAA,GACXW,IAAQL,EAASD,GAAI,UAAU;AAErC,aAAO,MAAM,IAAI,QAAwC,CAACJ,MAAY;AACpE,cAAME,IAAUQ,EAAM,IAAID,CAAO;AAEjC,QAAAP,EAAQ,YAAY,MAAYF,EAAQtB,EAAGwB,EAAQ,MAAgC,CAAC,GACpFA,EAAQ,UAAU,MAChBF;AAAA,UACEpB;AAAA,YACEN;AAAA,cACE;AAAA,cACA;AAAA,cACA4B,EAAQ;AAAA,YAAA;AAAA,UACV;AAAA,QACF;AAAA,MAEN,CAAC;AAAA,IACH,SAASrB,GAAgB;AACvB,aAAOD,EAAI2B,EAAc1B,GAAO,yBAAyB,2BAA2B,CAAC;AAAA,IACvF;AAAA,EACF,GA2Bc,KAzBF,OAAO8B,MAA8C;AAC/D,QAAI;AACF,YAAMP,IAAK,MAAML,EAAA,GACXW,IAAQL,EAASD,GAAI,WAAW;AAEtC,aAAO,MAAM,IAAI,QAAsB,CAACJ,MAAY;AAClD,cAAME,IAAUQ,EAAM,IAAIC,CAAM;AAEhC,QAAAT,EAAQ,YAAY,MAAYF,EAAQtB,EAAG,MAAS,CAAC,GACrDwB,EAAQ,UAAU,MAChBF;AAAA,UACEpB;AAAA,YACEN;AAAA,cACE;AAAA,cACA;AAAA,cACA4B,EAAQ;AAAA,YAAA;AAAA,UACV;AAAA,QACF;AAAA,MAEN,CAAC;AAAA,IACH,SAASrB,GAAgB;AACvB,aAAOD,EAAIN,EAAkB,yBAAyB,6BAA6BO,CAAK,CAAC;AAAA,IAC3F;AAAA,EACF,EAEc;AAChB,GClHa+B,IAAsB,MAAmB;AACpD,QAAMF,wBAAY,IAAA;AAgBlB,SAAO,EAAE,KAdG,OAAOD,MACZC,EAAM,IAAID,CAAO,IAIf/B,EAAG,EAAE,SAAA+B,GAAS,MAAMC,EAAM,IAAID,CAAO,KAAK,IAAI,IAH5C/B,EAAG,MAAS,GAYT,KANF,OAAOiC,OACjBD,EAAM,IAAIC,EAAO,SAASA,EAAO,IAAI,GAE9BjC,EAAG,MAAS,GAGP;AAChB,GCbamC,IAAuB,CAAClB,IAAiC,OAAoB;AACxF,QAAMmB,IAAYnB,EAAQ,aAAa,UAEjCoB,IAAiB,MACjB,OAAO,SAAW,OAAe,CAAC,OAAO,iBACpCnC,EAAIN,EAAkB,uBAAuB,kCAAkC,CAAC,IAGlFI,EAAG,OAAO,cAAc;AA6CjC,SAAO,EAAE,KA1CG,OAAO+B,MAA6D;AAC9E,UAAMO,IAAgBD,EAAA;AAEtB,QAAI,CAACC,EAAc;AACjB,aAAOA;AAGT,QAAI;AACF,YAAMC,IAAMD,EAAc,MAAM,QAAQ,GAAGF,CAAS,IAAIL,CAAO,EAAE;AAEjE,UAAI,CAACQ;AACH,eAAOvC,EAAG,MAAS;AAGrB,YAAMwC,IAAS,KAAK,MAAMD,CAAG;AAE7B,aAAOvC,EAAGwC,CAAM;AAAA,IAClB,SAASrC,GAAgB;AACvB,aAAOD;AAAA,QACLN,EAAkB,uBAAuB,uCAAuCO,CAAK;AAAA,MAAA;AAAA,IAEzF;AAAA,EACF,GAoBc,KAlBF,OAAO8B,MAA8C;AAC/D,UAAMK,IAAgBD,EAAA;AAEtB,QAAI,CAACC,EAAc;AACjB,aAAOA;AAGT,QAAI;AACF,aAAAA,EAAc,MAAM,QAAQ,GAAGF,CAAS,IAAIH,EAAO,OAAO,IAAI,KAAK,UAAUA,CAAM,CAAC,GAE7EjC,EAAG,MAAS;AAAA,IACrB,SAASG,GAAgB;AACvB,aAAOD;AAAA,QACLN,EAAkB,wBAAwB,sCAAsCO,CAAK;AAAA,MAAA;AAAA,IAEzF;AAAA,EACF,EAEc;AAChB,GCnDakC,IAAiB,CAC5BI,GACAxB,MAEI,CAACwB,KAAYA,MAAa,cACrBzB,EAAuB;AAAA,EAC5B,QAAQC,EAAQ;AAAA,EAChB,WAAWA,EAAQ;AAAA,CACpB,IAGCwB,MAAa,WACRP,EAAA,IAGLO,MAAa,YACRN,EAAqB,EAAE,WAAWlB,EAAQ,kBAAkB,IAG9DwB,GCbIC,IAAe,CAACC,IAAuB,OAAuB;AACzE,QAAMC,IAAiC;AAAA,IACrC,MAAMD,EAAO,QAAQ;AAAA,IACrB,SAASA,EAAO,WAAW;AAAA,IAC3B,OAAOA,EAAO,SAAS;AAAA,IACvB,WAAWA,EAAO;AAAA,IAClB,QAAQA,EAAO;AAAA,IACf,SAASA,EAAO;AAAA,IAChB,SAASA,EAAO;AAAA,EAAA,GAGZE,IAAuBR,EAAeM,EAAO,SAAS;AAAA,IAC1D,QAAQA,EAAO;AAAA,IACf,WAAWA,EAAO;AAAA,IAClB,kBAAkBA,EAAO;AAAA,EAAA,CAC1B;AAED,MAAIG,IAAqC;AAEzC,QAAMC,IAAQ,MAAY;AACxB,IAAAD,KAAA,QAAAA,EAAY;AAAA,EACd,GAEME,IAAmB,MAA2B;AAClD,QAAI,OAAO,WAAa;AACtB,aAAO9C;AAAA,QACLN,EAAkB,qBAAqB,gDAAgD;AAAA,MAAA;AAI3F,QAAI,OAAOgD,EAAS,aAAc,UAAU;AAC1C,YAAMK,IAAQ,SAAS,cAAcL,EAAS,SAAS;AAEvD,aAAI,CAACK,KAAS,EAAEA,aAAiB,eACxB/C;AAAA,QACLN;AAAA,UACE;AAAA,UACA,gCAAgCgD,EAAS,SAAS;AAAA,QAAA;AAAA,MACpD,IAIG5C,EAAGiD,CAAK;AAAA,IACjB;AAEA,QAAIL,EAAS,qBAAqB;AAChC,aAAO5C,EAAG4C,EAAS,SAAS;AAG9B,UAAMM,IAAW,SAAS,QAAQ,SAAS;AAE3C,WAAKA,IAIElD,EAAGkD,CAAQ,IAHThD,EAAIN,EAAkB,qBAAqB,mCAAmC,CAAC;AAAA,EAI1F,GAEMuD,IAAW,IAAIC,MAA8B;ARzE9C,QAAAC,GAAAC,GAAAC;AQ0EH,IAAKX,EAAS,WAIdS,IAAAT,EAAS,YAAT,QAAAS,EAAA,KAAAT,GAAmB,GAAGQ,KACtBG,KAAAD,IAAAV,EAAS,WAAT,gBAAAU,EAAiB,UAAjB,QAAAC,EAAA,KAAAD,GAAyB,kBAAkB,GAAGF;AAAA,EAChD,GAEMI,IAAW,CAACrD,MAA6B;ARlF1C,QAAAkD,GAAAC,GAAAC;AQmFH,KAAAF,IAAAT,EAAS,YAAT,QAAAS,EAAA,KAAAT,GAAmBzC,KACnBoD,KAAAD,IAAAV,EAAS,WAAT,gBAAAU,EAAiB,UAAjB,QAAAC,EAAA,KAAAD,GAAyB,kBAAkBnD;AAAA,EAC7C,GAEMsD,IAAO,CAACtD,OACZqD,EAASrD,CAAK,GAEPD,EAAIC,CAAK;AAoDlB,SAAO,EAAE,MAjDI,YAAmC;AR7F3C,QAAAkD;AQ8FH,UAAMK,IAAkBV,EAAA;AAExB,QAAI,CAACU,EAAgB;AACnB,aAAOD,EAAKC,EAAgB,KAAK;AAGnC,UAAMC,IAAc,MAAMd,EAAQ,IAAID,EAAS,OAAO;AAEtD,QAAI,CAACe,EAAY;AACf,aAAOF,EAAKE,EAAY,KAAK;AAG/B,QAAIrD,KAAO+C,IAAAM,EAAY,UAAZ,gBAAAN,EAAmB;AAE9B,QAAK/C;AAoBH,MAAA6C,EAAS,yBAAyBP,EAAS,OAAO;AAAA,SApBzC;AACT,MAAAE,IAAa,IAAI,gBAAA;AAEjB,YAAMc,IAAc,MAAMhD,EAASgC,EAAS,MAAME,EAAW,MAAM;AAEnE,UAAI,CAACc,EAAY;AACf,eAAOH,EAAKG,EAAY,KAAK;AAG/B,MAAAtD,IAAOsD,EAAY;AAEnB,YAAMC,IAAc,MAAMhB,EAAQ,IAAI;AAAA,QACpC,SAASD,EAAS;AAAA,QAClB,MAAAtC;AAAA,MAAA,CACD;AAED,UAAI,CAACuD,EAAY;AACf,eAAOJ,EAAKI,EAAY,KAAK;AAAA,IAEjC;AAIA,UAAMC,IAAe1D,EAAUsD,EAAgB,OAAOpD,CAAI;AAE1D,WAAKwD,EAAa,MAIlBX,EAAS,sCAAsC,GAExCnD,EAAG,MAAS,KALVyD,EAAKK,EAAa,KAAK;AAAA,EAMlC,GAEe,OAAAf,EAAA;AACjB;"}
package/dist/index.umd.js CHANGED
@@ -1 +1,2 @@
1
- (function(s,t){typeof exports=="object"&&typeof module<"u"?module.exports=t():typeof define=="function"&&define.amd?define(t):(s=typeof globalThis<"u"?globalThis:s||self).Iconly=t()})(this,function(){"use strict";var g=Object.defineProperty;var h=(s,t,l)=>t in s?g(s,t,{enumerable:!0,configurable:!0,writable:!0,value:l}):s[t]=l;var u=(s,t,l)=>h(s,typeof t!="symbol"?t+"":t,l);const t=class t{constructor(r={}){u(this,"options");u(this,"container");const e={file:"./icons.svg",version:"1.0",debug:!1,container:document.body??document.documentElement,...r};let i;if(typeof e.container=="string"){const a=document.querySelector(e.container);if(!(a&&a instanceof HTMLElement))throw new Error(`Invalid container selector: "${e.container}"`);i=a}else i=e.container;this.container=i,this.options={file:e.file,version:e.version,debug:e.debug},t.dbInstance||(t.dbInstance=this.openDB("iconlyDB",1))}async openDB(r,e){if(!("indexedDB"in window))throw this.logError("This browser does not support IndexedDB"),new Error("IndexedDB not supported");return await new Promise((i,a)=>{const n=indexedDB.open(r,e);n.onerror=()=>{const c=this.createErrorMessage(n.error,"IndexedDB error");a(new Error(c))},n.onupgradeneeded=c=>{const o=c.target.result;o.objectStoreNames.contains("icons")||o.createObjectStore("icons",{keyPath:"version"})},n.onsuccess=()=>{i(n.result)}})}getIconStore(r,e){return r.transaction("icons",e).objectStore("icons")}static async fetchData(r){const e=await fetch(r);if(!e.ok)throw new Error(`Failed to fetch icons from "${r}"`);return e.text()}insert(r){let e=document.getElementById("iconset");e||(e=document.createElement("div"),e.id="iconset",e.setAttribute("aria-hidden","true"),e.style.cssText="width: 0; height: 0; position: absolute; left: -9999px;",this.container.appendChild(e));const i=new DOMParser().parseFromString(r,"image/svg+xml"),a=i.querySelector("parsererror");if(a)return void this.logError("SVG parsing error:",a.textContent??"");e.innerHTML="";const n=i.documentElement;if(n){const c=document.importNode(n,!0);e.appendChild(c)}else this.logError("No valid SVG content found to insert.")}async init(){try{let r=await t.fetchData(this.options.file);const e=await t.dbInstance;if(!e)throw new Error("Failed to open IndexedDB");const i=this.getIconStore(e,"readwrite"),a=await new Promise((n,c)=>{const o=i.get(this.options.version);o.onsuccess=()=>{n(o.result)},o.onerror=()=>{const d=this.createErrorMessage(o.error,"Error getting record from store");c(new Error(d))}});a?r=a.data:await new Promise((n,c)=>{const o=i.put({version:this.options.version,data:r});o.onsuccess=()=>n(),o.onerror=()=>{const d=this.createErrorMessage(o.error,"Error putting record into store");c(new Error(d))}}),await new Promise((n,c)=>{const o=i.transaction;o.oncomplete=()=>n(),o.onerror=()=>{const d=this.createErrorMessage(o.error,"Transaction error");c(new Error(d))},o.onabort=()=>{const d=this.createErrorMessage(o.error,"Transaction aborted");c(new Error(d))}}),this.insert(r),this.logDebug("Iconly has successfully initialized.")}catch(r){const e=r instanceof Error?r:new Error(String(r));this.logError("Error initializing Iconly:",e.message)}}createErrorMessage(r,e){return r&&(r instanceof DOMException||r instanceof Error)&&r.message||e}logDebug(...r){this.options.debug}logError(...r){}};u(t,"dbInstance",null);let s=t;return s});
1
+ (function(p,i){typeof exports=="object"&&typeof module<"u"?i(exports):typeof define=="function"&&define.amd?define(["exports"],i):(p=typeof globalThis<"u"?globalThis:p||self,i(p.Iconly={}))})(this,(function(p){"use strict";const i=(e,t,r)=>({code:e,message:t,cause:r}),u=e=>({ok:!0,value:e}),d=e=>({ok:!1,error:e}),x=(e,t)=>{let r=document.getElementById("iconset");r||(r=document.createElement("div"),r.id="iconset",r.setAttribute("aria-hidden","true"),r.style.cssText="width: 0; height: 0; position: absolute; left: -9999px;",e.appendChild(r));const b=new DOMParser().parseFromString(t,"image/svg+xml"),g=b.querySelector("parsererror");if(g)return d(i("parse_error",`SVG parsing error: ${g.textContent??"Unknown error"}`));r.innerHTML="";const l=b.documentElement;if(!l)return d(i("parse_error","No valid SVG content found."));const m=document.importNode(l,!0);return r.appendChild(m),u(void 0)},S=async(e,t)=>{try{const r=await fetch(e,{signal:t});if(!r.ok)return d(i("fetch_failed",`Failed to fetch icons from "${e}".`));const a=await r.text();return u(a)}catch(r){return r instanceof DOMException&&r.name==="AbortError"?d(i("fetch_aborted","Fetch request was aborted.",r)):d(i("fetch_failed","Failed to fetch icons.",r))}},_=(e={})=>{const t=e.dbName??"iconlyDB",r=e.storeName??"icons";let a=null;const b=async()=>{if(a)return a;if(typeof indexedDB>"u")throw i("indexeddb_not_supported","IndexedDB is not supported.");return a=new Promise((f,n)=>{const o=indexedDB.open(t,1);o.onerror=()=>{n(i("indexeddb_open_failed","Failed to open IndexedDB connection.",o.error))},o.onupgradeneeded=s=>{const c=s.target.result;c.objectStoreNames.contains(r)||c.createObjectStore(r,{keyPath:"version"})},o.onsuccess=()=>f(o.result)}),a},g=(f,n)=>f.transaction(r,n).objectStore(r),l=(f,n,o)=>f&&typeof f=="object"&&"code"in f&&"message"in f?f:i(n,o,f);return{get:async f=>{try{const n=await b(),o=g(n,"readonly");return await new Promise(s=>{const c=o.get(f);c.onsuccess=()=>s(u(c.result)),c.onerror=()=>s(d(i("indexeddb_request_failed","Failed to read from IndexedDB.",c.error)))})}catch(n){return d(l(n,"indexeddb_open_failed","Failed to open IndexedDB."))}},set:async f=>{try{const n=await b(),o=g(n,"readwrite");return await new Promise(s=>{const c=o.put(f);c.onsuccess=()=>s(u(void 0)),c.onerror=()=>s(d(i("indexeddb_request_failed","Failed to write to IndexedDB.",c.error)))})}catch(n){return d(i("indexeddb_open_failed","Failed to open IndexedDB.",n))}}}},D=()=>{const e=new Map;return{get:async a=>e.has(a)?u({version:a,data:e.get(a)??""}):u(void 0),set:async a=>(e.set(a.version,a.data),u(void 0))}},I=(e={})=>{const t=e.keyPrefix??"iconly",r=()=>typeof window>"u"||!window.sessionStorage?d(i("storage_unavailable","SessionStorage is not available.")):u(window.sessionStorage);return{get:async g=>{const l=r();if(!l.ok)return l;try{const m=l.value.getItem(`${t}:${g}`);if(!m)return u(void 0);const y=JSON.parse(m);return u(y)}catch(m){return d(i("storage_read_failed","Failed to read from SessionStorage.",m))}},set:async g=>{const l=r();if(!l.ok)return l;try{return l.value.setItem(`${t}:${g.version}`,JSON.stringify(g)),u(void 0)}catch(m){return d(i("storage_write_failed","Failed to write to SessionStorage.",m))}}}},N=(e,t)=>!e||e==="indexeddb"?_({dbName:t.dbName,storeName:t.storeName}):e==="memory"?D():e==="session"?I({keyPrefix:t.sessionKeyPrefix}):e,k=(e={})=>{const t={file:e.file??"./icons.svg",version:e.version??"1.0",debug:e.debug??!1,container:e.container,logger:e.logger,onError:e.onError,onDebug:e.onDebug},r=N(e.storage,{dbName:e.dbName,storeName:e.storeName,sessionKeyPrefix:e.sessionKeyPrefix});let a=null;const b=()=>{a==null||a.abort()},g=()=>{if(typeof document>"u")return d(i("container_invalid","Document is not available in this environment."));if(typeof t.container=="string"){const o=document.querySelector(t.container);return!o||!(o instanceof HTMLElement)?d(i("container_invalid",`Invalid container selector: "${t.container}".`)):u(o)}if(t.container instanceof HTMLElement)return u(t.container);const n=document.body??document.documentElement;return n?u(n):d(i("container_invalid","No valid container element found."))},l=(...n)=>{var o,s,c;t.debug&&((o=t.onDebug)==null||o.call(t,...n),(c=(s=t.logger)==null?void 0:s.debug)==null||c.call(s,"[Iconly debug]",...n))},m=n=>{var o,s,c;(o=t.onError)==null||o.call(t,n),(c=(s=t.logger)==null?void 0:s.error)==null||c.call(s,"[Iconly error]",n)},y=n=>(m(n),d(n));return{init:async()=>{var h;const n=g();if(!n.ok)return y(n.error);const o=await r.get(t.version);if(!o.ok)return y(o.error);let s=(h=o.value)==null?void 0:h.data;if(s)l("Using cached icon set",t.version);else{a=new AbortController;const v=await S(t.file,a.signal);if(!v.ok)return y(v.error);s=v.value;const w=await r.set({version:t.version,data:s});if(!w.ok)return y(w.error)}const c=x(n.value,s);return c.ok?(l("Iconly has successfully initialized."),u(void 0)):y(c.error)},abort:b}};p.createIconly=k,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})}));
2
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../src/errors.ts","../src/result.ts","../src/dom.ts","../src/fetcher.ts","../src/storage/indexeddb.ts","../src/storage/memory.ts","../src/storage/session.ts","../src/storage/index.ts","../src/core.ts"],"sourcesContent":["import type { IconlyError, IconlyErrorCode } from './types';\n\nexport const createIconlyError = (\n code: IconlyErrorCode,\n message: string,\n cause?: unknown,\n): IconlyError => ({\n code,\n message,\n cause,\n});\n","import type { IconlyError, Result } from './types';\n\nexport const ok = <T>(value: T): Result<T> => ({ ok: true, value });\n\nexport const err = <T = never>(error: IconlyError): Result<T> => ({ ok: false, error });\n","import { createIconlyError } from './errors';\nimport { err, ok } from './result';\nimport type { Result } from './types';\n\nexport const insertSvg = (container: HTMLElement, data: string): Result<void> => {\n let iconSetDiv = document.getElementById('iconset');\n\n if (!iconSetDiv) {\n iconSetDiv = document.createElement('div');\n iconSetDiv.id = 'iconset';\n iconSetDiv.setAttribute('aria-hidden', 'true');\n iconSetDiv.style.cssText = 'width: 0; height: 0; position: absolute; left: -9999px;';\n container.appendChild(iconSetDiv);\n }\n\n const parser = new DOMParser();\n const svgDoc = parser.parseFromString(data, 'image/svg+xml');\n const parserError = svgDoc.querySelector('parsererror');\n\n if (parserError) {\n return err(\n createIconlyError(\n 'parse_error',\n `SVG parsing error: ${parserError.textContent ?? 'Unknown error'}`,\n ),\n );\n }\n\n iconSetDiv.innerHTML = '';\n\n const svgEl = svgDoc.documentElement;\n\n if (!svgEl) {\n return err(createIconlyError('parse_error', 'No valid SVG content found.'));\n }\n\n const imported = document.importNode(svgEl, true);\n\n iconSetDiv.appendChild(imported);\n\n return ok(undefined);\n};\n","import { createIconlyError } from './errors';\nimport { err, ok } from './result';\nimport type { Result } from './types';\n\nexport const fetchSvg = async (file: string, signal?: AbortSignal): Promise<Result<string>> => {\n try {\n const response = await fetch(file, { signal });\n\n if (!response.ok) {\n return err(createIconlyError('fetch_failed', `Failed to fetch icons from \"${file}\".`));\n }\n\n const data = await response.text();\n\n return ok(data);\n } catch (error: unknown) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n return err(createIconlyError('fetch_aborted', 'Fetch request was aborted.', error));\n }\n\n return err(createIconlyError('fetch_failed', 'Failed to fetch icons.', error));\n }\n};\n","import { createIconlyError } from '../errors';\nimport { err, ok } from '../result';\nimport type { IconlyError, IconRecord, IconStorage, Result } from '../types';\n\ninterface IndexedDbOptions {\n dbName?: string;\n storeName?: string;\n}\n\nexport const createIndexedDbStorage = (options: IndexedDbOptions = {}): IconStorage => {\n const dbName = options.dbName ?? 'iconlyDB';\n const storeName = options.storeName ?? 'icons';\n\n let dbPromise: Promise<IDBDatabase> | null = null;\n\n const openDb = async (): Promise<IDBDatabase> => {\n if (dbPromise) {\n return dbPromise;\n }\n\n if (typeof indexedDB === 'undefined') {\n throw createIconlyError('indexeddb_not_supported', 'IndexedDB is not supported.');\n }\n\n dbPromise = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDB.open(dbName, 1);\n\n request.onerror = (): void => {\n reject(\n createIconlyError(\n 'indexeddb_open_failed',\n 'Failed to open IndexedDB connection.',\n request.error,\n ),\n );\n };\n\n request.onupgradeneeded = (event): void => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName, { keyPath: 'version' });\n }\n };\n\n request.onsuccess = (): void => resolve(request.result);\n });\n\n return dbPromise;\n };\n\n const getStore = (db: IDBDatabase, mode: IDBTransactionMode): IDBObjectStore =>\n db.transaction(storeName, mode).objectStore(storeName);\n\n const toIconlyError = (\n error: unknown,\n fallbackCode: IconlyError['code'],\n message: string,\n ): IconlyError => {\n if (error && typeof error === 'object' && 'code' in error && 'message' in error) {\n return error as IconlyError;\n }\n\n return createIconlyError(fallbackCode, message, error);\n };\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n try {\n const db = await openDb();\n const store = getStore(db, 'readonly');\n\n return await new Promise<Result<IconRecord | undefined>>((resolve) => {\n const request = store.get(version);\n\n request.onsuccess = (): void => resolve(ok(request.result as IconRecord | undefined));\n request.onerror = (): void =>\n resolve(\n err(\n createIconlyError(\n 'indexeddb_request_failed',\n 'Failed to read from IndexedDB.',\n request.error,\n ),\n ),\n );\n });\n } catch (error: unknown) {\n return err(toIconlyError(error, 'indexeddb_open_failed', 'Failed to open IndexedDB.'));\n }\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n try {\n const db = await openDb();\n const store = getStore(db, 'readwrite');\n\n return await new Promise<Result<void>>((resolve) => {\n const request = store.put(record);\n\n request.onsuccess = (): void => resolve(ok(undefined));\n request.onerror = (): void =>\n resolve(\n err(\n createIconlyError(\n 'indexeddb_request_failed',\n 'Failed to write to IndexedDB.',\n request.error,\n ),\n ),\n );\n });\n } catch (error: unknown) {\n return err(createIconlyError('indexeddb_open_failed', 'Failed to open IndexedDB.', error));\n }\n };\n\n return { get, set };\n};\n","import { ok } from '../result';\nimport type { IconRecord, IconStorage, Result } from '../types';\n\nexport const createMemoryStorage = (): IconStorage => {\n const store = new Map<string, string>();\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n if (!store.has(version)) {\n return ok(undefined);\n }\n\n return ok({ version, data: store.get(version) ?? '' });\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n store.set(record.version, record.data);\n\n return ok(undefined);\n };\n\n return { get, set };\n};\n","import { createIconlyError } from '../errors';\nimport { err, ok } from '../result';\nimport type { IconRecord, IconStorage, Result } from '../types';\n\ninterface SessionStorageOptions {\n keyPrefix?: string;\n}\n\nexport const createSessionStorage = (options: SessionStorageOptions = {}): IconStorage => {\n const keyPrefix = options.keyPrefix ?? 'iconly';\n\n const resolveStorage = (): Result<Storage> => {\n if (typeof window === 'undefined' || !window.sessionStorage) {\n return err(createIconlyError('storage_unavailable', 'SessionStorage is not available.'));\n }\n\n return ok(window.sessionStorage);\n };\n\n const get = async (version: string): Promise<Result<IconRecord | undefined>> => {\n const storageResult = resolveStorage();\n\n if (!storageResult.ok) {\n return storageResult;\n }\n\n try {\n const raw = storageResult.value.getItem(`${keyPrefix}:${version}`);\n\n if (!raw) {\n return ok(undefined);\n }\n\n const parsed = JSON.parse(raw) as IconRecord;\n\n return ok(parsed);\n } catch (error: unknown) {\n return err(\n createIconlyError('storage_read_failed', 'Failed to read from SessionStorage.', error),\n );\n }\n };\n\n const set = async (record: IconRecord): Promise<Result<void>> => {\n const storageResult = resolveStorage();\n\n if (!storageResult.ok) {\n return storageResult;\n }\n\n try {\n storageResult.value.setItem(`${keyPrefix}:${record.version}`, JSON.stringify(record));\n\n return ok(undefined);\n } catch (error: unknown) {\n return err(\n createIconlyError('storage_write_failed', 'Failed to write to SessionStorage.', error),\n );\n }\n };\n\n return { get, set };\n};\n","import type { IconStorage, StorageStrategy } from '../types';\nimport { createIndexedDbStorage } from './indexeddb';\nimport { createMemoryStorage } from './memory';\nimport { createSessionStorage } from './session';\n\nexport interface StorageFactoryOptions {\n dbName?: string;\n storeName?: string;\n sessionKeyPrefix?: string;\n}\n\nexport const resolveStorage = (\n strategy: StorageStrategy | undefined,\n options: StorageFactoryOptions,\n): IconStorage => {\n if (!strategy || strategy === 'indexeddb') {\n return createIndexedDbStorage({\n dbName: options.dbName,\n storeName: options.storeName,\n });\n }\n\n if (strategy === 'memory') {\n return createMemoryStorage();\n }\n\n if (strategy === 'session') {\n return createSessionStorage({ keyPrefix: options.sessionKeyPrefix });\n }\n\n return strategy;\n};\n","import { insertSvg } from './dom';\nimport { createIconlyError } from './errors';\nimport { fetchSvg } from './fetcher';\nimport { err, ok } from './result';\nimport { resolveStorage } from './storage';\nimport type { IconlyConfig, IconlyError, IconlyInstance, IconStorage, Result } from './types';\n\ninterface ResolvedIconlyConfig {\n file: string;\n version: string;\n debug: boolean;\n container?: string | HTMLElement;\n logger?: IconlyConfig['logger'];\n onError?: IconlyConfig['onError'];\n onDebug?: IconlyConfig['onDebug'];\n}\n\nexport const createIconly = (config: IconlyConfig = {}): IconlyInstance => {\n const resolved: ResolvedIconlyConfig = {\n file: config.file ?? './icons.svg',\n version: config.version ?? '1.0',\n debug: config.debug ?? false,\n container: config.container,\n logger: config.logger,\n onError: config.onError,\n onDebug: config.onDebug,\n };\n\n const storage: IconStorage = resolveStorage(config.storage, {\n dbName: config.dbName,\n storeName: config.storeName,\n sessionKeyPrefix: config.sessionKeyPrefix,\n });\n\n let controller: AbortController | null = null;\n\n const abort = (): void => {\n controller?.abort();\n };\n\n const resolveContainer = (): Result<HTMLElement> => {\n if (typeof document === 'undefined') {\n return err(\n createIconlyError('container_invalid', 'Document is not available in this environment.'),\n );\n }\n\n if (typeof resolved.container === 'string') {\n const found = document.querySelector(resolved.container);\n\n if (!found || !(found instanceof HTMLElement)) {\n return err(\n createIconlyError(\n 'container_invalid',\n `Invalid container selector: \"${resolved.container}\".`,\n ),\n );\n }\n\n return ok(found);\n }\n\n if (resolved.container instanceof HTMLElement) {\n return ok(resolved.container);\n }\n\n const fallback = document.body ?? document.documentElement;\n\n if (!fallback) {\n return err(createIconlyError('container_invalid', 'No valid container element found.'));\n }\n\n return ok(fallback);\n };\n\n const logDebug = (...messages: unknown[]): void => {\n if (!resolved.debug) {\n return;\n }\n\n resolved.onDebug?.(...messages);\n resolved.logger?.debug?.('[Iconly debug]', ...messages);\n };\n\n const logError = (error: IconlyError): void => {\n resolved.onError?.(error);\n resolved.logger?.error?.('[Iconly error]', error);\n };\n\n const fail = (error: IconlyError): Result<void> => {\n logError(error);\n\n return err(error);\n };\n\n const init = async (): Promise<Result<void>> => {\n const containerResult = resolveContainer();\n\n if (!containerResult.ok) {\n return fail(containerResult.error);\n }\n\n const cacheResult = await storage.get(resolved.version);\n\n if (!cacheResult.ok) {\n return fail(cacheResult.error);\n }\n\n let data = cacheResult.value?.data;\n\n if (!data) {\n controller = new AbortController();\n\n const fetchResult = await fetchSvg(resolved.file, controller.signal);\n\n if (!fetchResult.ok) {\n return fail(fetchResult.error);\n }\n\n data = fetchResult.value;\n\n const storeResult = await storage.set({\n version: resolved.version,\n data,\n });\n\n if (!storeResult.ok) {\n return fail(storeResult.error);\n }\n } else {\n logDebug('Using cached icon set', resolved.version);\n }\n\n const insertResult = insertSvg(containerResult.value, data);\n\n if (!insertResult.ok) {\n return fail(insertResult.error);\n }\n\n logDebug('Iconly has successfully initialized.');\n\n return ok(undefined);\n };\n\n return { init, abort };\n};\n"],"names":["createIconlyError","code","message","cause","ok","value","err","error","insertSvg","container","data","iconSetDiv","svgDoc","parserError","svgEl","imported","fetchSvg","file","signal","response","createIndexedDbStorage","options","dbName","storeName","dbPromise","openDb","resolve","reject","request","event","db","getStore","mode","toIconlyError","fallbackCode","version","store","record","createMemoryStorage","createSessionStorage","keyPrefix","resolveStorage","storageResult","raw","parsed","strategy","createIconly","config","resolved","storage","controller","abort","resolveContainer","found","fallback","logDebug","messages","_a","_c","_b","logError","fail","containerResult","cacheResult","fetchResult","storeResult","insertResult"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { IconlyError, Result } from './types';
2
+ export declare const ok: <T>(value: T) => Result<T>;
3
+ export declare const err: <T = never>(error: IconlyError) => Result<T>;
4
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEnD,eAAO,MAAM,EAAE,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,CAAC,CAA0B,CAAC;AAEpE,eAAO,MAAM,GAAG,GAAI,CAAC,GAAG,KAAK,EAAE,OAAO,WAAW,KAAG,MAAM,CAAC,CAAC,CAA2B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { IconStorage, StorageStrategy } from '../types';
2
+ export interface StorageFactoryOptions {
3
+ dbName?: string;
4
+ storeName?: string;
5
+ sessionKeyPrefix?: string;
6
+ }
7
+ export declare const resolveStorage: (strategy: StorageStrategy | undefined, options: StorageFactoryOptions) => IconStorage;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAK7D,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,GACzB,UAAU,eAAe,GAAG,SAAS,EACrC,SAAS,qBAAqB,KAC7B,WAiBF,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { IconStorage } from '../types';
2
+ interface IndexedDbOptions {
3
+ dbName?: string;
4
+ storeName?: string;
5
+ }
6
+ export declare const createIndexedDbStorage: (options?: IndexedDbOptions) => IconStorage;
7
+ export {};
8
+ //# sourceMappingURL=indexeddb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb.d.ts","sourceRoot":"","sources":["../../src/storage/indexeddb.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA2B,WAAW,EAAU,MAAM,UAAU,CAAC;AAE7E,UAAU,gBAAgB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,sBAAsB,GAAI,UAAS,gBAAqB,KAAG,WA4GvE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { IconStorage } from '../types';
2
+ export declare const createMemoryStorage: () => IconStorage;
3
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,WAAW,EAAU,MAAM,UAAU,CAAC;AAEhE,eAAO,MAAM,mBAAmB,QAAO,WAkBtC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { IconStorage } from '../types';
2
+ interface SessionStorageOptions {
3
+ keyPrefix?: string;
4
+ }
5
+ export declare const createSessionStorage: (options?: SessionStorageOptions) => IconStorage;
6
+ export {};
7
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/storage/session.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,WAAW,EAAU,MAAM,UAAU,CAAC;AAEhE,UAAU,qBAAqB;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,oBAAoB,GAAI,UAAS,qBAA0B,KAAG,WAsD1E,CAAC"}
@@ -0,0 +1,44 @@
1
+ export type Result<T> = {
2
+ ok: true;
3
+ value: T;
4
+ } | {
5
+ ok: false;
6
+ error: IconlyError;
7
+ };
8
+ export type IconlyErrorCode = 'container_invalid' | 'fetch_aborted' | 'fetch_failed' | 'indexeddb_not_supported' | 'indexeddb_open_failed' | 'indexeddb_request_failed' | 'parse_error' | 'storage_read_failed' | 'storage_unavailable' | 'storage_write_failed';
9
+ export interface IconlyError {
10
+ code: IconlyErrorCode;
11
+ message: string;
12
+ cause?: unknown;
13
+ }
14
+ export interface Logger {
15
+ debug?: (...messages: unknown[]) => void;
16
+ error?: (...messages: unknown[]) => void;
17
+ }
18
+ export interface IconRecord {
19
+ version: string;
20
+ data: string;
21
+ }
22
+ export interface IconStorage {
23
+ get(version: string): Promise<Result<IconRecord | undefined>>;
24
+ set(record: IconRecord): Promise<Result<void>>;
25
+ }
26
+ export interface IconlyInstance {
27
+ init: () => Promise<Result<void>>;
28
+ abort: () => void;
29
+ }
30
+ export type StorageStrategy = 'indexeddb' | 'memory' | 'session' | IconStorage;
31
+ export interface IconlyConfig {
32
+ file?: string;
33
+ version?: string;
34
+ debug?: boolean;
35
+ container?: string | HTMLElement;
36
+ storage?: StorageStrategy;
37
+ dbName?: string;
38
+ storeName?: string;
39
+ sessionKeyPrefix?: string;
40
+ logger?: Logger;
41
+ onError?: (error: IconlyError) => void;
42
+ onDebug?: (...messages: unknown[]) => void;
43
+ }
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAEnF,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,eAAe,GACf,cAAc,GACd,yBAAyB,GACzB,uBAAuB,GACvB,0BAA0B,GAC1B,aAAa,GACb,qBAAqB,GACrB,qBAAqB,GACrB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC;IAC9D,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACjC,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CAC5C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iconly",
3
- "version": "2.0.1-dev.0",
3
+ "version": "3.0.0-dev.0",
4
4
  "description": "Iconly is designed to load and cache SVG icons in the browser, using IndexedDB to store the data. It retrieves the icons from a given SVG file, stores them in IndexedDB, and inserts them into the DOM for easy access and use.",
5
5
  "author": "ux-ui.pro",
6
6
  "license": "MIT",
@@ -13,13 +13,21 @@
13
13
  },
14
14
  "homepage": "https://github.com/ux-ui-pro/iconly",
15
15
  "sideEffects": false,
16
+ "type": "module",
17
+ "engines": {
18
+ "node": ">=18.0.0"
19
+ },
16
20
  "scripts": {
17
21
  "clean": "rimraf dist",
18
22
  "build": "vite build",
19
- "lint:js": "eslint src/**/*.{ts,js}",
20
- "lint:fix:js": "eslint src/**/*.{ts,js} --fix",
21
- "format:js": "prettier --write src/**/*.{ts,js}",
22
- "lint:fix": "yarn lint:fix:js && yarn format:js"
23
+ "lint": "biome check src tests",
24
+ "lint:fix": "biome check --write src tests",
25
+ "format": "biome format --write src tests",
26
+ "typecheck": "tsc -p tsconfig.json --noEmit",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "verify": "npm run lint && npm run typecheck && npm run test",
30
+ "prepublishOnly": "npm run verify"
23
31
  },
24
32
  "source": "src/index.ts",
25
33
  "main": "dist/index.cjs.js",
@@ -28,31 +36,27 @@
28
36
  "types": "dist/index.d.ts",
29
37
  "exports": {
30
38
  ".": {
39
+ "types": "./dist/index.d.ts",
31
40
  "require": "./dist/index.cjs.js",
32
41
  "import": "./dist/index.es.js",
33
42
  "default": "./dist/index.umd.js"
34
- },
35
- "./dist/*": "./dist/*"
43
+ }
36
44
  },
37
45
  "files": [
38
- "dist/"
46
+ "dist",
47
+ "README.md",
48
+ "LICENSE"
39
49
  ],
40
50
  "devDependencies": {
41
- "@eslint/js": "9.22.0",
42
- "@rollup/plugin-terser": "0.4.4",
51
+ "@biomejs/biome": "2.3.10",
43
52
  "@types/node": "22.13.10",
44
- "@typescript-eslint/eslint-plugin": "8.26.0",
45
- "@typescript-eslint/parser": "8.26.0",
46
- "eslint": "9.22.0",
47
- "eslint-config-prettier": "10.1.1",
48
- "eslint-import-resolver-typescript": "3.8.3",
49
- "eslint-plugin-import": "2.31.0",
50
- "globals": "16.0.0",
51
- "prettier": "3.5.3",
53
+ "fake-indexeddb": "6.2.5",
54
+ "jsdom": "27.4.0",
52
55
  "rimraf": "6.0.1",
53
56
  "typescript": "5.8.2",
54
57
  "vite": "6.2.1",
55
- "vite-plugin-dts": "4.5.3"
58
+ "vite-plugin-dts": "4.5.3",
59
+ "vitest": "4.0.18"
56
60
  },
57
61
  "keywords": [
58
62
  "icon",
@@ -71,7 +75,6 @@
71
75
  "sprites",
72
76
  "typescript",
73
77
  "utility",
74
- "javascript",
75
- "es6"
78
+ "javascript"
76
79
  ]
77
80
  }