lightview 1.3.0-b → 1.4.1-b

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # lightview v1.3.0b (BETA)
1
+ # lightview v1.4.1b (BETA)
2
2
 
3
- Small, simple, powerful web UI creation ...
3
+ Small, simple, powerful web UI and micro front end creation ...
4
4
 
5
5
  Great ideas from Svelte, React, Vue and Riot combined into one small tool: < 6K (minified/gzipped).
6
6
 
package/directives.html CHANGED
@@ -7,65 +7,57 @@
7
7
 
8
8
  <body>
9
9
 
10
-
11
- <p>
12
- Show: <input type="checkbox" :="${on}" l-bind="on">
10
+ <div style="margin:20px">
11
+ <p>
12
+ Show: <input type="checkbox" value="${on}">
13
13
  <div l-if="${on}">
14
- Show is true
14
+ Now you've done it. You've exposed me.
15
15
  </div>
16
- </p>
17
- <p>
18
-
19
- <input id="red" type="radio" name="myradio" value="red" :="${color}" l-bind="color"> Red
20
- <input id="yellow" type="radio" name="myradio" value="yellow" :="${color}" l-bind="color"> Yellow
21
- <input id="green" type="radio" name="myradio" value="green" :="${color}" l-bind="color"> Green
22
- </p>
23
-
24
- <p>
25
- <select l-bind="color" value="${color}">
26
- <option value="red">Red</option>
27
- <option value="yellow">Yellow</option>
28
- <option value="green">Green</option>
29
- </select>
30
- </p>
31
-
32
-
33
- <p>
34
- How would you like that burger?<br>
35
- <select l-bind="options" value="${options}" multiple>
36
- <option>lettuce</option>
37
- <option>tomato</option>
38
- <option>cheese</option>
39
- </select>
40
- </p>
41
-
42
-
43
-
44
- <ul l-for:each="${children}">
45
- <li>${index}:${element}</li>
46
- </ul>
47
- <ul l-for:values:value:index='{"1":"v1","2":"v2","3":"v3"}'>
48
- <li>${value}:${index}</li>
49
- </ul>
50
- <ul l-for:keys:key='{"name":"joe","age":27}'>
51
- <li>${key}</li>
52
- </ul>
53
- <ul l-for:entries:entry="${children}">
54
- <li>${entry[0]}:${entry[1]}</li>
55
- </ul>
56
-
57
- Variable Values
58
- <p id="variables"></p>
59
-
16
+ </p>
17
+ <p>
18
+
19
+ <p>
20
+ How would you like that burger?<br>
21
+ <select value="${options}" multiple>
22
+ <option>lettuce</option>
23
+ <option>tomato</option>
24
+ <option>cheese</option>
25
+ </select>
26
+ </p>
27
+
28
+
29
+ For (defaults to each)
30
+ <ul l-for:each="${options}">
31
+ <li>${index}:${item}</li>
32
+ </ul>
33
+ For Each
34
+ <ul l-for:each="${options}">
35
+ <li>${index}:${item}</li>
36
+ </ul>
37
+ For Values
38
+ <ul l-for:values="${options}">
39
+ <li>${item}:${index}</li>
40
+ </ul>
41
+ For Keys
42
+ <ul l-for:keys="${options}">
43
+ <li>${item}</li>
44
+ </ul>
45
+ For Entries
46
+ <ul l-for:entries="${options}">
47
+ <li>${item[0]}:${item[1]}</li>
48
+ </ul>
49
+
50
+ Variable Values
51
+ <p id="variables"></p>
52
+ </div>
60
53
  <script type="lightview/module">
61
- self.variables({on:boolean,off:boolean,color:string,children:Array,options:Array},{reactive});
54
+ self.variables({on:boolean,options:Array},{reactive});
62
55
 
63
56
  on = true;
64
- color = "yellow";
65
- children = ["John","Mary","Jane"];
66
- options = ["tomato"];
57
+ options = ["lettuce"];
67
58
 
