iconly
Version:
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.
200 lines (199 loc) • 6.46 kB
JavaScript
const i = (e, t, o) => ({
code: e,
message: t,
cause: o
}), u = (e) => ({ ok: !0, value: e }), a = (e) => ({ ok: !1, error: e }), w = (e, t) => {
const o = e.querySelector('[data-iconly="iconset"]');
let n = o instanceof HTMLElement ? o : null;
n || (n = document.createElement("div"), n.setAttribute("data-iconly", "iconset"), n.setAttribute("aria-hidden", "true"), n.style.cssText = "width: 0; height: 0; position: absolute; left: -9999px;", e.appendChild(n));
const f = new DOMParser().parseFromString(t, "image/svg+xml"), c = f.querySelector("parsererror");
if (c)
return a(
i(
"parse_error",
`SVG parsing error: ${c.textContent ?? "Unknown error"}`
)
);
n.innerHTML = "";
const g = f.documentElement;
if (!g)
return a(i("parse_error", "No valid SVG content found."));
const b = document.importNode(g, !0);
return n.appendChild(b), u(void 0);
}, x = async (e, t) => {
try {
const o = await fetch(e, { signal: t });
if (!o.ok)
return a(i("fetch_failed", `Failed to fetch icons from "${e}".`));
const n = await o.text();
return u(n);
} catch (o) {
return o instanceof DOMException && o.name === "AbortError" ? a(i("fetch_aborted", "Fetch request was aborted.", o)) : a(i("fetch_failed", "Failed to fetch icons.", o));
}
}, S = (e = {}) => {
const t = e.dbName ?? "iconlyDB", o = e.storeName ?? "icons";
let n = null;
const y = async () => {
if (n)
return n;
if (typeof indexedDB > "u")
throw i("indexeddb_not_supported", "IndexedDB is not supported.");
return n = new Promise((d, r) => {
const s = indexedDB.open(t, 1);
s.onerror = () => {
r(
i(
"indexeddb_open_failed",
"Failed to open IndexedDB connection.",
s.error
)
);
}, s.onupgradeneeded = (m) => {
const l = m.target.result;
l.objectStoreNames.contains(o) || l.createObjectStore(o, { keyPath: "version" });
}, s.onsuccess = () => d(s.result);
}), n;
}, f = (d, r) => d.transaction(o, r).objectStore(o), c = (d, r, s) => d && typeof d == "object" && "code" in d && "message" in d ? d : i(r, s, d);
return { get: async (d) => {
try {
const r = await y(), s = f(r, "readonly");
return await new Promise((m) => {
const l = s.get(d);
l.onsuccess = () => m(u(l.result)), l.onerror = () => m(
a(
i(
"indexeddb_request_failed",
"Failed to read from IndexedDB.",
l.error
)
)
);
});
} catch (r) {
return a(c(r, "indexeddb_open_failed", "Failed to open IndexedDB."));
}
}, set: async (d) => {
try {
const r = await y(), s = f(r, "readwrite");
return await new Promise((m) => {
const l = s.put(d);
l.onsuccess = () => m(u(void 0)), l.onerror = () => m(
a(
i(
"indexeddb_request_failed",
"Failed to write to IndexedDB.",
l.error
)
)
);
});
} catch (r) {
return a(i("indexeddb_open_failed", "Failed to open IndexedDB.", r));
}
} };
}, h = () => {
const e = /* @__PURE__ */ new Map();
return { get: async (n) => e.has(n) ? u({ version: n, data: e.get(n) ?? "" }) : u(void 0), set: async (n) => (e.set(n.version, n.data), u(void 0)) };
}, _ = (e = {}) => {
const t = e.keyPrefix ?? "iconly", o = () => typeof window > "u" || !window.sessionStorage ? a(i("storage_unavailable", "SessionStorage is not available.")) : u(window.sessionStorage);
return { get: async (f) => {
const c = o();
if (!c.ok)
return c;
try {
const g = c.value.getItem(`${t}:${f}`);
if (!g)
return u(void 0);
const b = JSON.parse(g);
return u(b);
} catch (g) {
return a(
i("storage_read_failed", "Failed to read from SessionStorage.", g)
);
}
}, set: async (f) => {
const c = o();
if (!c.ok)
return c;
try {
return c.value.setItem(`${t}:${f.version}`, JSON.stringify(f)), u(void 0);
} catch (g) {
return a(
i("storage_write_failed", "Failed to write to SessionStorage.", g)
);
}
} };
}, D = (e, t) => !e || e === "indexeddb" ? S({
dbName: t.dbName,
storeName: t.storeName
}) : e === "memory" ? h() : e === "session" ? _({ 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
}, o = D(e.storage, {
dbName: e.dbName,
storeName: e.storeName,
sessionKeyPrefix: e.sessionKeyPrefix
});
let n = null;
const y = () => {
n?.abort();
}, f = () => {
if (typeof document > "u")
return a(
i("container_invalid", "Document is not available in this environment.")
);
if (typeof t.container == "string") {
const s = document.querySelector(t.container);
return !s || !(s instanceof HTMLElement) ? a(
i(
"container_invalid",
`Invalid container selector: "${t.container}".`
)
) : u(s);
}
if (t.container instanceof HTMLElement)
return u(t.container);
const r = document.body ?? document.documentElement;
return r ? u(r) : a(i("container_invalid", "No valid container element found."));
}, c = (...r) => {
t.debug && (t.onDebug?.(...r), t.logger?.debug?.("[Iconly debug]", ...r));
}, g = (r) => {
t.onError?.(r), t.logger?.error?.("[Iconly error]", r);
}, b = (r) => (g(r), a(r));
return { init: async () => {
const r = f();
if (!r.ok)
return b(r.error);
const s = await o.get(t.version);
if (!s.ok)
return b(s.error);
let m = s.value?.data;
if (m)
c("Using cached icon set", t.version);
else {
n = new AbortController();
const v = await x(t.file, n.signal);
if (!v.ok)
return b(v.error);
m = v.value;
const p = await o.set({
version: t.version,
data: m
});
if (!p.ok)
return b(p.error);
}
const l = w(r.value, m);
return l.ok ? (c("Iconly has successfully initialized."), u(void 0)) : b(l.error);
}, abort: y };
};
export {
N as createIconly
};
//# sourceMappingURL=index.es.js.map