lightview 2.1.0 → 2.2.2
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/build-bundles.mjs +2 -6
- package/build.js +236 -46
- package/components/data-display/avatar.js +25 -1
- package/components/data-display/chart.js +22 -5
- package/components/data-display/countdown.js +3 -2
- package/components/data-input/checkbox.js +23 -1
- package/components/data-input/input.js +24 -1
- package/components/data-input/radio.js +37 -2
- package/components/data-input/select.js +24 -1
- package/components/data-input/toggle.js +21 -1
- package/components/navigation/breadcrumbs.js +42 -2
- package/docs/assets/js/examplify.js +1 -1
- package/docs/cdom-nav.html +32 -6
- package/docs/cdom.html +610 -180
- package/docs/components/avatar.html +24 -54
- package/docs/components/badge.html +14 -14
- package/docs/components/breadcrumbs.html +95 -29
- package/docs/components/chart-area.html +3 -3
- package/docs/components/chart-bar.html +4 -181
- package/docs/components/chart-column.html +4 -189
- package/docs/components/chart-line.html +3 -3
- package/docs/components/chart-pie.html +112 -166
- package/docs/components/chart.html +11 -13
- package/docs/components/checkbox.html +48 -28
- package/docs/components/collapse.html +6 -6
- package/docs/components/countdown.html +12 -12
- package/docs/components/dropdown.html +1 -1
- package/docs/components/file-input.html +4 -4
- package/docs/components/footer.html +11 -11
- package/docs/components/input.html +45 -29
- package/docs/components/join.html +4 -4
- package/docs/components/kbd.html +3 -3
- package/docs/components/loading.html +41 -53
- package/docs/components/pagination.html +4 -4
- package/docs/components/progress.html +6 -4
- package/docs/components/radio.html +42 -31
- package/docs/components/select.html +48 -59
- package/docs/components/toggle.html +44 -25
- package/docs/getting-started/index.html +4 -4
- package/jprx/LICENSE +21 -0
- package/jprx/README.md +130 -0
- package/{cdom → jprx}/helpers/array.js +9 -4
- package/{cdom → jprx}/helpers/state.js +6 -3
- package/jprx/index.js +69 -0
- package/jprx/package.json +24 -0
- package/jprx/parser.js +1517 -0
- package/lightview-all.js +3785 -1
- package/lightview-cdom.js +2128 -1
- package/lightview-router.js +179 -208
- package/lightview-x.js +1435 -1
- package/lightview.js +613 -1
- package/package.json +5 -2
- package/src/lightview-cdom.js +201 -49
- package/src/lightview-router.js +210 -0
- package/src/lightview-x.js +104 -55
- package/src/lightview.js +12 -1
- package/{watch.js → start-dev.js} +2 -1
- package/tests/cdom/parser.test.js +83 -12
- package/wrangler.toml +0 -3
- package/cdom/parser.js +0 -602
- package/test-text-tag.js +0 -6
- /package/{cdom → jprx}/helpers/compare.js +0 -0
- /package/{cdom → jprx}/helpers/conditional.js +0 -0
- /package/{cdom → jprx}/helpers/datetime.js +0 -0
- /package/{cdom → jprx}/helpers/format.js +0 -0
- /package/{cdom → jprx}/helpers/logic.js +0 -0
- /package/{cdom → jprx}/helpers/lookup.js +0 -0
- /package/{cdom → jprx}/helpers/math.js +0 -0
- /package/{cdom → jprx}/helpers/network.js +0 -0
- /package/{cdom → jprx}/helpers/stats.js +0 -0
- /package/{cdom → jprx}/helpers/string.js +0 -0
package/lightview.js
CHANGED
|
@@ -1 +1,613 @@
|
|
|
1
|
-
|
|
1
|
+
(function() {
|
|
2
|
+
"use strict";
|
|
3
|
+
const _LV = globalThis.__LIGHTVIEW_INTERNALS__ || (globalThis.__LIGHTVIEW_INTERNALS__ = {
|
|
4
|
+
currentEffect: null,
|
|
5
|
+
registry: /* @__PURE__ */ new Map(),
|
|
6
|
+
dependencyMap: /* @__PURE__ */ new WeakMap()
|
|
7
|
+
// Tracking signals -> subscribers
|
|
8
|
+
});
|
|
9
|
+
const signal = (initialValue, optionsOrName) => {
|
|
10
|
+
let name = typeof optionsOrName === "string" ? optionsOrName : optionsOrName == null ? void 0 : optionsOrName.name;
|
|
11
|
+
const storage = optionsOrName == null ? void 0 : optionsOrName.storage;
|
|
12
|
+
if (name && storage) {
|
|
13
|
+
try {
|
|
14
|
+
const stored = storage.getItem(name);
|
|
15
|
+
if (stored !== null) {
|
|
16
|
+
initialValue = JSON.parse(stored);
|
|
17
|
+
}
|
|
18
|
+
} catch (e) {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
let value = initialValue;
|
|
22
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
23
|
+
const f = (...args) => {
|
|
24
|
+
if (args.length === 0) return f.value;
|
|
25
|
+
f.value = args[0];
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(f, "value", {
|
|
28
|
+
get() {
|
|
29
|
+
if (_LV.currentEffect) {
|
|
30
|
+
subscribers.add(_LV.currentEffect);
|
|
31
|
+
_LV.currentEffect.dependencies.add(subscribers);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
},
|
|
35
|
+
set(newValue) {
|
|
36
|
+
if (value !== newValue) {
|
|
37
|
+
value = newValue;
|
|
38
|
+
if (name && storage) {
|
|
39
|
+
try {
|
|
40
|
+
storage.setItem(name, JSON.stringify(value));
|
|
41
|
+
} catch (e) {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
[...subscribers].forEach((effect2) => effect2());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (name) {
|
|
49
|
+
if (_LV.registry.has(name)) {
|
|
50
|
+
if (_LV.registry.get(name) !== f) {
|
|
51
|
+
throw new Error(`Lightview: A signal or state with the name "${name}" is already registered.`);
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
_LV.registry.set(name, f);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return f;
|
|
58
|
+
};
|
|
59
|
+
const getSignal = (name, defaultValue) => {
|
|
60
|
+
if (!_LV.registry.has(name) && defaultValue !== void 0) {
|
|
61
|
+
return signal(defaultValue, name);
|
|
62
|
+
}
|
|
63
|
+
return _LV.registry.get(name);
|
|
64
|
+
};
|
|
65
|
+
signal.get = getSignal;
|
|
66
|
+
const effect = (fn) => {
|
|
67
|
+
const execute = () => {
|
|
68
|
+
if (!execute.active || execute.running) return;
|
|
69
|
+
execute.dependencies.forEach((dep) => dep.delete(execute));
|
|
70
|
+
execute.dependencies.clear();
|
|
71
|
+
execute.running = true;
|
|
72
|
+
_LV.currentEffect = execute;
|
|
73
|
+
try {
|
|
74
|
+
fn();
|
|
75
|
+
} finally {
|
|
76
|
+
_LV.currentEffect = null;
|
|
77
|
+
execute.running = false;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
execute.active = true;
|
|
81
|
+
execute.running = false;
|
|
82
|
+
execute.dependencies = /* @__PURE__ */ new Set();
|
|
83
|
+
execute.stop = () => {
|
|
84
|
+
execute.dependencies.forEach((dep) => dep.delete(execute));
|
|
85
|
+
execute.dependencies.clear();
|
|
86
|
+
execute.active = false;
|
|
87
|
+
};
|
|
88
|
+
execute();
|
|
89
|
+
return execute;
|
|
90
|
+
};
|
|
91
|
+
const computed = (fn) => {
|
|
92
|
+
const sig = signal(void 0);
|
|
93
|
+
effect(() => {
|
|
94
|
+
sig.value = fn();
|
|
95
|
+
});
|
|
96
|
+
return sig;
|
|
97
|
+
};
|
|
98
|
+
const getRegistry = () => _LV.registry;
|
|
99
|
+
const protoMethods = (proto, test) => Object.getOwnPropertyNames(proto).filter((k) => typeof proto[k] === "function" && test(k));
|
|
100
|
+
protoMethods(Date.prototype, (k) => /^(to|get|valueOf)/.test(k));
|
|
101
|
+
protoMethods(Date.prototype, (k) => /^set/.test(k));
|
|
102
|
+
const getOrSet = (map, key, factory) => {
|
|
103
|
+
let v = map.get(key);
|
|
104
|
+
if (!v) {
|
|
105
|
+
v = factory();
|
|
106
|
+
map.set(key, v);
|
|
107
|
+
}
|
|
108
|
+
return v;
|
|
109
|
+
};
|
|
110
|
+
const core = {
|
|
111
|
+
get currentEffect() {
|
|
112
|
+
return (globalThis.__LIGHTVIEW_INTERNALS__ || (globalThis.__LIGHTVIEW_INTERNALS__ = {})).currentEffect;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const nodeState = /* @__PURE__ */ new WeakMap();
|
|
116
|
+
const nodeStateFactory = () => ({ effects: [], onmount: null, onunmount: null });
|
|
117
|
+
const registry = getRegistry();
|
|
118
|
+
const trackEffect = (node, effectFn) => {
|
|
119
|
+
const state = getOrSet(nodeState, node, nodeStateFactory);
|
|
120
|
+
if (!state.effects) state.effects = [];
|
|
121
|
+
state.effects.push(effectFn);
|
|
122
|
+
};
|
|
123
|
+
const SHADOW_DOM_MARKER = Symbol("lightview.shadowDOM");
|
|
124
|
+
const createShadowDOMMarker = (attributes, children) => ({
|
|
125
|
+
[SHADOW_DOM_MARKER]: true,
|
|
126
|
+
mode: attributes.mode || "open",
|
|
127
|
+
styles: attributes.styles || [],
|
|
128
|
+
adoptedStyleSheets: attributes.adoptedStyleSheets || [],
|
|
129
|
+
children
|
|
130
|
+
});
|
|
131
|
+
const isShadowDOMMarker = (obj) => obj && typeof obj === "object" && obj[SHADOW_DOM_MARKER] === true;
|
|
132
|
+
const processShadowDOM = (marker, parentNode) => {
|
|
133
|
+
if (parentNode.shadowRoot) {
|
|
134
|
+
console.warn("Lightview: Element already has a shadowRoot, skipping shadowDOM directive");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const shadowRoot = parentNode.attachShadow({ mode: marker.mode });
|
|
138
|
+
const sheets = [];
|
|
139
|
+
const linkUrls = [...marker.styles || []];
|
|
140
|
+
if (marker.adoptedStyleSheets && marker.adoptedStyleSheets.length > 0) {
|
|
141
|
+
marker.adoptedStyleSheets.forEach((item) => {
|
|
142
|
+
if (item instanceof CSSStyleSheet) {
|
|
143
|
+
sheets.push(item);
|
|
144
|
+
} else if (typeof item === "string") {
|
|
145
|
+
linkUrls.push(item);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (sheets.length > 0) {
|
|
150
|
+
try {
|
|
151
|
+
shadowRoot.adoptedStyleSheets = sheets;
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.warn("Lightview: adoptedStyleSheets not supported");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const styleUrl of linkUrls) {
|
|
157
|
+
const link = document.createElement("link");
|
|
158
|
+
link.rel = "stylesheet";
|
|
159
|
+
link.href = styleUrl;
|
|
160
|
+
shadowRoot.appendChild(link);
|
|
161
|
+
}
|
|
162
|
+
if (marker.children && marker.children.length > 0) {
|
|
163
|
+
setupChildrenInTarget(marker.children, shadowRoot);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
let inSVG = false;
|
|
167
|
+
const domToElement = /* @__PURE__ */ new WeakMap();
|
|
168
|
+
const wrapDomElement = (domNode, tag, attributes = {}, children = []) => {
|
|
169
|
+
const el = {
|
|
170
|
+
tag,
|
|
171
|
+
attributes,
|
|
172
|
+
children,
|
|
173
|
+
get domEl() {
|
|
174
|
+
return domNode;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const proxy = makeReactive(el);
|
|
178
|
+
domToElement.set(domNode, proxy);
|
|
179
|
+
return proxy;
|
|
180
|
+
};
|
|
181
|
+
const element = (tag, attributes = {}, children = []) => {
|
|
182
|
+
if (customTags[tag]) tag = customTags[tag];
|
|
183
|
+
if (typeof tag === "function") {
|
|
184
|
+
const result = tag({ ...attributes }, children);
|
|
185
|
+
return processComponentResult(result);
|
|
186
|
+
}
|
|
187
|
+
if (tag === "shadowDOM") {
|
|
188
|
+
return createShadowDOMMarker(attributes, children);
|
|
189
|
+
}
|
|
190
|
+
if (tag === "text" && !inSVG) {
|
|
191
|
+
const domNode2 = document.createTextNode("");
|
|
192
|
+
const el = {
|
|
193
|
+
tag,
|
|
194
|
+
attributes,
|
|
195
|
+
children,
|
|
196
|
+
get domEl() {
|
|
197
|
+
return domNode2;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const update = () => {
|
|
201
|
+
const flat = (Array.isArray(el.children) ? el.children : [el.children]).flat(Infinity);
|
|
202
|
+
const bits = flat.map((c) => {
|
|
203
|
+
const val = typeof c === "function" ? c() : c;
|
|
204
|
+
if (val && typeof val === "object" && val.domEl) return val.domEl.textContent;
|
|
205
|
+
return val === null || val === void 0 ? "" : String(val);
|
|
206
|
+
});
|
|
207
|
+
domNode2.textContent = bits.join(" ");
|
|
208
|
+
};
|
|
209
|
+
const proxy2 = new Proxy(el, {
|
|
210
|
+
set(target, prop, value) {
|
|
211
|
+
target[prop] = value;
|
|
212
|
+
if (prop === "children") update();
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
const hasReactive = children.flat(Infinity).some((c) => typeof c === "function");
|
|
217
|
+
if (hasReactive) {
|
|
218
|
+
const runner = effect(update);
|
|
219
|
+
trackEffect(domNode2, runner);
|
|
220
|
+
}
|
|
221
|
+
update();
|
|
222
|
+
return proxy2;
|
|
223
|
+
}
|
|
224
|
+
const isSVG = tag.toLowerCase() === "svg";
|
|
225
|
+
const wasInSVG = inSVG;
|
|
226
|
+
if (isSVG) inSVG = true;
|
|
227
|
+
const domNode = inSVG ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag);
|
|
228
|
+
const proxy = wrapDomElement(domNode, tag, attributes, children);
|
|
229
|
+
proxy.attributes = attributes;
|
|
230
|
+
proxy.children = children;
|
|
231
|
+
if (isSVG) inSVG = wasInSVG;
|
|
232
|
+
return proxy;
|
|
233
|
+
};
|
|
234
|
+
const processComponentResult = (result) => {
|
|
235
|
+
if (!result) return null;
|
|
236
|
+
if (Lightview.hooks.processChild) {
|
|
237
|
+
result = Lightview.hooks.processChild(result) ?? result;
|
|
238
|
+
}
|
|
239
|
+
if (result.domEl) return result;
|
|
240
|
+
const type = typeof result;
|
|
241
|
+
if (type === "object" && result instanceof HTMLElement) {
|
|
242
|
+
return wrapDomElement(result, result.tagName.toLowerCase(), {}, []);
|
|
243
|
+
}
|
|
244
|
+
if (type === "object" && result instanceof String) {
|
|
245
|
+
const span = document.createElement("span");
|
|
246
|
+
span.textContent = result.toString();
|
|
247
|
+
return wrapDomElement(span, "span", {}, []);
|
|
248
|
+
}
|
|
249
|
+
if (type === "string") {
|
|
250
|
+
const template = document.createElement("template");
|
|
251
|
+
template.innerHTML = result.trim();
|
|
252
|
+
const content = template.content;
|
|
253
|
+
if (content.childNodes.length === 1 && content.firstChild instanceof HTMLElement) {
|
|
254
|
+
const el = content.firstChild;
|
|
255
|
+
return wrapDomElement(el, el.tagName.toLowerCase(), {}, []);
|
|
256
|
+
} else {
|
|
257
|
+
const wrapper = document.createElement("span");
|
|
258
|
+
wrapper.style.display = "contents";
|
|
259
|
+
wrapper.appendChild(content);
|
|
260
|
+
return wrapDomElement(wrapper, "span", {}, []);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (typeof result === "object" && result.tag) {
|
|
264
|
+
return element(result.tag, result.attributes || {}, result.children || []);
|
|
265
|
+
}
|
|
266
|
+
return null;
|
|
267
|
+
};
|
|
268
|
+
const makeReactive = (el) => {
|
|
269
|
+
const domNode = el.domEl;
|
|
270
|
+
return new Proxy(el, {
|
|
271
|
+
set(target, prop, value) {
|
|
272
|
+
if (prop === "attributes") {
|
|
273
|
+
target[prop] = makeReactiveAttributes(value, domNode);
|
|
274
|
+
} else if (prop === "children") {
|
|
275
|
+
target[prop] = setupChildren(value, domNode);
|
|
276
|
+
} else {
|
|
277
|
+
target[prop] = value;
|
|
278
|
+
}
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
const NODE_PROPERTIES = /* @__PURE__ */ new Set(["value", "checked", "selected", "selectedIndex", "className", "innerHTML", "innerText"]);
|
|
284
|
+
const setAttributeValue = (domNode, key, value) => {
|
|
285
|
+
const isBool = typeof domNode[key] === "boolean";
|
|
286
|
+
if ((key === "href" || key === "src") && typeof value === "string" && /^(javascript|vbscript|data:text\/html|data:application\/javascript)/i.test(value)) {
|
|
287
|
+
console.warn(`[Lightview] Blocked dangerous protocol in ${key}: ${value}`);
|
|
288
|
+
value = "javascript:void(0)";
|
|
289
|
+
}
|
|
290
|
+
if (NODE_PROPERTIES.has(key) || isBool || key.startsWith("cdom-")) {
|
|
291
|
+
domNode[key] = isBool ? value !== null && value !== void 0 && value !== false && value !== "false" : value;
|
|
292
|
+
} else if (value === null || value === void 0) {
|
|
293
|
+
domNode.removeAttribute(key);
|
|
294
|
+
} else {
|
|
295
|
+
domNode.setAttribute(key, value);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const makeReactiveAttributes = (attributes, domNode) => {
|
|
299
|
+
const reactiveAttrs = {};
|
|
300
|
+
for (let [key, value] of Object.entries(attributes)) {
|
|
301
|
+
if (key === "onmount" || key === "onunmount") {
|
|
302
|
+
const state = getOrSet(nodeState, domNode, nodeStateFactory);
|
|
303
|
+
state[key] = value;
|
|
304
|
+
if (key === "onmount" && domNode.isConnected) {
|
|
305
|
+
value(domNode);
|
|
306
|
+
}
|
|
307
|
+
} else if (key.startsWith("on")) {
|
|
308
|
+
if (typeof value === "function") {
|
|
309
|
+
const eventName = key.slice(2).toLowerCase();
|
|
310
|
+
domNode.addEventListener(eventName, value);
|
|
311
|
+
} else if (typeof value === "string") {
|
|
312
|
+
domNode.setAttribute(key, value);
|
|
313
|
+
}
|
|
314
|
+
reactiveAttrs[key] = value;
|
|
315
|
+
} else if (typeof value === "function") {
|
|
316
|
+
const runner = effect(() => {
|
|
317
|
+
const result = value();
|
|
318
|
+
if (key === "style" && typeof result === "object") {
|
|
319
|
+
Object.assign(domNode.style, result);
|
|
320
|
+
} else {
|
|
321
|
+
setAttributeValue(domNode, key, result);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
trackEffect(domNode, runner);
|
|
325
|
+
reactiveAttrs[key] = value;
|
|
326
|
+
} else if (key === "style" && typeof value === "object") {
|
|
327
|
+
Object.entries(value).forEach(([styleKey, styleValue]) => {
|
|
328
|
+
if (typeof styleValue === "function") {
|
|
329
|
+
const runner = effect(() => {
|
|
330
|
+
domNode.style[styleKey] = styleValue();
|
|
331
|
+
});
|
|
332
|
+
trackEffect(domNode, runner);
|
|
333
|
+
} else {
|
|
334
|
+
domNode.style[styleKey] = styleValue;
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
reactiveAttrs[key] = value;
|
|
338
|
+
} else {
|
|
339
|
+
setAttributeValue(domNode, key, value);
|
|
340
|
+
reactiveAttrs[key] = value;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return reactiveAttrs;
|
|
344
|
+
};
|
|
345
|
+
const processChildren = (children, targetNode, clearExisting = true) => {
|
|
346
|
+
if (clearExisting && targetNode.innerHTML !== void 0) {
|
|
347
|
+
targetNode.innerHTML = "";
|
|
348
|
+
}
|
|
349
|
+
const childElements = [];
|
|
350
|
+
const isSpecialElement = targetNode.tagName && (targetNode.tagName.toLowerCase() === "script" || targetNode.tagName.toLowerCase() === "style");
|
|
351
|
+
const flatChildren = children.flat(Infinity);
|
|
352
|
+
for (let child of flatChildren) {
|
|
353
|
+
if (Lightview.hooks.processChild && !isSpecialElement) {
|
|
354
|
+
child = Lightview.hooks.processChild(child) ?? child;
|
|
355
|
+
}
|
|
356
|
+
if (isShadowDOMMarker(child)) {
|
|
357
|
+
if (targetNode instanceof ShadowRoot) {
|
|
358
|
+
console.warn("Lightview: Cannot nest shadowDOM inside another shadowDOM");
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
processShadowDOM(child, targetNode);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const type = typeof child;
|
|
365
|
+
if (type === "function") {
|
|
366
|
+
const startMarker = document.createComment("lv:s");
|
|
367
|
+
const endMarker = document.createComment("lv:e");
|
|
368
|
+
targetNode.appendChild(startMarker);
|
|
369
|
+
targetNode.appendChild(endMarker);
|
|
370
|
+
let runner;
|
|
371
|
+
const update = () => {
|
|
372
|
+
while (startMarker.nextSibling && startMarker.nextSibling !== endMarker) {
|
|
373
|
+
startMarker.nextSibling.remove();
|
|
374
|
+
}
|
|
375
|
+
const val = child();
|
|
376
|
+
if (val === void 0 || val === null) return;
|
|
377
|
+
if (runner && !startMarker.isConnected) {
|
|
378
|
+
runner.stop();
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (typeof val === "object" && val instanceof String) {
|
|
382
|
+
const textNode = document.createTextNode(val);
|
|
383
|
+
endMarker.parentNode.insertBefore(textNode, endMarker);
|
|
384
|
+
} else {
|
|
385
|
+
const fragment = document.createDocumentFragment();
|
|
386
|
+
const childrenToProcess = Array.isArray(val) ? val : [val];
|
|
387
|
+
processChildren(childrenToProcess, fragment, false);
|
|
388
|
+
endMarker.parentNode.insertBefore(fragment, endMarker);
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
runner = effect(update);
|
|
392
|
+
trackEffect(startMarker, runner);
|
|
393
|
+
childElements.push(child);
|
|
394
|
+
} else if (["string", "number", "boolean", "symbol"].includes(type) || child && type === "object" && child instanceof String) {
|
|
395
|
+
targetNode.appendChild(document.createTextNode(child));
|
|
396
|
+
childElements.push(child);
|
|
397
|
+
} else if (child instanceof Node) {
|
|
398
|
+
const node = child.domEl || child;
|
|
399
|
+
if (node instanceof HTMLElement || node instanceof SVGElement) {
|
|
400
|
+
const wrapped = wrapDomElement(node, node.tagName.toLowerCase());
|
|
401
|
+
targetNode.appendChild(node);
|
|
402
|
+
childElements.push(wrapped);
|
|
403
|
+
} else {
|
|
404
|
+
targetNode.appendChild(node);
|
|
405
|
+
childElements.push(child);
|
|
406
|
+
}
|
|
407
|
+
} else if (child && type === "object" && child.tag) {
|
|
408
|
+
const childEl = child.domEl ? child : element(child.tag, child.attributes || {}, child.children || []);
|
|
409
|
+
targetNode.appendChild(childEl.domEl);
|
|
410
|
+
childElements.push(childEl);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return childElements;
|
|
414
|
+
};
|
|
415
|
+
const setupChildrenInTarget = (children, targetNode) => {
|
|
416
|
+
return processChildren(children, targetNode, false);
|
|
417
|
+
};
|
|
418
|
+
const setupChildren = (children, domNode) => {
|
|
419
|
+
return processChildren(children, domNode, true);
|
|
420
|
+
};
|
|
421
|
+
const enhance = (selectorOrNode, options = {}) => {
|
|
422
|
+
const domNode = typeof selectorOrNode === "string" ? document.querySelector(selectorOrNode) : selectorOrNode;
|
|
423
|
+
const node = domNode.domEl || domNode;
|
|
424
|
+
if (!(node instanceof HTMLElement)) return null;
|
|
425
|
+
const tagName = node.tagName.toLowerCase();
|
|
426
|
+
let el = domToElement.get(node);
|
|
427
|
+
if (!el) {
|
|
428
|
+
el = wrapDomElement(node, tagName);
|
|
429
|
+
}
|
|
430
|
+
const { innerText, innerHTML, ...attrs } = options;
|
|
431
|
+
if (innerText !== void 0) {
|
|
432
|
+
if (typeof innerText === "function") {
|
|
433
|
+
effect(() => {
|
|
434
|
+
node.innerText = innerText();
|
|
435
|
+
});
|
|
436
|
+
} else {
|
|
437
|
+
node.innerText = innerText;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (innerHTML !== void 0) {
|
|
441
|
+
if (typeof innerHTML === "function") {
|
|
442
|
+
effect(() => {
|
|
443
|
+
node.innerHTML = innerHTML();
|
|
444
|
+
});
|
|
445
|
+
} else {
|
|
446
|
+
node.innerHTML = innerHTML;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (Object.keys(attrs).length > 0) {
|
|
450
|
+
el.attributes = attrs;
|
|
451
|
+
}
|
|
452
|
+
return el;
|
|
453
|
+
};
|
|
454
|
+
const $ = (cssSelectorOrElement, startingDomEl = document.body) => {
|
|
455
|
+
const el = typeof cssSelectorOrElement === "string" ? startingDomEl.querySelector(cssSelectorOrElement) : cssSelectorOrElement;
|
|
456
|
+
if (!el) return null;
|
|
457
|
+
Object.defineProperty(el, "content", {
|
|
458
|
+
value(child, location = "inner") {
|
|
459
|
+
location = location.toLowerCase();
|
|
460
|
+
Lightview.tags;
|
|
461
|
+
const isSpecialElement = el.tagName && (el.tagName.toLowerCase() === "script" || el.tagName.toLowerCase() === "style");
|
|
462
|
+
const array = (Array.isArray(child) ? child : [child]).map((item) => {
|
|
463
|
+
if (Lightview.hooks.processChild && !isSpecialElement) {
|
|
464
|
+
item = Lightview.hooks.processChild(item) ?? item;
|
|
465
|
+
}
|
|
466
|
+
if (item.tag && !item.domEl) {
|
|
467
|
+
return element(item.tag, item.attributes || {}, item.children || []).domEl;
|
|
468
|
+
} else {
|
|
469
|
+
return item.domEl || item;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
const target = location === "shadow" ? el.shadowRoot || el.attachShadow({ mode: "open" }) : el;
|
|
473
|
+
if (location === "inner" || location === "shadow") {
|
|
474
|
+
target.replaceChildren(...array);
|
|
475
|
+
} else if (location === "outer") {
|
|
476
|
+
target.replaceWith(...array);
|
|
477
|
+
} else if (location === "afterbegin") {
|
|
478
|
+
target.prepend(...array);
|
|
479
|
+
} else if (location === "beforeend") {
|
|
480
|
+
target.append(...array);
|
|
481
|
+
} else {
|
|
482
|
+
array.forEach((item) => el.insertAdjacentElement(location, item));
|
|
483
|
+
}
|
|
484
|
+
return el;
|
|
485
|
+
},
|
|
486
|
+
configurable: true,
|
|
487
|
+
writable: true
|
|
488
|
+
});
|
|
489
|
+
return el;
|
|
490
|
+
};
|
|
491
|
+
const customTags = {};
|
|
492
|
+
const tags = new Proxy({}, {
|
|
493
|
+
get(_, tag) {
|
|
494
|
+
if (tag === "_customTags") return { ...customTags };
|
|
495
|
+
const wrapper = (...args) => {
|
|
496
|
+
let attributes = {};
|
|
497
|
+
let children = args;
|
|
498
|
+
const arg0 = args[0];
|
|
499
|
+
if (args.length > 0 && arg0 && typeof arg0 === "object" && !arg0.tag && !arg0.domEl && !Array.isArray(arg0)) {
|
|
500
|
+
attributes = arg0;
|
|
501
|
+
children = args.slice(1);
|
|
502
|
+
}
|
|
503
|
+
return element(customTags[tag] || tag, attributes, children);
|
|
504
|
+
};
|
|
505
|
+
if (customTags[tag]) {
|
|
506
|
+
Object.assign(wrapper, customTags[tag]);
|
|
507
|
+
}
|
|
508
|
+
return wrapper;
|
|
509
|
+
},
|
|
510
|
+
set(_, tag, value) {
|
|
511
|
+
customTags[tag] = value;
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
const Lightview = {
|
|
516
|
+
signal,
|
|
517
|
+
get: signal.get,
|
|
518
|
+
computed,
|
|
519
|
+
effect,
|
|
520
|
+
registry,
|
|
521
|
+
element,
|
|
522
|
+
// do not document this
|
|
523
|
+
enhance,
|
|
524
|
+
tags,
|
|
525
|
+
$,
|
|
526
|
+
// Extension hooks
|
|
527
|
+
hooks: {
|
|
528
|
+
onNonStandardHref: null,
|
|
529
|
+
processChild: null,
|
|
530
|
+
validateUrl: null
|
|
531
|
+
},
|
|
532
|
+
// Internals exposed for extensions
|
|
533
|
+
internals: {
|
|
534
|
+
core,
|
|
535
|
+
domToElement,
|
|
536
|
+
wrapDomElement,
|
|
537
|
+
setupChildren
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
541
|
+
module.exports = Lightview;
|
|
542
|
+
}
|
|
543
|
+
if (typeof window !== "undefined") {
|
|
544
|
+
globalThis.Lightview = Lightview;
|
|
545
|
+
globalThis.addEventListener("click", (e) => {
|
|
546
|
+
const path = e.composedPath();
|
|
547
|
+
const link = path.find((el) => {
|
|
548
|
+
var _a, _b;
|
|
549
|
+
return el.tagName === "A" && ((_b = (_a = el.getAttribute) == null ? void 0 : _a.call(el, "href")) == null ? void 0 : _b.startsWith("#"));
|
|
550
|
+
});
|
|
551
|
+
if (link && !e.defaultPrevented) {
|
|
552
|
+
const href = link.getAttribute("href");
|
|
553
|
+
if (href.length > 1) {
|
|
554
|
+
const id = href.slice(1);
|
|
555
|
+
const root = link.getRootNode();
|
|
556
|
+
const target = (root.getElementById ? root.getElementById(id) : null) || (root.querySelector ? root.querySelector(`#${id}`) : null);
|
|
557
|
+
if (target) {
|
|
558
|
+
e.preventDefault();
|
|
559
|
+
requestAnimationFrame(() => {
|
|
560
|
+
requestAnimationFrame(() => {
|
|
561
|
+
target.style.scrollMarginTop = "calc(var(--site-nav-height, 0px) + 2rem)";
|
|
562
|
+
target.scrollIntoView({ behavior: "smooth", block: "start", inline: "start" });
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (Lightview.hooks.onNonStandardHref) {
|
|
569
|
+
Lightview.hooks.onNonStandardHref(e);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
if (typeof MutationObserver !== "undefined") {
|
|
573
|
+
const walkNodes = (node, fn) => {
|
|
574
|
+
var _a;
|
|
575
|
+
fn(node);
|
|
576
|
+
(_a = node.childNodes) == null ? void 0 : _a.forEach((n) => walkNodes(n, fn));
|
|
577
|
+
if (node.shadowRoot) walkNodes(node.shadowRoot, fn);
|
|
578
|
+
};
|
|
579
|
+
const cleanupNode = (node) => walkNodes(node, (n) => {
|
|
580
|
+
var _a, _b;
|
|
581
|
+
const s = nodeState.get(n);
|
|
582
|
+
if (s) {
|
|
583
|
+
(_a = s.effects) == null ? void 0 : _a.forEach((e) => e.stop());
|
|
584
|
+
(_b = s.onunmount) == null ? void 0 : _b.call(s, n);
|
|
585
|
+
nodeState.delete(n);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
const mountNode = (node) => walkNodes(node, (n) => {
|
|
589
|
+
var _a, _b;
|
|
590
|
+
(_b = (_a = nodeState.get(n)) == null ? void 0 : _a.onmount) == null ? void 0 : _b.call(_a, n);
|
|
591
|
+
});
|
|
592
|
+
const observer = new MutationObserver((mutations) => {
|
|
593
|
+
mutations.forEach((mutation) => {
|
|
594
|
+
mutation.removedNodes.forEach(cleanupNode);
|
|
595
|
+
mutation.addedNodes.forEach(mountNode);
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
const startObserving = () => {
|
|
599
|
+
if (document.body) {
|
|
600
|
+
observer.observe(document.body, {
|
|
601
|
+
childList: true,
|
|
602
|
+
subtree: true
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
if (document.readyState === "loading") {
|
|
607
|
+
document.addEventListener("DOMContentLoaded", startObserving);
|
|
608
|
+
} else {
|
|
609
|
+
startObserving();
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightview",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "A lightweight reactive UI library with features of Bau, Juris, and HTMX",
|
|
5
5
|
"main": "lightview.js",
|
|
6
|
+
"workspaces": [
|
|
7
|
+
"jprx"
|
|
8
|
+
],
|
|
6
9
|
"directories": {
|
|
7
10
|
"doc": "docs"
|
|
8
11
|
},
|
|
@@ -10,7 +13,7 @@
|
|
|
10
13
|
"dev": "wrangler pages dev . --port 3000",
|
|
11
14
|
"preview": "npm run build && wrangler pages dev ./dist --port 8788",
|
|
12
15
|
"build": "node build-bundles.mjs && node build.js",
|
|
13
|
-
"watch": "node
|
|
16
|
+
"watch": "node build-bundles.mjs && node build.js --watch --env=dev",
|
|
14
17
|
"deploy": "npm run build && wrangler pages deploy dist",
|
|
15
18
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
16
19
|
},
|