68
- addEventListener("change",()=> {
59
+ // demo instrumentation
60
+ const variableValues = () => {
69
61
  const el = self.getElementById("variables");
70
62
  while(el.lastElementChild) el.lastElementChild.remove();
71
63
  self.getVariableNames().forEach((name) => {
@@ -73,7 +65,12 @@ addEventListener("change",()=> {
73
65
  line.innerText = `${name} = ${JSON.stringify(self.getValue(name))}`;
74
66
  el.appendChild(line);
75
67
  });
68
+ };
69
+ variableValues();
70
+ addEventListener("change",()=> {
71
+ variableValues()
76
72
  });
73
+
77
74
  </script>
78
75
  </body>
79
76
 
package/lightview.js CHANGED
@@ -264,14 +264,14 @@ const {observe} = (() => {
264
264
  nodes.push(node);
265
265
  } else if (node.nodeType === Node.ELEMENT_NODE) {
266
266
  let skip;
267
+ if(node.getAttribute("type")==="radio") nodes.push(node);
267
268
  [...node.attributes].forEach((attr) => {
268
269
  if (attr.value.includes("${")) {
269
270
  attr.template ||= attr.value;
270
- if (!nodes.includes(node)) nodes.push(node);
271
- }
272
- if (attr.name.includes(":") || attr.name.startsWith("l-")) {
271
+ nodes.push(node);
272
+ } else if (attr.name.includes(":") || attr.name.startsWith("l-")) {
273
273
  skip = attr.name.includes("l-for:");
274
- if (!nodes.includes(node)) nodes.push(node);
274
+ nodes.push(node)
275
275
  }
276
276
  })
277
277
  if (!skip && !node.shadowRoot) nodes.push(...getNodes(node));
@@ -281,7 +281,7 @@ const {observe} = (() => {
281
281
  return nodes;
282
282
  }
283
283
  const resolveNode = (node, component) => {
284
- if (node.template) {
284
+ if (node?.template) {
285
285
  try {
286
286
  const value = Function("context", "with(context) { return `" + node.template + "` }")(component.varsProxy);
287
287
  node.nodeValue = value === "null" || value === "undefined" ? "" : value;
@@ -289,11 +289,11 @@ const {observe} = (() => {
289
289
  if (!e.message.includes("defined")) throw e; // actually looking for undefined or not defined
290
290
  }
291
291
  }
292
- return node.nodeValue;
292
+ return node?.nodeValue;
293
293
  }
294
- const render = (template, render) => {
294
+ const render = (hasTemplate, render) => {
295
295
  let observer;
296
- if (template) {
296
+ if (hasTemplate) {
297
297
  if (observer) observer.cancel();
298
298
  observer = observe(render)
299
299
  } else {
@@ -302,7 +302,7 @@ const {observe} = (() => {
302
302
  }
303
303
  const inputTypeToType = (inputType) => {
304
304
  if (!inputType) return "any"
305
- if (["text", "tel", "email", "url", "search", "radio"].includes(inputType)) return "string";
305
+ if (["text", "tel", "email", "url", "search", "radio","color","password"].includes(inputType)) return "string";
306
306
  if (["number", "range"].includes(inputType)) return "number";
307
307
  if (["datetime"].includes(inputType)) return Date;
308
308
  if (["checkbox"].includes(inputType)) return "boolean";
@@ -314,38 +314,22 @@ const {observe} = (() => {
314
314
  addListener(node,"click", anchorHandler);
315
315
  })
316
316
  }
317
- const _bindForms = (node, component) => {
318
- [...node.querySelectorAll("input")].forEach((input) => bindInput(input, component))
319
- }
320
- const bindInput = (input, component) => {
321
- let name = input.getAttribute("name"),
322
- vname = input.getAttribute("l-bind") || name;
323
- name ||= vname;
324
- if (name) {
325
- if (!input.hasAttribute("l-bind")) input.setAttribute("l-bind", vname)
317
+ const bindInput = (input, name, component) => {
326
318
  const inputtype = input.tagName === "SELECT" ? "text" : input.getAttribute("type"),
327
319
  type = input.tagName === "SELECT" && input.hasAttribute("multiple") ? Array : inputTypeToType(inputtype),
328
320
  deflt = input.getAttribute("default"),
329
321
  value = input.getAttribute("value");
330
- let variable = component.vars[vname] || {type};
322
+ let variable = component.vars[name] || {type};
331
323
  if (type !== variable.type) {
332
324
  if (variable.type === "any" || variable.type === "unknown") variable.type = type;
333
- else throw new TypeError(`Attempt to bind <input name="${name}" type="${type}"> to variable ${vname}:${variable.type}`)
325
+ else throw new TypeError(`Attempt to bind <input name="${name}" type="${type}"> to variable ${name}:${variable.type}`)
334
326
  }
335
- component.variables({[vname]: type});
336
- variable = component.vars[vname];
337
- //if (value || deflt) {
338
- if (inputtype !== "radio") {
339
- if (value && !value.includes("${")) {
340
- variable.value = coerce(value, type);
341
- //input.setAttribute("value", `\${${name}}`);
342
- } else if (deflt && !deflt.includes("${")) {
343
- variable.value = coerce(deflt, type);
344
- //input.setAttribute("default", `\${${name}}`);
345
- }
327
+ component.variables({[name]: type});
328
+ let eventname = "change";
329
+ if(input.tagName!=="SELECT" && (!inputtype || ["text","number","tel","email","url","search","password"].includes(inputtype))) {
330
+ eventname = "input";
346
331
  }
347
- //}
348
- addListener(input,"change", (event) => {
332
+ addListener(input,eventname, (event) => {
349
333
  event.stopImmediatePropagation();
350
334
  const target = event.target;
351
335
  let value = target.value;
@@ -354,12 +338,18 @@ const {observe} = (() => {
354
338
  } else if (target.tagName === "SELECT") {
355
339
  if (target.hasAttribute("multiple")) {
356
340
  value = [...target.querySelectorAll("option")]
357
- .filter((option) => option.selected || option.getAttribute("value") == value || option.innerText == value)
341
+ .filter((option) => option.selected || resolveNode(option.attributes.value,component)==value || option.innerText == value)
358
342
  .map((option) => option.getAttribute("value") || option.innerText);
359
343
  }
360
344
  }
361
- component.varsProxy[vname] = coerce(value, type);
345
+ component.varsProxy[name] = coerce(value, type);
362
346
  })
347
+ }
348
+ const tryParse = (value) => {
349
+ try {
350
+ return JSON.parse(value);
351
+ } catch(e) {
352
+ return value;
363
353
  }
364
354
  }
365
355
  let reserved = {
@@ -372,7 +362,7 @@ const {observe} = (() => {
372
362
  exported: {value: true, constant: true},
373
363
  imported: {value: true, constant: true}
374
364
  };
375
- const createClass = (domElementNode, {observer, bindForms, importAnchors}) => {
365
+ const createClass = (domElementNode, {observer, importAnchors}) => {
376
366
  const instances = new Set(),
377
367
  dom = domElementNode.tagName === "TEMPLATE"
378
368
  ? domElementNode.content.cloneNode(true)
@@ -425,7 +415,6 @@ const {observe} = (() => {
425
415
  })
426
416
  });
427
417
  [...dom.childNodes].forEach((child) => shadow.appendChild(child.cloneNode(true)));
428
- if (bindForms) _bindForms(shadow, this);
429
418
  if (importAnchors) _importAnchors(shadow, this);
430
419
  }
431
420
 
@@ -459,9 +448,7 @@ const {observe} = (() => {
459
448
  const text = script.innerHTML.replaceAll(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, "$1").replaceAll(/\r?\n/g, "");
460
449
  currentScript.innerHTML = `Function('if(window["${scriptid}"]?.ctx) { with(window["${scriptid}"].ctx) { ${text}; } window["${scriptid}"](); }')(); `;
461
450
  let resolver;
462
- promises.push(new Promise((resolve) => {
463
- resolver = resolve;
464
- }));
451
+ promises.push(new Promise((resolve) => resolver = resolve));
465
452
  window[scriptid] = () => {
466
453
  delete window[scriptid];
467
454
  currentScript.remove();
@@ -471,49 +458,93 @@ const {observe} = (() => {
471
458
  ctx.appendChild(currentScript);
472
459
  }
473
460
  Promise.all(promises).then(() => {
474
- const inputs = [...ctx.shadowRoot.querySelectorAll("input[l-bind]"), ...ctx.shadowRoot.querySelectorAll("select[l-bind]")];
475
- inputs.forEach((input) => {
476
- bindInput(input, ctx);
477
- })
478
461
  const nodes = getNodes(ctx);
479
462
  nodes.forEach((node) => {
480
463
  if (node.nodeType === Node.TEXT_NODE && node.template.includes("${")) {
481
464
  render(!!node.template, () => resolveNode(node, this))
482
465
  } else if (node.nodeType === Node.ELEMENT_NODE) {
466
+ // resolve the value before all else;
467
+ const attr = node.attributes.value;
468
+ let name;
469
+ if(attr && attr.template) {
470
+ render(!!attr.template,() => {
471
+ const value = resolveNode(attr, this),
472
+ eltype = resolveNode(node.attributes.type,ctx);
473
+ if(eltype==="checkbox") {
474
+ if(coerce(value,"boolean")===true) {
475
+ node.setAttribute("checked","");
476
+ node.checked = true;
477
+ } else {
478
+ node.removeAttribute("checked");
479
+ node.checked = false;
480
+ }
481
+ const vname = resolveNode(node.attributes.name,ctx);
482
+ if(vname) ctx.setValue(vname,node.checked,{coerceTo:"boolean"});
483
+ }
484
+ if(node.tagName==="SELECT") {
485
+ let values = [value];
486
+ if(node.hasAttribute("multiple")) values = coerce(value,Array);
487
+ [...node.querySelectorAll("option")].forEach((option) => {
488
+ if(option.hasAttribute("value")) {
489
+ if (values.includes(resolveNode(option.attributes.value, ctx))) {
490
+ option.setAttribute("selected", "");
491
+ option.selected = true;
492
+ }
493
+ } else if(option.innerText.trim()===value) {
494
+ option.setAttribute("selected","");
495
+ option.selected = true;
496
+ }
497
+ })
498
+ }
499
+ });
500
+ let name;
501
+ for(const vname of this.getVariableNames()) {
502
+ if("${" + vname + "}" === attr.template) {
503
+ name = vname;
504
+ break;
505
+ }
506
+ }
507
+ if(name) bindInput(node,name,ctx);
508
+ }
483
509
  [...node.attributes].forEach((attr) => {
484
- const {name, value} = attr,
485
- [type, ...params] = name.split(":");
486
- if (type === "" || type=="checked" || node.tagName === "SELECT") { // name is :something
510
+ if(attr.name==="value") return;
511
+ const {name, value} = attr;
512
+ if(name==="type") {
513
+ if (value === "radio") {
514
+ const name = resolveNode(node.attributes.name, ctx);
515
+ for (const vname of this.getVariableNames()) {
516
+ if (vname === name) {
517
+ render(true, () => {
518
+ const name = resolveNode(node.attributes.name, ctx),
519
+ varvalue = Function("context", "with(context) { return `${" + name + "}` }")(ctx.varsProxy);
520
+ if (varvalue == resolveNode(node.attributes.value,ctx)) {
521
+ node.setAttribute("checked", "");
522
+ node.checked = true;
523
+ } else {
524
+ node.removeAttribute("checked");
525
+ node.checked = false;
526
+ }
527
+ });
528
+ bindInput(node, name, ctx);
529
+ break;
530
+ }
531
+ }
532
+ }
533
+ }
534
+
535
+ const [type, ...params] = name.split(":");
536
+ if (type === "") { // name is :something
487
537
  render(!!attr.template, () => {
488
- const attrtype = node.getAttribute("type"),
489
- value = resolveNode(attr, this),
490
- elvalue = node.getAttribute("value"),
491
- elname = node.getAttribute("name");
538
+ const value = attr.value,
539
+ elvalue = resolveNode(node.attributes.value,ctx),
540
+ eltype = resolveNode(node.attributes.type,ctx),
541
+ elname = resolveNode(node.attributes.name,ctx);
492
542
  if (params[0]) {
493
543
  if (value === "true") node.setAttribute(params[0], "")
494
544
  else node.removeAttribute(params[0]);
495
- } else if (attrtype === "checkbox" || node.tagName === "OPTION") {
496
- if (value === "true") {
497
- node.setAttribute("checked", "");
498
- } else {
499
- node.removeAttribute("checked");
500
- }
501
- } else if (attrtype === "radio") {
502
- if (elvalue === value) {
503
- node.setAttribute("checked", "");
504
- }
505
- } else if (name === "value" && node.tagName === "SELECT") {
506
- node.setAttribute("value", value);
507
- const values = value[0] === "[" ? JSON.parse(value) : value.split(","); // handle multiselect
508
- [...node.querySelectorAll("option")].forEach((option) => {
509
- if (option.hasAttribute("value")) {
510
- if (values.includes(option.getAttribute("value"))) {
511
- option.setAttribute("selected", true);
512
- }
513
- } else if (values.includes(option.innerText)) {
514
- option.setAttribute("selected", true);
515
- }
516
- })
545
+ } else if (eltype=== "checkbox" || node.tagName === "OPTION") {
546
+ if (value === "true") node.setAttribute("checked", "")
547
+ else node.removeAttribute("checked");
517
548
  }
518
549
  })
519
550
  } else if (type === "l-on") {
@@ -532,7 +563,7 @@ const {observe} = (() => {
532
563
  } else if (type === "l-for") {
533
564
  node.template ||= node.innerHTML;
534
565
  render(!!attr.template, () => {
535
- const [what = "each", vname = "element", index = "index", array = "array", after = false] = params,
566
+ const [what = "each", vname = "item", index = "index", array = "array", after = false] = params,
536
567
  value = resolveNode(attr, this),
537
568
  coerced = coerce(value, what === "each" ? Array : "object"),
538
569
  target = what === "each" ? coerced : Object[what](coerced),
@@ -652,9 +683,7 @@ const {observe} = (() => {
652
683
  variable.shared = true;
653
684
  addEventListener("change", ({variableName, value}) => {
654
685
  if (this.vars[variableName]?.shared) {
655
- this.siblings.forEach((instance) => {
656
- instance.setValue(variableName, value);
657
- })
686
+ this.siblings.forEach((instance) => instance.setValue(variableName, value))
658
687
  }
659
688
  })
660
689
  }
@@ -669,47 +698,6 @@ const {observe} = (() => {
669
698
  })
670
699
  }
671
700
  });
672
- addEventListener("change", ({variableName, value}) => {
673
- [...this.shadowRoot.querySelectorAll(`input[l-bind=${variableName}]`),
674
- ...this.shadowRoot.querySelectorAll(`select[l-bind=${variableName}]`)]
675
- .forEach((input) => {
676
- const eltype = input.getAttribute("type");
677
- if (eltype === "checkbox") { // at el option selected
678
- if(!!value) {
679
- input.setAttribute("checked", "");
680
- } else {
681
- input.removeAttribute("checked");
682
- }
683
- input.checked = !!value;
684
- } else if (eltype === "radio") {
685
- if (input.getAttribute("value") === value) {
686
- input.setAttribute("checked", "");
687
- input.checked = true;
688
- }
689
- } else if (input.tagName === "SELECT") {
690
- const values = value && typeof (value) === "object" && value instanceof Array ? value : [value];
691
- [...input.querySelectorAll("option")].forEach((option) => {
692
- if (values.includes(option.getAttribute("value") || option.innerText)) {
693
- option.setAttribute("selected", "");
694
- option.selected = true;
695
- }
696
- })
697
- } else if (!eltype || eltype === "text") {
698
- value = typeof (value) === "string" || value == null ? value : JSON.stringify(value);
699
- const oldvalue = input.getAttribute("value") || "";
700
- if (oldvalue !== value) {
701
- if (value == null) input.removeAttribute("value");
702
- else input.setAttribute("value", value);
703
- try {
704
- input.setSelectionRange(0, Math.max(oldvalue.length, value ? value.length : 0)); // shadowDom sometimes fails to rerender unless this is done;
705
- input.setRangeText(value || "", 0, Math.max(oldvalue.length, value ? value.length : 0));
706
- } catch (e) {
707
-
708
- }
709
- }
710
- }
711
- })
712
- })
713
701
  }
714
702
  return Object.entries(this.vars)
715
703
  .reduce((result, [key, variable]) => {
@@ -737,13 +725,13 @@ const {observe} = (() => {
737
725
  }
738
726
  }
739
727
  }
740
- const createComponent = (name, node, {observer, bindForms, importAnchors} = {}) => {
728
+ const createComponent = (name, node, {observer, importAnchors} = {}) => {
741
729
  let ctor = customElements.get(name);
742
730
  if (ctor) {
743
731
  console.warn(new Error(`${name} is already a CustomElement. Not redefining`));
744
732
  return ctor;
745
733
  }
746
- ctor = createClass(node, {observer, bindForms, importAnchors});
734
+ ctor = createClass(node, {observer, importAnchors});
747
735
  customElements.define(name, ctor);
748
736
  return ctor;
749
737
  }
@@ -759,10 +747,9 @@ const {observe} = (() => {
759
747
  const html = await (await fetch(url.href)).text(),
760
748
  dom = parser.parseFromString(html, "text/html"),
761
749
  importAnchors = !!dom.head.querySelector('meta[name="l-importAnchors"]'),
762
- bindForms = !!dom.head.querySelector('meta[name="l-bindForms"]'),
763
750
  unhide = !!dom.head.querySelector('meta[name="l-unhide"]');
764
751
  if (unhide) dom.body.removeAttribute("hidden");
765
- createComponent(as, dom.body, {observer, importAnchors, bindForms});
752
+ createComponent(as, dom.body, {observer, importAnchors});
766
753
  }
767
754
  return {as};
768
755
  }
@@ -773,9 +760,9 @@ const {observe} = (() => {
773
760
  }
774
761
  }
775
762
 
776
- const bodyAsComponent = ({as = "x-body", unhide, importAnchors, bindForms} = {}) => {
763
+ const bodyAsComponent = ({as = "x-body", unhide, importAnchors} = {}) => {
777
764
  const parent = document.body.parentElement;
778
- createComponent(as, document.body, {importAnchors, bindForms});
765
+ createComponent(as, document.body, {importAnchors});
779
766
  const component = document.createElement(as);
780
767
  parent.replaceChild(component, document.body);
781
768
  Object.defineProperty(document, "body", {
@@ -821,12 +808,11 @@ const {observe} = (() => {
821
808
  const loader = async (whenFramed) => {
822
809
  if (!!document.querySelector('meta[name="l-importLinks"]')) await importLinks();
823
810
  const importAnchors = !!document.querySelector('meta[name="l-importAnchors"]'),
824
- bindForms = !!document.querySelector('meta[name="l-bindForms"]'),
825
811
  unhide = !!document.querySelector('meta[name="l-unhide"]'),
826
812
  isolated = !!document.querySelector('meta[name="l-isolate"]'),
827
813
  enableFrames = !!document.querySelector('meta[name="l-enableFrames"]');
828
814
  if (whenFramed) {
829
- whenFramed({unhide, importAnchors, bindForms, isolated, enableFrames});
815
+ whenFramed({unhide, importAnchors, isolated, enableFrames});
830
816
  if (!isolated) {
831
817
  postMessage.enabled = true;
832
818
  addListener(window,"message", ({data}) => {
@@ -861,7 +847,7 @@ const {observe} = (() => {
861
847
  postMessage({type: "DOMContentLoaded"})
862
848
  }
863
849
  } else if (url.searchParams.has("as")) {
864
- bodyAsComponent({as: url.searchParams.get("as"), unhide, importAnchors, bindForms});
850
+ bodyAsComponent({as: url.searchParams.get("as"), unhide, importAnchors});
865
851
  }
866
852
  if (enableFrames) {
867
853
  postMessage.enabled = true;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lightview",
3
- "version": "1.3.0b",
4
- "description": "Small, simple, powerful web UI creation ...",
3
+ "version": "1.4.1b",
4
+ "description": "Small, simple, powerful web UI and micro front end creation ... imagine a blend of Svelte, React, Vue, Riot and more.",
5
5
  "main": "lightview.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -15,7 +15,13 @@
15
15
  "react",
16
16
  "angular",
17
17
  "riot",
18
- "vue"
18
+ "vue",
19
+ "moon",
20
+ "hyperapp",
21
+ "hyperhtml",
22
+ "micro front end",
23
+ "custom elements",
24
+ "web components"
19
25
  ],
20
26
  "author": "Simon Y. Blackwell",
21
27
  "license": "MIT",
package/remote.html CHANGED
@@ -9,7 +9,8 @@
9
9
 
10
10
  <body>
11
11
  <p>
12
- The component below is loaded from an alternate domain and running in an iframe.
12
+ The component below is loaded from an alternate domain and running in a child iframe.
13
+ The logging console is below the component in this frame.
13
14
  </p>
14
15
  <iframe id="myframe" src="https://lightview.dev/remoteform.html?id=myframe"></iframe>
15
16
  <div id="console" style="max-height:250px;scroll:auto"></div>
package/remoteform.html CHANGED
@@ -2,45 +2,73 @@
2
2
 
3
3
  <head>
4
4
  <title>Form</title>
5
- <meta name="l-bindForms">
6
5
  <script src="./lightview.js?as=x-body"></script>
7
- <script>Lightview.whenFramed(({as,unhide,importAnchors,bindForms,isolated,enableFrames}) => {
8
- Lightview.bodyAsComponent({as,unhide,importAnchors,bindForms,isolated,enableFrames});
6
+ <script>Lightview.whenFramed(({as,unhide,importAnchors,isolated,enableFrames}) => {
7
+ Lightview.bodyAsComponent({as,unhide,importAnchors,isolated,enableFrames});
9
8
  })</script>
10
9
  </head>
11
10
 
12
11
  <body style="height:fit-content;width:fit-content;display:flex;flex-direction:column;max-height:100%;overflow:auto;">
13
- <p>
14
- <button l-on:click="run">Run</button> <button l-on:click="reset">Reset</button> <button l-on:click="setNull">Set Null</button>
15
- </p>
16
- <form>
17
- <input name="name" type="text" value="Joe"><br>
18
- <input name="age" type="number" value="20"><br>
19
- </form>
20
- <div id="console"></div>
12
+ <div style="margin:20px">
13
+ <p>
14
+ <input type="text" value="${color}">
15
+ <input type="checkbox" value="${checked}">
16
+ <input type="radio" name="color" value="red">
17
+ <input type="radio" name="color" value="yellow">
18
+ <input type="radio" name="color" value="green">
19
+ <select value="${color}">
20
+ <option value="red">red</option>
21
+ <option>yellow</option>
22
+ <option> green </option>
23
+ </select>
24
+ <div>Hamburger options:</div>
25
+ <select value="${hamburger}" multiple>
26
+ <option value="lettuce">lettuce</option>
27
+ <option>tomato</option>
28
+ <option>cheese</option>
29
+ </select>
30
+ </p>
31
+ <p l-if="${checked}">
32
+ Now you've done it. You've exposed me.
33
+ </p>
34
+ <ul l-for="${hamburger}">
35
+ <li>${item}</li>
36
+ </ul>
37
+ <ul l-for:entries="${hamburger}">
38
+ <li>${item[0]}:${item[1]}</li>
39
+ </ul>
40
+ <ul l-for:values="${hamburger}">
41
+ <li>${item}</li>
42
+ </ul>
43
+ <p id="variables">
44
+
45
+ </p>
46
+ </div>
21
47
  <script type="lightview/module">
22
- self.variables({name:string,age:number},{exported,imported});
23
- self.run = () => {
24
- name = "Bill";
25
- age = 30;
26
- action("run");
27
- };
28
- self.reset = () => {
29
- name = "Joe";
30
- age = 20;
31
- const console = self.getElementById("console");
32
- while(console.lastElementChild) console.lastElementChild.remove();
33
- };
34
- self.setNull = () => {
35
- name = null;
36
- age = undefined;
37
- action("setNull");
48
+ self.variables({
49
+ color: string,
50
+ checked: boolean,
51
+ hamburger: Array
52
+ }, {
53
+ reactive
54
+ });
55
+ color = "green";
56
+ checked = true;
57
+ hamburger = ["lettuce"];
58
+ // demo instrumentation
59
+ const variableValues = () => {
60
+ const el = self.getElementById("variables");
61
+ while (el.lastElementChild) el.lastElementChild.remove();
62
+ self.getVariableNames().forEach((name) => {
63
+ const line = document.createElement("div");
64
+ line.innerText = `${name} = ${JSON.stringify(self.getValue(name))}`;
65
+ el.appendChild(line);
66
+ });
38
67
  };
39
- const action = (name) => {
40
- const div = document.createElement("div");
41
- div.innerText = name;
42
- self.getElementById("console").appendChild(div);
43
- }
68
+ variableValues();
69
+ addEventListener("change", () => {
70
+ variableValues()
71
+ });
44
72
  </script>
45
73
  </body>
46
74
 
package/scratch.html ADDED
@@ -0,0 +1,69 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Scratch</title>
6
+ <script src="./lightview.js?as=x-body"></script>
7
+ </head>
8
+ <body>
9
+ <div style="margin:20px;padding:5px;border:1px;border-style:solid;border-color:${color}">
10
+ <p>
11
+ <input type="text" value="${color}">
12
+ <input type="radio" name="color" value="red">
13
+ <input type="radio" name="color" value="yellow">
14
+ <input type="radio" name="color" value="green">
15
+ <select value="${color}">
16
+ <option value="red">red</option>
17
+ <option>yellow</option>
18
+ <option> green</option>
19
+ </select>
20
+ <div>Hamburger options:</div>
21
+ <select value="${hamburger}" multiple>
22
+ <option value="lettuce">lettuce</option>
23
+ <option>tomato</option>
24
+ <option>cheese</option>
25
+ </select>
26
+ </p>
27
+ Expose: <input type="checkbox" value="${checked}">
28
+ <p l-if="${checked}">
29
+ Now you've done it. You've exposed me.
30
+ </p>
31
+ <ul l-for="${hamburger}">
32
+ <li>${item}</li>
33
+ </ul>
34
+ <ul l-for:entries="${hamburger}">
35
+ <li>${item[0]}:${item[1]}</li>
36
+ </ul>
37
+ <ul l-for:values="${hamburger}">
38
+ <li>${item}</li>
39
+ </ul>
40
+ <p id="variables">
41
+
42
+ </p>
43
+ </div>
44
+ <script type="lightview/module">
45
+ self.variables({color:string,checked:boolean,hamburger:Array},{reactive});
46
+
47
+ color = "green";
48
+ checked = true;
49
+ hamburger = ["lettuce"];
50
+
51
+
52
+ // demo instrumentation
53
+ const variableValues = () => {
54
+ const el = self.getElementById("variables");
55
+ while (el.lastElementChild) el.lastElementChild.remove();
56
+ self.getVariableNames().forEach((name) => {
57
+ const line = document.createElement("div");
58
+ line.innerText = `${name} = ${JSON.stringify(self.getValue(name))}`;
59
+ el.appendChild(line);
60
+ });
61
+ };
62
+ variableValues();
63
+ addEventListener("change", () => {
64
+ variableValues()
65
+ });
66
+
67
+ </script>
68
+ </body>
69
+ </html>
package/xor.html CHANGED
@@ -5,12 +5,12 @@
5
5
  <template id="audiostream">
6
6
  <p>${name}</p>
7
7
  <p>
8
- Play: <input name="play" type="checkbox" l-bind="run" checked="${run}">
8
+ Play: <input type="checkbox" value="${run}">
9
9
  </p>
10
10
  <script type="lightview/module">
11
11
  self.variables({
12
12
  run: boolean
13
- });
13
+ },{reactive});
14
14
  self.variables({
15
15
  name: string
16
16
  }, {
@@ -31,9 +31,7 @@
31
31
  <title>Form</title>
32
32
  <script src="./lightview.js"></script>
33
33
  <script>
34
- Lightview.createComponent("x-audiostream", document.getElementById("audiostream"), {
35
- bindForms: true
36
- })
34
+ Lightview.createComponent("x-audiostream", document.getElementById("audiostream"))
37
35
  </script>
38
36
  </head>
39
37