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.
Files changed (71) hide show
  1. package/build-bundles.mjs +2 -6
  2. package/build.js +236 -46
  3. package/components/data-display/avatar.js +25 -1
  4. package/components/data-display/chart.js +22 -5
  5. package/components/data-display/countdown.js +3 -2
  6. package/components/data-input/checkbox.js +23 -1
  7. package/components/data-input/input.js +24 -1
  8. package/components/data-input/radio.js +37 -2
  9. package/components/data-input/select.js +24 -1
  10. package/components/data-input/toggle.js +21 -1
  11. package/components/navigation/breadcrumbs.js +42 -2
  12. package/docs/assets/js/examplify.js +1 -1
  13. package/docs/cdom-nav.html +32 -6
  14. package/docs/cdom.html +610 -180
  15. package/docs/components/avatar.html +24 -54
  16. package/docs/components/badge.html +14 -14
  17. package/docs/components/breadcrumbs.html +95 -29
  18. package/docs/components/chart-area.html +3 -3
  19. package/docs/components/chart-bar.html +4 -181
  20. package/docs/components/chart-column.html +4 -189
  21. package/docs/components/chart-line.html +3 -3
  22. package/docs/components/chart-pie.html +112 -166
  23. package/docs/components/chart.html +11 -13
  24. package/docs/components/checkbox.html +48 -28
  25. package/docs/components/collapse.html +6 -6
  26. package/docs/components/countdown.html +12 -12
  27. package/docs/components/dropdown.html +1 -1
  28. package/docs/components/file-input.html +4 -4
  29. package/docs/components/footer.html +11 -11
  30. package/docs/components/input.html +45 -29
  31. package/docs/components/join.html +4 -4
  32. package/docs/components/kbd.html +3 -3
  33. package/docs/components/loading.html +41 -53
  34. package/docs/components/pagination.html +4 -4
  35. package/docs/components/progress.html +6 -4
  36. package/docs/components/radio.html +42 -31
  37. package/docs/components/select.html +48 -59
  38. package/docs/components/toggle.html +44 -25
  39. package/docs/getting-started/index.html +4 -4
  40. package/jprx/LICENSE +21 -0
  41. package/jprx/README.md +130 -0
  42. package/{cdom → jprx}/helpers/array.js +9 -4
  43. package/{cdom → jprx}/helpers/state.js +6 -3
  44. package/jprx/index.js +69 -0
  45. package/jprx/package.json +24 -0
  46. package/jprx/parser.js +1517 -0
  47. package/lightview-all.js +3785 -1
  48. package/lightview-cdom.js +2128 -1
  49. package/lightview-router.js +179 -208
  50. package/lightview-x.js +1435 -1
  51. package/lightview.js +613 -1
  52. package/package.json +5 -2
  53. package/src/lightview-cdom.js +201 -49
  54. package/src/lightview-router.js +210 -0
  55. package/src/lightview-x.js +104 -55
  56. package/src/lightview.js +12 -1
  57. package/{watch.js → start-dev.js} +2 -1
  58. package/tests/cdom/parser.test.js +83 -12
  59. package/wrangler.toml +0 -3
  60. package/cdom/parser.js +0 -602
  61. package/test-text-tag.js +0 -6
  62. /package/{cdom → jprx}/helpers/compare.js +0 -0
  63. /package/{cdom → jprx}/helpers/conditional.js +0 -0
  64. /package/{cdom → jprx}/helpers/datetime.js +0 -0
  65. /package/{cdom → jprx}/helpers/format.js +0 -0
  66. /package/{cdom → jprx}/helpers/logic.js +0 -0
  67. /package/{cdom → jprx}/helpers/lookup.js +0 -0
  68. /package/{cdom → jprx}/helpers/math.js +0 -0
  69. /package/{cdom → jprx}/helpers/network.js +0 -0
  70. /package/{cdom → jprx}/helpers/stats.js +0 -0
  71. /package/{cdom → jprx}/helpers/string.js +0 -0
