viconic-react-icons 1.5.6 → 1.5.8

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/dist/index.js CHANGED
@@ -1665,8 +1665,6 @@ var import_react = __toESM(require("react"));
1665
1665
  display: inline-flex !important;
1666
1666
  align-items: center;
1667
1667
  justify-content: center;
1668
- background: none !important;
1669
- background-color: transparent !important;
1670
1668
 
1671
1669
  }
1672
1670
  :where(viconic-icon).svg-loaded:not(.ci-multicolor) svg {
@@ -1992,8 +1990,7 @@ var import_react = __toESM(require("react"));
1992
1990
  if (c && c.d && Date.now() - c.t < TTL) {
1993
1991
  for (const n in c.d) {
1994
1992
  if (!Object.prototype.hasOwnProperty.call(c.d, n)) continue;
1995
- const svg = c.d[n];
1996
- if (!W.icons[n]) W.icons[n] = svg;
1993
+ if (!W.icons[n]) W.icons[n] = c.d[n];
1997
1994
  }
1998
1995
  }
1999
1996
  } catch (e) {
@@ -2003,101 +2000,16 @@ var import_react = __toESM(require("react"));
2003
2000
  }
2004
2001
  })();
2005
2002
  var _initializedKits = /* @__PURE__ */ new Set();
