@servlyadmin/runtime-core 0.1.36 → 0.1.38

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.cjs CHANGED
@@ -31,10 +31,102 @@ __export(tailwind_exports, {
31
31
  injectTailwind: () => injectTailwind,
32
32
  injectTailwindStyles: () => injectTailwindStyles,
33
33
  isTailwindLoaded: () => isTailwindLoaded,
34
+ isTailwindReady: () => isTailwindReady,
35
+ markElementReady: () => markElementReady,
36
+ preloadTailwind: () => preloadTailwind,
37
+ preventFOUC: () => preventFOUC,
34
38
  removeCustomStyles: () => removeCustomStyles,
39
+ removeFOUCPrevention: () => removeFOUCPrevention,
35
40
  removeTailwind: () => removeTailwind,
36
- updateTailwindConfig: () => updateTailwindConfig
41
+ updateTailwindConfig: () => updateTailwindConfig,
42
+ waitForTailwind: () => waitForTailwind
37
43
  });
44
+ function wasTailwindPreviouslyLoaded() {
45
+ if (typeof localStorage === "undefined") return false;
46
+ try {
47
+ return localStorage.getItem(TAILWIND_CACHE_KEY) === "true";
48
+ } catch {
49
+ return false;
50
+ }
51
+ }
52
+ function markTailwindAsLoaded() {
53
+ if (typeof localStorage === "undefined") return;
54
+ try {
55
+ localStorage.setItem(TAILWIND_CACHE_KEY, "true");
56
+ } catch {
57
+ }
58
+ }
59
+ function preloadTailwind(cdnUrl, usePlayCdn) {
60
+ if (typeof document === "undefined") return;
61
+ if (document.querySelector("link[data-servly-tailwind-preload]")) return;
62
+ const url = cdnUrl || DEFAULT_TAILWIND_CDN;
63
+ const fullUrl = usePlayCdn ? `${url}?plugins=forms,typography,aspect-ratio` : url;
64
+ const link = document.createElement("link");
65
+ link.rel = "preload";
66
+ link.as = "script";
67
+ link.href = fullUrl;
68
+ link.setAttribute("data-servly-tailwind-preload", "true");
69
+ if (document.head.firstChild) {
70
+ document.head.insertBefore(link, document.head.firstChild);
71
+ } else {
72
+ document.head.appendChild(link);
73
+ }
74
+ const dnsPrefetch = document.createElement("link");
75
+ dnsPrefetch.rel = "dns-prefetch";
76
+ dnsPrefetch.href = "https://cdn.tailwindcss.com";
77
+ document.head.appendChild(dnsPrefetch);
78
+ }
79
+ function preventFOUC() {
80
+ if (typeof document === "undefined") return;
81
+ if (foucStyleElement) return;
82
+ const wasLoaded = wasTailwindPreviouslyLoaded();
83
+ foucStyleElement = document.createElement("style");
84
+ foucStyleElement.id = "servly-fouc-prevention";
85
+ foucStyleElement.textContent = FOUC_PREVENTION_CSS;
86
+ if (document.head.firstChild) {
87
+ document.head.insertBefore(foucStyleElement, document.head.firstChild);
88
+ } else {
89
+ document.head.appendChild(foucStyleElement);
90
+ }
91
+ if (wasLoaded) {
92
+ setTimeout(() => {
93
+ if (window.tailwind) {
94
+ removeFOUCPrevention();
95
+ }
96
+ }, 100);
97
+ }
98
+ }
99
+ function removeFOUCPrevention() {
100
+ if (foucStyleElement && foucStyleElement.parentNode) {
101
+ foucStyleElement.parentNode.removeChild(foucStyleElement);
102
+ foucStyleElement = null;
103
+ }
104
+ if (typeof document !== "undefined") {
105
+ document.querySelectorAll(".servly-component, [data-servly-id]").forEach((el) => {
106
+ el.classList.add("servly-ready");
107
+ });
108
+ }
109
+ }
110
+ function markElementReady(element) {
111
+ element.classList.add("servly-ready");
112
+ element.classList.remove("servly-fouc-hidden");
113
+ }
114
+ function isTailwindReady() {
115
+ if (typeof window === "undefined") return false;
116
+ return tailwindInjected && !!window.tailwind;
117
+ }
118
+ function waitForTailwind() {
119
+ if (isTailwindReady()) {
120
+ return Promise.resolve();
121
+ }
122
+ if (tailwindReadyPromise) {
123
+ return tailwindReadyPromise;
124
+ }
125
+ tailwindReadyPromise = new Promise((resolve) => {
126
+ tailwindReadyResolve = resolve;
127
+ });
128
+ return tailwindReadyPromise;
129
+ }
38
130
  function injectTailwind(config = {}) {
39
131
  return new Promise((resolve, reject) => {
40
132
  if (tailwindInjected && tailwindScript) {
@@ -45,34 +137,69 @@ function injectTailwind(config = {}) {
45
137
  resolve();
46
138
  return;
47
139
  }
48
- if (window.tailwind) {
49
- tailwindInjected = true;
50
- config.onReady?.();
51
- resolve();
52
- return;
53
- }
54
140
  const {
55
141
  cdnUrl = DEFAULT_TAILWIND_CDN,
56
142
  config: tailwindConfig,
57
143
  plugins = [],
58
144
  usePlayCdn = false,
59
145
  onReady,
60
- onError
146
+ onError,
147
+ preventFOUC: shouldPreventFOUC = true,
148
+ enablePreload = true
61
149
  } = config;
150
+ if (shouldPreventFOUC) {
151
+ preventFOUC();
152
+ }
153
+ if (enablePreload) {
154
+ preloadTailwind(cdnUrl, usePlayCdn);
155
+ }
156
+ if (window.tailwind) {
157
+ tailwindInjected = true;
158
+ markTailwindAsLoaded();
159
+ if (shouldPreventFOUC) {
160
+ removeFOUCPrevention();
161
+ }
162
+ if (tailwindReadyResolve) {
163
+ tailwindReadyResolve();
164
+ tailwindReadyResolve = null;
165
+ }
166
+ config.onReady?.();
167
+ resolve();
168
+ return;
169
+ }
62
170
  const script = document.createElement("script");
63
171
  script.src = usePlayCdn ? `${cdnUrl}?plugins=forms,typography,aspect-ratio` : cdnUrl;
64
172
  script.async = true;
173
+ script.crossOrigin = "anonymous";
65
174
  script.onload = () => {
66
175
  tailwindInjected = true;
67
176
  tailwindScript = script;
177
+ markTailwindAsLoaded();
68
178
  if (tailwindConfig && window.tailwind) {
69
179
  window.tailwind.config = tailwindConfig;
70
180
  }
71
- onReady?.();
72
- resolve();
181
+ const delay = wasTailwindPreviouslyLoaded() ? 10 : 50;
182
+ setTimeout(() => {
183
+ if (shouldPreventFOUC) {
184
+ removeFOUCPrevention();
185
+ }
186
+ if (tailwindReadyResolve) {
187
+ tailwindReadyResolve();
188
+ tailwindReadyResolve = null;
189
+ }
190
+ onReady?.();
191
+ resolve();
192
+ }, delay);
73
193
  };
74
194
  script.onerror = (event) => {
75
195
  const error = new Error(`Failed to load Tailwind CSS from ${cdnUrl}`);
196
+ if (shouldPreventFOUC) {
197
+ removeFOUCPrevention();
198
+ }
199
+ if (tailwindReadyResolve) {
200
+ tailwindReadyResolve();
201
+ tailwindReadyResolve = null;
202
+ }
76
203
  onError?.(error);
77
204
  reject(error);
78
205
  };
@@ -84,6 +211,8 @@ function removeTailwind() {
84
211
  tailwindScript.parentNode.removeChild(tailwindScript);
85
212
  tailwindScript = null;
86
213
  tailwindInjected = false;
214
+ tailwindReadyPromise = null;
215
+ tailwindReadyResolve = null;
87
216
  delete window.tailwind;
88
217
  }
89
218
  }
@@ -131,13 +260,26 @@ async function initServlyTailwind(customConfig) {
131
260
  usePlayCdn: true
132
261
  });
133
262
  }
134
- var DEFAULT_TAILWIND_CDN, tailwindInjected, tailwindScript, DEFAULT_SERVLY_TAILWIND_CONFIG, injectTailwindStyles, tailwind_default;
263
+ var DEFAULT_TAILWIND_CDN, TAILWIND_CACHE_KEY, tailwindInjected, tailwindScript, foucStyleElement, tailwindReadyPromise, tailwindReadyResolve, FOUC_PREVENTION_CSS, DEFAULT_SERVLY_TAILWIND_CONFIG, injectTailwindStyles, tailwind_default;
135
264
  var init_tailwind = __esm({
136
265
  "src/tailwind.ts"() {
137
266
  "use strict";
138
267
  DEFAULT_TAILWIND_CDN = "https://cdn.tailwindcss.com";
268
+ TAILWIND_CACHE_KEY = "servly-tailwind-loaded";
139
269
  tailwindInjected = false;
140
270
  tailwindScript = null;
271
+ foucStyleElement = null;
272
+ tailwindReadyPromise = null;
273
+ tailwindReadyResolve = null;
274
+ FOUC_PREVENTION_CSS = `
275
+ .servly-component:not(.servly-ready),
276
+ [data-servly-id]:not(.servly-ready) {
277
+ visibility: hidden !important;
278
+ }
279
+ .servly-fouc-hidden {
280
+ visibility: hidden !important;
281
+ }
282
+ `;
141
283
  DEFAULT_SERVLY_TAILWIND_CONFIG = {
142
284
  theme: {
143
285
  extend: {
@@ -174,11 +316,17 @@ var init_tailwind = __esm({
174
316
  injectTailwindStyles,
175
317
  removeTailwind,
176
318
  isTailwindLoaded,
319
+ isTailwindReady,
320
+ waitForTailwind,
177
321
  getTailwind,
178
322
  updateTailwindConfig,
179
323
  addCustomStyles,
180
324
  removeCustomStyles,
181
325
  initServlyTailwind,
326
+ preventFOUC,
327
+ removeFOUCPrevention,
328
+ markElementReady,
329
+ preloadTailwind,
182
330
  DEFAULT_SERVLY_TAILWIND_CONFIG
183
331
  };
184
332
  }
@@ -377,6 +525,7 @@ var index_exports = {};
377
525
  __export(index_exports, {
378
526
  AnalyticsCollector: () => AnalyticsCollector,
379
527
  DEFAULT_CACHE_CONFIG: () => DEFAULT_CACHE_CONFIG,
528
+ DEFAULT_REGISTRY_URL: () => DEFAULT_REGISTRY_URL,
380
529
  DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
381
530
  DEFAULT_SERVLY_TAILWIND_CONFIG: () => DEFAULT_SERVLY_TAILWIND_CONFIG,
382
531
  EVENT_HANDLERS: () => EVENT_HANDLERS,
@@ -461,16 +610,21 @@ __export(index_exports, {
461
610
  isIconRegistered: () => isIconRegistered,
462
611
  isIconSetSupported: () => isIconSetSupported,
463
612
  isTailwindLoaded: () => isTailwindLoaded,
613
+ isTailwindReady: () => isTailwindReady,
464
614
  isValidSpecifier: () => isValidSpecifier,
615
+ markElementReady: () => markElementReady,
465
616
  navigateTo: () => navigateTo,
466
617
  parseVersion: () => parseVersion,
467
618
  prefetchComponents: () => prefetchComponents,
468
619
  preloadIcons: () => preloadIcons,
620
+ preloadTailwind: () => preloadTailwind,
621
+ preventFOUC: () => preventFOUC,
469
622
  processStyles: () => processStyles,
470
623
  registerIcon: () => registerIcon,
471
624
  registerIcons: () => registerIcons,
472
625
  removeClass: () => removeClass,
473
626
  removeCustomStyles: () => removeCustomStyles,
627
+ removeFOUCPrevention: () => removeFOUCPrevention,
474
628
  removeLocalStorage: () => removeLocalStorage,
475
629
  removeSessionStorage: () => removeSessionStorage,
476
630
  removeTailwind: () => removeTailwind,
@@ -505,7 +659,8 @@ __export(index_exports, {
505
659
  updateStyles: () => updateStyles,
506
660
  updateTailwindConfig: () => updateTailwindConfig,
507
661
  validateAssertion: () => validateAssertion,
508
- validateProps: () => validateProps
662
+ validateProps: () => validateProps,
663
+ waitForTailwind: () => waitForTailwind
509
664
  });
510
665
  module.exports = __toCommonJS(index_exports);
511
666
 
@@ -3437,7 +3592,30 @@ function resolveComponentViewInputs(bindings, context, parentInputs) {
3437
3592
  case "static":
3438
3593
  case "value":
3439
3594
  case "constant":
3440
- resolved[key] = binding.value;
3595
+ if (binding.value && typeof binding.value === "object" && Array.isArray(binding.value.plugins)) {
3596
+ const plugins = binding.value.plugins;
3597
+ resolved[key] = (event) => {
3598
+ for (const plugin of plugins) {
3599
+ const pluginType = plugin.type || plugin.key;
3600
+ if (pluginType === "executeCode" && plugin.code) {
3601
+ try {
3602
+ const fn = new Function(
3603
+ "event",
3604
+ "props",
3605
+ "state",
3606
+ "context",
3607
+ plugin.code
3608
+ );
3609
+ fn(event, context.props || {}, context.state || {}, context.context || {});
3610
+ } catch (error) {
3611
+ console.error("[Servly] executeCode error:", error);
3612
+ }
3613
+ }
3614
+ }
3615
+ };
3616
+ } else {
3617
+ resolved[key] = binding.value;
3618
+ }
3441
3619
  break;
3442
3620
  case "state":
3443
3621
  if (binding.path && context.state) {
@@ -4422,7 +4600,8 @@ var DEFAULT_RETRY_CONFIG = {
4422
4600
  maxDelay: 1e4,
4423
4601
  backoffMultiplier: 2
4424
4602
  };
4425
- var registryBaseUrl = "/api/views/registry";
4603
+ var DEFAULT_REGISTRY_URL = "https://core-api.servly.app/v1/views/registry";
4604
+ var registryBaseUrl = DEFAULT_REGISTRY_URL;
4426
4605
  function setRegistryUrl(url) {
4427
4606
  registryBaseUrl = url;
4428
4607
  }
@@ -4557,7 +4736,7 @@ async function fetchComponent(id, options = {}) {
4557
4736
  const {
4558
4737
  version = "latest",
4559
4738
  apiKey,
4560
- cacheStrategy = "memory",
4739
+ cacheStrategy = "localStorage",
4561
4740
  cacheConfig = DEFAULT_CACHE_CONFIG,
4562
4741
  retryConfig = {},
4563
4742
  forceRefresh = false,
@@ -4725,7 +4904,7 @@ async function prefetchComponents(ids, options = {}) {
4725
4904
  await Promise.all(promises);
4726
4905
  }
4727
4906
  async function isComponentAvailable(id, version = "latest", options = {}) {
4728
- const { cacheStrategy = "memory", cacheConfig = DEFAULT_CACHE_CONFIG } = options;
4907
+ const { cacheStrategy = "localStorage", cacheConfig = DEFAULT_CACHE_CONFIG } = options;
4729
4908
  const cached = getFromCache(id, version, cacheStrategy, cacheConfig);
4730
4909
  if (cached) {
4731
4910
  return { available: true, cached: true, version: cached.version };
@@ -5149,6 +5328,7 @@ init_tailwind();
5149
5328
  0 && (module.exports = {
5150
5329
  AnalyticsCollector,
5151
5330
  DEFAULT_CACHE_CONFIG,
5331
+ DEFAULT_REGISTRY_URL,
5152
5332
  DEFAULT_RETRY_CONFIG,
5153
5333
  DEFAULT_SERVLY_TAILWIND_CONFIG,
5154
5334
  EVENT_HANDLERS,
@@ -5233,16 +5413,21 @@ init_tailwind();
5233
5413
  isIconRegistered,
5234
5414
  isIconSetSupported,
5235
5415
  isTailwindLoaded,
5416
+ isTailwindReady,
5236
5417
  isValidSpecifier,
5418
+ markElementReady,
5237
5419
  navigateTo,
5238
5420
  parseVersion,
5239
5421
  prefetchComponents,
5240
5422
  preloadIcons,
5423
+ preloadTailwind,
5424
+ preventFOUC,
5241
5425
  processStyles,
5242
5426
  registerIcon,
5243
5427
  registerIcons,
5244
5428
  removeClass,
5245
5429
  removeCustomStyles,
5430
+ removeFOUCPrevention,
5246
5431
  removeLocalStorage,
5247
5432
  removeSessionStorage,
5248
5433
  removeTailwind,
@@ -5277,5 +5462,6 @@ init_tailwind();
5277
5462
  updateStyles,
5278
5463
  updateTailwindConfig,
5279
5464
  validateAssertion,
5280
- validateProps
5465
+ validateProps,
5466
+ waitForTailwind
5281
5467
  });
package/dist/index.js CHANGED
@@ -6,10 +6,16 @@ import {
6
6
  injectTailwind,
7
7
  injectTailwindStyles,
8
8
  isTailwindLoaded,
9
+ isTailwindReady,
10
+ markElementReady,
11
+ preloadTailwind,
12
+ preventFOUC,
9
13
  removeCustomStyles,
14
+ removeFOUCPrevention,
10
15
  removeTailwind,
11
- updateTailwindConfig
12
- } from "./chunk-SMHCCKAZ.js";
16
+ updateTailwindConfig,
17
+ waitForTailwind
18
+ } from "./chunk-5O72RMSO.js";
13
19
  import {
14
20
  buildRegistryFromBundle,
15
21
  collectAllDependencies,
@@ -2946,7 +2952,30 @@ function resolveComponentViewInputs(bindings, context, parentInputs) {
2946
2952
  case "static":
2947
2953
  case "value":
2948
2954
  case "constant":
2949
- resolved[key] = binding.value;
2955
+ if (binding.value && typeof binding.value === "object" && Array.isArray(binding.value.plugins)) {
2956
+ const plugins = binding.value.plugins;
2957
+ resolved[key] = (event) => {
2958
+ for (const plugin of plugins) {
2959
+ const pluginType = plugin.type || plugin.key;
2960
+ if (pluginType === "executeCode" && plugin.code) {
2961
+ try {
2962
+ const fn = new Function(
2963
+ "event",
2964
+ "props",
2965
+ "state",
2966
+ "context",
2967
+ plugin.code
2968
+ );
2969
+ fn(event, context.props || {}, context.state || {}, context.context || {});
2970
+ } catch (error) {
2971
+ console.error("[Servly] executeCode error:", error);
2972
+ }
2973
+ }
2974
+ }
2975
+ };
2976
+ } else {
2977
+ resolved[key] = binding.value;
2978
+ }
2950
2979
  break;
2951
2980
  case "state":
2952
2981
  if (binding.path && context.state) {
@@ -3581,7 +3610,7 @@ async function createServlyRenderer(options) {
3581
3610
  container = containerOption;
3582
3611
  }
3583
3612
  if (shouldInjectTailwind) {
3584
- const { initServlyTailwind: initServlyTailwind2 } = await import("./tailwind-DMUQ7TOT.js");
3613
+ const { initServlyTailwind: initServlyTailwind2 } = await import("./tailwind-4IK6HZC6.js");
3585
3614
  await initServlyTailwind2(tailwindConfig);
3586
3615
  }
3587
3616
  const activeRenders = [];
@@ -3930,7 +3959,8 @@ var DEFAULT_RETRY_CONFIG = {
3930
3959
  maxDelay: 1e4,
3931
3960
  backoffMultiplier: 2
3932
3961
  };
3933
- var registryBaseUrl = "/api/views/registry";
3962
+ var DEFAULT_REGISTRY_URL = "https://core-api.servly.app/v1/views/registry";
3963
+ var registryBaseUrl = DEFAULT_REGISTRY_URL;
3934
3964
  function setRegistryUrl(url) {
3935
3965
  registryBaseUrl = url;
3936
3966
  }
@@ -4065,7 +4095,7 @@ async function fetchComponent(id, options = {}) {
4065
4095
  const {
4066
4096
  version = "latest",
4067
4097
  apiKey,
4068
- cacheStrategy = "memory",
4098
+ cacheStrategy = "localStorage",
4069
4099
  cacheConfig = DEFAULT_CACHE_CONFIG,
4070
4100
  retryConfig = {},
4071
4101
  forceRefresh = false,
@@ -4233,7 +4263,7 @@ async function prefetchComponents(ids, options = {}) {
4233
4263
  await Promise.all(promises);
4234
4264
  }
4235
4265
  async function isComponentAvailable(id, version = "latest", options = {}) {
4236
- const { cacheStrategy = "memory", cacheConfig = DEFAULT_CACHE_CONFIG } = options;
4266
+ const { cacheStrategy = "localStorage", cacheConfig = DEFAULT_CACHE_CONFIG } = options;
4237
4267
  const cached = getFromCache(id, version, cacheStrategy, cacheConfig);
4238
4268
  if (cached) {
4239
4269
  return { available: true, cached: true, version: cached.version };
@@ -4652,6 +4682,7 @@ function getSampleValue(def) {
4652
4682
  export {
4653
4683
  AnalyticsCollector,
4654
4684
  DEFAULT_CACHE_CONFIG,
4685
+ DEFAULT_REGISTRY_URL,
4655
4686
  DEFAULT_RETRY_CONFIG,
4656
4687
  DEFAULT_SERVLY_TAILWIND_CONFIG,
4657
4688
  EVENT_HANDLERS,
@@ -4736,16 +4767,21 @@ export {
4736
4767
  isIconRegistered,
4737
4768
  isIconSetSupported,
4738
4769
  isTailwindLoaded,
4770
+ isTailwindReady,
4739
4771
  isValidSpecifier,
4772
+ markElementReady,
4740
4773
  navigateTo,
4741
4774
  parseVersion,
4742
4775
  prefetchComponents,
4743
4776
  preloadIcons,
4777
+ preloadTailwind,
4778
+ preventFOUC,
4744
4779
  processStyles,
4745
4780
  registerIcon,
4746
4781
  registerIcons,
4747
4782
  removeClass,
4748
4783
  removeCustomStyles,
4784
+ removeFOUCPrevention,
4749
4785
  removeLocalStorage,
4750
4786
  removeSessionStorage,
4751
4787
  removeTailwind,
@@ -4780,5 +4816,6 @@ export {
4780
4816
  updateStyles,
4781
4817
  updateTailwindConfig,
4782
4818
  validateAssertion,
4783
- validateProps
4819
+ validateProps,
4820
+ waitForTailwind
4784
4821
  };
@@ -6,11 +6,17 @@ import {
6
6
  injectTailwind,
7
7
  injectTailwindStyles,
8
8
  isTailwindLoaded,
9
+ isTailwindReady,
10
+ markElementReady,
11
+ preloadTailwind,
12
+ preventFOUC,
9
13
  removeCustomStyles,
14
+ removeFOUCPrevention,
10
15
  removeTailwind,
11
16
  tailwind_default,
12
- updateTailwindConfig
13
- } from "./chunk-SMHCCKAZ.js";
17
+ updateTailwindConfig,
18
+ waitForTailwind
19
+ } from "./chunk-5O72RMSO.js";
14
20
  export {
15
21
  DEFAULT_SERVLY_TAILWIND_CONFIG,
16
22
  addCustomStyles,
@@ -20,7 +26,13 @@ export {
20
26
  injectTailwind,
21
27
  injectTailwindStyles,
22
28
  isTailwindLoaded,
29
+ isTailwindReady,
30
+ markElementReady,
31
+ preloadTailwind,
32
+ preventFOUC,
23
33
  removeCustomStyles,
34
+ removeFOUCPrevention,
24
35
  removeTailwind,
25
- updateTailwindConfig
36
+ updateTailwindConfig,
37
+ waitForTailwind
26
38
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servlyadmin/runtime-core",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "Framework-agnostic core renderer for Servly components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -1,157 +0,0 @@
1
- // src/tailwind.ts
2
- var DEFAULT_TAILWIND_CDN = "https://cdn.tailwindcss.com";
3
- var tailwindInjected = false;
4
- var tailwindScript = null;
5
- function injectTailwind(config = {}) {
6
- return new Promise((resolve, reject) => {
7
- if (tailwindInjected && tailwindScript) {
8
- resolve();
9
- return;
10
- }
11
- if (typeof document === "undefined") {
12
- resolve();
13
- return;
14
- }
15
- if (window.tailwind) {
16
- tailwindInjected = true;
17
- config.onReady?.();
18
- resolve();
19
- return;
20
- }
21
- const {
22
- cdnUrl = DEFAULT_TAILWIND_CDN,
23
- config: tailwindConfig,
24
- plugins = [],
25
- usePlayCdn = false,
26
- onReady,
27
- onError
28
- } = config;
29
- const script = document.createElement("script");
30
- script.src = usePlayCdn ? `${cdnUrl}?plugins=forms,typography,aspect-ratio` : cdnUrl;
31
- script.async = true;
32
- script.onload = () => {
33
- tailwindInjected = true;
34
- tailwindScript = script;
35
- if (tailwindConfig && window.tailwind) {
36
- window.tailwind.config = tailwindConfig;
37
- }
38
- onReady?.();
39
- resolve();
40
- };
41
- script.onerror = (event) => {
42
- const error = new Error(`Failed to load Tailwind CSS from ${cdnUrl}`);
43
- onError?.(error);
44
- reject(error);
45
- };
46
- document.head.appendChild(script);
47
- });
48
- }
49
- function removeTailwind() {
50
- if (tailwindScript && tailwindScript.parentNode) {
51
- tailwindScript.parentNode.removeChild(tailwindScript);
52
- tailwindScript = null;
53
- tailwindInjected = false;
54
- delete window.tailwind;
55
- }
56
- }
57
- function isTailwindLoaded() {
58
- return tailwindInjected || !!window.tailwind;
59
- }
60
- function getTailwind() {
61
- return window.tailwind;
62
- }
63
- function updateTailwindConfig(config) {
64
- if (window.tailwind) {
65
- window.tailwind.config = {
66
- ...window.tailwind.config,
67
- ...config
68
- };
69
- }
70
- }
71
- function addCustomStyles(css, id) {
72
- if (typeof document === "undefined") {
73
- throw new Error("addCustomStyles can only be used in browser environment");
74
- }
75
- const styleId = id || `servly-custom-styles-${Date.now()}`;
76
- let existingStyle = document.getElementById(styleId);
77
- if (existingStyle) {
78
- existingStyle.textContent = css;
79
- return existingStyle;
80
- }
81
- const style = document.createElement("style");
82
- style.id = styleId;
83
- style.textContent = css;
84
- document.head.appendChild(style);
85
- return style;
86
- }
87
- function removeCustomStyles(id) {
88
- if (typeof document === "undefined") return;
89
- const style = document.getElementById(id);
90
- if (style && style.parentNode) {
91
- style.parentNode.removeChild(style);
92
- }
93
- }
94
- var DEFAULT_SERVLY_TAILWIND_CONFIG = {
95
- theme: {
96
- extend: {
97
- // Add any Servly-specific theme extensions here
98
- }
99
- },
100
- // Safelist common dynamic classes
101
- safelist: [
102
- // Spacing
103
- { pattern: /^(p|m|gap)-/ },
104
- // Sizing
105
- { pattern: /^(w|h|min-w|min-h|max-w|max-h)-/ },
106
- // Flexbox
107
- { pattern: /^(flex|justify|items|self)-/ },
108
- // Grid
109
- { pattern: /^(grid|col|row)-/ },
110
- // Colors
111
- { pattern: /^(bg|text|border|ring)-/ },
112
- // Typography
113
- { pattern: /^(font|text|leading|tracking)-/ },
114
- // Borders
115
- { pattern: /^(rounded|border)-/ },
116
- // Effects
117
- { pattern: /^(shadow|opacity|blur)-/ },
118
- // Transforms
119
- { pattern: /^(scale|rotate|translate|skew)-/ },
120
- // Transitions
121
- { pattern: /^(transition|duration|ease|delay)-/ }
122
- ]
123
- };
124
- async function initServlyTailwind(customConfig) {
125
- const config = customConfig ? { ...DEFAULT_SERVLY_TAILWIND_CONFIG, ...customConfig } : DEFAULT_SERVLY_TAILWIND_CONFIG;
126
- await injectTailwind({
127
- config,
128
- usePlayCdn: true
129
- });
130
- }
131
- var injectTailwindStyles = initServlyTailwind;
132
- var tailwind_default = {
133
- injectTailwind,
134
- injectTailwindStyles,
135
- removeTailwind,
136
- isTailwindLoaded,
137
- getTailwind,
138
- updateTailwindConfig,
139
- addCustomStyles,
140
- removeCustomStyles,
141
- initServlyTailwind,
142
- DEFAULT_SERVLY_TAILWIND_CONFIG
143
- };
144
-
145
- export {
146
- injectTailwind,
147
- removeTailwind,
148
- isTailwindLoaded,
149
- getTailwind,
150
- updateTailwindConfig,
151
- addCustomStyles,
152
- removeCustomStyles,
153
- DEFAULT_SERVLY_TAILWIND_CONFIG,
154
- initServlyTailwind,
155
- injectTailwindStyles,
156
- tailwind_default
157
- };