package/lightview.js CHANGED
@@ -1 +1,613 @@
1
- !function(){"use strict";const e=globalThis.__LIGHTVIEW_INTERNALS__||(globalThis.__LIGHTVIEW_INTERNALS__={currentEffect:null,registry:new Map,dependencyMap:new WeakMap}),t=(t,n)=>{let o="string"==typeof n?n:null==n?void 0:n.name;const r=null==n?void 0:n.storage;if(o&&r)try{const e=r.getItem(o);null!==e&&(t=JSON.parse(e))}catch(l){}let s=t;const i=new Set,a=(...e)=>{if(0===e.length)return a.value;a.value=e[0]};if(Object.defineProperty(a,"value",{get:()=>(e.currentEffect&&(i.add(e.currentEffect),e.currentEffect.dependencies.add(i)),s),set(e){if(s!==e){if(s=e,o&&r)try{r.setItem(o,JSON.stringify(s))}catch(l){}[...i].forEach(e=>e())}}}),o)if(e.registry.has(o)){if(e.registry.get(o)!==a)throw new Error(`Lightview: A signal or state with the name "${o}" is already registered.`)}else e.registry.set(o,a);return a};t.get=(n,o)=>e.registry.has(n)||void 0===o?e.registry.get(n):t(o,n);const n=t=>{const n=()=>{if(n.active&&!n.running){n.dependencies.forEach(e=>e.delete(n)),n.dependencies.clear(),n.running=!0,e.currentEffect=n;try{t()}finally{e.currentEffect=null,n.running=!1}}};return n.active=!0,n.running=!1,n.dependencies=new Set,n.stop=()=>{n.dependencies.forEach(e=>e.delete(n)),n.dependencies.clear(),n.active=!1},n(),n},o=(e,t)=>Object.getOwnPropertyNames(e).filter(n=>"function"==typeof e[n]&&t(n));o(Date.prototype,e=>/^(to|get|valueOf)/.test(e)),o(Date.prototype,e=>/^set/.test(e));const r=(e,t,n)=>{let o=e.get(t);return o||(o=n(),e.set(t,o)),o},s={get currentEffect(){return(globalThis.__LIGHTVIEW_INTERNALS__||(globalThis.__LIGHTVIEW_INTERNALS__={})).currentEffect}},i=new WeakMap,a=()=>({effects:[],onmount:null,onunmount:null}),l=e.registry,c=(e,t)=>{const n=r(i,e,a);n.effects||(n.effects=[]),n.effects.push(t)},d=Symbol("lightview.shadowDOM"),u=e=>e&&"object"==typeof e&&!0===e[d],f=(e,t)=>{if(t.shadowRoot)return void console.warn("Lightview: Element already has a shadowRoot, skipping shadowDOM directive");const n=t.attachShadow({mode:e.mode}),o=[],r=[...e.styles||[]];if(e.adoptedStyleSheets&&e.adoptedStyleSheets.length>0&&e.adoptedStyleSheets.forEach(e=>{e instanceof CSSStyleSheet?o.push(e):"string"==typeof e&&r.push(e)}),o.length>0)try{n.adoptedStyleSheets=o}catch(s){console.warn("Lightview: adoptedStyleSheets not supported")}for(const i of r){const e=document.createElement("link");e.rel="stylesheet",e.href=i,n.appendChild(e)}e.children&&e.children.length>0&&L(e.children,n)};let h=!1;const p=new WeakMap,g=(e,t,n={},o=[])=>{const r=b({tag:t,attributes:n,children:o,get domEl(){return e}});return p.set(e,r),r},m=(e,t={},o=[])=>{if(N[e]&&(e=N[e]),"function"==typeof e){const n=e({...t},o);return y(n)}if("shadowDOM"===e)return((e,t)=>({[d]:!0,mode:e.mode||"open",styles:e.styles||[],adoptedStyleSheets:e.adoptedStyleSheets||[],children:t}))(t,o);if("text"===e&&!h){const r=document.createTextNode(""),s={tag:e,attributes:t,children:o,get domEl(){return r}},i=()=>{const e=(Array.isArray(s.children)?s.children:[s.children]).flat(1/0).map(e=>{const t="function"==typeof e?e():e;return t&&"object"==typeof t&&t.domEl?t.domEl.textContent:null==t?"":String(t)});r.textContent=e.join(" ")},a=new Proxy(s,{set:(e,t,n)=>(e[t]=n,"children"===t&&i(),!0)});if(o.flat(1/0).some(e=>"function"==typeof e)){const e=n(i);c(r,e)}return i(),a}const r="svg"===e.toLowerCase(),s=h;r&&(h=!0);const i=h?document.createElementNS("http://www.w3.org/2000/svg",e):document.createElement(e),a=g(i,e,t,o);return a.attributes=t,a.children=o,r&&(h=s),a},y=e=>{if(!e)return null;if(j.hooks.processChild&&(e=j.hooks.processChild(e)??e),e.domEl)return e;const t=typeof e;if("object"===t&&e instanceof HTMLElement)return g(e,e.tagName.toLowerCase(),{},[]);if("object"===t&&e instanceof String){const t=document.createElement("span");return t.textContent=e.toString(),g(t,"span",{},[])}if("string"===t){const t=document.createElement("template");t.innerHTML=e.trim();const n=t.content;if(1===n.childNodes.length&&n.firstChild instanceof HTMLElement){const e=n.firstChild;return g(e,e.tagName.toLowerCase(),{},[])}{const e=document.createElement("span");return e.style.display="contents",e.appendChild(n),g(e,"span",{},[])}}return"object"==typeof e&&e.tag?m(e.tag,e.attributes||{},e.children||[]):null},b=e=>{const t=e.domEl;return new Proxy(e,{set:(e,n,o)=>(e[n]="attributes"===n?v(o,t):"children"===n?C(o,t):o,!0)})},w=new Set(["value","checked","selected","selectedIndex","className","innerHTML","innerText"]),E=(e,t,n)=>{const o="boolean"==typeof e[t];"href"!==t&&"src"!==t||"string"!=typeof n||!/^(javascript|vbscript|data:text\/html|data:application\/javascript)/i.test(n)||(console.warn(`[Lightview] Blocked dangerous protocol in ${t}: ${n}`),n="javascript:void(0)"),w.has(t)||o?e[t]=o?null!=n&&!1!==n&&"false"!==n:n:null==n?e.removeAttribute(t):e.setAttribute(t,n)},v=(e,t)=>{const o={};for(let[s,l]of Object.entries(e))if("onmount"===s||"onunmount"===s){r(i,t,a)[s]=l,"onmount"===s&&t.isConnected&&l(t)}else if(s.startsWith("on")){if("function"==typeof l){const e=s.slice(2).toLowerCase();t.addEventListener(e,l)}else"string"==typeof l&&t.setAttribute(s,l);o[s]=l}else if("function"==typeof l){const e=n(()=>{const e=l();"style"===s&&"object"==typeof e?Object.assign(t.style,e):E(t,s,e)});c(t,e),o[s]=l}else"style"===s&&"object"==typeof l?(Object.entries(l).forEach(([e,o])=>{if("function"==typeof o){const r=n(()=>{t.style[e]=o()});c(t,r)}else t.style[e]=o}),o[s]=l):(E(t,s,l),o[s]=l);return o},S=(e,t,o=!0)=>{o&&void 0!==t.innerHTML&&(t.innerHTML="");const r=[],s=t.tagName&&("script"===t.tagName.toLowerCase()||"style"===t.tagName.toLowerCase()),i=e.flat(1/0);for(let a of i){if(j.hooks.processChild&&!s&&(a=j.hooks.processChild(a)??a),u(a)){if(t instanceof ShadowRoot){console.warn("Lightview: Cannot nest shadowDOM inside another shadowDOM");continue}f(a,t);continue}const e=typeof a;if("function"===e){const e=document.createComment("lv:s"),o=document.createComment("lv:e");let s;t.appendChild(e),t.appendChild(o);const i=()=>{for(;e.nextSibling&&e.nextSibling!==o;)e.nextSibling.remove();const t=a();if(null!=t)if(!s||e.isConnected)if("object"==typeof t&&t instanceof String){const e=document.createTextNode(t);o.parentNode.insertBefore(e,o)}else{const e=document.createDocumentFragment(),n=Array.isArray(t)?t:[t];S(n,e,!1),o.parentNode.insertBefore(e,o)}else s.stop()};s=n(i),c(e,s),r.push(a)}else if(["string","number","boolean","symbol"].includes(e)||a&&"object"===e&&a instanceof String)t.appendChild(document.createTextNode(a)),r.push(a);else if(a&&"object"===e&&a.tag){const e=a.domEl?a:m(a.tag,a.attributes||{},a.children||[]);t.appendChild(e.domEl),r.push(e)}}return r},L=(e,t)=>S(e,t,!1),C=(e,t)=>S(e,t,!0),N={},T=new Proxy({},{get(e,t){if("_customTags"===t)return{...N};const n=(...e)=>{let n={},o=e;const r=e[0];return e.length>0&&r&&"object"==typeof r&&!r.tag&&!r.domEl&&!Array.isArray(r)&&(n=r,o=e.slice(1)),m(N[t]||t,n,o)};return N[t]&&Object.assign(n,N[t]),n},set:(e,t,n)=>(N[t]=n,!0)}),j={signal:t,get:t.get,computed:e=>{const o=t(void 0);return n(()=>{o.value=e()}),o},effect:n,registry:l,element:m,enhance:(e,t={})=>{const o="string"==typeof e?document.querySelector(e):e,r=o.domEl||o;if(!(r instanceof HTMLElement))return null;const s=r.tagName.toLowerCase();let i=p.get(r);i||(i=g(r,s));const{innerText:a,innerHTML:l,...c}=t;return void 0!==a&&("function"==typeof a?n(()=>{r.innerText=a()}):r.innerText=a),void 0!==l&&("function"==typeof l?n(()=>{r.innerHTML=l()}):r.innerHTML=l),Object.keys(c).length>0&&(i.attributes=c),i},tags:T,$:(e,t=document.body)=>{const n="string"==typeof e?t.querySelector(e):e;return n?(Object.defineProperty(n,"content",{value(e,t="inner"){t=t.toLowerCase(),j.tags;const o=n.tagName&&("script"===n.tagName.toLowerCase()||"style"===n.tagName.toLowerCase()),r=(Array.isArray(e)?e:[e]).map(e=>(j.hooks.processChild&&!o&&(e=j.hooks.processChild(e)??e),e.tag&&!e.domEl?m(e.tag,e.attributes||{},e.children||[]).domEl:e.domEl||e)),s="shadow"===t?n.shadowRoot||n.attachShadow({mode:"open"}):n;return"inner"===t||"shadow"===t?s.replaceChildren(...r):"outer"===t?s.replaceWith(...r):"afterbegin"===t?s.prepend(...r):"beforeend"===t?s.append(...r):r.forEach(e=>n.insertAdjacentElement(t,e)),n},configurable:!0,writable:!0}),n):null},hooks:{onNonStandardHref:null,processChild:null,validateUrl:null},internals:{core:s,domToElement:p,wrapDomElement:g,setupChildren:C}};if("undefined"!=typeof module&&module.exports&&(module.exports=j),"undefined"!=typeof window&&(globalThis.Lightview=j,globalThis.addEventListener("click",e=>{const t=e.composedPath().find(e=>{var t,n;return"A"===e.tagName&&(null==(n=null==(t=e.getAttribute)?void 0:t.call(e,"href"))?void 0:n.startsWith("#"))});if(t&&!e.defaultPrevented){const n=t.getAttribute("href");if(n.length>1){const o=n.slice(1),r=t.getRootNode(),s=(r.getElementById?r.getElementById(o):null)||(r.querySelector?r.querySelector(`#${o}`):null);s&&(e.preventDefault(),requestAnimationFrame(()=>{requestAnimationFrame(()=>{s.style.scrollMarginTop="calc(var(--site-nav-height, 0px) + 2rem)",s.scrollIntoView({behavior:"smooth",block:"start",inline:"start"})})}))}}j.hooks.onNonStandardHref&&j.hooks.onNonStandardHref(e)}),"undefined"!=typeof MutationObserver)){const e=(t,n)=>{var o;n(t),null==(o=t.childNodes)||o.forEach(t=>e(t,n)),t.shadowRoot&&e(t.shadowRoot,n)},t=t=>e(t,e=>{var t,n;const o=i.get(e);o&&(null==(t=o.effects)||t.forEach(e=>e.stop()),null==(n=o.onunmount)||n.call(o,e),i.delete(e))}),n=t=>e(t,e=>{var t,n;null==(n=null==(t=i.get(e))?void 0:t.onmount)||n.call(t,e)}),o=new MutationObserver(e=>{e.forEach(e=>{e.removedNodes.forEach(t),e.addedNodes.forEach(n)})}),r=()=>{document.body&&o.observe(document.body,{childList:!0,subtree:!0})};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",r):r()}}();
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.1.0",
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 watch.js",
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
  },