lightview 2.3.7 → 2.3.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.
@@ -1,1608 +0,0 @@
1
- (function() {
2
- "use strict";
3
- var _a, _b;
4
- const _LV = globalThis.__LIGHTVIEW_INTERNALS__ || (globalThis.__LIGHTVIEW_INTERNALS__ = {
5
- currentEffect: null,
6
- registry: /* @__PURE__ */ new Map(),
7
- // Global name -> Signal/Proxy
8
- localRegistries: /* @__PURE__ */ new WeakMap(),
9
- // Object/Element -> Map(name -> Signal/Proxy)
10
- futureSignals: /* @__PURE__ */ new Map(),
11
- // name -> Set of (signal) => void
12
- schemas: /* @__PURE__ */ new Map(),
13
- // name -> Schema (Draft 7+ or Shorthand)
14
- parents: /* @__PURE__ */ new WeakMap(),
15
- // Proxy -> Parent (Proxy/Element)
16
- helpers: /* @__PURE__ */ new Map(),
17
- // name -> function (used for transforms and expressions)
18
- hooks: {
19
- validate: (value, schema) => true
20
- // Hook for extensions (like JPRX) to provide full validation
21
- }
22
- });
23
- const lookup = (name, scope) => {
24
- let current = scope;
25
- while (current && typeof current === "object") {
26
- const registry = _LV.localRegistries.get(current);
27
- if (registry && registry.has(name)) return registry.get(name);
28
- current = current.parentElement || _LV.parents.get(current);
29
- }
30
- return _LV.registry.get(name);
31
- };
32
- const signal = (initialValue, optionsOrName) => {
33
- const name = typeof optionsOrName === "string" ? optionsOrName : optionsOrName == null ? void 0 : optionsOrName.name;
34
- const storage = optionsOrName == null ? void 0 : optionsOrName.storage;
35
- const scope = optionsOrName == null ? void 0 : optionsOrName.scope;
36
- if (name && storage) {
37
- try {
38
- const stored = storage.getItem(name);
39
- if (stored !== null) initialValue = JSON.parse(stored);
40
- } catch (e) {
41
- }
42
- }
43
- let value = initialValue;
44
- const subscribers = /* @__PURE__ */ new Set();
45
- const f = (...args) => args.length === 0 ? f.value : f.value = args[0];
46
- Object.defineProperty(f, "value", {
47
- get() {
48
- if (_LV.currentEffect) {
49
- subscribers.add(_LV.currentEffect);
50
- _LV.currentEffect.dependencies.add(subscribers);
51
- }
52
- return value;
53
- },
54
- set(newValue) {
55
- if (value !== newValue) {
56
- value = newValue;
57
- if (name && storage) {
58
- try {
59
- storage.setItem(name, JSON.stringify(value));
60
- } catch (e) {
61
- }
62
- }
63
- [...subscribers].forEach((effect2) => effect2());
64
- }
65
- }
66
- });
67
- if (name) {
68
- const registry = scope && typeof scope === "object" ? _LV.localRegistries.get(scope) || _LV.localRegistries.set(scope, /* @__PURE__ */ new Map()).get(scope) : _LV.registry;
69
- if (registry && registry.has(name) && registry.get(name) !== f) {
70
- throw new Error(`Lightview: A signal or state with the name "${name}" is already registered.`);
71
- }
72
- if (registry) registry.set(name, f);
73
- const futures = _LV.futureSignals.get(name);
74
- if (futures) {
75
- futures.forEach((resolve) => resolve(f));
76
- }
77
- }
78
- return f;
79
- };
80
- const getSignal = (name, defaultValueOrOptions) => {
81
- const options = typeof defaultValueOrOptions === "object" && defaultValueOrOptions !== null ? defaultValueOrOptions : { defaultValue: defaultValueOrOptions };
82
- const { scope, defaultValue } = options;
83
- const existing = lookup(name, scope);
84
- if (existing) return existing;
85
- if (defaultValue !== void 0) return signal(defaultValue, { name, scope });
86
- const future = signal(void 0);
87
- const handler = (realSignal) => {
88
- const hasValue = realSignal && (typeof realSignal === "object" || typeof realSignal === "function") && "value" in realSignal;
89
- if (hasValue) {
90
- future.value = realSignal.value;
91
- effect(() => {
92
- future.value = realSignal.value;
93
- });
94
- } else {
95
- future.value = realSignal;
96
- }
97
- };
98
- if (!_LV.futureSignals.has(name)) _LV.futureSignals.set(name, /* @__PURE__ */ new Set());
99
- _LV.futureSignals.get(name).add(handler);
100
- return future;
101
- };
102
- signal.get = getSignal;
103
- const effect = (fn) => {
104
- const execute = () => {
105
- if (!execute.active || execute.running) return;
106
- execute.dependencies.forEach((dep) => dep.delete(execute));
107
- execute.dependencies.clear();
108
- execute.running = true;
109
- _LV.currentEffect = execute;
110
- try {
111
- fn();
112
- } finally {
113
- _LV.currentEffect = null;
114
- execute.running = false;
115
- }
116
- };
117
- execute.active = true;
118
- execute.running = false;
119
- execute.dependencies = /* @__PURE__ */ new Set();
120
- execute.stop = () => {
121
- execute.dependencies.forEach((dep) => dep.delete(execute));
122
- execute.dependencies.clear();
123
- execute.active = false;
124
- };
125
- execute();
126
- return execute;
127
- };
128
- const getRegistry = () => _LV.registry;
129
- const internals = _LV;
130
- const stateCache = /* @__PURE__ */ new WeakMap();
131
- const stateSignals = /* @__PURE__ */ new WeakMap();
132
- const stateSchemas = /* @__PURE__ */ new WeakMap();
133
- const { parents, schemas, hooks } = internals;
134
- const validate = (target, prop, value, schema) => {
135
- var _a2, _b2;
136
- const current = target[prop];
137
- const type = typeof current;
138
- const isNew = !(prop in target);
139
- let behavior = schema;
140
- if (typeof schema === "object" && schema !== null) behavior = schema.type;
141
- if (behavior === "auto" && isNew) throw new Error(`Lightview: Cannot add new property "${prop}" to fixed 'auto' state.`);
142
- if (behavior === "polymorphic" || typeof behavior === "object" && (behavior == null ? void 0 : behavior.coerce)) {
143
- if (type === "number") return Number(value);
144
- if (type === "boolean") return Boolean(value);
145
- if (type === "string") return String(value);
146
- } else if (behavior === "auto" || behavior === "dynamic") {
147
- if (!isNew && typeof value !== type) {
148
- throw new Error(`Lightview: Type mismatch for "${prop}". Expected ${type}, got ${typeof value}.`);
149
- }
150
- }
151
- if (typeof schema === "object" && schema !== null && schema.transform) {
152
- const trans = schema.transform;
153
- const transformFn = typeof trans === "function" ? trans : internals.helpers.get(trans) || ((_b2 = (_a2 = globalThis.Lightview) == null ? void 0 : _a2.helpers) == null ? void 0 : _b2[trans]);
154
- if (transformFn) value = transformFn(value);
155
- }
156
- if (hooks.validate(value, schema) === false) {
157
- throw new Error(`Lightview: Validation failed for "${prop}".`);
158
- }
159
- return value;
160
- };
161
- const protoMethods = (proto, test) => Object.getOwnPropertyNames(proto).filter((k) => typeof proto[k] === "function" && test(k));
162
- const DATE_TRACKING = protoMethods(Date.prototype, (k) => /^(to|get|valueOf)/.test(k));
163
- const DATE_MUTATING = protoMethods(Date.prototype, (k) => /^set/.test(k));
164
- const ARRAY_TRACKING = [
165
- "map",
166
- "forEach",
167
- "filter",
168
- "find",
169
- "findIndex",
170
- "some",
171
- "every",
172
- "reduce",
173
- "reduceRight",
174
- "includes",
175
- "indexOf",
176
- "lastIndexOf",
177
- "join",
178
- "slice",
179
- "concat",
180
- "flat",
181
- "flatMap",
182
- "at",
183
- "entries",
184
- "keys",
185
- "values"
186
- ];
187
- const ARRAY_MUTATING = ["push", "pop", "shift", "unshift", "splice", "sort", "reverse", "fill", "copyWithin"];
188
- const ARRAY_ITERATION = ["map", "forEach", "filter", "find", "findIndex", "some", "every", "flatMap"];
189
- const getOrSet = (map, key, factory) => {
190
- let v = map.get(key);
191
- if (!v) {
192
- v = factory();
193
- map.set(key, v);
194
- }
195
- return v;
196
- };
197
- const proxyGet = (target, prop, receiver, signals) => {
198
- if (prop === "__parent__") return parents.get(receiver);
199
- if (!signals.has(prop)) {
200
- signals.set(prop, signal(Reflect.get(target, prop, receiver)));
201
- }
202
- const signal$1 = signals.get(prop);
203
- const val = signal$1.value;
204
- if (typeof val === "object" && val !== null) {
205
- const childProxy = state(val);
206
- parents.set(childProxy, receiver);
207
- return childProxy;
208
- }
209
- return val;
210
- };
211
- const proxySet = (target, prop, value, receiver, signals) => {
212
- const schema = stateSchemas.get(receiver);
213
- const validatedValue = schema ? validate(target, prop, value, schema) : value;
214
- if (!signals.has(prop)) {
215
- signals.set(prop, signal(Reflect.get(target, prop, receiver)));
216
- }
217
- const success = Reflect.set(target, prop, validatedValue, receiver);
218
- const signal$1 = signals.get(prop);
219
- if (success && signal$1) signal$1.value = validatedValue;
220
- return success;
221
- };
222
- const createSpecialProxy = (obj, monitor, trackingProps = []) => {
223
- const signals = getOrSet(stateSignals, obj, () => /* @__PURE__ */ new Map());
224
- if (!signals.has(monitor)) {
225
- const initialValue = typeof obj[monitor] === "function" ? obj[monitor].call(obj) : obj[monitor];
226
- signals.set(monitor, signal(initialValue));
227
- }
228
- const isDate = obj instanceof Date;
229
- const isArray = Array.isArray(obj);
230
- const trackingMethods = isDate ? DATE_TRACKING : isArray ? ARRAY_TRACKING : trackingProps;
231
- const mutatingMethods = isDate ? DATE_MUTATING : isArray ? ARRAY_MUTATING : [];
232
- return new Proxy(obj, {
233
- get(target, prop, receiver) {
234
- if (prop === "__parent__") return parents.get(receiver);
235
- const value = target[prop];
236
- if (typeof value === "function") {
237
- const isTracking = trackingMethods.includes(prop);
238
- const isMutating = mutatingMethods.includes(prop);
239
- return function(...args) {
240
- if (isTracking) {
241
- const sig = signals.get(monitor);
242
- if (sig) void sig.value;
243
- }
244
- const startValue = typeof target[monitor] === "function" ? target[monitor].call(target) : target[monitor];
245
- if (isArray && ARRAY_ITERATION.includes(prop) && typeof args[0] === "function") {
246
- const originalCallback = args[0];
247
- args[0] = function(element, index, array) {
248
- const wrappedElement = typeof element === "object" && element !== null ? state(element) : element;
249
- if (wrappedElement && typeof wrappedElement === "object") {
250
- parents.set(wrappedElement, receiver);
251
- }
252
- return originalCallback.call(this, wrappedElement, index, array);
253
- };
254
- }
255
- const result = value.apply(target, args);
256
- const endValue = typeof target[monitor] === "function" ? target[monitor].call(target) : target[monitor];
257
- if (startValue !== endValue || isMutating) {
258
- const sig = signals.get(monitor);
259
- if (sig && sig.value !== endValue) {
260
- sig.value = endValue;
261
- }
262
- }
263
- return result;
264
- };
265
- }
266
- if (prop === monitor) {
267
- const sig = signals.get(monitor);
268
- return sig ? sig.value : Reflect.get(target, prop, receiver);
269
- }
270
- if (isArray && !isNaN(parseInt(prop))) {
271
- const monitorSig = signals.get(monitor);
272
- if (monitorSig) void monitorSig.value;
273
- }
274
- return proxyGet(target, prop, receiver, signals);
275
- },
276
- set(target, prop, value, receiver) {
277
- if (prop === monitor) {
278
- const success = Reflect.set(target, prop, value, receiver);
279
- if (success) {
280
- const sig = signals.get(monitor);
281
- if (sig) sig.value = value;
282
- }
283
- return success;
284
- }
285
- return proxySet(target, prop, value, receiver, signals);
286
- }
287
- });
288
- };
289
- const state = (obj, optionsOrName) => {
290
- if (typeof obj !== "object" || obj === null) return obj;
291
- const name = typeof optionsOrName === "string" ? optionsOrName : optionsOrName == null ? void 0 : optionsOrName.name;
292
- const storage = optionsOrName == null ? void 0 : optionsOrName.storage;
293
- const scope = optionsOrName == null ? void 0 : optionsOrName.scope;
294
- const schema = optionsOrName == null ? void 0 : optionsOrName.schema;
295
- if (name && storage) {
296
- try {
297
- const item = storage.getItem(name);
298
- if (item) {
299
- const loaded = JSON.parse(item);
300
- Array.isArray(obj) && Array.isArray(loaded) ? (obj.length = 0, obj.push(...loaded)) : Object.assign(obj, loaded);
301
- }
302
- } catch (e) {
303
- }
304
- }
305
- let proxy = stateCache.get(obj);
306
- if (!proxy) {
307
- const isArray = Array.isArray(obj), isDate = obj instanceof Date;
308
- const isSpecial = isArray || isDate;
309
- const monitor = isArray ? "length" : isDate ? "getTime" : null;
310
- if (isSpecial || !(obj instanceof RegExp || obj instanceof Map || obj instanceof Set || obj instanceof WeakMap || obj instanceof WeakSet)) {
311
- proxy = isSpecial ? createSpecialProxy(obj, monitor) : new Proxy(obj, {
312
- get(t, p, r) {
313
- if (p === "__parent__") return parents.get(r);
314
- return proxyGet(t, p, r, getOrSet(stateSignals, t, () => /* @__PURE__ */ new Map()));
315
- },
316
- set(t, p, v, r) {
317
- return proxySet(t, p, v, r, getOrSet(stateSignals, t, () => /* @__PURE__ */ new Map()));
318
- }
319
- });
320
- stateCache.set(obj, proxy);
321
- } else return obj;
322
- }
323
- if (schema) stateSchemas.set(proxy, schema);
324
- if (name && storage) {
325
- effect(() => {
326
- try {
327
- storage.setItem(name, JSON.stringify(proxy));
328
- } catch (e) {
329
- }
330
- });
331
- }
332
- if (name) {
333
- const registry = scope && typeof scope === "object" ? internals.localRegistries.get(scope) || internals.localRegistries.set(scope, /* @__PURE__ */ new Map()).get(scope) : getRegistry();
334
- if (registry && registry.has(name) && registry.get(name) !== proxy) {
335
- throw new Error(`Lightview: A signal or state with the name "${name}" is already registered.`);
336
- }
337
- if (registry) registry.set(name, proxy);
338
- const futures = internals.futureSignals.get(name);
339
- if (futures) {
340
- futures.forEach((resolve) => resolve(proxy));
341
- }
342
- }
343
- return proxy;
344
- };
345
- const getState = (name, defaultValueOrOptions) => {
346
- const options = typeof defaultValueOrOptions === "object" && defaultValueOrOptions !== null ? defaultValueOrOptions : { defaultValue: defaultValueOrOptions };
347
- const { scope, defaultValue } = options;
348
- const existing = lookup(name, scope);
349
- if (existing) return existing;
350
- if (defaultValue !== void 0) return state(defaultValue, { name, scope });
351
- const future = signal(void 0);
352
- const handler = (realState) => {
353
- future.value = realState;
354
- };
355
- if (!internals.futureSignals.has(name)) internals.futureSignals.set(name, /* @__PURE__ */ new Set());
356
- internals.futureSignals.get(name).add(handler);
357
- return future;
358
- };
359
- state.get = getState;
360
- const STANDARD_SRC_TAGS = ["img", "script", "iframe", "video", "audio", "source", "track", "embed", "input"];
361
- const isStandardSrcTag = (tagName) => STANDARD_SRC_TAGS.includes(tagName) || tagName.startsWith("lv-");
362
- const STANDARD_HREF_TAGS = ["a", "area", "base", "link"];
363
- const isValidTagName = (name) => typeof name === "string" && name.length > 0 && name !== "children";
364
- const isDangerousProtocol = (url) => {
365
- if (!url || typeof url !== "string") return false;
366
- const normalized = url.trim().toLowerCase();
367
- return normalized.startsWith("javascript:") || normalized.startsWith("vbscript:") || normalized.startsWith("data:text/html") || normalized.startsWith("data:application/javascript");
368
- };
369
- const validateUrl = (url) => {
370
- if (!url) return false;
371
- if (!/^[a-z][a-z0-9+.-]*:/i.test(url)) return true;
372
- try {
373
- const base = typeof document !== "undefined" ? document.baseURI : globalThis.location.origin;
374
- const target = new URL(url, base === "null" ? void 0 : base);
375
- const current = globalThis.location;
376
- if (target.origin === current.origin && target.origin !== "null") return true;
377
- if (target.hostname && target.hostname === current.hostname) return true;
378
- if (target.hostname && current.hostname && target.hostname.endsWith("." + current.hostname)) return true;
379
- if (current.protocol === "file:" && target.protocol === "file:") return true;
380
- return false;
381
- } catch (e) {
382
- return false;
383
- }
384
- };
385
- const isObjectDOM = (obj) => {
386
- if (typeof obj !== "object" || obj === null || Array.isArray(obj) || obj.tag || obj.domEl) return false;
387
- const keys = Object.keys(obj);
388
- return keys.length === 1 && isValidTagName(keys[0]) && typeof obj[keys[0]] === "object";
389
- };
390
- const convertObjectDOM = (obj) => {
391
- var _a2, _b2;
392
- if (typeof obj !== "object" || obj === null) return obj;
393
- if (Array.isArray(obj)) return obj.map(convertObjectDOM);
394
- if (obj.tag) return { ...obj, children: obj.children ? convertObjectDOM(obj.children) : [] };
395
- if (obj.domEl || !isObjectDOM(obj)) return obj;
396
- const tagKey = Object.keys(obj)[0];
397
- const content = obj[tagKey];
398
- const LV = typeof window !== "undefined" ? globalThis.Lightview : typeof globalThis !== "undefined" ? globalThis.Lightview : null;
399
- const tag = ((_b2 = (_a2 = LV == null ? void 0 : LV.tags) == null ? void 0 : _a2._customTags) == null ? void 0 : _b2[tagKey]) || tagKey;
400
- const { children, ...attributes } = content;
401
- return { tag, attributes, children: children ? convertObjectDOM(children) : [] };
402
- };
403
- const DAISYUI_CDN = "https://cdn.jsdelivr.net/npm/daisyui@4.12.23/dist/full.min.css";
404
- const componentConfig = {
405
- initialized: false,
406
- shadowDefault: true,
407
- // Default: components use shadow DOM
408
- daisyStyleSheet: null,
409
- themeStyleSheet: null,
410
- // Global theme stylesheet
411
- componentStyleSheets: /* @__PURE__ */ new Map(),
412
- customStyleSheets: /* @__PURE__ */ new Map(),
413
- // Registry for named custom stylesheets
414
- customStyleSheetPromises: /* @__PURE__ */ new Map()
415
- // Cache for pending stylesheet fetches
416
- };
417
- const registerStyleSheet = async (nameOrIdOrUrl, cssText) => {
418
- if (componentConfig.customStyleSheets.has(nameOrIdOrUrl)) return componentConfig.customStyleSheets.get(nameOrIdOrUrl);
419
- if (componentConfig.customStyleSheetPromises.has(nameOrIdOrUrl)) return componentConfig.customStyleSheetPromises.get(nameOrIdOrUrl);
420
- const promise = (async () => {
421
- try {
422
- let finalCss = cssText;
423
- if (finalCss === void 0) {
424
- if (nameOrIdOrUrl.startsWith("#")) {
425
- const el = document.querySelector(nameOrIdOrUrl);
426
- if (el) {
427
- finalCss = el.textContent;
428
- } else {
429
- throw new Error(`Style block '${nameOrIdOrUrl}' not found`);
430
- }
431
- } else {
432
- const response = await fetch(nameOrIdOrUrl);
433
- if (!response.ok) throw new Error(`Fetch failed: ${response.status}`);
434
- finalCss = await response.text();
435
- }
436
- }
437
- if (finalCss !== void 0) {
438
- const sheet = new CSSStyleSheet();
439
- sheet.replaceSync(finalCss);
440
- componentConfig.customStyleSheets.set(nameOrIdOrUrl, sheet);
441
- return sheet;
442
- }
443
- } catch (e) {
444
- console.error(`LightviewX: Failed to register stylesheet '${nameOrIdOrUrl}':`, e);
445
- } finally {
446
- componentConfig.customStyleSheetPromises.delete(nameOrIdOrUrl);
447
- }
448
- })();
449
- componentConfig.customStyleSheetPromises.set(nameOrIdOrUrl, promise);
450
- return promise;
451
- };
452
- const getSavedTheme = () => {
453
- try {
454
- if (typeof localStorage !== "undefined") {
455
- return localStorage.getItem("lightview-theme");
456
- }
457
- } catch (e) {
458
- return null;
459
- }
460
- };
461
- const themeSignal = signal(
462
- typeof document !== "undefined" && document.documentElement.getAttribute("data-theme") || getSavedTheme() || "light"
463
- );
464
- const setTheme = (themeName) => {
465
- if (!themeName) return;
466
- if (typeof document !== "undefined") {
467
- document.documentElement.setAttribute("data-theme", themeName);
468
- }
469
- if (themeSignal && themeSignal.value !== themeName) {
470
- themeSignal.value = themeName;
471
- }
472
- try {
473
- if (typeof localStorage !== "undefined") {
474
- localStorage.setItem("lightview-theme", themeName);
475
- }
476
- } catch (e) {
477
- }
478
- };
479
- const registerThemeSheet = async (url) => {
480
- try {
481
- const response = await fetch(url);
482
- if (!response.ok) throw new Error(`Failed to fetch theme CSS: ${response.status}`);
483
- const cssText = await response.text();
484
- const sheet = new CSSStyleSheet();
485
- sheet.replaceSync(cssText);
486
- componentConfig.themeStyleSheet = sheet;
487
- } catch (e) {
488
- console.error(`LightviewX: Failed to register theme stylesheet '${url}':`, e);
489
- }
490
- };
491
- const initComponents = async (options = {}) => {
492
- const { shadowDefault = true } = options;
493
- componentConfig.shadowDefault = shadowDefault;
494
- if (shadowDefault) {
495
- try {
496
- const response = await fetch(DAISYUI_CDN);
497
- if (!response.ok) {
498
- throw new Error(`Failed to fetch DaisyUI CSS: ${response.status}`);
499
- }
500
- const cssText = await response.text();
501
- const sheet = new CSSStyleSheet();
502
- sheet.replaceSync(cssText);
503
- componentConfig.daisyStyleSheet = sheet;
504
- } catch (e) {
505
- console.error("LightviewX: Failed to preload DaisyUI stylesheet:", e);
506
- }
507
- }
508
- componentConfig.initialized = true;
509
- };
510
- (async () => await initComponents())();
511
- const getComponentStyleSheet = async (cssUrl) => {
512
- if (componentConfig.componentStyleSheets.has(cssUrl)) {
513
- return componentConfig.componentStyleSheets.get(cssUrl);
514
- }
515
- try {
516
- const response = await fetch(cssUrl);
517
- if (!response.ok) {
518
- throw new Error(`Failed to fetch component CSS: ${response.status}`);
519
- }
520
- const cssText = await response.text();
521
- const sheet = new CSSStyleSheet();
522
- sheet.replaceSync(cssText);
523
- componentConfig.componentStyleSheets.set(cssUrl, sheet);
524
- return sheet;
525
- } catch (e) {
526
- console.error(`LightviewX: Failed to create stylesheet for ${cssUrl}:`, e);
527
- return null;
528
- }
529
- };
530
- const shouldUseShadow = (useShadowProp) => {
531
- if (useShadowProp !== void 0) {
532
- return useShadowProp;
533
- }
534
- return componentConfig.shadowDefault;
535
- };
536
- const getAdoptedStyleSheets = (componentCssUrl, requestedSheets = []) => {
537
- const result = [];
538
- if (componentConfig.daisyStyleSheet) {
539
- result.push(componentConfig.daisyStyleSheet);
540
- } else {
541
- result.push(DAISYUI_CDN);
542
- }
543
- if (componentConfig.themeStyleSheet) {
544
- result.push(componentConfig.themeStyleSheet);
545
- }
546
- if (componentCssUrl) {
547
- const componentSheet = componentConfig.componentStyleSheets.get(componentCssUrl);
548
- if (componentSheet) {
549
- result.push(componentSheet);
550
- }
551
- }
552
- if (Array.isArray(requestedSheets)) {
553
- requestedSheets.forEach((url) => {
554
- const sheet = componentConfig.customStyleSheets.get(url);
555
- if (sheet) {
556
- result.push(sheet);
557
- } else {
558
- registerStyleSheet(url);
559
- result.push(url);
560
- }
561
- });
562
- }
563
- return result;
564
- };
565
- const preloadComponentCSS = async (cssUrl) => {
566
- if (!componentConfig.componentStyleSheets.has(cssUrl)) {
567
- await getComponentStyleSheet(cssUrl);
568
- }
569
- };
570
- const compileTemplate = (code) => {
571
- try {
572
- const isSingle = code.trim().startsWith("${") && code.trim().endsWith("}") && !code.trim().includes("${", 2);
573
- const body = isSingle ? "return " + code.trim().slice(2, -1) : "return `" + code.replace(/\\/g, "\\\\").replace(/`/g, "\\`") + "`";
574
- return new Function("state", "signal", body);
575
- } catch (e) {
576
- return () => "";
577
- }
578
- };
579
- const processTemplateChild = (child, LV) => {
580
- if (typeof child === "string" && child.includes("${")) {
581
- const fn = compileTemplate(child);
582
- return () => fn(LV.state, LV.signal);
583
- }
584
- return child;
585
- };
586
- const transformTextNode = (node, isRaw, LV) => {
587
- const text = node.textContent;
588
- if (isRaw) return text;
589
- if (!text.trim() && !text.includes("${")) return null;
590
- if (text.includes("${")) {
591
- const fn = compileTemplate(text);
592
- return () => fn(LV.state, LV.signal);
593
- }
594
- return text;
595
- };
596
- const transformElementNode = (node, element, domToElements2) => {
597
- const tagName = node.tagName.toLowerCase();
598
- const attributes = {};
599
- const skip = tagName === "script" || tagName === "style";
600
- const LV = typeof window !== "undefined" ? globalThis.Lightview : typeof globalThis !== "undefined" ? globalThis.Lightview : null;
601
- for (let attr of node.attributes) {
602
- const val = attr.value;
603
- attributes[attr.name] = !skip && val.includes("${") ? (() => {
604
- const fn = compileTemplate(val);
605
- return () => fn(LV.state, LV.signal);
606
- })() : val;
607
- }
608
- return element(tagName, attributes, domToElements2(Array.from(node.childNodes), element, tagName));
609
- };
610
- const domToElements = (domNodes, element, parentTagName = null) => {
611
- const isRaw = parentTagName === "script" || parentTagName === "style";
612
- const LV = globalThis.Lightview;
613
- return domNodes.map((node) => {
614
- if (node.nodeType === Node.TEXT_NODE) return transformTextNode(node, isRaw, LV);
615
- if (node.nodeType === Node.ELEMENT_NODE) return transformElementNode(node, element, domToElements);
616
- return null;
617
- }).filter((n) => n !== null);
618
- };
619
- const insertedContentMap = /* @__PURE__ */ new WeakMap();
620
- const hashContent = (str) => {
621
- let hash = 0;
622
- for (let i = 0; i < str.length; i++) {
623
- const char = str.charCodeAt(i);
624
- hash = (hash << 5) - hash + char;
625
- hash = hash & hash;
626
- }
627
- return hash.toString(36);
628
- };
629
- const createMarker = (id, isEnd = false) => {
630
- return document.createComment(`lv-src-${isEnd ? "end" : "start"}:${id}`);
631
- };
632
- const executeScripts = (container) => {
633
- if (!container) return;
634
- const scripts = container.querySelectorAll("script");
635
- scripts.forEach((oldScript) => {
636
- const newScript = document.createElement("script");
637
- Array.from(oldScript.attributes).forEach((attr) => {
638
- newScript.setAttribute(attr.name, attr.value);
639
- });
640
- if (oldScript.src) {
641
- newScript.src = oldScript.src;
642
- } else {
643
- newScript.textContent = oldScript.textContent;
644
- }
645
- oldScript.parentNode.replaceChild(newScript, oldScript);
646
- });
647
- };
648
- const removeInsertedContent = (parentEl, markerId) => {
649
- const startMarker = `lv-src-start:${markerId}`;
650
- const endMarker = `lv-src-end:${markerId}`;
651
- let inRange = false;
652
- const nodesToRemove = [];
653
- const walker = document.createTreeWalker(
654
- parentEl.parentElement || parentEl,
655
- NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT,
656
- null,
657
- false
658
- );
659
- while (walker.nextNode()) {
660
- const node = walker.currentNode;
661
- if (node.nodeType === Node.COMMENT_NODE) {
662
- if (node.textContent === startMarker) {
663
- inRange = true;
664
- nodesToRemove.push(node);
665
- continue;
666
- }
667
- if (node.textContent === endMarker) {
668
- nodesToRemove.push(node);
669
- break;
670
- }
671
- }
672
- if (inRange) {
673
- nodesToRemove.push(node);
674
- }
675
- }
676
- nodesToRemove.forEach((node) => node.remove());
677
- return nodesToRemove.length > 0;
678
- };
679
- const insert = (elements, parent, location, markerId, { element, setupChildren }) => {
680
- const isSibling = location === "beforebegin" || location === "afterend";
681
- const isOuter = location === "outerhtml";
682
- const target = isSibling || isOuter ? parent.parentElement : parent;
683
- if (!target) return console.warn(`LightviewX: No parent for ${location}`);
684
- const frag = document.createDocumentFragment();
685
- frag.appendChild(createMarker(markerId, false));
686
- elements.forEach((c) => {
687
- var _a2, _b2, _c;
688
- if (typeof c === "string") frag.appendChild(document.createTextNode(c));
689
- else if (c.domEl) frag.appendChild(c.domEl);
690
- else if (c instanceof Node) frag.appendChild(c);
691
- else {
692
- const v = ((_c = (_a2 = globalThis.Lightview) == null ? void 0 : (_b2 = _a2.hooks).processChild) == null ? void 0 : _c.call(_b2, c)) || c;
693
- if (v.tag) {
694
- const n = element(v.tag, v.attributes || {}, v.children || []);
695
- if (n == null ? void 0 : n.domEl) frag.appendChild(n.domEl);
696
- }
697
- }
698
- });
699
- frag.appendChild(createMarker(markerId, true));
700
- if (isOuter) target.replaceChild(frag, parent);
701
- else if (location === "beforebegin") target.insertBefore(frag, parent);
702
- else if (location === "afterend") target.insertBefore(frag, parent.nextSibling);
703
- else if (location === "afterbegin") parent.insertBefore(frag, parent.firstChild);
704
- else if (location === "beforeend") parent.appendChild(frag);
705
- executeScripts(target);
706
- };
707
- const isPath = (s) => typeof s === "string" && !isDangerousProtocol(s) && /^(https?:|\.|\/|[\w])|(\.(html|json|[vo]dom|cdomc?))$/i.test(s);
708
- const fetchContent = async (src) => {
709
- var _a2;
710
- try {
711
- const LV = globalThis.Lightview;
712
- if (((_a2 = LV == null ? void 0 : LV.hooks) == null ? void 0 : _a2.validateUrl) && !LV.hooks.validateUrl(src)) {
713
- console.warn(`[LightviewX] Fetch blocked by validateUrl hook: ${src}`);
714
- return null;
715
- }
716
- const url = new URL(src, document.baseURI);
717
- const res = await fetch(url);
718
- if (!res.ok) return null;
719
- const ext = url.pathname.split(".").pop().toLowerCase();
720
- const isJson = ext === "vdom" || ext === "odom" || ext === "cdom";
721
- const isHtml = ext === "html";
722
- const isCdom = ext === "cdom" || ext === "cdomc";
723
- const content = isJson ? await res.json() : await res.text();
724
- return {
725
- content,
726
- isJson,
727
- isHtml,
728
- isCdom,
729
- ext,
730
- raw: isJson ? JSON.stringify(content) : content
731
- };
732
- } catch (e) {
733
- return null;
734
- }
735
- };
736
- const parseElements = (content, isJson, isHtml, el, element, isCdom = false, ext = "") => {
737
- if (isJson) return Array.isArray(content) ? content : [content];
738
- if (isCdom && ext === "cdomc") {
739
- const CDOM = globalThis.LightviewCDOM;
740
- const parser = CDOM == null ? void 0 : CDOM.parseCDOMC;
741
- if (parser) {
742
- try {
743
- const obj = parser(content);
744
- const hydrated = CDOM.hydrate ? CDOM.hydrate(obj) : obj;
745
- return Array.isArray(hydrated) ? hydrated : [hydrated];
746
- } catch (e) {
747
- console.warn("LightviewX: Failed to parse .cdomc:", e);
748
- return [];
749
- }
750
- } else {
751
- console.warn("LightviewX: CDOMC parser not found. Ensure lightview-cdom.js is loaded.");
752
- return [];
753
- }
754
- }
755
- if (isHtml) {
756
- if (el.domEl.getAttribute("escape") === "true") return [content];
757
- const doc = new DOMParser().parseFromString(content.replace(/<head[^>]*>[\s\S]*?<\/head>/i, ""), "text/html");
758
- return domToElements([...Array.from(doc.head.childNodes), ...Array.from(doc.body.childNodes)], element);
759
- }
760
- return [content];
761
- };
762
- const elementsFromSelector = (selector, element) => {
763
- try {
764
- const sel = document.querySelectorAll(selector);
765
- if (!sel.length) return null;
766
- return {
767
- elements: domToElements(Array.from(sel), element),
768
- raw: Array.from(sel).map((n) => n.outerHTML || n.textContent).join("")
769
- };
770
- } catch (e) {
771
- return null;
772
- }
773
- };
774
- const updateTargetContent = (el, elements, raw, loc, contentHash, options, targetHash = null) => {
775
- var _a2;
776
- const { element, setupChildren, saveScrolls, restoreScrolls } = { ...options, ...(_a2 = globalThis.Lightview) == null ? void 0 : _a2.internals };
777
- const markerId = `${loc}-${contentHash.slice(0, 8)}`;
778
- let track = getOrSet(insertedContentMap, el.domEl, () => ({}));
779
- if (track[loc]) removeInsertedContent(el.domEl, `${loc}-${track[loc].slice(0, 8)}`);
780
- track[loc] = contentHash;
781
- const scrollMap = saveScrolls ? saveScrolls() : null;
782
- const performScroll = (root) => {
783
- if (!targetHash) return;
784
- requestAnimationFrame(() => {
785
- requestAnimationFrame(() => {
786
- const id = targetHash.startsWith("#") ? targetHash.slice(1) : targetHash;
787
- const target = root.getElementById ? root.getElementById(id) : root.querySelector(`#${id}`);
788
- if (target) {
789
- target.style.scrollMarginTop = "calc(var(--site-nav-height, 0px) + 2rem)";
790
- target.scrollIntoView({ behavior: "smooth", block: "start", inline: "start" });
791
- }
792
- });
793
- });
794
- };
795
- const runRestore = (root) => {
796
- if (restoreScrolls && scrollMap) restoreScrolls(scrollMap, root);
797
- };
798
- if (loc === "shadow") {
799
- if (!el.domEl.shadowRoot) el.domEl.attachShadow({ mode: "open" });
800
- setupChildren(elements, el.domEl.shadowRoot);
801
- executeScripts(el.domEl.shadowRoot);
802
- performScroll(el.domEl.shadowRoot);
803
- runRestore(el.domEl.shadowRoot);
804
- } else if (loc === "innerhtml") {
805
- el.children = elements;
806
- executeScripts(el.domEl);
807
- performScroll(document);
808
- runRestore(el.domEl);
809
- } else {
810
- insert(elements, el.domEl, loc, markerId, { element, setupChildren });
811
- performScroll(document);
812
- runRestore(el.domEl);
813
- }
814
- };
815
- const handleSrcAttribute = async (el, src, tagName, { element, setupChildren }) => {
816
- if (STANDARD_SRC_TAGS.includes(tagName)) return;
817
- let elements = [], raw = "", targetHash = null;
818
- if (isPath(src)) {
819
- if (src.includes("#")) {
820
- [src, targetHash] = src.split("#");
821
- }
822
- const result = await fetchContent(src);
823
- if (result) {
824
- elements = parseElements(result.content, result.isJson, result.isHtml, el, element, result.isCdom, result.ext);
825
- raw = result.raw;
826
- }
827
- }
828
- if (!elements.length) {
829
- const result = elementsFromSelector(src, element);
830
- if (result) {
831
- elements = result.elements;
832
- raw = result.raw;
833
- }
834
- }
835
- if (!elements.length) return;
836
- const loc = (el.domEl.getAttribute("location") || "innerhtml").toLowerCase();
837
- const contentHash = hashContent(raw);
838
- const track = getOrSet(insertedContentMap, el.domEl, () => ({}));
839
- if (track[loc] === contentHash) {
840
- if (targetHash) {
841
- const root = loc === "shadow" ? el.domEl.shadowRoot : document;
842
- if (root) {
843
- requestAnimationFrame(() => {
844
- requestAnimationFrame(() => {
845
- var _a2;
846
- const id = targetHash.startsWith("#") ? targetHash.slice(1) : targetHash;
847
- const target = root.getElementById ? root.getElementById(id) : (_a2 = root.querySelector) == null ? void 0 : _a2.call(root, `#${id}`);
848
- if (target) {
849
- target.style.scrollMarginTop = "calc(var(--site-nav-height, 0px) + 2rem)";
850
- target.scrollIntoView({ behavior: "smooth", block: "start", inline: "start" });
851
- }
852
- });
853
- });
854
- }
855
- }
856
- return;
857
- }
858
- updateTargetContent(el, elements, raw, loc, contentHash, { element, setupChildren }, targetHash);
859
- };
860
- const VALID_LOCATIONS = ["beforebegin", "afterbegin", "beforeend", "afterend", "innerhtml", "outerhtml", "shadow"];
861
- const parseTargetWithLocation = (targetStr) => {
862
- for (const loc of VALID_LOCATIONS) {
863
- const suffix = ":" + loc;
864
- if (targetStr.toLowerCase().endsWith(suffix)) {
865
- return {
866
- selector: targetStr.slice(0, -suffix.length),
867
- location: loc
868
- };
869
- }
870
- }
871
- return { selector: targetStr, location: null };
872
- };
873
- const handleNonStandardHref = (e, { domToElement, wrapDomElement }) => {
874
- var _a2;
875
- const clickedEl = e.target.closest("[href]");
876
- if (!clickedEl) return;
877
- const tagName = clickedEl.tagName.toLowerCase();
878
- if (STANDARD_HREF_TAGS.includes(tagName)) return;
879
- e.preventDefault();
880
- const href = clickedEl.getAttribute("href");
881
- const LV = globalThis.Lightview;
882
- if (href && (isDangerousProtocol(href) || ((_a2 = LV == null ? void 0 : LV.hooks) == null ? void 0 : _a2.validateUrl) && !LV.hooks.validateUrl(href))) {
883
- console.warn(`[LightviewX] Navigation or fetch blocked by security policy: ${href}`);
884
- return;
885
- }
886
- const targetAttr = clickedEl.getAttribute("target");
887
- if (!targetAttr) {
888
- let el = domToElement.get(clickedEl);
889
- if (!el) {
890
- const attrs = {};
891
- for (let attr of clickedEl.attributes) attrs[attr.name] = attr.value;
892
- el = wrapDomElement(clickedEl, tagName, attrs);
893
- }
894
- const newAttrs = { ...el.attributes, src: href };
895
- el.attributes = newAttrs;
896
- return;
897
- }
898
- if (targetAttr.startsWith("_")) {
899
- switch (targetAttr) {
900
- case "_self":
901
- globalThis.location.href = href;
902
- break;
903
- case "_parent":
904
- globalThis.parent.location.href = href;
905
- break;
906
- case "_top":
907
- globalThis.top.location.href = href;
908
- break;
909
- case "_blank":
910
- default:
911
- globalThis.open(href, targetAttr);
912
- break;
913
- }
914
- return;
915
- }
916
- const { selector, location } = parseTargetWithLocation(targetAttr);
917
- try {
918
- const targetElements = document.querySelectorAll(selector);
919
- targetElements.forEach((targetEl) => {
920
- let el = domToElement.get(targetEl);
921
- if (!el) {
922
- const attrs = {};
923
- for (let attr of targetEl.attributes) attrs[attr.name] = attr.value;
924
- el = wrapDomElement(targetEl, targetEl.tagName.toLowerCase(), attrs);
925
- }
926
- const newAttrs = { ...el.attributes, src: href };
927
- if (location) {
928
- newAttrs.location = location;
929
- }
930
- el.attributes = newAttrs;
931
- });
932
- } catch (err) {
933
- console.warn("Invalid target selector:", selector, err);
934
- }
935
- };
936
- const gateStates = /* @__PURE__ */ new WeakMap();
937
- const BYPASS_FLAG = "__lv_passed";
938
- const RESUME_FLAG = "__lv_resume";
939
- const SENSIBLE_EVENTS = [
940
- "click",
941
- "dblclick",
942
- "mousedown",
943
- "mouseup",
944
- "contextmenu",
945
- "submit",
946
- "reset",
947
- "change",
948
- "input",
949
- "invalid",
950
- "keydown",
951
- "keyup",
952
- "keypress",
953
- "touchstart",
954
- "touchend"
955
- ];
956
- const CAPTURE_EVENTS = ["focus", "blur"];
957
- const getGateState = (el, key) => {
958
- let elState = gateStates.get(el);
959
- if (!elState) {
960
- elState = /* @__PURE__ */ new Map();
961
- gateStates.set(el, elState);
962
- }
963
- let state2 = elState.get(key);
964
- if (!state2) {
965
- state2 = {};
966
- elState.set(key, state2);
967
- }
968
- return state2;
969
- };
970
- const gateThrottle = function(ms) {
971
- const event = arguments[arguments.length - 1];
972
- if (event == null ? void 0 : event[RESUME_FLAG]) return true;
973
- const key = `throttle-${(event == null ? void 0 : event.type) || "all"}-${ms}`;
974
- const state2 = getGateState(this, key);
975
- const now = Date.now();
976
- if (now - (state2.last || 0) >= ms) {
977
- state2.last = now;
978
- return true;
979
- }
980
- return false;
981
- };
982
- const gateDebounce = function(ms) {
983
- const event = arguments[arguments.length - 1];
984
- const key = `debounce-${(event == null ? void 0 : event.type) || "all"}-${ms}`;
985
- const state2 = getGateState(this, key);
986
- if (state2.timer) clearTimeout(state2.timer);
987
- if ((event == null ? void 0 : event[RESUME_FLAG]) && state2.passed) {
988
- state2.passed = false;
989
- return true;
990
- }
991
- state2.timer = setTimeout(() => {
992
- state2.passed = true;
993
- const newEvent = new event.constructor(event.type, event);
994
- newEvent[RESUME_FLAG] = true;
995
- this.dispatchEvent(newEvent);
996
- }, ms);
997
- return false;
998
- };
999
- const parseBeforeAttribute = (attrValue) => {
1000
- const tokens = [];
1001
- let current = "", depth = 0, inQuote = null;
1002
- for (let i2 = 0; i2 < attrValue.length; i2++) {
1003
- const char = attrValue[i2];
1004
- if (inQuote) {
1005
- current += char;
1006
- if (char === inQuote && attrValue[i2 - 1] !== "\\") inQuote = null;
1007
- } else if (char === "'" || char === '"') {
1008
- inQuote = char;
1009
- current += char;
1010
- } else if (char === "(") {
1011
- depth++;
1012
- current += char;
1013
- } else if (char === ")") {
1014
- depth--;
1015
- current += char;
1016
- } else if (/\s/.test(char) && depth === 0) {
1017
- if (current) tokens.push(current);
1018
- current = "";
1019
- } else {
1020
- current += char;
1021
- }
1022
- }
1023
- if (current) tokens.push(current);
1024
- const events = [];
1025
- const exclusions = [];
1026
- const calls = [];
1027
- let i = 0;
1028
- while (i < tokens.length) {
1029
- const token = tokens[i];
1030
- if (!token || token.includes("(")) break;
1031
- if (token.startsWith("!")) exclusions.push(token.slice(1));
1032
- else events.push(token);
1033
- i++;
1034
- }
1035
- while (i < tokens.length) {
1036
- if (tokens[i]) calls.push(tokens[i]);
1037
- i++;
1038
- }
1039
- return { events, exclusions, calls };
1040
- };
1041
- const globalBeforeInterceptor = async (e) => {
1042
- var _a2, _b2;
1043
- if (e[BYPASS_FLAG]) return;
1044
- const target = (_b2 = (_a2 = e.target).closest) == null ? void 0 : _b2.call(_a2, "[lv-before]");
1045
- if (!target) return;
1046
- const { events, exclusions, calls } = parseBeforeAttribute(target.getAttribute("lv-before"));
1047
- const isExcluded = exclusions.includes(e.type);
1048
- const isIncluded = events.includes("*") || events.includes(e.type);
1049
- if (isExcluded || !isIncluded) return;
1050
- e.stopImmediatePropagation();
1051
- e.preventDefault();
1052
- for (const callStr of calls) {
1053
- try {
1054
- const match = callStr.match(/^([\w\.]+)\((.*)\)$/);
1055
- if (!match) continue;
1056
- const funcName = match[1];
1057
- const argsStr = match[2];
1058
- const LV = globalThis.Lightview;
1059
- const LVX = globalThis.LightviewX;
1060
- let fn = funcName.split(".").reduce((obj, key) => obj == null ? void 0 : obj[key], globalThis);
1061
- if (!fn && funcName === "throttle") fn = gateThrottle;
1062
- if (!fn && funcName === "debounce") fn = gateDebounce;
1063
- if (!fn && LVX && LVX[funcName]) fn = LVX[funcName];
1064
- if (typeof fn !== "function") {
1065
- console.warn(`LightviewX: lv-before function '${funcName}' not found`);
1066
- continue;
1067
- }
1068
- const evalArgs = new Function("event", "state", "signal", `return [${argsStr}]`);
1069
- const args = evalArgs.call(target, e, (LV == null ? void 0 : LV.state) || {}, (LV == null ? void 0 : LV.signal) || {});
1070
- args.push(e);
1071
- let result = fn.apply(target, args);
1072
- if (result instanceof Promise) result = await result;
1073
- if (result === false || result === null || result === void 0) return;
1074
- } catch (err) {
1075
- console.error(`LightviewX: Error executing lv-before gate '${callStr}':`, err);
1076
- return;
1077
- }
1078
- }
1079
- const finalEvent = new e.constructor(e.type, e);
1080
- finalEvent[BYPASS_FLAG] = true;
1081
- target.dispatchEvent(finalEvent);
1082
- };
1083
- const processSrcOnNode = (node, LV) => {
1084
- if (node.nodeType !== Node.ELEMENT_NODE) return;
1085
- const tagName = node.tagName.toLowerCase();
1086
- if (isStandardSrcTag(tagName)) return;
1087
- const src = node.getAttribute("src");
1088
- if (!src) return;
1089
- let el = LV.internals.domToElement.get(node);
1090
- if (!el) {
1091
- const attrs = {};
1092
- for (let attr of node.attributes) attrs[attr.name] = attr.value;
1093
- el = LV.internals.wrapDomElement(node, tagName, attrs, []);
1094
- }
1095
- handleSrcAttribute(el, src, tagName, {
1096
- element: LV.element,
1097
- setupChildren: LV.internals.setupChildren
1098
- });
1099
- };
1100
- const processedNodes = /* @__PURE__ */ new WeakSet();
1101
- const activateReactiveSyntax = (root, LV) => {
1102
- if (!root || !LV) return;
1103
- const bindEffect = (node, codeStr, isAttr = false, attrName = null) => {
1104
- if (processedNodes.has(node) && !isAttr) return;
1105
- if (!isAttr) processedNodes.add(node);
1106
- const fn = compileTemplate(codeStr);
1107
- LV.effect(() => {
1108
- try {
1109
- const val = fn(LV.state, LV.signal);
1110
- if (isAttr) {
1111
- if (attrName.startsWith("cdom-")) {
1112
- node[attrName] = val;
1113
- } else {
1114
- val === null || val === void 0 || val === false ? node.removeAttribute(attrName) : node.setAttribute(attrName, val);
1115
- }
1116
- } else node.textContent = val !== void 0 ? val : "";
1117
- } catch (e) {
1118
- }
1119
- });
1120
- };
1121
- const textXPath = ".//text()[contains(., '${')]";
1122
- const textResult = document.evaluate(
1123
- textXPath,
1124
- root,
1125
- null,
1126
- XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
1127
- null
1128
- );
1129
- for (let i = 0; i < textResult.snapshotLength; i++) {
1130
- const node = textResult.snapshotItem(i);
1131
- if (node.parentElement && node.parentElement.closest("SCRIPT, STYLE, CODE, PRE, TEMPLATE, NOSCRIPT")) continue;
1132
- bindEffect(node, node.textContent);
1133
- }
1134
- const attrXPath = ".//*[@*[contains(., '${')]]";
1135
- const attrResult = document.evaluate(
1136
- attrXPath,
1137
- root,
1138
- null,
1139
- XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
1140
- null
1141
- );
1142
- for (let i = 0; i < attrResult.snapshotLength; i++) {
1143
- const element = attrResult.snapshotItem(i);
1144
- if (["SCRIPT", "STYLE", "CODE", "PRE", "TEMPLATE", "NOSCRIPT"].includes(element.tagName)) continue;
1145
- Array.from(element.attributes).forEach((attr) => {
1146
- if (attr.value.includes("${")) {
1147
- bindEffect(element, attr.value, true, attr.name);
1148
- }
1149
- });
1150
- }
1151
- if (root.nodeType === Node.ELEMENT_NODE && !["SCRIPT", "STYLE", "CODE", "PRE", "TEMPLATE", "NOSCRIPT"].includes(root.tagName)) {
1152
- Array.from(root.attributes).forEach((attr) => {
1153
- if (attr.value.includes("${")) {
1154
- bindEffect(root, attr.value, true, attr.name);
1155
- }
1156
- });
1157
- }
1158
- };
1159
- const processAddedNode = (node, nodesToProcess, nodesToActivate) => {
1160
- if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE) {
1161
- nodesToActivate.push(node);
1162
- }
1163
- if (node.nodeType !== Node.ELEMENT_NODE) return;
1164
- nodesToProcess.push(node);
1165
- const selector = "[src]:not(" + STANDARD_SRC_TAGS.join("):not(") + ")";
1166
- const descendants = node.querySelectorAll(selector);
1167
- for (const desc of descendants) {
1168
- if (!desc.tagName.toLowerCase().startsWith("lv-")) {
1169
- nodesToProcess.push(desc);
1170
- }
1171
- }
1172
- };
1173
- const collectNodesFromMutations = (mutations) => {
1174
- const nodesToProcess = [];
1175
- const nodesToActivate = [];
1176
- for (const mutation of mutations) {
1177
- if (mutation.type === "childList") {
1178
- mutation.addedNodes.forEach((node) => processAddedNode(node, nodesToProcess, nodesToActivate));
1179
- } else if (mutation.type === "attributes" && mutation.attributeName === "src") {
1180
- nodesToProcess.push(mutation.target);
1181
- }
1182
- }
1183
- return { nodesToProcess, nodesToActivate };
1184
- };
1185
- const setupSrcObserver = (LV) => {
1186
- const observer = new MutationObserver((mutations) => {
1187
- const { nodesToProcess, nodesToActivate } = collectNodesFromMutations(mutations);
1188
- if (nodesToProcess.length > 0 || nodesToActivate.length > 0) {
1189
- requestAnimationFrame(() => {
1190
- nodesToActivate.forEach((node) => activateReactiveSyntax(node, LV));
1191
- nodesToProcess.forEach((node) => processSrcOnNode(node, LV));
1192
- });
1193
- }
1194
- });
1195
- observer.observe(document.body, {
1196
- childList: true,
1197
- subtree: true,
1198
- attributes: true,
1199
- attributeFilter: ["src"]
1200
- });
1201
- return observer;
1202
- };
1203
- if (typeof window !== "undefined" && globalThis.Lightview) {
1204
- const LV = globalThis.Lightview;
1205
- if (document.readyState === "loading") {
1206
- document.addEventListener("DOMContentLoaded", () => setupSrcObserver(LV));
1207
- } else {
1208
- setupSrcObserver(LV);
1209
- }
1210
- const initialScan = () => {
1211
- requestAnimationFrame(() => {
1212
- activateReactiveSyntax(document.body, LV);
1213
- const selector = "[src]:not(" + STANDARD_SRC_TAGS.join("):not(") + ")";
1214
- const nodes = document.querySelectorAll(selector);
1215
- nodes.forEach((node) => {
1216
- if (node.tagName.toLowerCase().startsWith("lv-")) return;
1217
- processSrcOnNode(node, LV);
1218
- });
1219
- });
1220
- };
1221
- if (document.body) {
1222
- initialScan();
1223
- } else {
1224
- document.addEventListener("DOMContentLoaded", initialScan);
1225
- }
1226
- LV.hooks.onNonStandardHref = (e) => {
1227
- handleNonStandardHref(e, {
1228
- domToElement: LV.internals.domToElement,
1229
- wrapDomElement: LV.internals.wrapDomElement
1230
- });
1231
- };
1232
- SENSIBLE_EVENTS.forEach((ev) => window.addEventListener(ev, globalBeforeInterceptor, true));
1233
- CAPTURE_EVENTS.forEach((ev) => window.addEventListener(ev, globalBeforeInterceptor, true));
1234
- LV.hooks.processChild = (child) => {
1235
- if (!child) return child;
1236
- if (typeof child === "object" && !Array.isArray(child) && !child.tag && !child.domEl) {
1237
- child = convertObjectDOM(child);
1238
- }
1239
- if (typeof child === "string" && child.startsWith("$") && isNaN(parseInt(child[1]))) {
1240
- const CDOM = globalThis.LightviewCDOM;
1241
- if (CDOM) return CDOM.parseExpression(child);
1242
- }
1243
- if (typeof child === "string" && (child.trim().startsWith("{") || child.trim().startsWith("["))) {
1244
- try {
1245
- const parsed = new Function("return (" + child + ")")();
1246
- if (typeof parsed === "object" && parsed !== null) {
1247
- if (Array.isArray(parsed)) {
1248
- return parsed;
1249
- }
1250
- if (parsed.tag || parsed.domEl) {
1251
- return parsed;
1252
- }
1253
- return convertObjectDOM(parsed);
1254
- }
1255
- } catch (e) {
1256
- }
1257
- }
1258
- return processTemplateChild(child, {
1259
- state,
1260
- signal: LV.signal
1261
- });
1262
- };
1263
- }
1264
- const createCustomElement = (Component, options = {}) => {
1265
- return class extends HTMLElement {
1266
- constructor() {
1267
- super();
1268
- this.attachShadow({ mode: "open" });
1269
- }
1270
- async connectedCallback() {
1271
- const { cssUrl, styles } = options;
1272
- this.themeWrapper = document.createElement("div");
1273
- this.themeWrapper.style.display = "contents";
1274
- const syncTheme = () => {
1275
- const theme = document.documentElement.getAttribute("data-theme") || "light";
1276
- this.themeWrapper.setAttribute("data-theme", theme);
1277
- };
1278
- syncTheme();
1279
- this.themeObserver = new MutationObserver(syncTheme);
1280
- this.themeObserver.observe(document.documentElement, {
1281
- attributes: true,
1282
- attributeFilter: ["data-theme"]
1283
- });
1284
- this.shadowRoot.appendChild(this.themeWrapper);
1285
- const adoptedStyleSheets = getAdoptedStyleSheets(cssUrl, styles);
1286
- try {
1287
- const sheets = adoptedStyleSheets.filter((s) => s instanceof CSSStyleSheet);
1288
- this.shadowRoot.adoptedStyleSheets = sheets;
1289
- } catch (e) {
1290
- }
1291
- if (!componentConfig.daisyStyleSheet) {
1292
- const link = document.createElement("link");
1293
- link.rel = "stylesheet";
1294
- link.href = DAISYUI_CDN;
1295
- this.shadowRoot.appendChild(link);
1296
- }
1297
- adoptedStyleSheets.forEach((s) => {
1298
- if (typeof s === "string") {
1299
- const link = document.createElement("link");
1300
- link.rel = "stylesheet";
1301
- link.href = s;
1302
- this.shadowRoot.appendChild(link);
1303
- }
1304
- });
1305
- this.render = () => {
1306
- const props = {};
1307
- for (const attr of this.attributes) {
1308
- const name = attr.name.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
1309
- if (attr.value === "") {
1310
- props[name] = true;
1311
- } else {
1312
- props[name] = attr.value;
1313
- }
1314
- }
1315
- props.useShadow = false;
1316
- const slot = globalThis.Lightview.tags.slot();
1317
- const result = Component(props, slot);
1318
- globalThis.Lightview.internals.setupChildren([result], this.themeWrapper);
1319
- };
1320
- if (typeof MutationObserver !== "undefined" && typeof HTMLElement !== "undefined") {
1321
- this.attrObserver = new MutationObserver((mutations) => {
1322
- this.render();
1323
- });
1324
- this.attrObserver.observe(this, {
1325
- attributes: true
1326
- });
1327
- }
1328
- this.render();
1329
- }
1330
- disconnectedCallback() {
1331
- if (this.themeObserver) {
1332
- this.themeObserver.disconnect();
1333
- }
1334
- if (this.attrObserver) {
1335
- this.attrObserver.disconnect();
1336
- }
1337
- }
1338
- };
1339
- };
1340
- const customElementWrapper = (Component, config = {}) => {
1341
- const {
1342
- attributeMap = {},
1343
- childElements = {}
1344
- } = config;
1345
- return class extends HTMLElement {
1346
- constructor() {
1347
- super();
1348
- this.attachShadow({ mode: "open" });
1349
- }
1350
- connectedCallback() {
1351
- let adopted = false;
1352
- if (componentConfig.daisyStyleSheet) {
1353
- try {
1354
- const sheets = [componentConfig.daisyStyleSheet];
1355
- if (componentConfig.themeStyleSheet) {
1356
- sheets.push(componentConfig.themeStyleSheet);
1357
- }
1358
- this.shadowRoot.adoptedStyleSheets = sheets;
1359
- adopted = true;
1360
- } catch (e) {
1361
- }
1362
- }
1363
- if (!adopted) {
1364
- const link = document.createElement("link");
1365
- link.rel = "stylesheet";
1366
- link.href = DAISYUI_CDN;
1367
- this.shadowRoot.appendChild(link);
1368
- }
1369
- const themeWrapper = document.createElement("div");
1370
- themeWrapper.setAttribute("data-theme", document.documentElement.getAttribute("data-theme") || "light");
1371
- themeWrapper.style.display = "contents";
1372
- this.shadowRoot.appendChild(themeWrapper);
1373
- this.themeWrapper = themeWrapper;
1374
- this.themeObserver = new MutationObserver(() => {
1375
- const theme = document.documentElement.getAttribute("data-theme") || "light";
1376
- this.themeWrapper.setAttribute("data-theme", theme);
1377
- });
1378
- this.themeObserver.observe(document.documentElement, {
1379
- attributes: true,
1380
- attributeFilter: ["data-theme"]
1381
- });
1382
- this.render();
1383
- const attrs = Object.keys(attributeMap);
1384
- if (attrs.length > 0) {
1385
- this.attrObserver = new MutationObserver(() => this.render());
1386
- this.attrObserver.observe(this, {
1387
- attributes: true,
1388
- attributeFilter: attrs
1389
- });
1390
- }
1391
- if (Object.keys(childElements).length > 0) {
1392
- this.childObserver = new MutationObserver(() => this.render());
1393
- this.childObserver.observe(this, {
1394
- childList: true,
1395
- subtree: true,
1396
- attributes: true
1397
- });
1398
- }
1399
- }
1400
- disconnectedCallback() {
1401
- if (this.themeObserver) this.themeObserver.disconnect();
1402
- if (this.attrObserver) this.attrObserver.disconnect();
1403
- if (this.childObserver) this.childObserver.disconnect();
1404
- }
1405
- parseChildrenToVDOM() {
1406
- return Array.from(this.children).map((child) => {
1407
- const tagName = child.tagName.toLowerCase();
1408
- const componentInfo = childElements[tagName];
1409
- if (!componentInfo) return null;
1410
- const { component, attributeMap: attributeMap2 = {} } = componentInfo;
1411
- const attributes = {};
1412
- for (const attr of child.attributes) {
1413
- const name = attr.name.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
1414
- const type = attributeMap2[name];
1415
- const value = attr.value;
1416
- if (type === Boolean) {
1417
- attributes[name] = value === "true" || value === "";
1418
- } else if (type === Number) {
1419
- attributes[name] = Number(value);
1420
- } else if (type === Array || type === Object) {
1421
- try {
1422
- attributes[name] = JSON.parse(value);
1423
- } catch (e) {
1424
- console.warn(`[Lightview] Failed to parse child attribute ${name} as JSON:`, value);
1425
- attributes[name] = value;
1426
- }
1427
- } else {
1428
- attributes[name] = value;
1429
- }
1430
- }
1431
- if (child.onclick) attributes.onclick = child.onclick.bind(child);
1432
- return {
1433
- tag: component,
1434
- attributes,
1435
- children: Array.from(child.childNodes)
1436
- };
1437
- }).filter(Boolean);
1438
- }
1439
- render() {
1440
- var _a2, _b2;
1441
- const props = { useShadow: false };
1442
- for (const attr of this.attributes) {
1443
- const name = attr.name.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
1444
- const type = attributeMap[name];
1445
- const value = attr.value;
1446
- if (type === Boolean) {
1447
- props[name] = value === "true" || value === "";
1448
- } else if (type === Number) {
1449
- props[name] = Number(value);
1450
- } else if (type === Array || type === Object) {
1451
- try {
1452
- props[name] = JSON.parse(value);
1453
- } catch (e) {
1454
- console.warn(`[Lightview] Failed to parse ${name} as JSON:`, value);
1455
- props[name] = value;
1456
- }
1457
- } else {
1458
- props[name] = value;
1459
- }
1460
- }
1461
- const vdomChildren = this.parseChildrenToVDOM();
1462
- const children = Object.keys(childElements).length > 0 ? vdomChildren : [{ tag: globalThis.Lightview.tags.slot }];
1463
- const result = Component(props, ...children);
1464
- if (((_b2 = (_a2 = globalThis.Lightview) == null ? void 0 : _a2.internals) == null ? void 0 : _b2.setupChildren) && this.themeWrapper) {
1465
- this.themeWrapper.innerHTML = "";
1466
- globalThis.Lightview.internals.setupChildren([result], this.themeWrapper);
1467
- }
1468
- }
1469
- static get observedAttributes() {
1470
- return Object.keys(attributeMap);
1471
- }
1472
- attributeChangedCallback() {
1473
- this.render();
1474
- }
1475
- };
1476
- };
1477
- const validateJSONSchema = (value, schema) => {
1478
- var _a2;
1479
- if (!schema) return true;
1480
- const errors = [];
1481
- const internals2 = (_a2 = globalThis.Lightview) == null ? void 0 : _a2.internals;
1482
- const check = (val, sch, path = "") => {
1483
- var _a3;
1484
- if (!sch) return true;
1485
- if (typeof sch === "string") {
1486
- const registered = (_a3 = internals2 == null ? void 0 : internals2.schemas) == null ? void 0 : _a3.get(sch);
1487
- if (registered) return check(val, registered, path);
1488
- return true;
1489
- }
1490
- const type = sch.type;
1491
- const getType = (v) => {
1492
- if (v === null) return "null";
1493
- if (Array.isArray(v)) return "array";
1494
- return typeof v;
1495
- };
1496
- const currentType = getType(val);
1497
- if (type && type !== currentType) {
1498
- if (type === "integer" && Number.isInteger(val)) ;
1499
- else if (!(type === "number" && typeof val === "number")) {
1500
- errors.push({ path, message: `Expected type ${type}, got ${currentType}`, keyword: "type" });
1501
- return false;
1502
- }
1503
- }
1504
- if (currentType === "string") {
1505
- if (sch.minLength !== void 0 && val.length < sch.minLength) errors.push({ path, keyword: "minLength" });
1506
- if (sch.maxLength !== void 0 && val.length > sch.maxLength) errors.push({ path, keyword: "maxLength" });
1507
- if (sch.pattern !== void 0 && !new RegExp(sch.pattern).test(val)) errors.push({ path, keyword: "pattern" });
1508
- if (sch.format === "email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val)) errors.push({ path, keyword: "format" });
1509
- }
1510
- if (currentType === "number") {
1511
- if (sch.minimum !== void 0 && val < sch.minimum) errors.push({ path, keyword: "minimum" });
1512
- if (sch.maximum !== void 0 && val > sch.maximum) errors.push({ path, keyword: "maximum" });
1513
- if (sch.multipleOf !== void 0 && val % sch.multipleOf !== 0) errors.push({ path, keyword: "multipleOf" });
1514
- }
1515
- if (currentType === "object") {
1516
- if (sch.required && Array.isArray(sch.required)) {
1517
- for (const key of sch.required) {
1518
- if (!(key in val)) errors.push({ path: path ? `${path}.${key}` : key, keyword: "required" });
1519
- }
1520
- }
1521
- if (sch.properties) {
1522
- for (const key in sch.properties) {
1523
- if (key in val) check(val[key], sch.properties[key], path ? `${path}.${key}` : key);
1524
- }
1525
- }
1526
- if (sch.additionalProperties === false) {
1527
- for (const key in val) {
1528
- if (!sch.properties || !(key in sch.properties)) errors.push({ path: path ? `${path}.${key}` : key, keyword: "additionalProperties" });
1529
- }
1530
- }
1531
- }
1532
- if (currentType === "array") {
1533
- if (sch.minItems !== void 0 && val.length < sch.minItems) errors.push({ path, keyword: "minItems" });
1534
- if (sch.maxItems !== void 0 && val.length > sch.maxItems) errors.push({ path, keyword: "maxItems" });
1535
- if (sch.uniqueItems && new Set(val).size !== val.length) errors.push({ path, keyword: "uniqueItems" });
1536
- if (sch.items) {
1537
- val.forEach((item, i) => check(item, sch.items, `${path}[${i}]`));
1538
- }
1539
- }
1540
- if (sch.const !== void 0 && val !== sch.const) errors.push({ path, keyword: "const" });
1541
- if (sch.enum && !sch.enum.includes(val)) errors.push({ path, keyword: "enum" });
1542
- return errors.length === 0;
1543
- };
1544
- const valid = check(value, schema);
1545
- return valid || errors;
1546
- };
1547
- const lvInternals = globalThis.__LIGHTVIEW_INTERNALS__ || ((_a = globalThis.Lightview) == null ? void 0 : _a.internals);
1548
- if (lvInternals) {
1549
- const hooks2 = lvInternals.hooks || ((_b = globalThis.Lightview) == null ? void 0 : _b.hooks);
1550
- if (hooks2) {
1551
- hooks2.validate = (value, schema) => {
1552
- const result = validateJSONSchema(value, schema);
1553
- if (result === true) return true;
1554
- const msg = result.map((e) => `${e.path || "root"}: failed ${e.keyword}${e.message ? " (" + e.message + ")" : ""}`).join(", ");
1555
- throw new Error(`Lightview Validation Error: ${msg}`);
1556
- };
1557
- }
1558
- if (globalThis.Lightview) globalThis.Lightview.validate = validateJSONSchema;
1559
- }
1560
- const LightviewX = {
1561
- state,
1562
- themeSignal,
1563
- setTheme,
1564
- registerStyleSheet,
1565
- registerThemeSheet,
1566
- // Gate modifiers
1567
- throttle: gateThrottle,
1568
- debounce: gateDebounce,
1569
- // Component initialization
1570
- initComponents,
1571
- componentConfig,
1572
- shouldUseShadow,
1573
- getAdoptedStyleSheets,
1574
- preloadComponentCSS,
1575
- createCustomElement,
1576
- customElementWrapper,
1577
- validate: validateJSONSchema,
1578
- internals: {
1579
- handleSrcAttribute,
1580
- parseElements
1581
- }
1582
- };
1583
- if (typeof module !== "undefined" && module.exports) {
1584
- module.exports = LightviewX;
1585
- }
1586
- if (typeof window !== "undefined") {
1587
- globalThis.LightviewX = LightviewX;
1588
- }
1589
- if (typeof window !== "undefined") {
1590
- try {
1591
- const savedTheme = getSavedTheme();
1592
- if (savedTheme) {
1593
- setTheme(savedTheme);
1594
- }
1595
- } catch (e) {
1596
- }
1597
- if (typeof window !== "undefined" && globalThis.Lightview) {
1598
- if (!globalThis.Lightview.hooks.validateUrl) {
1599
- globalThis.Lightview.hooks.validateUrl = validateUrl;
1600
- }
1601
- }
1602
- }
1603
- if (typeof globalThis !== "undefined" && globalThis.Lightview) {
1604
- if (!globalThis.Lightview.hooks.validateUrl) {
1605
- globalThis.Lightview.hooks.validateUrl = validateUrl;
1606
- }
1607
- }
1608
- })();