2006
- var _kitRegistry = {};
2007
- var _pendingMisses = {};
2008
- if (typeof document !== "undefined") {
2009
- document.addEventListener("viconic:ready", (e) => {
2010
- const prefix = e && e.detail && e.detail.prefix;
2011
- if (prefix) _flushPendingMisses(prefix);
2012
- });
2013
- }
2014
- var _kitMissQueues = {};
2015
- var _kitMissTimers = {};
2016
- var _kitQueued = {};
2017
- function _resolveRegistry(prefix) {
2018
- if (_kitRegistry[prefix]) return _kitRegistry[prefix];
2019
- const kits = window.CopyIconsKit || {};
2020
- for (const kId in kits) {
2021
- const kit = kits[kId];
2022
- if (kit.config && kit.config.prefix === prefix) {
2023
- const entry = { kitId: kId, api: kit.config.api || "https://api.viconic.dev" };
2024
- _kitRegistry[prefix] = entry;
2025
- return entry;
2026
- }
2027
- }
2028
- return null;
2029
- }
2030
- function _flushPendingMisses(prefix) {
2031
- const pending = _pendingMisses[prefix];
2032
- if (!pending || !pending.size) return;
2033
- const entry = _resolveRegistry(prefix);
2034
- if (!entry) return;
2035
- delete _pendingMisses[prefix];
2036
- pending.forEach((name) => _dispatchBatchFetch(prefix, name, entry));
2037
- }
2038
- function _dispatchBatchFetch(prefix, iconBaseName, entry) {
2039
- const { kitId, api } = entry;
2040
- if (!_kitQueued[kitId]) _kitQueued[kitId] = /* @__PURE__ */ new Set();
2041
- if (_kitQueued[kitId].has(iconBaseName)) return;
2042
- _kitQueued[kitId].add(iconBaseName);
2043
- if (!_kitMissQueues[kitId]) _kitMissQueues[kitId] = /* @__PURE__ */ new Set();
2044
- _kitMissQueues[kitId].add(iconBaseName);
2045
- if (_kitMissTimers[kitId]) return;
2046
- _kitMissTimers[kitId] = setTimeout(() => {
2047
- delete _kitMissTimers[kitId];
2048
- const names = [..._kitMissQueues[kitId] || []];
2049
- delete _kitMissQueues[kitId];
2050
- if (!names.length) return;
2051
- fetch(`${api}/api/v1/kits/${kitId}/icons/?icons=${names.join(",")}`).then((r) => r.ok ? r.json() : null).then((bj) => {
2052
- if (!bj || !bj.icons) return;
2053
- const W = window.__viconic = window.__viconic || {};
2054
- W.icons = W.icons || {};
2055
- const cdnFetches = [];
2056
- for (const n in bj.icons) {
2057
- if (!Object.prototype.hasOwnProperty.call(bj.icons, n)) continue;
2058
- const d = bj.icons[n];
2059
- const svg = d.svg || "";
2060
- if (svg && svg.includes("<")) {
2061
- W.icons[`@${prefix}/${n}`] = svg;
2062
- W.icons[`${prefix}:${n}`] = svg;
2063
- W.icons[`${prefix}/${n}`] = svg;
2064
- W.icons[n] = W.icons[n] || svg;
2065
- } else if (d.cdn_url) {
2066
- cdnFetches.push(
2067
- fetch(d.cdn_url).then((r) => r.ok ? r.text() : "").then((s) => {
2068
- if (s && s.includes("<")) {
2069
- W.icons[`@${prefix}/${n}`] = s;
2070
- W.icons[`${prefix}:${n}`] = s;
2071
- W.icons[`${prefix}/${n}`] = s;
2072
- W.icons[n] = W.icons[n] || s;
2073
- }
2074
- }).catch(() => {
2075
- })
2076
- );
2077
- }
2078
- }
2079
- Promise.all(cdnFetches).then(() => {
2080
- try {
2081
- document.dispatchEvent(new CustomEvent("viconic:ready", { detail: { prefix, kitId } }));
2082
- } catch (e) {
2083
- }
2084
- });
2085
- }).catch(() => {
2086
- });
2087
- }, 150);
2088
- }
2089
- function _queueKitMiss(prefix, iconBaseName) {
2090
- if (typeof window === "undefined") return;
2091
- const entry = _resolveRegistry(prefix);
2092
- if (entry) {
2093
- _dispatchBatchFetch(prefix, iconBaseName, entry);
2094
- } else {
2095
- if (!_pendingMisses[prefix]) _pendingMisses[prefix] = /* @__PURE__ */ new Set();
2096
- _pendingMisses[prefix].add(iconBaseName);
2097
- }
2003
+ function _isQueued(kitId, iconName) {
2004
+ if (typeof window === "undefined") return false;
2005
+ const q = window.__viconicQueued = window.__viconicQueued || {};
2006
+ const k = kitId + ":" + iconName;
2007
+ if (q[k]) return true;
2008
+ q[k] = 1;
2009
+ return false;
2098
2010
  }
2099
2011
  function initViconic(options = {}) {
2100
- const { kitId, cdnBase = "cdn.viconic.dev", version, prefix: explicitPrefix, api = "https://api.viconic.dev" } = options;
2012
+ const { kitId, cdnBase = "cdn.viconic.dev", version } = options;
2101
2013
  if (typeof window === "undefined") return;
2102
2014
  if (!kitId) {
2103
2015
  console.warn("[Viconic] initViconic requires a kitId");
@@ -2105,31 +2017,14 @@ function initViconic(options = {}) {
2105
2017
  }
2106
2018
  if (_initializedKits.has(kitId)) return;
2107
2019
  _initializedKits.add(kitId);
2108
- if (explicitPrefix) {
2109
- _kitRegistry[explicitPrefix] = { kitId, api };
2110
- }
2111
- if (typeof window !== "undefined") {
2112
- window.__viconicKitIds = window.__viconicKitIds || {};
2113
- window.__viconicKitIds[kitId] = { api };
2114
- }
2115
2020
  const scriptId = `viconic-kit-${kitId}`;
2116
2021
  if (document.getElementById(scriptId)) return;
2117
2022
  const script = document.createElement("script");
2118
2023
  script.id = scriptId;
2119
2024
  let url = `https://${cdnBase}/kits/${kitId}/loader.js`;
2120
2025
  if (version) {
2121
- const vQuery = version === "dev" ? Date.now() : version;
2122
- url += `?v=${vQuery}`;
2026
+ url += `?v=${version === "dev" ? Date.now() : version}`;
2123
2027
  }
2124
- script.onload = () => {
2125
- const kits = window.CopyIconsKit || {};
2126
- const kit = kits[kitId];
2127
- if (kit && kit.config && kit.config.prefix) {
2128
- const pfx = kit.config.prefix;
2129
- _kitRegistry[pfx] = { kitId, api: kit.config.api || api };
2130
- _flushPendingMisses(pfx);
2131
- }
2132
- };
2133
2028
  script.src = url;
2134
2029
  script.async = true;
2135
2030
  document.head.appendChild(script);
@@ -2150,51 +2045,50 @@ var ViconicIcon = ({ name, className, style, size, color, ...props }) => {
2150
2045
  function isInjected() {
2151
2046
  return el.classList.contains("vi-ok") || el.classList.contains("svg-loaded");
2152
2047
  }
2153
- if (!isInjected()) {
2048
+ function tryInjectFromCache() {
2049
+ if (isInjected()) return false;
2154
2050
  const W = window.__viconic;
2155
- if (W && W.icons) {
2156
- const iconBaseName = prefixMatch ? prefixMatch[2] : null;
2157
- const svg = iconBaseName && W.icons[iconBaseName] || name && W.icons[name] || null;
2158
- if (svg) {
2159
- el.innerHTML = svg;
2160
- el.classList.add("vi-ok", "svg-loaded");
2161
- }
2051
+ if (!W || !W.icons) return false;
2052
+ const baseName = prefixMatch ? prefixMatch[2] : null;
2053
+ const svg = baseName && W.icons[baseName] || name && W.icons[name] || null;
2054
+ if (svg) {
2055
+ el.innerHTML = svg;
2056
+ el.classList.add("vi-ok", "svg-loaded");
2057
+ return true;
2162
2058
  }
2059
+ return false;
2163
2060
  }
2164
- if (!isInjected() && !isKitIcon) {
2061
+ if (tryInjectFromCache()) return;
2062
+ if (!isKitIcon) {
2165
2063
  if (window.CopyIcons && window.CopyIcons.forceProcess) {
2166
2064
  window.CopyIcons.forceProcess(el);
2065
+ } else if (el._u) {
2066
+ el._u();
2167
2067
  }
2168
2068
  }
2169
- if (!isInjected() && !isKitIcon && el._u) {
2170
- el._u();
2171
- }
2172
2069
  if (isInjected()) return;
2173
- function tryInjectFromEvent() {
2174
- if (isInjected()) return;
2175
- const W = window.__viconic;
2176
- if (W && W.icons) {
2177
- const iconBaseName = prefixMatch ? prefixMatch[2] : null;
2178
- const svg = iconBaseName && W.icons[iconBaseName] || name && W.icons[name] || null;
2179
- if (svg) {
2180
- el.innerHTML = svg;
2181
- el.classList.add("vi-ok", "svg-loaded");
2182
- return;
2070
+ if (isKitIcon && prefixMatch) {
2071
+ const kitId = (() => {
2072
+ const kits = window.CopyIconsKit || {};
2073
+ for (const kId in kits) {
2074
+ if (kits[kId].config && kits[kId].config.prefix === prefixMatch[1]) return kId;
2075
+ }
2076
+ return prefixMatch[1];
2077
+ })();
2078
+ if (!_isQueued(kitId, prefixMatch[2])) {
2079
+ if (el._u) {
2080
+ el._u();
2183
2081
  }
2184
- }
2185
- if (!isKitIcon && el._u) el._u();
2186
- if (!isKitIcon && window.CopyIcons && window.CopyIcons.forceProcess) {
2187
- window.CopyIcons.forceProcess(el);
2188
2082
  }
2189
2083
  }
2190
- document.addEventListener("viconic:ready", tryInjectFromEvent);
2191
- if (!isInjected() && isKitIcon && prefixMatch) {
2192
- const prefix = prefixMatch[1];
2193
- const iconBaseName = prefixMatch[2];
2194
- _queueKitMiss(prefix, iconBaseName);
2084
+ function onReady() {
2085
+ if (tryInjectFromCache()) {
2086
+ document.removeEventListener("viconic:ready", onReady);
2087
+ }
2195
2088
  }
2089
+ document.addEventListener("viconic:ready", onReady);
2196
2090
  return () => {
2197
- document.removeEventListener("viconic:ready", tryInjectFromEvent);
2091
+ document.removeEventListener("viconic:ready", onReady);
2198
2092
  };
2199
2093
  }, [name, className, size, color, style]);
2200
2094
  const combinedStyle = {
package/dist/index.mjs CHANGED
@@ -1630,8 +1630,6 @@ import React, { useEffect, useRef } from "react";
1630
1630
  display: inline-flex !important;
1631
1631
  align-items: center;
1632
1632
  justify-content: center;
1633
- background: none !important;
1634
- background-color: transparent !important;
1635
1633
 
1636
1634
  }
1637
1635
  :where(viconic-icon).svg-loaded:not(.ci-multicolor) svg {
@@ -1957,8 +1955,7 @@ import React, { useEffect, useRef } from "react";
1957
1955
  if (c && c.d && Date.now() - c.t < TTL) {
1958
1956
  for (const n in c.d) {
1959
1957
  if (!Object.prototype.hasOwnProperty.call(c.d, n)) continue;
1960
- const svg = c.d[n];
1961
- if (!W.icons[n]) W.icons[n] = svg;
1958
+ if (!W.icons[n]) W.icons[n] = c.d[n];
1962
1959
  }
1963
1960
  }
1964
1961
  } catch (e) {
@@ -1968,101 +1965,16 @@ import React, { useEffect, useRef } from "react";
1968
1965
  }
1969
1966
  })();
1970
1967
  var _initializedKits = /* @__PURE__ */ new Set();
1971
- var _kitRegistry = {};
1972
- var _pendingMisses = {};
1973
- if (typeof document !== "undefined") {
1974
- document.addEventListener("viconic:ready", (e) => {
1975
- const prefix = e && e.detail && e.detail.prefix;
1976
- if (prefix) _flushPendingMisses(prefix);
1977
- });
1978
- }
1979
- var _kitMissQueues = {};
1980
- var _kitMissTimers = {};
1981
- var _kitQueued = {};
1982
- function _resolveRegistry(prefix) {
1983
- if (_kitRegistry[prefix]) return _kitRegistry[prefix];
1984
- const kits = window.CopyIconsKit || {};
1985
- for (const kId in kits) {
1986
- const kit = kits[kId];
1987
- if (kit.config && kit.config.prefix === prefix) {
1988
- const entry = { kitId: kId, api: kit.config.api || "https://api.viconic.dev" };
1989
- _kitRegistry[prefix] = entry;
1990
- return entry;
1991
- }
1992
- }
1993
- return null;
1994
- }
1995
- function _flushPendingMisses(prefix) {
1996
- const pending = _pendingMisses[prefix];
1997
- if (!pending || !pending.size) return;
1998
- const entry = _resolveRegistry(prefix);
1999
- if (!entry) return;
2000
- delete _pendingMisses[prefix];
2001
- pending.forEach((name) => _dispatchBatchFetch(prefix, name, entry));
2002
- }
2003
- function _dispatchBatchFetch(prefix, iconBaseName, entry) {
2004
- const { kitId, api } = entry;
2005
- if (!_kitQueued[kitId]) _kitQueued[kitId] = /* @__PURE__ */ new Set();
2006
- if (_kitQueued[kitId].has(iconBaseName)) return;
2007
- _kitQueued[kitId].add(iconBaseName);
2008
- if (!_kitMissQueues[kitId]) _kitMissQueues[kitId] = /* @__PURE__ */ new Set();
2009
- _kitMissQueues[kitId].add(iconBaseName);
2010
- if (_kitMissTimers[kitId]) return;
2011
- _kitMissTimers[kitId] = setTimeout(() => {
2012
- delete _kitMissTimers[kitId];
2013
- const names = [..._kitMissQueues[kitId] || []];
2014
- delete _kitMissQueues[kitId];
2015
- if (!names.length) return;
2016
- fetch(`${api}/api/v1/kits/${kitId}/icons/?icons=${names.join(",")}`).then((r) => r.ok ? r.json() : null).then((bj) => {
2017
- if (!bj || !bj.icons) return;
2018
- const W = window.__viconic = window.__viconic || {};
2019
- W.icons = W.icons || {};
2020
- const cdnFetches = [];
2021
- for (const n in bj.icons) {
2022
- if (!Object.prototype.hasOwnProperty.call(bj.icons, n)) continue;
2023
- const d = bj.icons[n];
2024
- const svg = d.svg || "";
2025
- if (svg && svg.includes("<")) {
2026
- W.icons[`@${prefix}/${n}`] = svg;
2027
- W.icons[`${prefix}:${n}`] = svg;
2028
- W.icons[`${prefix}/${n}`] = svg;
2029
- W.icons[n] = W.icons[n] || svg;
2030
- } else if (d.cdn_url) {
2031
- cdnFetches.push(
2032
- fetch(d.cdn_url).then((r) => r.ok ? r.text() : "").then((s) => {
2033
- if (s && s.includes("<")) {
2034
- W.icons[`@${prefix}/${n}`] = s;
2035
- W.icons[`${prefix}:${n}`] = s;
2036
- W.icons[`${prefix}/${n}`] = s;
2037
- W.icons[n] = W.icons[n] || s;
2038
- }
2039
- }).catch(() => {
2040
- })
2041
- );
2042
- }
2043
- }
2044
- Promise.all(cdnFetches).then(() => {
2045
- try {
2046
- document.dispatchEvent(new CustomEvent("viconic:ready", { detail: { prefix, kitId } }));
2047
- } catch (e) {
2048
- }
2049
- });
2050
- }).catch(() => {
2051
- });
2052
- }, 150);
2053
- }
2054
- function _queueKitMiss(prefix, iconBaseName) {
2055
- if (typeof window === "undefined") return;
2056
- const entry = _resolveRegistry(prefix);
2057
- if (entry) {
2058
- _dispatchBatchFetch(prefix, iconBaseName, entry);
2059
- } else {
2060
- if (!_pendingMisses[prefix]) _pendingMisses[prefix] = /* @__PURE__ */ new Set();
2061
- _pendingMisses[prefix].add(iconBaseName);
2062
- }
1968
+ function _isQueued(kitId, iconName) {
1969
+ if (typeof window === "undefined") return false;
1970
+ const q = window.__viconicQueued = window.__viconicQueued || {};
1971
+ const k = kitId + ":" + iconName;
1972
+ if (q[k]) return true;
1973
+ q[k] = 1;
1974
+ return false;
2063
1975
  }
2064
1976
  function initViconic(options = {}) {
2065
- const { kitId, cdnBase = "cdn.viconic.dev", version, prefix: explicitPrefix, api = "https://api.viconic.dev" } = options;
1977
+ const { kitId, cdnBase = "cdn.viconic.dev", version } = options;
2066
1978
  if (typeof window === "undefined") return;
2067
1979
  if (!kitId) {
2068
1980
  console.warn("[Viconic] initViconic requires a kitId");
@@ -2070,31 +1982,14 @@ function initViconic(options = {}) {
2070
1982
  }
2071
1983
  if (_initializedKits.has(kitId)) return;
2072
1984
  _initializedKits.add(kitId);
2073
- if (explicitPrefix) {
2074
- _kitRegistry[explicitPrefix] = { kitId, api };
2075
- }
2076
- if (typeof window !== "undefined") {
2077
- window.__viconicKitIds = window.__viconicKitIds || {};
2078
- window.__viconicKitIds[kitId] = { api };
2079
- }
2080
1985
  const scriptId = `viconic-kit-${kitId}`;
2081
1986
  if (document.getElementById(scriptId)) return;
2082
1987
  const script = document.createElement("script");
2083
1988
  script.id = scriptId;
2084
1989
  let url = `https://${cdnBase}/kits/${kitId}/loader.js`;
2085
1990
  if (version) {
2086
- const vQuery = version === "dev" ? Date.now() : version;
2087
- url += `?v=${vQuery}`;
1991
+ url += `?v=${version === "dev" ? Date.now() : version}`;
2088
1992
  }
2089
- script.onload = () => {
2090
- const kits = window.CopyIconsKit || {};
2091
- const kit = kits[kitId];
2092
- if (kit && kit.config && kit.config.prefix) {
2093
- const pfx = kit.config.prefix;
2094
- _kitRegistry[pfx] = { kitId, api: kit.config.api || api };
2095
- _flushPendingMisses(pfx);
2096
- }
2097
- };
2098
1993
  script.src = url;
2099
1994
  script.async = true;
2100
1995
  document.head.appendChild(script);
@@ -2115,51 +2010,50 @@ var ViconicIcon = ({ name, className, style, size, color, ...props }) => {
2115
2010
  function isInjected() {
2116
2011
  return el.classList.contains("vi-ok") || el.classList.contains("svg-loaded");
2117
2012
  }
2118
- if (!isInjected()) {
2013
+ function tryInjectFromCache() {
2014
+ if (isInjected()) return false;
2119
2015
  const W = window.__viconic;
2120
- if (W && W.icons) {
2121
- const iconBaseName = prefixMatch ? prefixMatch[2] : null;
2122
- const svg = iconBaseName && W.icons[iconBaseName] || name && W.icons[name] || null;
2123
- if (svg) {
2124
- el.innerHTML = svg;
2125
- el.classList.add("vi-ok", "svg-loaded");
2126
- }
2016
+ if (!W || !W.icons) return false;
2017
+ const baseName = prefixMatch ? prefixMatch[2] : null;
2018
+ const svg = baseName && W.icons[baseName] || name && W.icons[name] || null;
2019
+ if (svg) {
2020
+ el.innerHTML = svg;
2021
+ el.classList.add("vi-ok", "svg-loaded");
2022
+ return true;
2127
2023
  }
2024
+ return false;
2128
2025
  }
2129
- if (!isInjected() && !isKitIcon) {
2026
+ if (tryInjectFromCache()) return;
2027
+ if (!isKitIcon) {
2130
2028
  if (window.CopyIcons && window.CopyIcons.forceProcess) {
2131
2029
  window.CopyIcons.forceProcess(el);
2030
+ } else if (el._u) {
2031
+ el._u();
2132
2032
  }
2133
2033
  }
2134
- if (!isInjected() && !isKitIcon && el._u) {
2135
- el._u();
2136
- }
2137
2034
  if (isInjected()) return;
2138
- function tryInjectFromEvent() {
2139
- if (isInjected()) return;
2140
- const W = window.__viconic;
2141
- if (W && W.icons) {
2142
- const iconBaseName = prefixMatch ? prefixMatch[2] : null;
2143
- const svg = iconBaseName && W.icons[iconBaseName] || name && W.icons[name] || null;
2144
- if (svg) {
2145
- el.innerHTML = svg;
2146
- el.classList.add("vi-ok", "svg-loaded");
2147
- return;
2035
+ if (isKitIcon && prefixMatch) {
2036
+ const kitId = (() => {
2037
+ const kits = window.CopyIconsKit || {};
2038
+ for (const kId in kits) {
2039
+ if (kits[kId].config && kits[kId].config.prefix === prefixMatch[1]) return kId;
2040
+ }
2041
+ return prefixMatch[1];
2042
+ })();
2043
+ if (!_isQueued(kitId, prefixMatch[2])) {
2044
+ if (el._u) {
2045
+ el._u();
2148
2046
  }
2149
- }
2150
- if (!isKitIcon && el._u) el._u();
2151
- if (!isKitIcon && window.CopyIcons && window.CopyIcons.forceProcess) {
2152
- window.CopyIcons.forceProcess(el);
2153
2047
  }
2154
2048
  }
2155
- document.addEventListener("viconic:ready", tryInjectFromEvent);
2156
- if (!isInjected() && isKitIcon && prefixMatch) {
2157
- const prefix = prefixMatch[1];
2158
- const iconBaseName = prefixMatch[2];
2159
- _queueKitMiss(prefix, iconBaseName);
2049
+ function onReady() {
2050
+ if (tryInjectFromCache()) {
2051
+ document.removeEventListener("viconic:ready", onReady);
2052
+ }
2160
2053
  }
2054
+ document.addEventListener("viconic:ready", onReady);
2161
2055
  return () => {
2162
- document.removeEventListener("viconic:ready", tryInjectFromEvent);
2056
+ document.removeEventListener("viconic:ready", onReady);
2163
2057
  };
2164
2058
  }, [name, className, size, color, style]);
2165
2059
  const combinedStyle = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viconic-react-icons",
3
- "version": "1.5.6",
3
+ "version": "1.5.8",
4
4
  "description": "Viconic Smart Icons loader for React — supports Kit and 200k+ system icons",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1855,8 +1855,6 @@
1855
1855
  display: inline-flex !important;
1856
1856
  align-items: center;
1857
1857
  justify-content: center;
1858
- background: none !important;
1859
- background-color: transparent !important;
1860
1858
 
1861
1859
  }
1862
1860
  :where(viconic-icon).svg-loaded:not(.ci-multicolor) svg {
package/src/index.jsx CHANGED
@@ -3,32 +3,27 @@ import './copyicons-smart-loader.js';
3
3
 
4
4
  // ============================================
5
5
  // PRE-LOAD KIT CACHE SYNCHRONOUSLY AT MODULE LEVEL
6
- // Same architecture as kit loader: read localStorage before any render
7
- // so icons are available instantly when components mount.
8
6
  // ============================================
9
7
  (function _preloadKitCache() {
10
8
  if (typeof window === 'undefined' || typeof localStorage === 'undefined') return;
11
9
  try {
12
10
  const W = (window.__viconic = window.__viconic || {});
13
11
  W.icons = W.icons || {};
14
- const TTL = 3 * 24 * 60 * 60 * 1000; // 3 days
12
+ const TTL = 3 * 24 * 60 * 60 * 1000;
15
13
  for (let i = 0; i < localStorage.length; i++) {
16
14
  const key = localStorage.key(i);
17
15
  if (!key || !key.startsWith('viconic:')) continue;
18
16
  try {
19
17
  const c = JSON.parse(localStorage.getItem(key));
20
18
  if (c && c.d && Date.now() - c.t < TTL) {
21
- // Register all icon name variants into W.icons
22
19
  for (const n in c.d) {
23
20
  if (!Object.prototype.hasOwnProperty.call(c.d, n)) continue;
24
- const svg = c.d[n];
25
- // Store by plain name so _u() can find it regardless of prefix
26
- if (!W.icons[n]) W.icons[n] = svg;
21
+ if (!W.icons[n]) W.icons[n] = c.d[n];
27
22
  }
28
23
  }
29
- } catch (e) { /* corrupted entry, skip */ }
24
+ } catch (e) {}
30
25
  }
31
- } catch (e) { }
26
+ } catch (e) {}
32
27
  })();
33
28
 
34
29
  // ============================================
@@ -37,189 +32,58 @@ import './copyicons-smart-loader.js';
37
32
  const _initializedKits = new Set();
38
33
 
39
34
  // ============================================
40
- // Kit registry: prefix -> { kitId, api }
41
- // Populated by initViconic() via script.onload
42
- // and by viconic:ready event handler.
35
+ // Window-level dedup set: survives HMR module reloads and Strict Mode remounts.
36
+ // Keyed by iconKey = "kitId:iconName". Cleared after loader fires viconic:ready.
43
37
  // ============================================
44
- const _kitRegistry = {}; // prefix -> { kitId, api }
45
-
46
- // Pending misses buffered before registry is ready
47
- // prefix -> Set of icon names
48
- const _pendingMisses = {};
49
-
50
- // Global viconic:ready listener — fires when kit loader calls register()
51
- // This is the main trigger for flushing pending misses when loader.js
52
- // completes its first batch fetch (which happens after script.onload).
53
- if (typeof document !== 'undefined') {
54
- document.addEventListener('viconic:ready', (e) => {
55
- const prefix = e && e.detail && e.detail.prefix;
56
- if (prefix) _flushPendingMisses(prefix);
57
- });
58
- }
59
-
60
- // ============================================
61
- // DEBOUNCED BATCH FETCH for missing kit icons
62
- // ============================================
63
- const _kitMissQueues = {}; // kitId -> Set of icon names
64
- const _kitMissTimers = {}; // kitId -> timer handle
65
- const _kitQueued = {}; // kitId -> Set of icon names already queued (prevents Strict Mode double-queue)
66
-
67
- function _resolveRegistry(prefix) {
68
- if (_kitRegistry[prefix]) return _kitRegistry[prefix];
69
- // Fallback: check CopyIconsKit
70
- const kits = window.CopyIconsKit || {};
71
- for (const kId in kits) {
72
- const kit = kits[kId];
73
- if (kit.config && kit.config.prefix === prefix) {
74
- const entry = { kitId: kId, api: kit.config.api || 'https://api.viconic.dev' };
75
- _kitRegistry[prefix] = entry;
76
- return entry;
77
- }
78
- }
79
- return null;
38
+ function _isQueued(kitId, iconName) {
39
+ if (typeof window === 'undefined') return false;
40
+ const q = (window.__viconicQueued = window.__viconicQueued || {});
41
+ const k = kitId + ':' + iconName;
42
+ if (q[k]) return true;
43
+ q[k] = 1;
44
+ return false;
80
45
  }
81
46
 
82
- function _flushPendingMisses(prefix) {
83
- const pending = _pendingMisses[prefix];
84
- if (!pending || !pending.size) return;
85
- const entry = _resolveRegistry(prefix);
86
- if (!entry) return;
87
- delete _pendingMisses[prefix];
88
- pending.forEach(name => _dispatchBatchFetch(prefix, name, entry));
89
- }
90
-
91
- function _dispatchBatchFetch(prefix, iconBaseName, entry) {
92
- const { kitId, api } = entry;
93
- // Skip if already queued — prevents React Strict Mode double-invoke from making 2 requests
94
- if (!_kitQueued[kitId]) _kitQueued[kitId] = new Set();
95
- if (_kitQueued[kitId].has(iconBaseName)) return;
96
- _kitQueued[kitId].add(iconBaseName);
97
- if (!_kitMissQueues[kitId]) _kitMissQueues[kitId] = new Set();
98
- _kitMissQueues[kitId].add(iconBaseName);
99
- if (_kitMissTimers[kitId]) return; // already scheduled, will pick up new additions
100
- // 150ms debounce: collect all icons across the full React render cycle
101
- _kitMissTimers[kitId] = setTimeout(() => {
102
- delete _kitMissTimers[kitId];
103
- const names = [...(_kitMissQueues[kitId] || [])];
104
- delete _kitMissQueues[kitId];
105
- if (!names.length) return;
106
- fetch(`${api}/api/v1/kits/${kitId}/icons/?icons=${names.join(',')}`)
107
- .then(r => r.ok ? r.json() : null)
108
- .then(bj => {
109
- if (!bj || !bj.icons) return;
110
- const W = (window.__viconic = window.__viconic || {});
111
- W.icons = W.icons || {};
112
- const cdnFetches = [];
113
- for (const n in bj.icons) {
114
- if (!Object.prototype.hasOwnProperty.call(bj.icons, n)) continue;
115
- const d = bj.icons[n];
116
- const svg = d.svg || '';
117
- if (svg && svg.includes('<')) {
118
- W.icons[`@${prefix}/${n}`] = svg;
119
- W.icons[`${prefix}:${n}`] = svg;
120
- W.icons[`${prefix}/${n}`] = svg;
121
- W.icons[n] = W.icons[n] || svg;
122
- } else if (d.cdn_url) {
123
- // User-uploaded icon: fetch SVG from CDN and store in W.icons
124
- // so loader refresh() finds it and doesn't fetch individually
125
- cdnFetches.push(
126
- fetch(d.cdn_url)
127
- .then(r => r.ok ? r.text() : '')
128
- .then(s => {
129
- if (s && s.includes('<')) {
130
- W.icons[`@${prefix}/${n}`] = s;
131
- W.icons[`${prefix}:${n}`] = s;
132
- W.icons[`${prefix}/${n}`] = s;
133
- W.icons[n] = W.icons[n] || s;
134
- }
135
- })
136
- .catch(() => {})
137
- );
138
- }
139
- }
140
- Promise.all(cdnFetches).then(() => {
141
- try { document.dispatchEvent(new CustomEvent('viconic:ready', { detail: { prefix, kitId } })); } catch(e) {}
142
- });
143
- })
144
- .catch(() => {});
145
- }, 150);
146
- }
147
-
148
- function _queueKitMiss(prefix, iconBaseName) {
47
+ function _clearQueued(kitId) {
149
48
  if (typeof window === 'undefined') return;
150
- const entry = _resolveRegistry(prefix);
151
- if (entry) {
152
- _dispatchBatchFetch(prefix, iconBaseName, entry);
153
- } else {
154
- // Registry not ready yet — buffer until loader fires
155
- if (!_pendingMisses[prefix]) _pendingMisses[prefix] = new Set();
156
- _pendingMisses[prefix].add(iconBaseName);
49
+ const q = window.__viconicQueued;
50
+ if (!q) return;
51
+ const prefix = kitId + ':';
52
+ for (const k in q) {
53
+ if (k.startsWith(prefix)) delete q[k];
157
54
  }
158
55
  }
159
56
 
160
57
  /**
161
58
  * Initialize a Viconic Kit in your React app.
162
59
  * Injects the kit's loader.js script into <head>.
163
- * Supports multiple kits — call once per kit.
164
60
  *
165
61
  * @param {Object} options
166
62
  * @param {string} options.kitId - UUID of the Kit (required)
167
63
  * @param {string} [options.cdnBase] - Custom CDN domain (default: cdn.viconic.dev)
168
- *
169
- * @example
170
- * import { initViconic } from 'viconic-react-icons';
171
- *
172
- * initViconic({ kitId: '387a6161-cb39-411f-8f13-29a5813e4efd' });
173
- * // Multiple kits:
174
- * initViconic({ kitId: 'another-kit-uuid', version: '1.0' });
64
+ * @param {string} [options.version] - Version string for cache busting
175
65
  */
176
66
  export function initViconic(options = {}) {
177
- const { kitId, cdnBase = 'cdn.viconic.dev', version, prefix: explicitPrefix, api = 'https://api.viconic.dev' } = options;
178
- if (typeof window === 'undefined') return; // SSR guard
67
+ const { kitId, cdnBase = 'cdn.viconic.dev', version } = options;
68
+ if (typeof window === 'undefined') return;
179
69
  if (!kitId) {
180
70
  console.warn('[Viconic] initViconic requires a kitId');
181
71
  return;
182
72
  }
183
- if (_initializedKits.has(kitId)) return; // Already initialized
73
+ if (_initializedKits.has(kitId)) return;
184
74
  _initializedKits.add(kitId);
185
75
 
186
- // Register synchronously so _queueKitMiss can find kitId immediately,
187
- // even before the async loader.js script has loaded and populated CopyIconsKit.
188
- // If prefix is not known yet, we'll also register once CopyIconsKit fires.
189
- if (explicitPrefix) {
190
- _kitRegistry[explicitPrefix] = { kitId, api };
191
- }
192
- // Also register by kitId so we can backfill prefix once loader fires
193
- if (typeof window !== 'undefined') {
194
- window.__viconicKitIds = window.__viconicKitIds || {};
195
- window.__viconicKitIds[kitId] = { api };
196
- }
197
-
198
76
  const scriptId = `viconic-kit-${kitId}`;
199
- if (document.getElementById(scriptId)) return; // Script already in DOM
77
+ if (document.getElementById(scriptId)) return;
200
78
 
201
79
  const script = document.createElement('script');
202
80
  script.id = scriptId;
203
81
 
204
- // Add cache busting for development or specific version updates
205
82
  let url = `https://${cdnBase}/kits/${kitId}/loader.js`;
206
83
  if (version) {
207
- const vQuery = version === 'dev' ? Date.now() : version;
208
- url += `?v=${vQuery}`;
84
+ url += `?v=${version === 'dev' ? Date.now() : version}`;
209
85
  }
210
86
 
211
- // Once loader.js runs and registers CopyIconsKit, backfill _kitRegistry and flush pending misses
212
- script.onload = () => {
213
- const kits = window.CopyIconsKit || {};
214
- const kit = kits[kitId];
215
- if (kit && kit.config && kit.config.prefix) {
216
- const pfx = kit.config.prefix;
217
- _kitRegistry[pfx] = { kitId, api: kit.config.api || api };
218
- // Flush any misses buffered before the loader was ready
219
- _flushPendingMisses(pfx);
220
- }
221
- };
222
-
223
87
  script.src = url;
224
88
  script.async = true;
225
89
  document.head.appendChild(script);
@@ -227,11 +91,7 @@ export function initViconic(options = {}) {
227
91
 
228
92
  /**
229
93
  * ViconicIcon — React component for rendering Viconic icons.
230
- *
231
- * Works with both:
232
- * - System icons: <ViconicIcon name="lucide:home" />
233
- * - Kit icons: <ViconicIcon name="@myprefix/home" /> (after initViconic)
234
- *
94
+ *
235
95
  * @param {string} name - Icon identifier (e.g., "lucide:home", "@prefix/name")
236
96
  * @param {string} [className] - CSS class names
237
97
  * @param {object} [style] - Inline styles
@@ -246,7 +106,6 @@ export const ViconicIcon = ({ name, className, style, size, color, ...props }) =
246
106
  const el = iconRef.current;
247
107
  if (!el) return;
248
108
 
249
- // --- FIX DOM REUSE (Reconciliation) ---
250
109
  if (prevNameRef.current !== name) {
251
110
  el.innerHTML = '';
252
111
  el.classList.remove('vi-ok', 'svg-loaded', 'vi-mono', 'ci-multicolor');
@@ -260,78 +119,73 @@ export const ViconicIcon = ({ name, className, style, size, color, ...props }) =
260
119
  return el.classList.contains('vi-ok') || el.classList.contains('svg-loaded');
261
120
  }
262
121
 
263
- // --- PATH 1: Synchronous inject from W.icons (pre-loaded from localStorage at module init) ---
264
- if (!isInjected()) {
122
+ function tryInjectFromCache() {
123
+ if (isInjected()) return false;
265
124
  const W = window.__viconic;
266
- if (W && W.icons) {
267
- // Try all key variants: iconBaseName, @prefix/name, prefix:name, prefix/name
268
- const iconBaseName = prefixMatch ? prefixMatch[2] : null;
269
- const svg = (iconBaseName && W.icons[iconBaseName])
270
- || (name && W.icons[name])
271
- || null;
272
- if (svg) {
273
- el.innerHTML = svg;
274
- el.classList.add('vi-ok', 'svg-loaded');
275
- }
125
+ if (!W || !W.icons) return false;
126
+ const baseName = prefixMatch ? prefixMatch[2] : null;
127
+ const svg = (baseName && W.icons[baseName])
128
+ || (name && W.icons[name])
129
+ || null;
130
+ if (svg) {
131
+ el.innerHTML = svg;
132
+ el.classList.add('vi-ok', 'svg-loaded');
133
+ return true;
276
134
  }
135
+ return false;
277
136
  }
278
137
 
279
- // --- PATH 2: Smart loader for system icons (prefix:name) ---
280
- if (!isInjected() && !isKitIcon) {
138
+ // PATH 1: Already in W.icons (from localStorage preload or prior fetch)
139
+ if (tryInjectFromCache()) return;
140
+
141
+ // PATH 2: System icons — delegate to smart loader
142
+ if (!isKitIcon) {
281
143
  if (window.CopyIcons && window.CopyIcons.forceProcess) {
282
144
  window.CopyIcons.forceProcess(el);
145
+ } else if (el._u) {
146
+ el._u();
283
147
  }
284
148
  }
285
149
 
286
- // --- PATH 3: Custom element _u() call (kit loader registered element, system icons only) ---
287
- if (!isInjected() && !isKitIcon && el._u) {
288
- el._u();
289
- }
290
-
291
150
  if (isInjected()) return;
292
151
 
293
- // --- PATH 4: Event-drivenlisten for viconic:ready fired by kit loader after register() ---
294
- // Much faster than polling: icons appear the instant the loader finishes fetching them.
295
- function tryInjectFromEvent() {
296
- if (isInjected()) return;
297
- const W = window.__viconic;
298
- if (W && W.icons) {
299
- const iconBaseName = prefixMatch ? prefixMatch[2] : null;
300
- const svg = (iconBaseName && W.icons[iconBaseName])
301
- || (name && W.icons[name])
302
- || null;
303
- if (svg) {
304
- el.innerHTML = svg;
305
- el.classList.add('vi-ok', 'svg-loaded');
306
- return;
152
+ // PATH 3: Kit icons let loader.js handle batching via el._u()
153
+ // el._u() notifies the loader element to queue this icon.
154
+ // Loader already has its own debounced batch queue.
155
+ // Use window-level dedup to prevent Strict Mode / HMR double-calls.
156
+ if (isKitIcon && prefixMatch) {
157
+ const kitId = (() => {
158
+ const kits = window.CopyIconsKit || {};
159
+ for (const kId in kits) {
160
+ if (kits[kId].config && kits[kId].config.prefix === prefixMatch[1]) return kId;
161
+ }
162
+ return prefixMatch[1]; // fallback to prefix as key
163
+ })();
164
+
165
+ if (!_isQueued(kitId, prefixMatch[2])) {
166
+ if (el._u) {
167
+ el._u();
307
168
  }
308
- }
309
- if (!isKitIcon && el._u) el._u();
310
- if (!isKitIcon && window.CopyIcons && window.CopyIcons.forceProcess) {
311
- window.CopyIcons.forceProcess(el);
312
169
  }
313
170
  }
314
171
 
315
- document.addEventListener('viconic:ready', tryInjectFromEvent);
316
-
317
- // --- PATH 5: Immediate queue for missing kit icons ---
318
- // Call _queueKitMiss immediately (no per-component delay) so all icons from
319
- // the same render cycle are collected into the same debounced batch request.
320
- if (!isInjected() && isKitIcon && prefixMatch) {
321
- const prefix = prefixMatch[1];
322
- const iconBaseName = prefixMatch[2];
323
- _queueKitMiss(prefix, iconBaseName);
172
+ // PATH 4: Listen for viconic:ready to inject when loader finishes fetching
173
+ function onReady() {
174
+ if (tryInjectFromCache()) {
175
+ document.removeEventListener('viconic:ready', onReady);
176
+ }
324
177
  }
178
+ document.addEventListener('viconic:ready', onReady);
325
179
 
326
180
  return () => {
327
- document.removeEventListener('viconic:ready', tryInjectFromEvent);
181
+ document.removeEventListener('viconic:ready', onReady);
328
182
  };
329
183
  }, [name, className, size, color, style]);
330
184
 
331
185
  const combinedStyle = {
332
186
  ...(size ? { fontSize: size } : {}),
333
187
  ...(color ? { color: color } : {}),
334
- ...style
188
+ ...style,
335
189
  };
336
190
 
337
191
  return (