@servlyadmin/runtime-core 0.1.43 → 0.1.45

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.
@@ -33,6 +33,7 @@ function markTailwindAsLoaded() {
33
33
  function preloadTailwind(cdnUrl, usePlayCdn) {
34
34
  if (typeof document === "undefined") return;
35
35
  if (document.querySelector("link[data-servly-tailwind-preload]")) return;
36
+ if (document.querySelector('script[src*="tailwindcss.com"]')) return;
36
37
  const url = cdnUrl || DEFAULT_TAILWIND_CDN;
37
38
  const fullUrl = usePlayCdn ? `${url}?plugins=forms,typography,aspect-ratio` : url;
38
39
  const link = document.createElement("link");
@@ -40,15 +41,18 @@ function preloadTailwind(cdnUrl, usePlayCdn) {
40
41
  link.as = "script";
41
42
  link.href = fullUrl;
42
43
  link.setAttribute("data-servly-tailwind-preload", "true");
44
+ link.setAttribute("crossorigin", "anonymous");
43
45
  if (document.head.firstChild) {
44
46
  document.head.insertBefore(link, document.head.firstChild);
45
47
  } else {
46
48
  document.head.appendChild(link);
47
49
  }
48
- const dnsPrefetch = document.createElement("link");
49
- dnsPrefetch.rel = "dns-prefetch";
50
- dnsPrefetch.href = "https://cdn.tailwindcss.com";
51
- document.head.appendChild(dnsPrefetch);
50
+ if (!document.querySelector('link[rel="dns-prefetch"][href*="tailwindcss.com"]')) {
51
+ const dnsPrefetch = document.createElement("link");
52
+ dnsPrefetch.rel = "dns-prefetch";
53
+ dnsPrefetch.href = "https://cdn.tailwindcss.com";
54
+ document.head.appendChild(dnsPrefetch);
55
+ }
52
56
  }
53
57
  function preventFOUC() {
54
58
  if (typeof document === "undefined") return;
@@ -135,7 +139,6 @@ function injectTailwind(config = {}) {
135
139
  const {
136
140
  cdnUrl = DEFAULT_TAILWIND_CDN,
137
141
  config: tailwindConfig,
138
- plugins = [],
139
142
  usePlayCdn = false,
140
143
  onReady,
141
144
  onError,
package/dist/index.cjs CHANGED
@@ -61,6 +61,7 @@ function markTailwindAsLoaded() {
61
61
  function preloadTailwind(cdnUrl, usePlayCdn) {
62
62
  if (typeof document === "undefined") return;
63
63
  if (document.querySelector("link[data-servly-tailwind-preload]")) return;
64
+ if (document.querySelector('script[src*="tailwindcss.com"]')) return;
64
65
  const url = cdnUrl || DEFAULT_TAILWIND_CDN;
65
66
  const fullUrl = usePlayCdn ? `${url}?plugins=forms,typography,aspect-ratio` : url;
66
67
  const link = document.createElement("link");
@@ -68,15 +69,18 @@ function preloadTailwind(cdnUrl, usePlayCdn) {
68
69
  link.as = "script";
69
70
  link.href = fullUrl;
70
71
  link.setAttribute("data-servly-tailwind-preload", "true");
72
+ link.setAttribute("crossorigin", "anonymous");
71
73
  if (document.head.firstChild) {
72
74
  document.head.insertBefore(link, document.head.firstChild);
73
75
  } else {
74
76
  document.head.appendChild(link);
75
77
  }
76
- const dnsPrefetch = document.createElement("link");
77
- dnsPrefetch.rel = "dns-prefetch";
78
- dnsPrefetch.href = "https://cdn.tailwindcss.com";
79
- document.head.appendChild(dnsPrefetch);
78
+ if (!document.querySelector('link[rel="dns-prefetch"][href*="tailwindcss.com"]')) {
79
+ const dnsPrefetch = document.createElement("link");
80
+ dnsPrefetch.rel = "dns-prefetch";
81
+ dnsPrefetch.href = "https://cdn.tailwindcss.com";
82
+ document.head.appendChild(dnsPrefetch);
83
+ }
80
84
  }
81
85
  function preventFOUC() {
82
86
  if (typeof document === "undefined") return;
@@ -163,7 +167,6 @@ function injectTailwind(config = {}) {
163
167
  const {
164
168
  cdnUrl = DEFAULT_TAILWIND_CDN,
165
169
  config: tailwindConfig,
166
- plugins = [],
167
170
  usePlayCdn = false,
168
171
  onReady,
169
172
  onError,
@@ -684,6 +687,7 @@ __export(index_exports, {
684
687
  StateManager: () => StateManager,
685
688
  addClass: () => addClass,
686
689
  addCustomStyles: () => addCustomStyles,
690
+ addFontPreconnect: () => addFontPreconnect,
687
691
  analytics: () => analytics,
688
692
  applyStyles: () => applyStyles,
689
693
  batchFetchComponents: () => batchFetchComponents,
@@ -694,6 +698,7 @@ __export(index_exports, {
694
698
  camelToKebab: () => camelToKebab,
695
699
  clearAllCaches: () => clearAllCaches,
696
700
  clearIconCache: () => clearIconCache,
701
+ clearIconStorageCache: () => clearIconStorageCache,
697
702
  clearLocalStorageCache: () => clearLocalStorageCache,
698
703
  clearMemoryCache: () => clearMemoryCache,
699
704
  clearStyles: () => clearStyles,
@@ -709,6 +714,7 @@ __export(index_exports, {
709
714
  deepMerge: () => deepMerge,
710
715
  deleteValueByPath: () => deleteValueByPath,
711
716
  detectCircularDependencies: () => detectCircularDependencies,
717
+ ensureFonts: () => ensureFonts,
712
718
  extractBindingKeys: () => extractBindingKeys,
713
719
  extractDependencies: () => extractDependencies,
714
720
  extractDependenciesFromCode: () => extractDependenciesFromCode,
@@ -722,12 +728,14 @@ __export(index_exports, {
722
728
  getAnalytics: () => getAnalytics,
723
729
  getCacheKey: () => getCacheKey,
724
730
  getCleanupOverrides: () => getCleanupOverrides,
731
+ getDefaultFonts: () => getDefaultFonts,
725
732
  getDependencyTree: () => getDependencyTree,
726
733
  getEventSystem: () => getEventSystem,
727
734
  getFromCache: () => getFromCache,
728
735
  getIconData: () => getIconData,
729
736
  getIconDataSync: () => getIconDataSync,
730
737
  getIconifyCollection: () => getIconifyCollection,
738
+ getLoadedFonts: () => getLoadedFonts,
731
739
  getLocalStorage: () => getLocalStorage,
732
740
  getLongTaskObserver: () => getLongTaskObserver,
733
741
  getMemoryCacheSize: () => getMemoryCacheSize,
@@ -748,17 +756,22 @@ __export(index_exports, {
748
756
  hasDependencyOverrides: () => hasDependencyOverrides,
749
757
  hasOverrides: () => hasOverrides,
750
758
  hasTemplateSyntax: () => hasTemplateSyntax,
759
+ initFonts: () => initFonts,
751
760
  initServlyTailwind: () => initServlyTailwind,
752
761
  injectTailwind: () => injectTailwind,
753
762
  injectTailwindStyles: () => injectTailwindStyles,
754
763
  invalidateCache: () => invalidateCache,
755
764
  isComponentAvailable: () => isComponentAvailable,
765
+ isFontLoaded: () => isFontLoaded,
756
766
  isIconCdnEnabled: () => isIconCdnEnabled,
757
767
  isIconRegistered: () => isIconRegistered,
758
768
  isIconSetSupported: () => isIconSetSupported,
759
769
  isTailwindLoaded: () => isTailwindLoaded,
760
770
  isTailwindReady: () => isTailwindReady,
761
771
  isValidSpecifier: () => isValidSpecifier,
772
+ loadDefaultFonts: () => loadDefaultFonts,
773
+ loadFont: () => loadFont,
774
+ loadFonts: () => loadFonts,
762
775
  markElementReady: () => markElementReady,
763
776
  navigateTo: () => navigateTo,
764
777
  parseVersion: () => parseVersion,
@@ -3118,6 +3131,58 @@ function resetOverrideSystem() {
3118
3131
 
3119
3132
  // src/icons.ts
3120
3133
  var cdnEnabled = true;
3134
+ var ICON_CACHE_KEY = "servly-icon-cache";
3135
+ var ICON_CACHE_VERSION = "1";
3136
+ var localStorageLoaded = false;
3137
+ function loadIconCacheFromStorage() {
3138
+ if (localStorageLoaded) return;
3139
+ localStorageLoaded = true;
3140
+ if (typeof localStorage === "undefined") return;
3141
+ try {
3142
+ const cached = localStorage.getItem(ICON_CACHE_KEY);
3143
+ if (!cached) return;
3144
+ const parsed = JSON.parse(cached);
3145
+ if (parsed.version !== ICON_CACHE_VERSION) {
3146
+ localStorage.removeItem(ICON_CACHE_KEY);
3147
+ return;
3148
+ }
3149
+ for (const [key, data] of Object.entries(parsed.icons)) {
3150
+ if (!iconCache.has(key) && !registeredIcons.has(key)) {
3151
+ iconCache.set(key, data);
3152
+ }
3153
+ }
3154
+ } catch {
3155
+ }
3156
+ }
3157
+ function saveIconToStorage(key, data) {
3158
+ if (typeof localStorage === "undefined") return;
3159
+ try {
3160
+ const cached = localStorage.getItem(ICON_CACHE_KEY);
3161
+ let cacheData;
3162
+ if (cached) {
3163
+ cacheData = JSON.parse(cached);
3164
+ if (cacheData.version !== ICON_CACHE_VERSION) {
3165
+ cacheData = { version: ICON_CACHE_VERSION, icons: {} };
3166
+ }
3167
+ } else {
3168
+ cacheData = { version: ICON_CACHE_VERSION, icons: {} };
3169
+ }
3170
+ cacheData.icons[key] = data;
3171
+ const keys = Object.keys(cacheData.icons);
3172
+ if (keys.length > 500) {
3173
+ keys.slice(0, 100).forEach((k) => delete cacheData.icons[k]);
3174
+ }
3175
+ localStorage.setItem(ICON_CACHE_KEY, JSON.stringify(cacheData));
3176
+ } catch {
3177
+ }
3178
+ }
3179
+ function clearIconStorageCache() {
3180
+ if (typeof localStorage === "undefined") return;
3181
+ try {
3182
+ localStorage.removeItem(ICON_CACHE_KEY);
3183
+ } catch {
3184
+ }
3185
+ }
3121
3186
  function setIconCdnEnabled(enabled) {
3122
3187
  cdnEnabled = enabled;
3123
3188
  }
@@ -3290,6 +3355,7 @@ function parseSvgResponse(svgText) {
3290
3355
  }
3291
3356
  async function getIconData(icon) {
3292
3357
  const key = `${icon.set}:${icon.name}`;
3358
+ loadIconCacheFromStorage();
3293
3359
  if (iconCache.has(key)) {
3294
3360
  return iconCache.get(key);
3295
3361
  }
@@ -3305,11 +3371,13 @@ async function getIconData(icon) {
3305
3371
  pendingFetches.delete(key);
3306
3372
  if (data) {
3307
3373
  iconCache.set(key, data);
3374
+ saveIconToStorage(key, data);
3308
3375
  }
3309
3376
  return data;
3310
3377
  }
3311
3378
  function getIconDataSync(icon) {
3312
3379
  const key = `${icon.set}:${icon.name}`;
3380
+ loadIconCacheFromStorage();
3313
3381
  return iconCache.get(key) || null;
3314
3382
  }
3315
3383
  function createIconSVG(icon, data, size = 24, color = "currentColor") {
@@ -3409,12 +3477,15 @@ function renderIcon(container, icon, size = 24, color = "currentColor") {
3409
3477
  async function preloadIcons(icons) {
3410
3478
  await Promise.all(icons.map((icon) => getIconData(icon)));
3411
3479
  }
3412
- function clearIconCache() {
3480
+ function clearIconCache(clearStorage = false) {
3413
3481
  iconCache.clear();
3414
3482
  pendingFetches.clear();
3415
3483
  registeredIcons.forEach((data, key) => {
3416
3484
  iconCache.set(key, data);
3417
3485
  });
3486
+ if (clearStorage) {
3487
+ clearIconStorageCache();
3488
+ }
3418
3489
  }
3419
3490
  function isIconSetSupported(set) {
3420
3491
  return set in ICONIFY_COLLECTIONS;
@@ -3428,6 +3499,113 @@ function getIconifyCollection(set) {
3428
3499
 
3429
3500
  // src/renderer.ts
3430
3501
  init_tailwind();
3502
+
3503
+ // src/fonts.ts
3504
+ var DEFAULT_FONTS = [
3505
+ "Roboto",
3506
+ "Open Sans",
3507
+ "Lato",
3508
+ "Montserrat",
3509
+ "Poppins",
3510
+ "Inter",
3511
+ "Playfair Display",
3512
+ "Raleway",
3513
+ "Ubuntu",
3514
+ "Nunito",
3515
+ "Merriweather",
3516
+ "Work Sans",
3517
+ "Quicksand",
3518
+ "Mulish",
3519
+ "Manrope",
3520
+ "DM Sans",
3521
+ "Space Grotesk",
3522
+ "Plus Jakarta Sans",
3523
+ "Outfit",
3524
+ "Sora"
3525
+ ];
3526
+ var loadedFonts = /* @__PURE__ */ new Set();
3527
+ var fontsInitialized = false;
3528
+ var preconnectAdded = false;
3529
+ function addFontPreconnect() {
3530
+ if (typeof document === "undefined" || preconnectAdded) return;
3531
+ preconnectAdded = true;
3532
+ if (!document.querySelector('link[href="https://fonts.googleapis.com"]')) {
3533
+ const pc1 = document.createElement("link");
3534
+ pc1.rel = "preconnect";
3535
+ pc1.href = "https://fonts.googleapis.com";
3536
+ document.head.appendChild(pc1);
3537
+ }
3538
+ if (!document.querySelector('link[href="https://fonts.gstatic.com"]')) {
3539
+ const pc2 = document.createElement("link");
3540
+ pc2.rel = "preconnect";
3541
+ pc2.href = "https://fonts.gstatic.com";
3542
+ pc2.crossOrigin = "anonymous";
3543
+ document.head.appendChild(pc2);
3544
+ }
3545
+ }
3546
+ function loadFont(family, weights = ["400", "500", "600", "700"]) {
3547
+ if (typeof document === "undefined") return;
3548
+ const linkId = `google-font-${family.replace(/[\s+]/g, "-").toLowerCase()}`;
3549
+ if (document.getElementById(linkId) || loadedFonts.has(family)) {
3550
+ return;
3551
+ }
3552
+ addFontPreconnect();
3553
+ const weightsStr = weights.join(";");
3554
+ const encodedFontName = encodeURIComponent(family).replace(/%20/g, "+");
3555
+ const fontUrl = `https://fonts.googleapis.com/css2?family=${encodedFontName}:wght@${weightsStr}&display=swap`;
3556
+ const link = document.createElement("link");
3557
+ link.id = linkId;
3558
+ link.rel = "stylesheet";
3559
+ link.href = fontUrl;
3560
+ document.head.appendChild(link);
3561
+ loadedFonts.add(family);
3562
+ }
3563
+ function loadFonts(fonts, weights = ["400", "500", "600", "700"]) {
3564
+ for (const font of fonts) {
3565
+ loadFont(font, weights);
3566
+ }
3567
+ }
3568
+ function loadDefaultFonts() {
3569
+ if (fontsInitialized) return;
3570
+ fontsInitialized = true;
3571
+ console.log("[Servly Fonts] Loading default fonts...");
3572
+ loadFonts(DEFAULT_FONTS);
3573
+ console.log("[Servly Fonts] Default fonts loaded");
3574
+ }
3575
+ function isFontLoaded(family) {
3576
+ if (typeof document === "undefined") return false;
3577
+ const linkId = `google-font-${family.replace(/[\s+]/g, "-").toLowerCase()}`;
3578
+ return !!document.getElementById(linkId) || loadedFonts.has(family);
3579
+ }
3580
+ function getDefaultFonts() {
3581
+ return [...DEFAULT_FONTS];
3582
+ }
3583
+ function getLoadedFonts() {
3584
+ return Array.from(loadedFonts);
3585
+ }
3586
+ function initFonts(config = {}) {
3587
+ const {
3588
+ additionalFonts = [],
3589
+ weights = ["400", "500", "600", "700"],
3590
+ loadDefaults = true
3591
+ } = config;
3592
+ addFontPreconnect();
3593
+ if (loadDefaults) {
3594
+ loadDefaultFonts();
3595
+ }
3596
+ if (additionalFonts.length > 0) {
3597
+ loadFonts(additionalFonts, weights);
3598
+ }
3599
+ }
3600
+ var autoInitialized = false;
3601
+ function ensureFonts() {
3602
+ if (autoInitialized || typeof document === "undefined") return;
3603
+ autoInitialized = true;
3604
+ addFontPreconnect();
3605
+ loadDefaultFonts();
3606
+ }
3607
+
3608
+ // src/renderer.ts
3431
3609
  var tailwindAutoInjected = false;
3432
3610
  function ensureTailwind() {
3433
3611
  if (tailwindAutoInjected || typeof document === "undefined") return;
@@ -3435,6 +3613,7 @@ function ensureTailwind() {
3435
3613
  injectTailwind({ usePlayCdn: true }).catch((err) => {
3436
3614
  console.warn("Failed to auto-inject Tailwind CSS:", err);
3437
3615
  });
3616
+ ensureFonts();
3438
3617
  }
3439
3618
  var COMPONENT_TO_TAG = {
3440
3619
  container: "div",
@@ -4366,10 +4545,9 @@ function renderInShadow(options) {
4366
4545
  shadowRoot.insertBefore(styleEl, innerContainer);
4367
4546
  }
4368
4547
  if (shouldInjectTailwind) {
4369
- const tailwindLink = document.createElement("link");
4370
- tailwindLink.rel = "stylesheet";
4371
- tailwindLink.href = "https://cdn.tailwindcss.com";
4372
- shadowRoot.insertBefore(tailwindLink, innerContainer);
4548
+ const tailwindScript2 = document.createElement("script");
4549
+ tailwindScript2.src = "https://cdn.tailwindcss.com";
4550
+ shadowRoot.insertBefore(tailwindScript2, innerContainer);
4373
4551
  }
4374
4552
  const result = render({
4375
4553
  ...renderOptions,
@@ -5490,6 +5668,7 @@ init_tailwind();
5490
5668
  StateManager,
5491
5669
  addClass,
5492
5670
  addCustomStyles,
5671
+ addFontPreconnect,
5493
5672
  analytics,
5494
5673
  applyStyles,
5495
5674
  batchFetchComponents,
@@ -5500,6 +5679,7 @@ init_tailwind();
5500
5679
  camelToKebab,
5501
5680
  clearAllCaches,
5502
5681
  clearIconCache,
5682
+ clearIconStorageCache,
5503
5683
  clearLocalStorageCache,
5504
5684
  clearMemoryCache,
5505
5685
  clearStyles,
@@ -5515,6 +5695,7 @@ init_tailwind();
5515
5695
  deepMerge,
5516
5696
  deleteValueByPath,
5517
5697
  detectCircularDependencies,
5698
+ ensureFonts,
5518
5699
  extractBindingKeys,
5519
5700
  extractDependencies,
5520
5701
  extractDependenciesFromCode,
@@ -5528,12 +5709,14 @@ init_tailwind();
5528
5709
  getAnalytics,
5529
5710
  getCacheKey,
5530
5711
  getCleanupOverrides,
5712
+ getDefaultFonts,
5531
5713
  getDependencyTree,
5532
5714
  getEventSystem,
5533
5715
  getFromCache,
5534
5716
  getIconData,
5535
5717
  getIconDataSync,
5536
5718
  getIconifyCollection,
5719
+ getLoadedFonts,
5537
5720
  getLocalStorage,
5538
5721
  getLongTaskObserver,
5539
5722
  getMemoryCacheSize,
@@ -5554,17 +5737,22 @@ init_tailwind();
5554
5737
  hasDependencyOverrides,
5555
5738
  hasOverrides,
5556
5739
  hasTemplateSyntax,
5740
+ initFonts,
5557
5741
  initServlyTailwind,
5558
5742
  injectTailwind,
5559
5743
  injectTailwindStyles,
5560
5744
  invalidateCache,
5561
5745
  isComponentAvailable,
5746
+ isFontLoaded,
5562
5747
  isIconCdnEnabled,
5563
5748
  isIconRegistered,
5564
5749
  isIconSetSupported,
5565
5750
  isTailwindLoaded,
5566
5751
  isTailwindReady,
5567
5752
  isValidSpecifier,
5753
+ loadDefaultFonts,
5754
+ loadFont,
5755
+ loadFonts,
5568
5756
  markElementReady,
5569
5757
  navigateTo,
5570
5758
  parseVersion,
package/dist/index.d.cts CHANGED
@@ -1718,6 +1718,7 @@ declare function resetEventSystem(): void;
1718
1718
  /**
1719
1719
  * Add preload link for Tailwind CDN to start loading earlier
1720
1720
  * This helps the browser start fetching before we actually need it
1721
+ * Note: Only preload if we're going to use the script immediately after
1721
1722
  */
1722
1723
  declare function preloadTailwind(cdnUrl?: string, usePlayCdn?: boolean): void;
1723
1724
  /**
@@ -1822,6 +1823,55 @@ declare const DEFAULT_SERVLY_TAILWIND_CONFIG: {
1822
1823
  declare function initServlyTailwind(customConfig?: Record<string, any>): Promise<void>;
1823
1824
  declare const injectTailwindStyles: typeof initServlyTailwind;
1824
1825
 
1826
+ /**
1827
+ * Google Fonts Utilities for Runtime Core
1828
+ * Provides automatic font loading for Servly components
1829
+ */
1830
+ /**
1831
+ * Add preconnect links for Google Fonts (improves load performance)
1832
+ */
1833
+ declare function addFontPreconnect(): void;
1834
+ /**
1835
+ * Load a specific Google Font
1836
+ */
1837
+ declare function loadFont(family: string, weights?: string[]): void;
1838
+ /**
1839
+ * Load multiple fonts at once
1840
+ */
1841
+ declare function loadFonts(fonts: string[], weights?: string[]): void;
1842
+ /**
1843
+ * Load default popular fonts
1844
+ */
1845
+ declare function loadDefaultFonts(): void;
1846
+ /**
1847
+ * Check if a font is loaded
1848
+ */
1849
+ declare function isFontLoaded(family: string): boolean;
1850
+ /**
1851
+ * Get list of default fonts
1852
+ */
1853
+ declare function getDefaultFonts(): string[];
1854
+ /**
1855
+ * Get list of currently loaded fonts
1856
+ */
1857
+ declare function getLoadedFonts(): string[];
1858
+ interface FontConfig {
1859
+ /** Additional fonts to load beyond defaults */
1860
+ additionalFonts?: string[];
1861
+ /** Font weights to load */
1862
+ weights?: string[];
1863
+ /** Whether to load default fonts */
1864
+ loadDefaults?: boolean;
1865
+ }
1866
+ /**
1867
+ * Initialize fonts with configuration
1868
+ */
1869
+ declare function initFonts(config?: FontConfig): void;
1870
+ /**
1871
+ * Ensure fonts are loaded (called automatically by renderer)
1872
+ */
1873
+ declare function ensureFonts(): void;
1874
+
1825
1875
  /**
1826
1876
  * Overrides System for Runtime Core
1827
1877
  * Handles element overrides with dependency tracking
@@ -1951,6 +2001,10 @@ interface IconData {
1951
2001
  /** ViewBox (default: "0 0 24 24") */
1952
2002
  viewBox?: string;
1953
2003
  }
2004
+ /**
2005
+ * Clear icon cache from localStorage
2006
+ */
2007
+ declare function clearIconStorageCache(): void;
1954
2008
  /**
1955
2009
  * Enable or disable CDN fallback for icons not in bundle
1956
2010
  * Disabled by default for security - only bundled icons will render
@@ -1978,11 +2032,11 @@ declare function isIconRegistered(icon: IconConfig): boolean;
1978
2032
  */
1979
2033
  declare function getRegisteredIconKeys(): string[];
1980
2034
  /**
1981
- * Get icon data (from cache, registry, or CDN if enabled)
2035
+ * Get icon data (from cache, registry, localStorage, or CDN if enabled)
1982
2036
  */
1983
2037
  declare function getIconData(icon: IconConfig): Promise<IconData | null>;
1984
2038
  /**
1985
- * Get icon data synchronously (only returns cached/registered icons)
2039
+ * Get icon data synchronously (only returns cached/registered/localStorage icons)
1986
2040
  */
1987
2041
  declare function getIconDataSync(icon: IconConfig): IconData | null;
1988
2042
  /**
@@ -2003,9 +2057,9 @@ declare function renderIcon(container: HTMLElement, icon: IconConfig, size?: num
2003
2057
  */
2004
2058
  declare function preloadIcons(icons: IconConfig[]): Promise<void>;
2005
2059
  /**
2006
- * Clear the icon cache (keeps registered icons)
2060
+ * Clear the icon cache (keeps registered icons, optionally clears localStorage)
2007
2061
  */
2008
- declare function clearIconCache(): void;
2062
+ declare function clearIconCache(clearStorage?: boolean): void;
2009
2063
  /**
2010
2064
  * Check if an icon set is supported
2011
2065
  */
@@ -2019,4 +2073,4 @@ declare function getSupportedIconSets(): string[];
2019
2073
  */
2020
2074
  declare function getIconifyCollection(set: string): string | undefined;
2021
2075
 
2022
- export { AnalyticsCollector, type AnalyticsConfig, type AnalyticsEvent, type AnalyticsEventType, type Assertion$1 as Assertion, type AssertionResult$1 as AssertionResult, type BatchEventsRequest, type BatchEventsResponse, type BindingContext, type BundleStrategy, type BundledComponent, type CacheConfig, type CacheEntry, type CacheStrategy, type ClientInfo, type ComponentBundle, type ComponentData, type ComponentRegistry, DEFAULT_CACHE_CONFIG, DEFAULT_REGISTRY_URL, DEFAULT_RETRY_CONFIG, DEFAULT_SERVLY_TAILWIND_CONFIG, type DependencyEntry, type DependencyManifest, type DependencyType, EVENT_HANDLERS, type ElementConfig, type ErrorMetadata, type ErrorType, type EventContext, type EventHandlerConfig, EventSystem, type EventSystemConfig, type FetchMetadata, type FetchOptions, type FetchResult, type IconConfig, type IconData, type IconRenderer, type LayoutElement, LongTaskObserver, MemorySampler, type NavigationOptions, type Override, type OverrideState, OverrideSystem, type OverrideSystemConfig, type ParsedVersion, type PluginExecutor, type PropDefinition, type RenderMetadata, type RenderOptions, type RenderResult, type RetryConfig, type ServlyEventHandler, type ServlyPluginAction, type SessionInfo, SessionManager, type StateChangeEvent, StateManager, type StateManagerConfig, type TailwindConfig, type AssertionResult as TestAssertionResult, type TestCase$1 as TestCase, type TestCase as TestCaseInput, type TestCaseResult, type TestResult, type TestSummary as TestRunSummary, type TestSummary$1 as TestSummary, type ViewData, addClass, addCustomStyles, analytics, applyStyles, batchFetchComponents, buildClassName, buildElementStyles, buildRegistryFromBundle, bumpVersion, camelToKebab, clearAllCaches, clearIconCache, clearLocalStorageCache, clearMemoryCache, clearStyles, collectAllDependencies, collectAllViewDependencies, compareVersions, configureAnalytics, createIconSVG, createPlaceholderIcon, createRegistry, createServlyRenderer, createViewsMap, deepMerge, deleteValueByPath, detectCircularDependencies, extractBindingKeys, extractDependencies, extractDependenciesFromCode, extractOverrideDependencies, extractReferencedViewIds, fetchComponent, fetchComponentWithDependencies, formatStyleValue, formatVersion, generateTestCases, getAnalytics, getCacheKey, getCleanupOverrides, getDependencyTree, getEventSystem, getFromCache, getIconData, getIconDataSync, getIconifyCollection, getLocalStorage, getLongTaskObserver, getMemoryCacheSize, getMemorySampler, getMountOverrides, getOverrideSystem, getRegisteredIconKeys, getRegistryUrl, getSessionManager, getSessionStorage, getSupportedIconSets, getTailwind, getUrlInfo, getValueByPath, goBack, goForward, hasClass, hasDependencyOverrides, hasOverrides, hasTemplateSyntax, initServlyTailwind, injectTailwind, injectTailwindStyles, invalidateCache, isComponentAvailable, isIconCdnEnabled, isIconRegistered, isIconSetSupported, isTailwindLoaded, isTailwindReady, isValidSpecifier, markElementReady, navigateTo, parseVersion, prefetchComponents, preloadIcons, preloadTailwind, preventFOUC, processStyles, refreshTailwind, registerIcon, registerIcons, removeClass, removeCustomStyles, removeFOUCPrevention, removeLocalStorage, removeSessionStorage, removeTailwind, render, renderDynamicList, renderIcon, renderInShadow, renderNode, resetAnalytics, resetEventSystem, resetLongTaskObserver, resetMemorySampler, resetOverrideSystem, resetSessionManager, resolveBindingPath, resolveTemplate, resolveTemplateValue, resolveTemplatesDeep, resolveVersion, runAllTests, runTestCase, satisfiesVersion, scheduleRefresh, setIconCdnEnabled, setInCache, setLocalStorage, setRegistryUrl, setSessionStorage, setValueByPath, toDomEventName, toReactEventName, toggleClass, updateStyles, updateTailwindConfig, validateAssertion, validateProps, waitForTailwind };
2076
+ export { AnalyticsCollector, type AnalyticsConfig, type AnalyticsEvent, type AnalyticsEventType, type Assertion$1 as Assertion, type AssertionResult$1 as AssertionResult, type BatchEventsRequest, type BatchEventsResponse, type BindingContext, type BundleStrategy, type BundledComponent, type CacheConfig, type CacheEntry, type CacheStrategy, type ClientInfo, type ComponentBundle, type ComponentData, type ComponentRegistry, DEFAULT_CACHE_CONFIG, DEFAULT_REGISTRY_URL, DEFAULT_RETRY_CONFIG, DEFAULT_SERVLY_TAILWIND_CONFIG, type DependencyEntry, type DependencyManifest, type DependencyType, EVENT_HANDLERS, type ElementConfig, type ErrorMetadata, type ErrorType, type EventContext, type EventHandlerConfig, EventSystem, type EventSystemConfig, type FetchMetadata, type FetchOptions, type FetchResult, type FontConfig, type IconConfig, type IconData, type IconRenderer, type LayoutElement, LongTaskObserver, MemorySampler, type NavigationOptions, type Override, type OverrideState, OverrideSystem, type OverrideSystemConfig, type ParsedVersion, type PluginExecutor, type PropDefinition, type RenderMetadata, type RenderOptions, type RenderResult, type RetryConfig, type ServlyEventHandler, type ServlyPluginAction, type SessionInfo, SessionManager, type StateChangeEvent, StateManager, type StateManagerConfig, type TailwindConfig, type AssertionResult as TestAssertionResult, type TestCase$1 as TestCase, type TestCase as TestCaseInput, type TestCaseResult, type TestResult, type TestSummary as TestRunSummary, type TestSummary$1 as TestSummary, type ViewData, addClass, addCustomStyles, addFontPreconnect, analytics, applyStyles, batchFetchComponents, buildClassName, buildElementStyles, buildRegistryFromBundle, bumpVersion, camelToKebab, clearAllCaches, clearIconCache, clearIconStorageCache, clearLocalStorageCache, clearMemoryCache, clearStyles, collectAllDependencies, collectAllViewDependencies, compareVersions, configureAnalytics, createIconSVG, createPlaceholderIcon, createRegistry, createServlyRenderer, createViewsMap, deepMerge, deleteValueByPath, detectCircularDependencies, ensureFonts, extractBindingKeys, extractDependencies, extractDependenciesFromCode, extractOverrideDependencies, extractReferencedViewIds, fetchComponent, fetchComponentWithDependencies, formatStyleValue, formatVersion, generateTestCases, getAnalytics, getCacheKey, getCleanupOverrides, getDefaultFonts, getDependencyTree, getEventSystem, getFromCache, getIconData, getIconDataSync, getIconifyCollection, getLoadedFonts, getLocalStorage, getLongTaskObserver, getMemoryCacheSize, getMemorySampler, getMountOverrides, getOverrideSystem, getRegisteredIconKeys, getRegistryUrl, getSessionManager, getSessionStorage, getSupportedIconSets, getTailwind, getUrlInfo, getValueByPath, goBack, goForward, hasClass, hasDependencyOverrides, hasOverrides, hasTemplateSyntax, initFonts, initServlyTailwind, injectTailwind, injectTailwindStyles, invalidateCache, isComponentAvailable, isFontLoaded, isIconCdnEnabled, isIconRegistered, isIconSetSupported, isTailwindLoaded, isTailwindReady, isValidSpecifier, loadDefaultFonts, loadFont, loadFonts, markElementReady, navigateTo, parseVersion, prefetchComponents, preloadIcons, preloadTailwind, preventFOUC, processStyles, refreshTailwind, registerIcon, registerIcons, removeClass, removeCustomStyles, removeFOUCPrevention, removeLocalStorage, removeSessionStorage, removeTailwind, render, renderDynamicList, renderIcon, renderInShadow, renderNode, resetAnalytics, resetEventSystem, resetLongTaskObserver, resetMemorySampler, resetOverrideSystem, resetSessionManager, resolveBindingPath, resolveTemplate, resolveTemplateValue, resolveTemplatesDeep, resolveVersion, runAllTests, runTestCase, satisfiesVersion, scheduleRefresh, setIconCdnEnabled, setInCache, setLocalStorage, setRegistryUrl, setSessionStorage, setValueByPath, toDomEventName, toReactEventName, toggleClass, updateStyles, updateTailwindConfig, validateAssertion, validateProps, waitForTailwind };
package/dist/index.d.ts CHANGED
@@ -1718,6 +1718,7 @@ declare function resetEventSystem(): void;
1718
1718
  /**
1719
1719
  * Add preload link for Tailwind CDN to start loading earlier
1720
1720
  * This helps the browser start fetching before we actually need it
1721
+ * Note: Only preload if we're going to use the script immediately after
1721
1722
  */
1722
1723
  declare function preloadTailwind(cdnUrl?: string, usePlayCdn?: boolean): void;
1723
1724
  /**
@@ -1822,6 +1823,55 @@ declare const DEFAULT_SERVLY_TAILWIND_CONFIG: {
1822
1823
  declare function initServlyTailwind(customConfig?: Record<string, any>): Promise<void>;
1823
1824
  declare const injectTailwindStyles: typeof initServlyTailwind;
1824
1825
 
1826
+ /**
1827
+ * Google Fonts Utilities for Runtime Core
1828
+ * Provides automatic font loading for Servly components
1829
+ */
1830
+ /**
1831
+ * Add preconnect links for Google Fonts (improves load performance)
1832
+ */
1833
+ declare function addFontPreconnect(): void;
1834
+ /**
1835
+ * Load a specific Google Font
1836
+ */
1837
+ declare function loadFont(family: string, weights?: string[]): void;
1838
+ /**
1839
+ * Load multiple fonts at once
1840
+ */
1841
+ declare function loadFonts(fonts: string[], weights?: string[]): void;
1842
+ /**
1843
+ * Load default popular fonts
1844
+ */
1845
+ declare function loadDefaultFonts(): void;
1846
+ /**
1847
+ * Check if a font is loaded
1848
+ */
1849
+ declare function isFontLoaded(family: string): boolean;
1850
+ /**
1851
+ * Get list of default fonts
1852
+ */
1853
+ declare function getDefaultFonts(): string[];
1854
+ /**
1855
+ * Get list of currently loaded fonts
1856
+ */
1857
+ declare function getLoadedFonts(): string[];
1858
+ interface FontConfig {
1859
+ /** Additional fonts to load beyond defaults */
1860
+ additionalFonts?: string[];
1861
+ /** Font weights to load */
1862
+ weights?: string[];
1863
+ /** Whether to load default fonts */
1864
+ loadDefaults?: boolean;
1865
+ }
1866
+ /**
1867
+ * Initialize fonts with configuration
1868
+ */
1869
+ declare function initFonts(config?: FontConfig): void;
1870
+ /**
1871
+ * Ensure fonts are loaded (called automatically by renderer)
1872
+ */
1873
+ declare function ensureFonts(): void;
1874
+
1825
1875
  /**
1826
1876
  * Overrides System for Runtime Core
1827
1877
  * Handles element overrides with dependency tracking
@@ -1951,6 +2001,10 @@ interface IconData {
1951
2001
  /** ViewBox (default: "0 0 24 24") */
1952
2002
  viewBox?: string;
1953
2003
  }
2004
+ /**
2005
+ * Clear icon cache from localStorage
2006
+ */
2007
+ declare function clearIconStorageCache(): void;
1954
2008
  /**
1955
2009
  * Enable or disable CDN fallback for icons not in bundle
1956
2010
  * Disabled by default for security - only bundled icons will render
@@ -1978,11 +2032,11 @@ declare function isIconRegistered(icon: IconConfig): boolean;
1978
2032
  */
1979
2033
  declare function getRegisteredIconKeys(): string[];
1980
2034
  /**
1981
- * Get icon data (from cache, registry, or CDN if enabled)
2035
+ * Get icon data (from cache, registry, localStorage, or CDN if enabled)
1982
2036
  */
1983
2037
  declare function getIconData(icon: IconConfig): Promise<IconData | null>;
1984
2038
  /**
1985
- * Get icon data synchronously (only returns cached/registered icons)
2039
+ * Get icon data synchronously (only returns cached/registered/localStorage icons)
1986
2040
  */
1987
2041
  declare function getIconDataSync(icon: IconConfig): IconData | null;
1988
2042
  /**
@@ -2003,9 +2057,9 @@ declare function renderIcon(container: HTMLElement, icon: IconConfig, size?: num
2003
2057
  */
2004
2058
  declare function preloadIcons(icons: IconConfig[]): Promise<void>;
2005
2059
  /**
2006
- * Clear the icon cache (keeps registered icons)
2060
+ * Clear the icon cache (keeps registered icons, optionally clears localStorage)
2007
2061
  */
2008
- declare function clearIconCache(): void;
2062
+ declare function clearIconCache(clearStorage?: boolean): void;
2009
2063
  /**
2010
2064
  * Check if an icon set is supported
2011
2065
  */
@@ -2019,4 +2073,4 @@ declare function getSupportedIconSets(): string[];
2019
2073
  */
2020
2074
  declare function getIconifyCollection(set: string): string | undefined;
2021
2075
 
2022
- export { AnalyticsCollector, type AnalyticsConfig, type AnalyticsEvent, type AnalyticsEventType, type Assertion$1 as Assertion, type AssertionResult$1 as AssertionResult, type BatchEventsRequest, type BatchEventsResponse, type BindingContext, type BundleStrategy, type BundledComponent, type CacheConfig, type CacheEntry, type CacheStrategy, type ClientInfo, type ComponentBundle, type ComponentData, type ComponentRegistry, DEFAULT_CACHE_CONFIG, DEFAULT_REGISTRY_URL, DEFAULT_RETRY_CONFIG, DEFAULT_SERVLY_TAILWIND_CONFIG, type DependencyEntry, type DependencyManifest, type DependencyType, EVENT_HANDLERS, type ElementConfig, type ErrorMetadata, type ErrorType, type EventContext, type EventHandlerConfig, EventSystem, type EventSystemConfig, type FetchMetadata, type FetchOptions, type FetchResult, type IconConfig, type IconData, type IconRenderer, type LayoutElement, LongTaskObserver, MemorySampler, type NavigationOptions, type Override, type OverrideState, OverrideSystem, type OverrideSystemConfig, type ParsedVersion, type PluginExecutor, type PropDefinition, type RenderMetadata, type RenderOptions, type RenderResult, type RetryConfig, type ServlyEventHandler, type ServlyPluginAction, type SessionInfo, SessionManager, type StateChangeEvent, StateManager, type StateManagerConfig, type TailwindConfig, type AssertionResult as TestAssertionResult, type TestCase$1 as TestCase, type TestCase as TestCaseInput, type TestCaseResult, type TestResult, type TestSummary as TestRunSummary, type TestSummary$1 as TestSummary, type ViewData, addClass, addCustomStyles, analytics, applyStyles, batchFetchComponents, buildClassName, buildElementStyles, buildRegistryFromBundle, bumpVersion, camelToKebab, clearAllCaches, clearIconCache, clearLocalStorageCache, clearMemoryCache, clearStyles, collectAllDependencies, collectAllViewDependencies, compareVersions, configureAnalytics, createIconSVG, createPlaceholderIcon, createRegistry, createServlyRenderer, createViewsMap, deepMerge, deleteValueByPath, detectCircularDependencies, extractBindingKeys, extractDependencies, extractDependenciesFromCode, extractOverrideDependencies, extractReferencedViewIds, fetchComponent, fetchComponentWithDependencies, formatStyleValue, formatVersion, generateTestCases, getAnalytics, getCacheKey, getCleanupOverrides, getDependencyTree, getEventSystem, getFromCache, getIconData, getIconDataSync, getIconifyCollection, getLocalStorage, getLongTaskObserver, getMemoryCacheSize, getMemorySampler, getMountOverrides, getOverrideSystem, getRegisteredIconKeys, getRegistryUrl, getSessionManager, getSessionStorage, getSupportedIconSets, getTailwind, getUrlInfo, getValueByPath, goBack, goForward, hasClass, hasDependencyOverrides, hasOverrides, hasTemplateSyntax, initServlyTailwind, injectTailwind, injectTailwindStyles, invalidateCache, isComponentAvailable, isIconCdnEnabled, isIconRegistered, isIconSetSupported, isTailwindLoaded, isTailwindReady, isValidSpecifier, markElementReady, navigateTo, parseVersion, prefetchComponents, preloadIcons, preloadTailwind, preventFOUC, processStyles, refreshTailwind, registerIcon, registerIcons, removeClass, removeCustomStyles, removeFOUCPrevention, removeLocalStorage, removeSessionStorage, removeTailwind, render, renderDynamicList, renderIcon, renderInShadow, renderNode, resetAnalytics, resetEventSystem, resetLongTaskObserver, resetMemorySampler, resetOverrideSystem, resetSessionManager, resolveBindingPath, resolveTemplate, resolveTemplateValue, resolveTemplatesDeep, resolveVersion, runAllTests, runTestCase, satisfiesVersion, scheduleRefresh, setIconCdnEnabled, setInCache, setLocalStorage, setRegistryUrl, setSessionStorage, setValueByPath, toDomEventName, toReactEventName, toggleClass, updateStyles, updateTailwindConfig, validateAssertion, validateProps, waitForTailwind };
2076
+ export { AnalyticsCollector, type AnalyticsConfig, type AnalyticsEvent, type AnalyticsEventType, type Assertion$1 as Assertion, type AssertionResult$1 as AssertionResult, type BatchEventsRequest, type BatchEventsResponse, type BindingContext, type BundleStrategy, type BundledComponent, type CacheConfig, type CacheEntry, type CacheStrategy, type ClientInfo, type ComponentBundle, type ComponentData, type ComponentRegistry, DEFAULT_CACHE_CONFIG, DEFAULT_REGISTRY_URL, DEFAULT_RETRY_CONFIG, DEFAULT_SERVLY_TAILWIND_CONFIG, type DependencyEntry, type DependencyManifest, type DependencyType, EVENT_HANDLERS, type ElementConfig, type ErrorMetadata, type ErrorType, type EventContext, type EventHandlerConfig, EventSystem, type EventSystemConfig, type FetchMetadata, type FetchOptions, type FetchResult, type FontConfig, type IconConfig, type IconData, type IconRenderer, type LayoutElement, LongTaskObserver, MemorySampler, type NavigationOptions, type Override, type OverrideState, OverrideSystem, type OverrideSystemConfig, type ParsedVersion, type PluginExecutor, type PropDefinition, type RenderMetadata, type RenderOptions, type RenderResult, type RetryConfig, type ServlyEventHandler, type ServlyPluginAction, type SessionInfo, SessionManager, type StateChangeEvent, StateManager, type StateManagerConfig, type TailwindConfig, type AssertionResult as TestAssertionResult, type TestCase$1 as TestCase, type TestCase as TestCaseInput, type TestCaseResult, type TestResult, type TestSummary as TestRunSummary, type TestSummary$1 as TestSummary, type ViewData, addClass, addCustomStyles, addFontPreconnect, analytics, applyStyles, batchFetchComponents, buildClassName, buildElementStyles, buildRegistryFromBundle, bumpVersion, camelToKebab, clearAllCaches, clearIconCache, clearIconStorageCache, clearLocalStorageCache, clearMemoryCache, clearStyles, collectAllDependencies, collectAllViewDependencies, compareVersions, configureAnalytics, createIconSVG, createPlaceholderIcon, createRegistry, createServlyRenderer, createViewsMap, deepMerge, deleteValueByPath, detectCircularDependencies, ensureFonts, extractBindingKeys, extractDependencies, extractDependenciesFromCode, extractOverrideDependencies, extractReferencedViewIds, fetchComponent, fetchComponentWithDependencies, formatStyleValue, formatVersion, generateTestCases, getAnalytics, getCacheKey, getCleanupOverrides, getDefaultFonts, getDependencyTree, getEventSystem, getFromCache, getIconData, getIconDataSync, getIconifyCollection, getLoadedFonts, getLocalStorage, getLongTaskObserver, getMemoryCacheSize, getMemorySampler, getMountOverrides, getOverrideSystem, getRegisteredIconKeys, getRegistryUrl, getSessionManager, getSessionStorage, getSupportedIconSets, getTailwind, getUrlInfo, getValueByPath, goBack, goForward, hasClass, hasDependencyOverrides, hasOverrides, hasTemplateSyntax, initFonts, initServlyTailwind, injectTailwind, injectTailwindStyles, invalidateCache, isComponentAvailable, isFontLoaded, isIconCdnEnabled, isIconRegistered, isIconSetSupported, isTailwindLoaded, isTailwindReady, isValidSpecifier, loadDefaultFonts, loadFont, loadFonts, markElementReady, navigateTo, parseVersion, prefetchComponents, preloadIcons, preloadTailwind, preventFOUC, processStyles, refreshTailwind, registerIcon, registerIcons, removeClass, removeCustomStyles, removeFOUCPrevention, removeLocalStorage, removeSessionStorage, removeTailwind, render, renderDynamicList, renderIcon, renderInShadow, renderNode, resetAnalytics, resetEventSystem, resetLongTaskObserver, resetMemorySampler, resetOverrideSystem, resetSessionManager, resolveBindingPath, resolveTemplate, resolveTemplateValue, resolveTemplatesDeep, resolveVersion, runAllTests, runTestCase, satisfiesVersion, scheduleRefresh, setIconCdnEnabled, setInCache, setLocalStorage, setRegistryUrl, setSessionStorage, setValueByPath, toDomEventName, toReactEventName, toggleClass, updateStyles, updateTailwindConfig, validateAssertion, validateProps, waitForTailwind };
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  scheduleRefresh,
18
18
  updateTailwindConfig,
19
19
  waitForTailwind
20
- } from "./chunk-TXHGJYYM.js";
20
+ } from "./chunk-GN6KAMNI.js";
21
21
  import {
22
22
  buildRegistryFromBundle,
23
23
  collectAllDependencies,
@@ -2332,6 +2332,58 @@ function resetOverrideSystem() {
2332
2332
 
2333
2333
  // src/icons.ts
2334
2334
  var cdnEnabled = true;
2335
+ var ICON_CACHE_KEY = "servly-icon-cache";
2336
+ var ICON_CACHE_VERSION = "1";
2337
+ var localStorageLoaded = false;
2338
+ function loadIconCacheFromStorage() {
2339
+ if (localStorageLoaded) return;
2340
+ localStorageLoaded = true;
2341
+ if (typeof localStorage === "undefined") return;
2342
+ try {
2343
+ const cached = localStorage.getItem(ICON_CACHE_KEY);
2344
+ if (!cached) return;
2345
+ const parsed = JSON.parse(cached);
2346
+ if (parsed.version !== ICON_CACHE_VERSION) {
2347
+ localStorage.removeItem(ICON_CACHE_KEY);
2348
+ return;
2349
+ }
2350
+ for (const [key, data] of Object.entries(parsed.icons)) {
2351
+ if (!iconCache.has(key) && !registeredIcons.has(key)) {
2352
+ iconCache.set(key, data);
2353
+ }
2354
+ }
2355
+ } catch {
2356
+ }
2357
+ }
2358
+ function saveIconToStorage(key, data) {
2359
+ if (typeof localStorage === "undefined") return;
2360
+ try {
2361
+ const cached = localStorage.getItem(ICON_CACHE_KEY);
2362
+ let cacheData;
2363
+ if (cached) {
2364
+ cacheData = JSON.parse(cached);
2365
+ if (cacheData.version !== ICON_CACHE_VERSION) {
2366
+ cacheData = { version: ICON_CACHE_VERSION, icons: {} };
2367
+ }
2368
+ } else {
2369
+ cacheData = { version: ICON_CACHE_VERSION, icons: {} };
2370
+ }
2371
+ cacheData.icons[key] = data;
2372
+ const keys = Object.keys(cacheData.icons);
2373
+ if (keys.length > 500) {
2374
+ keys.slice(0, 100).forEach((k) => delete cacheData.icons[k]);
2375
+ }
2376
+ localStorage.setItem(ICON_CACHE_KEY, JSON.stringify(cacheData));
2377
+ } catch {
2378
+ }
2379
+ }
2380
+ function clearIconStorageCache() {
2381
+ if (typeof localStorage === "undefined") return;
2382
+ try {
2383
+ localStorage.removeItem(ICON_CACHE_KEY);
2384
+ } catch {
2385
+ }
2386
+ }
2335
2387
  function setIconCdnEnabled(enabled) {
2336
2388
  cdnEnabled = enabled;
2337
2389
  }
@@ -2504,6 +2556,7 @@ function parseSvgResponse(svgText) {
2504
2556
  }
2505
2557
  async function getIconData(icon) {
2506
2558
  const key = `${icon.set}:${icon.name}`;
2559
+ loadIconCacheFromStorage();
2507
2560
  if (iconCache.has(key)) {
2508
2561
  return iconCache.get(key);
2509
2562
  }
@@ -2519,11 +2572,13 @@ async function getIconData(icon) {
2519
2572
  pendingFetches.delete(key);
2520
2573
  if (data) {
2521
2574
  iconCache.set(key, data);
2575
+ saveIconToStorage(key, data);
2522
2576
  }
2523
2577
  return data;
2524
2578
  }
2525
2579
  function getIconDataSync(icon) {
2526
2580
  const key = `${icon.set}:${icon.name}`;
2581
+ loadIconCacheFromStorage();
2527
2582
  return iconCache.get(key) || null;
2528
2583
  }
2529
2584
  function createIconSVG(icon, data, size = 24, color = "currentColor") {
@@ -2623,12 +2678,15 @@ function renderIcon(container, icon, size = 24, color = "currentColor") {
2623
2678
  async function preloadIcons(icons) {
2624
2679
  await Promise.all(icons.map((icon) => getIconData(icon)));
2625
2680
  }
2626
- function clearIconCache() {
2681
+ function clearIconCache(clearStorage = false) {
2627
2682
  iconCache.clear();
2628
2683
  pendingFetches.clear();
2629
2684
  registeredIcons.forEach((data, key) => {
2630
2685
  iconCache.set(key, data);
2631
2686
  });
2687
+ if (clearStorage) {
2688
+ clearIconStorageCache();
2689
+ }
2632
2690
  }
2633
2691
  function isIconSetSupported(set) {
2634
2692
  return set in ICONIFY_COLLECTIONS;
@@ -2640,6 +2698,111 @@ function getIconifyCollection(set) {
2640
2698
  return ICONIFY_COLLECTIONS[set];
2641
2699
  }
2642
2700
 
2701
+ // src/fonts.ts
2702
+ var DEFAULT_FONTS = [
2703
+ "Roboto",
2704
+ "Open Sans",
2705
+ "Lato",
2706
+ "Montserrat",
2707
+ "Poppins",
2708
+ "Inter",
2709
+ "Playfair Display",
2710
+ "Raleway",
2711
+ "Ubuntu",
2712
+ "Nunito",
2713
+ "Merriweather",
2714
+ "Work Sans",
2715
+ "Quicksand",
2716
+ "Mulish",
2717
+ "Manrope",
2718
+ "DM Sans",
2719
+ "Space Grotesk",
2720
+ "Plus Jakarta Sans",
2721
+ "Outfit",
2722
+ "Sora"
2723
+ ];
2724
+ var loadedFonts = /* @__PURE__ */ new Set();
2725
+ var fontsInitialized = false;
2726
+ var preconnectAdded = false;
2727
+ function addFontPreconnect() {
2728
+ if (typeof document === "undefined" || preconnectAdded) return;
2729
+ preconnectAdded = true;
2730
+ if (!document.querySelector('link[href="https://fonts.googleapis.com"]')) {
2731
+ const pc1 = document.createElement("link");
2732
+ pc1.rel = "preconnect";
2733
+ pc1.href = "https://fonts.googleapis.com";
2734
+ document.head.appendChild(pc1);
2735
+ }
2736
+ if (!document.querySelector('link[href="https://fonts.gstatic.com"]')) {
2737
+ const pc2 = document.createElement("link");
2738
+ pc2.rel = "preconnect";
2739
+ pc2.href = "https://fonts.gstatic.com";
2740
+ pc2.crossOrigin = "anonymous";
2741
+ document.head.appendChild(pc2);
2742
+ }
2743
+ }
2744
+ function loadFont(family, weights = ["400", "500", "600", "700"]) {
2745
+ if (typeof document === "undefined") return;
2746
+ const linkId = `google-font-${family.replace(/[\s+]/g, "-").toLowerCase()}`;
2747
+ if (document.getElementById(linkId) || loadedFonts.has(family)) {
2748
+ return;
2749
+ }
2750
+ addFontPreconnect();
2751
+ const weightsStr = weights.join(";");
2752
+ const encodedFontName = encodeURIComponent(family).replace(/%20/g, "+");
2753
+ const fontUrl = `https://fonts.googleapis.com/css2?family=${encodedFontName}:wght@${weightsStr}&display=swap`;
2754
+ const link = document.createElement("link");
2755
+ link.id = linkId;
2756
+ link.rel = "stylesheet";
2757
+ link.href = fontUrl;
2758
+ document.head.appendChild(link);
2759
+ loadedFonts.add(family);
2760
+ }
2761
+ function loadFonts(fonts, weights = ["400", "500", "600", "700"]) {
2762
+ for (const font of fonts) {
2763
+ loadFont(font, weights);
2764
+ }
2765
+ }
2766
+ function loadDefaultFonts() {
2767
+ if (fontsInitialized) return;
2768
+ fontsInitialized = true;
2769
+ console.log("[Servly Fonts] Loading default fonts...");
2770
+ loadFonts(DEFAULT_FONTS);
2771
+ console.log("[Servly Fonts] Default fonts loaded");
2772
+ }
2773
+ function isFontLoaded(family) {
2774
+ if (typeof document === "undefined") return false;
2775
+ const linkId = `google-font-${family.replace(/[\s+]/g, "-").toLowerCase()}`;
2776
+ return !!document.getElementById(linkId) || loadedFonts.has(family);
2777
+ }
2778
+ function getDefaultFonts() {
2779
+ return [...DEFAULT_FONTS];
2780
+ }
2781
+ function getLoadedFonts() {
2782
+ return Array.from(loadedFonts);
2783
+ }
2784
+ function initFonts(config = {}) {
2785
+ const {
2786
+ additionalFonts = [],
2787
+ weights = ["400", "500", "600", "700"],
2788
+ loadDefaults = true
2789
+ } = config;
2790
+ addFontPreconnect();
2791
+ if (loadDefaults) {
2792
+ loadDefaultFonts();
2793
+ }
2794
+ if (additionalFonts.length > 0) {
2795
+ loadFonts(additionalFonts, weights);
2796
+ }
2797
+ }
2798
+ var autoInitialized = false;
2799
+ function ensureFonts() {
2800
+ if (autoInitialized || typeof document === "undefined") return;
2801
+ autoInitialized = true;
2802
+ addFontPreconnect();
2803
+ loadDefaultFonts();
2804
+ }
2805
+
2643
2806
  // src/renderer.ts
2644
2807
  var tailwindAutoInjected = false;
2645
2808
  function ensureTailwind() {
@@ -2648,6 +2811,7 @@ function ensureTailwind() {
2648
2811
  injectTailwind({ usePlayCdn: true }).catch((err) => {
2649
2812
  console.warn("Failed to auto-inject Tailwind CSS:", err);
2650
2813
  });
2814
+ ensureFonts();
2651
2815
  }
2652
2816
  var COMPONENT_TO_TAG = {
2653
2817
  container: "div",
@@ -3579,10 +3743,9 @@ function renderInShadow(options) {
3579
3743
  shadowRoot.insertBefore(styleEl, innerContainer);
3580
3744
  }
3581
3745
  if (shouldInjectTailwind) {
3582
- const tailwindLink = document.createElement("link");
3583
- tailwindLink.rel = "stylesheet";
3584
- tailwindLink.href = "https://cdn.tailwindcss.com";
3585
- shadowRoot.insertBefore(tailwindLink, innerContainer);
3746
+ const tailwindScript = document.createElement("script");
3747
+ tailwindScript.src = "https://cdn.tailwindcss.com";
3748
+ shadowRoot.insertBefore(tailwindScript, innerContainer);
3586
3749
  }
3587
3750
  const result = render({
3588
3751
  ...renderOptions,
@@ -3613,7 +3776,7 @@ async function createServlyRenderer(options) {
3613
3776
  container = containerOption;
3614
3777
  }
3615
3778
  if (shouldInjectTailwind) {
3616
- const { initServlyTailwind: initServlyTailwind2 } = await import("./tailwind-GU53TXCZ.js");
3779
+ const { initServlyTailwind: initServlyTailwind2 } = await import("./tailwind-MYAEYQPY.js");
3617
3780
  await initServlyTailwind2(tailwindConfig);
3618
3781
  }
3619
3782
  const activeRenders = [];
@@ -4697,6 +4860,7 @@ export {
4697
4860
  StateManager,
4698
4861
  addClass,
4699
4862
  addCustomStyles,
4863
+ addFontPreconnect,
4700
4864
  analytics,
4701
4865
  applyStyles,
4702
4866
  batchFetchComponents,
@@ -4707,6 +4871,7 @@ export {
4707
4871
  camelToKebab,
4708
4872
  clearAllCaches,
4709
4873
  clearIconCache,
4874
+ clearIconStorageCache,
4710
4875
  clearLocalStorageCache,
4711
4876
  clearMemoryCache,
4712
4877
  clearStyles,
@@ -4722,6 +4887,7 @@ export {
4722
4887
  deepMerge,
4723
4888
  deleteValueByPath,
4724
4889
  detectCircularDependencies,
4890
+ ensureFonts,
4725
4891
  extractBindingKeys,
4726
4892
  extractDependencies,
4727
4893
  extractDependenciesFromCode,
@@ -4735,12 +4901,14 @@ export {
4735
4901
  getAnalytics,
4736
4902
  getCacheKey,
4737
4903
  getCleanupOverrides,
4904
+ getDefaultFonts,
4738
4905
  getDependencyTree,
4739
4906
  getEventSystem,
4740
4907
  getFromCache,
4741
4908
  getIconData,
4742
4909
  getIconDataSync,
4743
4910
  getIconifyCollection,
4911
+ getLoadedFonts,
4744
4912
  getLocalStorage,
4745
4913
  getLongTaskObserver,
4746
4914
  getMemoryCacheSize,
@@ -4761,17 +4929,22 @@ export {
4761
4929
  hasDependencyOverrides,
4762
4930
  hasOverrides,
4763
4931
  hasTemplateSyntax,
4932
+ initFonts,
4764
4933
  initServlyTailwind,
4765
4934
  injectTailwind,
4766
4935
  injectTailwindStyles,
4767
4936
  invalidateCache,
4768
4937
  isComponentAvailable,
4938
+ isFontLoaded,
4769
4939
  isIconCdnEnabled,
4770
4940
  isIconRegistered,
4771
4941
  isIconSetSupported,
4772
4942
  isTailwindLoaded,
4773
4943
  isTailwindReady,
4774
4944
  isValidSpecifier,
4945
+ loadDefaultFonts,
4946
+ loadFont,
4947
+ loadFonts,
4775
4948
  markElementReady,
4776
4949
  navigateTo,
4777
4950
  parseVersion,
@@ -18,7 +18,7 @@ import {
18
18
  tailwind_default,
19
19
  updateTailwindConfig,
20
20
  waitForTailwind
21
- } from "./chunk-TXHGJYYM.js";
21
+ } from "./chunk-GN6KAMNI.js";
22
22
  export {
23
23
  DEFAULT_SERVLY_TAILWIND_CONFIG,
24
24
  addCustomStyles,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servlyadmin/runtime-core",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
4
4
  "description": "Framework-agnostic core renderer for Servly components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",