lightview 1.8.2 → 2.0.1
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/.codacy/cli.sh +149 -0
- package/.codacy/codacy.yaml +15 -0
- package/.github/instructions/codacy.instructions.md +72 -0
- package/.wranglerignore +21 -0
- package/README.md +1330 -19
- package/_headers +4 -0
- package/build.js +70 -0
- package/components/actions/button.js +151 -0
- package/components/actions/dropdown.js +120 -0
- package/components/actions/modal.js +146 -0
- package/components/actions/swap.js +118 -0
- package/components/daisyui.js +288 -0
- package/components/data-display/accordion.js +128 -0
- package/components/data-display/alert.js +112 -0
- package/components/data-display/avatar.js +170 -0
- package/components/data-display/badge.js +82 -0
- package/components/data-display/card.js +151 -0
- package/components/data-display/carousel.js +94 -0
- package/components/data-display/chart.js +220 -0
- package/components/data-display/chat.js +128 -0
- package/components/data-display/collapse.js +103 -0
- package/components/data-display/countdown.js +69 -0
- package/components/data-display/diff.js +111 -0
- package/components/data-display/kbd.js +65 -0
- package/components/data-display/loading.js +75 -0
- package/components/data-display/progress.js +79 -0
- package/components/data-display/radial-progress.js +88 -0
- package/components/data-display/skeleton.js +66 -0
- package/components/data-display/stats.js +159 -0
- package/components/data-display/table.js +146 -0
- package/components/data-display/timeline.js +146 -0
- package/components/data-display/toast.js +72 -0
- package/components/data-display/tooltip.js +74 -0
- package/components/data-input/checkbox.js +253 -0
- package/components/data-input/file-input.js +224 -0
- package/components/data-input/input.js +264 -0
- package/components/data-input/radio.js +338 -0
- package/components/data-input/range.js +204 -0
- package/components/data-input/rating.js +219 -0
- package/components/data-input/select.js +287 -0
- package/components/data-input/textarea.js +287 -0
- package/components/data-input/toggle.js +201 -0
- package/components/index.js +137 -0
- package/components/layout/divider.js +72 -0
- package/components/layout/drawer.js +142 -0
- package/components/layout/footer.js +100 -0
- package/components/layout/hero.js +109 -0
- package/components/layout/indicator.js +90 -0
- package/components/layout/join.js +78 -0
- package/components/layout/navbar.js +110 -0
- package/components/navigation/breadcrumbs.js +91 -0
- package/components/navigation/dock.js +103 -0
- package/components/navigation/menu.js +126 -0
- package/components/navigation/pagination.js +105 -0
- package/components/navigation/steps.js +89 -0
- package/components/navigation/tabs.css +177 -0
- package/components/navigation/tabs.js +123 -0
- package/components/theme/theme-switch.css +65 -0
- package/components/theme/theme-switch.js +177 -0
- package/docs/about.html +164 -0
- package/docs/api/computed.html +184 -0
- package/docs/api/effects.html +173 -0
- package/docs/api/elements.html +180 -0
- package/docs/api/enhance.html +225 -0
- package/docs/api/hypermedia.html +165 -0
- package/docs/api/index.html +178 -0
- package/docs/api/nav.html +18 -0
- package/docs/api/signals.html +136 -0
- package/docs/api/state.html +217 -0
- package/docs/assets/images/logo-favicon.svg +42 -0
- package/docs/assets/images/logo-static.svg +40 -0
- package/docs/assets/images/logo.svg +66 -0
- package/docs/assets/js/examplify.js +395 -0
- package/docs/assets/styles/site.css +1102 -0
- package/docs/assets/styles/themes.css +236 -0
- package/docs/components/accordion.html +439 -0
- package/docs/components/alert.html +528 -0
- package/docs/components/avatar.html +586 -0
- package/docs/components/badge.html +531 -0
- package/docs/components/breadcrumbs.html +278 -0
- package/docs/components/button.html +579 -0
- package/docs/components/card.html +561 -0
- package/docs/components/carousel.html +286 -0
- package/docs/components/chart-area.html +702 -0
- package/docs/components/chart-bar.html +782 -0
- package/docs/components/chart-column.html +735 -0
- package/docs/components/chart-line.html +794 -0
- package/docs/components/chart-pie.html +823 -0
- package/docs/components/chart.html +610 -15
- package/docs/components/chat.html +547 -0
- package/docs/components/checkbox.html +641 -0
- package/docs/components/collapse.html +536 -0
- package/docs/components/component-nav.html +53 -0
- package/docs/components/countdown.html +470 -0
- package/docs/components/diff.html +245 -0
- package/docs/components/divider.html +240 -0
- package/docs/components/dock.html +277 -0
- package/docs/components/drawer.html +515 -0
- package/docs/components/dropdown.html +479 -0
- package/docs/components/file-input.html +591 -0
- package/docs/components/footer.html +301 -0
- package/docs/components/gallery.html +504 -0
- package/docs/components/hero.html +264 -0
- package/docs/components/index.css +840 -0
- package/docs/components/index.html +735 -0
- package/docs/components/indicator.html +342 -0
- package/docs/components/input.html +644 -0
- package/docs/components/join.html +285 -0
- package/docs/components/kbd.html +322 -0
- package/docs/components/loading.html +521 -0
- package/docs/components/menu.html +461 -0
- package/docs/components/modal.html +639 -0
- package/docs/components/navbar.html +321 -0
- package/docs/components/pagination.html +279 -0
- package/docs/components/progress.html +514 -0
- package/docs/components/radial-progress.html +434 -0
- package/docs/components/radio.html +655 -0
- package/docs/components/range.html +611 -0
- package/docs/components/rating.html +642 -0
- package/docs/components/select.html +696 -0
- package/docs/components/sidebar-setup.js +93 -0
- package/docs/components/skeleton.html +447 -0
- package/docs/components/spinner.html +68 -0
- package/docs/components/stats.html +486 -0
- package/docs/components/steps.html +356 -0
- package/docs/components/swap.html +517 -0
- package/docs/components/switch.html +68 -0
- package/docs/components/table.html +668 -0
- package/docs/components/tabs.html +506 -0
- package/docs/components/text-input.html +68 -0
- package/docs/components/textarea.html +603 -0
- package/docs/components/timeline.html +485 -42
- package/docs/components/toast.html +474 -0
- package/docs/components/toggle.html +564 -0
- package/docs/components/tooltip.html +423 -0
- package/docs/examples/getting-started-example.html +40 -0
- package/docs/examples/index.html +93 -0
- package/docs/getting-started/index.html +739 -0
- package/docs/getting-started/reviews.html +23 -0
- package/docs/getting-started/reviews.odom +108 -0
- package/docs/getting-started/reviews.vdom +84 -0
- package/docs/index.html +132 -42
- package/docs/playground.html +416 -0
- package/docs/router.html +285 -0
- package/docs/styles/index.html +190 -0
- package/functions/_middleware.js +32 -0
- package/index.html +309 -0
- package/lightview-router.js +364 -0
- package/lightview-x.js +1577 -0
- package/lightview.js +659 -1200
- package/middleware/locale.js +25 -0
- package/middleware/markdown.js +44 -0
- package/middleware/notFound.js +37 -0
- package/package.json +27 -41
- package/watch.js +92 -0
- package/wrangler.toml +12 -0
- package/.idea/lightview.iml +0 -12
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/LICENSE +0 -21
- package/codepen-no-tabs-embed.css +0 -2
- package/docs/CNAME +0 -1
- package/docs/api.html +0 -674
- package/docs/blank.html +0 -10
- package/docs/comparedto.html +0 -89
- package/docs/components/chart-repl.html +0 -69
- package/docs/components/components.js +0 -113
- package/docs/components/contents.html +0 -17
- package/docs/components/gantt-repl.html +0 -61
- package/docs/components/gantt.html +0 -42
- package/docs/components/gauge-repl.html +0 -66
- package/docs/components/gauge.html +0 -20
- package/docs/components/orgchart-repl.html +0 -64
- package/docs/components/orgchart.html +0 -41
- package/docs/components/repl-as-src.html +0 -17
- package/docs/components/repl-repl.html +0 -95
- package/docs/components/repl.html +0 -527
- package/docs/components/timeline-repl.html +0 -72
- package/docs/components.html +0 -14
- package/docs/css/highlightjs.min.css +0 -9
- package/docs/css/tutorial.css +0 -35
- package/docs/examples/anchor.html +0 -11
- package/docs/examples/chart.html +0 -34
- package/docs/examples/counter.html +0 -26
- package/docs/examples/counter.test.mjs +0 -47
- package/docs/examples/counter2.html +0 -26
- package/docs/examples/directives.html +0 -79
- package/docs/examples/foreign.html +0 -50
- package/docs/examples/forgeinform.html +0 -98
- package/docs/examples/form.html +0 -61
- package/docs/examples/gauge.html +0 -18
- package/docs/examples/invalid-template-literals.html +0 -44
- package/docs/examples/medium/remote.html +0 -60
- package/docs/examples/message.html +0 -18
- package/docs/examples/nested.html +0 -11
- package/docs/examples/object-bound-form.html +0 -34
- package/docs/examples/remote-server.js +0 -51
- package/docs/examples/remote.html +0 -34
- package/docs/examples/remote.json +0 -1
- package/docs/examples/scratch.html +0 -69
- package/docs/examples/sensors/index.html +0 -44
- package/docs/examples/sensors/sensor-server.js +0 -30
- package/docs/examples/shared.html +0 -41
- package/docs/examples/template.html +0 -33
- package/docs/examples/timeline.html +0 -21
- package/docs/examples/todo.html +0 -40
- package/docs/examples/top.html +0 -10
- package/docs/examples/types.html +0 -94
- package/docs/examples/xor.html +0 -62
- package/docs/examples.html +0 -25
- package/docs/javascript/codejar.min.js +0 -8
- package/docs/javascript/highlightjs.min.js +0 -1173
- package/docs/javascript/isomorphic-git.js +0 -9
- package/docs/javascript/json5.min.js +0 -1
- package/docs/javascript/lightning-fs.js +0 -1
- package/docs/javascript/lightview.js +0 -1285
- package/docs/javascript/marked.min.js +0 -6
- package/docs/javascript/peerjs.min.js +0 -70
- package/docs/javascript/turndown.js +0 -973
- package/docs/javascript/types.js +0 -606
- package/docs/javascript/utils.js +0 -45
- package/docs/lightview.html +0 -63
- package/docs/old_index.html +0 -965
- package/docs/old_index.md +0 -1132
- package/docs/slidein.html +0 -51
- package/docs/tutorial/0-getting-started.html +0 -67
- package/docs/tutorial/1-intro-to-variables.html +0 -103
- package/docs/tutorial/10-template-components.html +0 -80
- package/docs/tutorial/11-linked-components.html +0 -76
- package/docs/tutorial/12-imported-components.html +0 -67
- package/docs/tutorial/13-input-binding.html +0 -94
- package/docs/tutorial/14-automatic-variable-creation.html +0 -74
- package/docs/tutorial/15-form-binding.html +0 -110
- package/docs/tutorial/16-if-directive.html +0 -60
- package/docs/tutorial/17-loop-directives.html +0 -83
- package/docs/tutorial/18-sanitizing-and-escaping-input.html +0 -79
- package/docs/tutorial/2-imported-and-exported-variables.html +0 -80
- package/docs/tutorial/3-data-types.html +0 -89
- package/docs/tutorial/4-extended-data-types.html +0 -83
- package/docs/tutorial/5-extended-functional-types.html +0 -96
- package/docs/tutorial/5.1-extended-functional-types.html +0 -79
- package/docs/tutorial/5.2-extended-functional-types.html +0 -70
- package/docs/tutorial/6-conventional-javascript.html +0 -75
- package/docs/tutorial/7-monitoring-with-observers.html +0 -107
- package/docs/tutorial/8-event-listeners.html +0 -65
- package/docs/tutorial/9-intro-to-components.html +0 -91
- package/docs/tutorial/contents.html +0 -32
- package/docs/tutorial/my-component.html +0 -29
- package/docs/tutorial/remote-value.json +0 -4
- package/docs/websiterepl.html +0 -46
- package/jest-puppeteer.config.js +0 -5
- package/jest.config.json +0 -12
- package/lightview.min.js +0 -1
- package/lightview_good.js +0 -1267
- package/lightview_optimized.js +0 -1274
- package/repl_hold.html +0 -320
- package/test/basic.html +0 -104
- package/test/basic.test.mjs +0 -315
- package/test/extended.html +0 -29
- package/test/extended.test.mjs +0 -448
- package/types.js +0 -607
- package/unsplash.key +0 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<!-- SEO-friendly SPA Shim -->
|
|
2
|
+
<script src="/lightview-router.js"></script>
|
|
3
|
+
<script>
|
|
4
|
+
if (window.LightviewRouter) {
|
|
5
|
+
LightviewRouter.base('/index.html');
|
|
6
|
+
}
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="docs-layout">
|
|
10
|
+
<aside class="docs-sidebar" src="./nav.html"></aside>
|
|
11
|
+
|
|
12
|
+
<main class="docs-content">
|
|
13
|
+
<h1>Signals</h1>
|
|
14
|
+
<p>
|
|
15
|
+
Signals are the heart of Lightview's reactivity. They hold values that can change over time,
|
|
16
|
+
and automatically notify anything that depends on them.
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<h2>Creating Signals</h2>
|
|
20
|
+
<pre><code>const { signal } = Lightview;
|
|
21
|
+
|
|
22
|
+
// Create a signal with an initial value
|
|
23
|
+
const count = signal(0);
|
|
24
|
+
const name = signal('World');
|
|
25
|
+
const items = signal([]);
|
|
26
|
+
const user = signal({ name: 'Alice', age: 25 });</code></pre>
|
|
27
|
+
|
|
28
|
+
<h2>Reading Values</h2>
|
|
29
|
+
<pre><code>// Two ways to read
|
|
30
|
+
console.log(count.value); // Property access: 0
|
|
31
|
+
console.log(count()); // Function call: 0
|
|
32
|
+
|
|
33
|
+
// Both work identically - pick your style</code></pre>
|
|
34
|
+
|
|
35
|
+
<h2>Writing Values</h2>
|
|
36
|
+
<pre><code>// Two ways to write
|
|
37
|
+
count.value = 5; // Property assignment
|
|
38
|
+
count(10); // Function call with argument
|
|
39
|
+
|
|
40
|
+
// Both trigger reactive updates</code></pre>
|
|
41
|
+
|
|
42
|
+
<h2>Reactive UI</h2>
|
|
43
|
+
<p>
|
|
44
|
+
The magic happens when you use signals in your UI. Wrap expressions in functions to make them reactive:
|
|
45
|
+
</p>
|
|
46
|
+
<pre><code>const { signal, tags } = Lightview;
|
|
47
|
+
const { div, p, button } = tags;
|
|
48
|
+
|
|
49
|
+
const count = signal(0);
|
|
50
|
+
|
|
51
|
+
// Static - won't update
|
|
52
|
+
p(`Count: ${count.value}`) // ❌ "Count: 0" forever
|
|
53
|
+
|
|
54
|
+
// Reactive - updates automatically
|
|
55
|
+
p(() => `Count: ${count.value}`) // ✅ Updates when count changes!</code></pre>
|
|
56
|
+
|
|
57
|
+
<div class="code-example">
|
|
58
|
+
<div class="code-example-preview" id="signal-demo"></div>
|
|
59
|
+
<div class="code-example-code">
|
|
60
|
+
<pre><code>const count = signal(0);
|
|
61
|
+
|
|
62
|
+
div(
|
|
63
|
+
p(() => `Count: ${count.value}`),
|
|
64
|
+
button({ onclick: () => count.value++ }, '+1')
|
|
65
|
+
)</code></pre>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<h2>Named Signals</h2>
|
|
70
|
+
<p>
|
|
71
|
+
You can give signals a name for easy access across your application:
|
|
72
|
+
</p>
|
|
73
|
+
<pre><code>// Create a named signal and keep it in sessionStorage
|
|
74
|
+
const count = signal(0, 'count');
|
|
75
|
+
|
|
76
|
+
// Retrieve it elsewhere (even in another file)
|
|
77
|
+
const sameCount = signal.get('count');
|
|
78
|
+
|
|
79
|
+
// Get or create with default value
|
|
80
|
+
// If ' ' exists, returns it. If not, creates it with 100.
|
|
81
|
+
const score = signal.get('count', 0);</code></pre>
|
|
82
|
+
|
|
83
|
+
<h2>Stored Signals</h2>
|
|
84
|
+
<p>
|
|
85
|
+
You can store named signals in Storage objects (e.g. sessionStorage or localStorage) for persistence. It
|
|
86
|
+
will be saved any time there is a change.
|
|
87
|
+
</p>
|
|
88
|
+
<pre><code>const count = signal(0, {name:'count', storage:sessionStorage});
|
|
89
|
+
|
|
90
|
+
// Retrieve it elsewhere (even in another file)
|
|
91
|
+
const sameCount = signal.get('count');
|
|
92
|
+
|
|
93
|
+
// Get or create with default value
|
|
94
|
+
// If ' ' exists, returns it. If not, creates it with 100.
|
|
95
|
+
const score = signal.get('count', {storage:sessionStorage, defaultValue:0});</code></pre>
|
|
96
|
+
<p>Note: Manually updating the value in storage will not trigger updates.</p>
|
|
97
|
+
|
|
98
|
+
<h2>Tips & Patterns</h2>
|
|
99
|
+
|
|
100
|
+
<h3>Derived State</h3>
|
|
101
|
+
<p>For values computed from signals, use <a href="./computed">computed()</a> instead:</p>
|
|
102
|
+
<pre><code>const count = signal(0);
|
|
103
|
+
const doubled = computed(() => count.value * 2); // Auto-updates</code></pre>
|
|
104
|
+
|
|
105
|
+
<h3>Objects & Arrays</h3>
|
|
106
|
+
<p>For deep reactivity on objects/arrays, consider <a href="./state">state()</a>:</p>
|
|
107
|
+
<pre><code>// Signal: only triggers on reassignment
|
|
108
|
+
const items = signal([1, 2, 3]);
|
|
109
|
+
items.value.push(4); // ❌ Won't trigger update
|
|
110
|
+
items.value = [...items.value, 4]; // ✅ Triggers update
|
|
111
|
+
|
|
112
|
+
// State: deep reactivity
|
|
113
|
+
const items = state([1, 2, 3]);
|
|
114
|
+
items.push(4); // ✅ Triggers update automatically</code></pre>
|
|
115
|
+
</main>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<script>
|
|
119
|
+
(function () {
|
|
120
|
+
const { signal, tags } = Lightview;
|
|
121
|
+
const { div, p, button } = tags;
|
|
122
|
+
|
|
123
|
+
const count = signal(0);
|
|
124
|
+
|
|
125
|
+
const demo = div({ style: 'display: flex; align-items: center; gap: 1rem;' },
|
|
126
|
+
p({ style: 'margin: 0; font-size: 1.25rem;' }, () => `Count: ${count.value}`),
|
|
127
|
+
button({
|
|
128
|
+
onclick: () => count.value++,
|
|
129
|
+
style: 'padding: 0.5rem 1rem; cursor: pointer; background: var(--site-primary); color: white; border: none; border-radius: 6px;'
|
|
130
|
+
}, '+1')
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const container = document.getElementById('signal-demo');
|
|
134
|
+
if (container) container.appendChild(demo.domEl);
|
|
135
|
+
})();
|
|
136
|
+
</script>
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
<!-- SEO-friendly SPA Shim -->
|
|
2
|
+
<script src="/lightview-router.js"></script>
|
|
3
|
+
<script>
|
|
4
|
+
if (window.LightviewRouter) {
|
|
5
|
+
LightviewRouter.base('/index.html');
|
|
6
|
+
}
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="docs-layout">
|
|
10
|
+
<aside class="docs-sidebar" src="./nav.html"></aside>
|
|
11
|
+
|
|
12
|
+
<main class="docs-content">
|
|
13
|
+
<h1>State (Store)</h1>
|
|
14
|
+
<p>
|
|
15
|
+
State provides deep reactivity for objects and arrays. Unlike signals which only track reassignment,
|
|
16
|
+
state tracks nested property changes automatically.
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<h2>The Problem with Signals + Objects</h2>
|
|
20
|
+
<pre><code>// Signals only react to reassignment
|
|
21
|
+
const user = signal({ name: 'Alice', age: 25 });
|
|
22
|
+
|
|
23
|
+
user.value.age = 26; // ❌ Won't trigger updates!
|
|
24
|
+
user.value = { ...user.value, age: 26 }; // ✅ Works, but verbose
|
|
25
|
+
|
|
26
|
+
// Arrays have the same issue
|
|
27
|
+
const items = signal([1, 2, 3]);
|
|
28
|
+
items.value.push(4); // ❌ Won't trigger updates!
|
|
29
|
+
items.value = [...items.value, 4]; // ✅ Works, but tedious</code></pre>
|
|
30
|
+
|
|
31
|
+
<h2>State to the Rescue</h2>
|
|
32
|
+
<pre><code>const { state } = LightviewX;
|
|
33
|
+
|
|
34
|
+
// Deep reactivity - mutations work!
|
|
35
|
+
const user = state({ name: 'Alice', age: 25 });
|
|
36
|
+
|
|
37
|
+
user.age = 26; // ✅ Triggers updates!
|
|
38
|
+
user.name = 'Bob'; // ✅ Triggers updates!
|
|
39
|
+
|
|
40
|
+
// Arrays just work
|
|
41
|
+
const items = state([1, 2, 3]);
|
|
42
|
+
items.push(4); // ✅ Triggers updates!
|
|
43
|
+
items[0] = 10; // ✅ Triggers updates!
|
|
44
|
+
items.sort(); // ✅ Triggers updates!</code></pre>
|
|
45
|
+
|
|
46
|
+
<h2>Nested Objects</h2>
|
|
47
|
+
<p>State tracks changes at any depth:</p>
|
|
48
|
+
<pre><code>const app = state({
|
|
49
|
+
user: {
|
|
50
|
+
profile: {
|
|
51
|
+
name: 'Alice',
|
|
52
|
+
settings: {
|
|
53
|
+
theme: 'dark',
|
|
54
|
+
notifications: true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
items: []
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// All of these trigger updates:
|
|
62
|
+
app.user.profile.name = 'Bob';
|
|
63
|
+
app.user.profile.settings.theme = 'light';
|
|
64
|
+
app.items.push({ id: 1, text: 'Hello' });</code></pre>
|
|
65
|
+
|
|
66
|
+
<h2>In the UI</h2>
|
|
67
|
+
|
|
68
|
+
<div class="code-example">
|
|
69
|
+
<div class="code-example-preview" id="state-demo"></div>
|
|
70
|
+
<div class="code-example-code">
|
|
71
|
+
<pre><code>const todos = state([
|
|
72
|
+
{ text: 'Learn Lightview', done: true },
|
|
73
|
+
{ text: 'Build app', done: false }
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
div(
|
|
77
|
+
ul(() => todos.map((todo, i) =>
|
|
78
|
+
li(
|
|
79
|
+
input({
|
|
80
|
+
type: 'checkbox',
|
|
81
|
+
checked: todo.done,
|
|
82
|
+
onchange: () => todos[i].done = !todos[i].done
|
|
83
|
+
}),
|
|
84
|
+
span(todo.text)
|
|
85
|
+
)
|
|
86
|
+
)),
|
|
87
|
+
button({ onclick: () => todos.push({ text: 'New', done: false }) }, 'Add')
|
|
88
|
+
)</code></pre>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<h2>Array Methods</h2>
|
|
93
|
+
<p>All mutating array methods are reactive:</p>
|
|
94
|
+
<pre><code>const items = state([1, 2, 3]);
|
|
95
|
+
|
|
96
|
+
items.push(4); // Add to end
|
|
97
|
+
items.pop(); // Remove from end
|
|
98
|
+
items.shift(); // Remove from start
|
|
99
|
+
items.unshift(0); // Add to start
|
|
100
|
+
items.splice(1, 1); // Remove at index
|
|
101
|
+
items.sort(); // Sort in place
|
|
102
|
+
items.reverse(); // Reverse in place
|
|
103
|
+
items.fill(0); // Fill with value</code></pre>
|
|
104
|
+
|
|
105
|
+
<h2>Named State</h2>
|
|
106
|
+
<p>
|
|
107
|
+
Like signals, you can name state objects for global access. This is especially useful for
|
|
108
|
+
shared application state:
|
|
109
|
+
</p>
|
|
110
|
+
<pre><code>// Create named state
|
|
111
|
+
const appState = state({
|
|
112
|
+
user: 'Guest',
|
|
113
|
+
theme: 'dark'
|
|
114
|
+
}, 'app');
|
|
115
|
+
|
|
116
|
+
// Retrieve it anywhere
|
|
117
|
+
const globalState = state.get('app');
|
|
118
|
+
|
|
119
|
+
// Get or create
|
|
120
|
+
const settings = state.get('settings', { notifications: true });</code></pre>
|
|
121
|
+
|
|
122
|
+
<h2>Stored State</h2>
|
|
123
|
+
<p>
|
|
124
|
+
You can store named state objects in Storage objects (e.g. sessionStorage or localStorage) for persistence.
|
|
125
|
+
It will be saved any time there is a change. Objects are automatically
|
|
126
|
+
serialized to JSON and deserialized back to objects.
|
|
127
|
+
</p>
|
|
128
|
+
<pre><code>const user = state({name:'Guest', theme:'dark'}, {name:'user', storage:sessionStorage});
|
|
129
|
+
|
|
130
|
+
// Retrieve it elsewhere (even in another file)
|
|
131
|
+
const sameUser = state.get('user');
|
|
132
|
+
|
|
133
|
+
// Get or create with default value
|
|
134
|
+
// If 'user' exists, returns it. If not, creates it with default value.
|
|
135
|
+
const score = state.get('user', {storage:sessionStorage, defaultValue:{name:'Guest', theme:'dark'}});</code></pre>
|
|
136
|
+
<p>Note: Manually updating the object in storage will not trigger updates.</p>
|
|
137
|
+
|
|
138
|
+
<h2>Signal vs State</h2>
|
|
139
|
+
<table class="api-table">
|
|
140
|
+
<thead>
|
|
141
|
+
<tr>
|
|
142
|
+
<th>Use Signal</th>
|
|
143
|
+
<th>Use State</th>
|
|
144
|
+
</tr>
|
|
145
|
+
</thead>
|
|
146
|
+
<tbody>
|
|
147
|
+
<tr>
|
|
148
|
+
<td>Primitives (numbers, strings, bools)</td>
|
|
149
|
+
<td>Objects with nested properties</td>
|
|
150
|
+
</tr>
|
|
151
|
+
<tr>
|
|
152
|
+
<td>Simple objects (replace whole thing)</td>
|
|
153
|
+
<td>Objects you'll mutate in place</td>
|
|
154
|
+
</tr>
|
|
155
|
+
<tr>
|
|
156
|
+
<td>Arrays you'll replace</td>
|
|
157
|
+
<td>Arrays you'll push/pop/splice</td>
|
|
158
|
+
</tr>
|
|
159
|
+
<tr>
|
|
160
|
+
<td>Slightly better performance</td>
|
|
161
|
+
<td>More convenient API</td>
|
|
162
|
+
</tr>
|
|
163
|
+
</tbody>
|
|
164
|
+
</table>
|
|
165
|
+
|
|
166
|
+
<h2>Pro Tip</h2>
|
|
167
|
+
<p>
|
|
168
|
+
You can mix both! Use signals for simple values and state for complex structures:
|
|
169
|
+
</p>
|
|
170
|
+
<pre><code>const isLoading = signal(false); // Simple boolean → signal
|
|
171
|
+
const error = signal(null); // Simple value → signal
|
|
172
|
+
const items = state([]); // Array to mutate → state (from LightviewX)
|
|
173
|
+
const formData = state({ // Object to mutate → state (from LightviewX)
|
|
174
|
+
name: '',
|
|
175
|
+
email: '',
|
|
176
|
+
message: ''
|
|
177
|
+
});</code></pre>
|
|
178
|
+
</main>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<script>
|
|
182
|
+
(function () {
|
|
183
|
+
const { tags } = Lightview;
|
|
184
|
+
const { state } = LightviewX;
|
|
185
|
+
const { div, ul, li, input, span, button } = tags;
|
|
186
|
+
|
|
187
|
+
const todos = state([
|
|
188
|
+
{ text: 'Learn Lightview', done: true },
|
|
189
|
+
{ text: 'Build something', done: false }
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
const demo = div({ style: 'padding: 0.5rem;' },
|
|
193
|
+
ul({ style: 'list-style: none; padding: 0; margin: 0 0 1rem;' },
|
|
194
|
+
() => todos.map((todo, i) =>
|
|
195
|
+
li({ style: 'display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0;' },
|
|
196
|
+
input({
|
|
197
|
+
type: 'checkbox',
|
|
198
|
+
checked: todo.done,
|
|
199
|
+
onchange: () => todos[i].done = !todos[i].done,
|
|
200
|
+
style: 'cursor: pointer;'
|
|
201
|
+
}),
|
|
202
|
+
span({
|
|
203
|
+
style: () => `${todo.done ? 'text-decoration: line-through; opacity: 0.6;' : ''}`
|
|
204
|
+
}, todo.text)
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
),
|
|
208
|
+
button({
|
|
209
|
+
onclick: () => todos.push({ text: `Task ${todos.length + 1}`, done: false }),
|
|
210
|
+
style: 'padding: 0.5rem 1rem; cursor: pointer; background: var(--site-primary); color: white; border: none; border-radius: 6px;'
|
|
211
|
+
}, '+ Add Task')
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const container = document.getElementById('state-demo');
|
|
215
|
+
if (container) container.appendChild(demo.domEl);
|
|
216
|
+
})();
|
|
217
|
+
</script>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Vibrant Blue/Purple Gradient -->
|
|
4
|
+
<linearGradient id="bladeGradient" x1="100" y1="100" x2="400" y2="400" gradientUnits="userSpaceOnUse">
|
|
5
|
+
<stop offset="0%" stop-color="#0ea5e9" /> <!-- Sky Blue -->
|
|
6
|
+
<stop offset="50%" stop-color="#8b5cf6" /> <!-- Violet -->
|
|
7
|
+
<stop offset="100%" stop-color="#ec4899" /> <!-- Pink/Magenta -->
|
|
8
|
+
</linearGradient>
|
|
9
|
+
|
|
10
|
+
<!-- Glow effect for the center -->
|
|
11
|
+
<filter id="centerGlow" x="-50%" y="-50%" width="200%" height="200%">
|
|
12
|
+
<feGaussianBlur stdDeviation="15" result="blur"/>
|
|
13
|
+
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
|
|
14
|
+
</filter>
|
|
15
|
+
</defs>
|
|
16
|
+
|
|
17
|
+
<!-- Group centered and scaled up by 25% -->
|
|
18
|
+
<g transform="translate(256 256) scale(1.25)">
|
|
19
|
+
|
|
20
|
+
<!-- 8-blade Geometric Aperture -->
|
|
21
|
+
<g class="aperture-panels" stroke="none">
|
|
22
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(0)" />
|
|
23
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(45)" />
|
|
24
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(90)" />
|
|
25
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(135)" />
|
|
26
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(180)" />
|
|
27
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(225)" />
|
|
28
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(270)" />
|
|
29
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(315)" />
|
|
30
|
+
</g>
|
|
31
|
+
|
|
32
|
+
</g>
|
|
33
|
+
|
|
34
|
+
<!-- Central Pupil (needs to be grouped/transformed similarly or manually adjusted) -->
|
|
35
|
+
<!-- Since the pupil is defined by absolute coordinates cx=256 cy=256, we can just wrap it in a group with the same transform relative to the center -->
|
|
36
|
+
<g transform="translate(256 256) scale(1.25)">
|
|
37
|
+
<!-- Circle coordinates must be 0,0 relative to the group for the scale to work from center -->
|
|
38
|
+
<circle cx="0" cy="0" r="60" fill="url(#bladeGradient)" opacity="0.3" filter="url(#centerGlow)" />
|
|
39
|
+
<circle cx="0" cy="0" r="24" fill="url(#bladeGradient)" />
|
|
40
|
+
</g>
|
|
41
|
+
|
|
42
|
+
</svg>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Vibrant Blue/Purple Gradient -->
|
|
4
|
+
<linearGradient id="bladeGradient" x1="100" y1="100" x2="400" y2="400" gradientUnits="userSpaceOnUse">
|
|
5
|
+
<stop offset="0%" stop-color="#0ea5e9" /> <!-- Sky Blue -->
|
|
6
|
+
<stop offset="50%" stop-color="#8b5cf6" /> <!-- Violet -->
|
|
7
|
+
<stop offset="100%" stop-color="#ec4899" /> <!-- Pink/Magenta -->
|
|
8
|
+
</linearGradient>
|
|
9
|
+
|
|
10
|
+
<!-- Glow effect for the center -->
|
|
11
|
+
<filter id="centerGlow" x="-50%" y="-50%" width="200%" height="200%">
|
|
12
|
+
<feGaussianBlur stdDeviation="15" result="blur"/>
|
|
13
|
+
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
|
|
14
|
+
</filter>
|
|
15
|
+
</defs>
|
|
16
|
+
|
|
17
|
+
<!-- Group centered -->
|
|
18
|
+
<g transform="translate(256 256)">
|
|
19
|
+
|
|
20
|
+
<!-- 8-blade Geometric Aperture -->
|
|
21
|
+
<g class="aperture-panels" stroke="none">
|
|
22
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(0)" />
|
|
23
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(45)" />
|
|
24
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(90)" />
|
|
25
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(135)" />
|
|
26
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(180)" />
|
|
27
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(225)" />
|
|
28
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(270)" />
|
|
29
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(315)" />
|
|
30
|
+
</g>
|
|
31
|
+
|
|
32
|
+
</g>
|
|
33
|
+
|
|
34
|
+
<!-- Central Pupil -->
|
|
35
|
+
<g class="hero-pupil">
|
|
36
|
+
<circle cx="256" cy="256" r="60" fill="url(#bladeGradient)" opacity="0.3" filter="url(#centerGlow)" />
|
|
37
|
+
<circle cx="256" cy="256" r="24" fill="url(#bladeGradient)" />
|
|
38
|
+
</g>
|
|
39
|
+
|
|
40
|
+
</svg>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Vibrant Blue/Purple Gradient -->
|
|
4
|
+
<linearGradient id="bladeGradient" x1="100" y1="100" x2="400" y2="400" gradientUnits="userSpaceOnUse">
|
|
5
|
+
<stop offset="0%" stop-color="#0ea5e9" /> <!-- Sky Blue -->
|
|
6
|
+
<stop offset="50%" stop-color="#8b5cf6" /> <!-- Violet -->
|
|
7
|
+
<stop offset="100%" stop-color="#ec4899" /> <!-- Pink/Magenta -->
|
|
8
|
+
</linearGradient>
|
|
9
|
+
|
|
10
|
+
<!-- Glow effect for the center -->
|
|
11
|
+
<filter id="centerGlow" x="-50%" y="-50%" width="200%" height="200%">
|
|
12
|
+
<feGaussianBlur stdDeviation="15" result="blur"/>
|
|
13
|
+
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
|
|
14
|
+
</filter>
|
|
15
|
+
</defs>
|
|
16
|
+
|
|
17
|
+
<style>
|
|
18
|
+
.aperture-panels {
|
|
19
|
+
transform-origin: 0 0;
|
|
20
|
+
animation: aperture-spin 5s ease-in-out infinite;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@keyframes aperture-spin {
|
|
24
|
+
0% { transform: rotate(0deg); }
|
|
25
|
+
5% { transform: rotate(-45deg); }
|
|
26
|
+
8% { transform: rotate(0deg); }
|
|
27
|
+
100% { transform: rotate(0deg); }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.hero-pupil {
|
|
31
|
+
transform-origin: 256px 256px;
|
|
32
|
+
animation: pupil-blink 5s ease-in-out infinite;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@keyframes pupil-blink {
|
|
36
|
+
0% { transform: scale(1); opacity: 1; }
|
|
37
|
+
5% { transform: scale(0.1); opacity: 0; }
|
|
38
|
+
8% { transform: scale(1); opacity: 1; }
|
|
39
|
+
100% { transform: scale(1); opacity: 1; }
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
42
|
+
|
|
43
|
+
<!-- Group centered -->
|
|
44
|
+
<g transform="translate(256 256)">
|
|
45
|
+
|
|
46
|
+
<!-- 8-blade Geometric Aperture -->
|
|
47
|
+
<g class="aperture-panels" stroke="none">
|
|
48
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(0)" />
|
|
49
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(45)" />
|
|
50
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(90)" />
|
|
51
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(135)" />
|
|
52
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(180)" />
|
|
53
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(225)" />
|
|
54
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(270)" />
|
|
55
|
+
<path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(315)" />
|
|
56
|
+
</g>
|
|
57
|
+
|
|
58
|
+
</g>
|
|
59
|
+
|
|
60
|
+
<!-- Central Pupil -->
|
|
61
|
+
<g class="hero-pupil">
|
|
62
|
+
<circle cx="256" cy="256" r="60" fill="url(#bladeGradient)" opacity="0.3" filter="url(#centerGlow)" />
|
|
63
|
+
<circle cx="256" cy="256" r="24" fill="url(#bladeGradient)" />
|
|
64
|
+
</g>
|
|
65
|
+
|
|
66
|
+
</svg>
|