sprae 2.14.2 → 3.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/package.json +3 -4
- package/r&d.md +24 -24
- package/readme.md +5 -87
- package/sprae.js +216 -566
- package/sprae.min.js +1 -1
- package/src/core.js +12 -6
- package/src/directives.js +8 -5
- package/src/state.js +113 -0
- package/test/dom.js +935 -0
- package/test/index.html +2 -1
- package/test/state.js +274 -0
- package/test/test.js +2 -922
- package/todo.md +4 -4
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprae",
|
|
3
3
|
"description": "DOM microhydration.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.1",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"module": "src/index.js",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@preact/signals-core": "^1.2.3",
|
|
10
|
-
"signal-struct": "^1.10.0",
|
|
11
9
|
"swapdom": "^1.1.1"
|
|
12
10
|
},
|
|
13
11
|
"devDependencies": {
|
|
@@ -16,6 +14,7 @@
|
|
|
16
14
|
"esbuild": "^0.15.14",
|
|
17
15
|
"hyperf": "^1.5.0",
|
|
18
16
|
"jsdom": "^21.1.0",
|
|
17
|
+
"signal-struct": "^1.10.0",
|
|
19
18
|
"terser": "^5.15.1",
|
|
20
19
|
"tst": "^7.1.1",
|
|
21
20
|
"usignal": "^0.8.9",
|
|
@@ -24,7 +23,7 @@
|
|
|
24
23
|
},
|
|
25
24
|
"scripts": {
|
|
26
25
|
"test": "node -r ./test/register.cjs test/test.js",
|
|
27
|
-
"build": "esbuild --bundle ./src/index.js --outfile=sprae.js --format=esm",
|
|
26
|
+
"build": "esbuild --bundle ./src/index.js --outfile=sprae.js --format=esm && npm run min",
|
|
28
27
|
"watch": "esbuild --bundle ./src/index.js --outfile=sprae.js --format=esm --sourcemap --watch",
|
|
29
28
|
"min": "terser sprae.js -o sprae.min.js --module -c passes=3 -m"
|
|
30
29
|
},
|
package/r&d.md
CHANGED
|
@@ -320,7 +320,7 @@
|
|
|
320
320
|
+ it has better control over serialization
|
|
321
321
|
+ `:onchange:oninput="e=>xyz"` is very good
|
|
322
322
|
|
|
323
|
-
## [
|
|
323
|
+
## [x] Sandbox? -> we need it anyways via Proxy, so yes
|
|
324
324
|
|
|
325
325
|
1. Use subscript?
|
|
326
326
|
+ solves access to any internal signals on syntactic level
|
|
@@ -365,6 +365,7 @@
|
|
|
365
365
|
+ does minimal catch
|
|
366
366
|
+ allows scope control
|
|
367
367
|
+ allows dynamic subscription to requested fields ( no need for preact/signals neither for signal-struct )
|
|
368
|
+
+ we anyways need sandbox even in case of subscript
|
|
368
369
|
|
|
369
370
|
## [x] :onclick="direct code" ? -> no: immediately invoked.
|
|
370
371
|
|
|
@@ -451,29 +452,28 @@
|
|
|
451
452
|
|
|
452
453
|
## [ ] Prop modifiers
|
|
453
454
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
* [ ] :x.always - update by _any_ dep change
|
|
455
|
+
- overall seems code complication without much benefit
|
|
456
|
+
* [ ] value.bind? value.watch?
|
|
457
|
+
- let's wait for use-case: value can be too big to set it every time
|
|
458
|
+
* [ ] prop.reflect, prop.observe
|
|
459
|
+
- let's wait for use-case
|
|
460
|
+
* [ ] prop.boolean, .number, .string, .array, .object
|
|
461
|
+
- let's wait for use-case
|
|
462
|
+
* [ ] prop.once, prop.fx ? prop.init?
|
|
463
|
+
- doesn't seem required, let's wait for use case
|
|
464
|
+
* [ ] prop.change - run only if value changes
|
|
465
|
+
- seems like unnecessary manual optimization that must be done always automatically
|
|
466
|
+
? are there cases where force-update is necessary?
|
|
467
|
+
* [ ] prop.throttle-xxx, prop.debounce-xxx
|
|
468
|
+
- let's wait until that's really a problem
|
|
469
|
+
* [ ] prop.class
|
|
470
|
+
? what's the use-case
|
|
471
|
+
* [ ] prop.next="" - run update after other DOM updates happen
|
|
472
|
+
* [ ] prop.fx="" - run effect without changing property
|
|
473
|
+
* [ ] x.prop="xyz" - set element property, rather than attribute (following topic)
|
|
474
|
+
* [ ] x.raf="abc" - run regularly?
|
|
475
|
+
* [ ] x.watch-a-b-c - update by change of any of the deps
|
|
476
|
+
* [ ] :x.always - update by _any_ dep change
|
|
477
477
|
|
|
478
478
|
## [x] Writing props on elements (like ones in :each) -> nah, just use `:x="this.x=abc"`
|
|
479
479
|
|
package/readme.md
CHANGED
|
@@ -22,6 +22,7 @@ Sprae defines attributes starting with `:` as directives:
|
|
|
22
22
|
|
|
23
23
|
* `sprae` initializes subtree with data and immediately evaporates `:` attrs.
|
|
24
24
|
* `state` is object reflecting current values, changing any of its props rerenders subtree.
|
|
25
|
+
* To batch-update multiple properties `sprae` can be run repeatedly as: `sprae(container, newValues)`
|
|
25
26
|
|
|
26
27
|
<!--
|
|
27
28
|
<details>
|
|
@@ -251,96 +252,13 @@ Expose element to data scope with the `id`:
|
|
|
251
252
|
</script>
|
|
252
253
|
```
|
|
253
254
|
|
|
255
|
+
## Sandbox
|
|
254
256
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
### Reactivity
|
|
258
|
-
|
|
259
|
-
_sprae_ is built on top of [_@preact/signals_](https://ghub.io/@preact/signals). That gives:
|
|
260
|
-
|
|
261
|
-
* Expressions don't require explicit access to `.value` (see [signal-struct](https://github.com/dy/signal-struct))
|
|
262
|
-
* Expressions support any reactive values in data (see [sube](https://github.com/dy/sube))
|
|
263
|
-
* Updates happen minimally only when used values update
|
|
264
|
-
* Subscription is weak and get disposed when element is disposed.
|
|
265
|
-
|
|
266
|
-
Directive expressions are natively reactive, ie. data may contain any async/reactive values, such as:
|
|
267
|
-
|
|
268
|
-
* _Promise_ / _Thenable_
|
|
269
|
-
* _Observable_ / _Subject_ / _Subscribable_
|
|
270
|
-
* _AsyncIterable_
|
|
271
|
-
* _observ-*_
|
|
272
|
-
* etc., see [sube](https://github.com/dy/sube/blob/main/README.md) for the full list.
|
|
273
|
-
|
|
274
|
-
This way, for example, _@preact/signals_ or _rxjs_ can be connected directly bypassing subscription or reading value.
|
|
275
|
-
-->
|
|
276
|
-
|
|
277
|
-
## Hints
|
|
278
|
-
|
|
279
|
-
**1.** To batch-update state (avoid multiple DOM changes), rerun sprae with new state:
|
|
280
|
-
|
|
281
|
-
```html
|
|
282
|
-
<li :each="item, id in items" :key="id" :text="item"></li>
|
|
283
|
-
|
|
284
|
-
<script type="module">
|
|
285
|
-
sprae(el, {items: ['foo', 'bar', 'baz']})
|
|
286
|
-
// <li>foo</li><li>bar</li><li>baz</li>
|
|
287
|
-
|
|
288
|
-
sprae(el, {items: ['foo', 'qux']})
|
|
289
|
-
// <li>foo</li><li>qux</li>
|
|
290
|
-
</script>
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
**2.** Data supports signal values, which can be an alternative way to control template state:
|
|
294
|
-
|
|
295
|
-
```html
|
|
296
|
-
<div id="done" :text="loading ? 'loading' : result">...</div>
|
|
297
|
-
|
|
298
|
-
<script type="module">
|
|
299
|
-
import sprae from 'sprae';
|
|
300
|
-
import { signal } from '@preact/signals';
|
|
257
|
+
Expressions are sandboxed, ie. have no access to global or window.
|
|
301
258
|
|
|
302
|
-
|
|
259
|
+
Default sandbox provides: _Array_, _Object_, _Number_, _String_, _Boolean_, _Date_, _console_.
|
|
303
260
|
|
|
304
|
-
|
|
305
|
-
sprae(done, { loading, result })
|
|
306
|
-
setTimeout(() => (loading.value = true, result.value = 'done'), 1000)
|
|
307
|
-
|
|
308
|
-
// <div id="done">loading</div>
|
|
309
|
-
|
|
310
|
-
// ... 1s after
|
|
311
|
-
// <div id="done">done</div>
|
|
312
|
-
</script>
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
**3.** Data recognizes reactive values as inputs as well: _Promise_ / _Thenable_, _Observable_ / _Subscribable_, _AsyncIterable_ (etc., see [sube](https://github.com/dy/sube/blob/main/README.md)). This way, for example, _rxjs_ can be connected to template directly.
|
|
316
|
-
|
|
317
|
-
```html
|
|
318
|
-
<div :text="clicks">#</div> clicks
|
|
319
|
-
|
|
320
|
-
<script type="module">
|
|
321
|
-
import sprae from 'sprae';
|
|
322
|
-
import { fromEvent, scan } from 'rxjs';
|
|
323
|
-
sprae(document, {
|
|
324
|
-
clicks: fromEvent(document, 'click').pipe(scan((count) => count + 1, 0))
|
|
325
|
-
});
|
|
326
|
-
</script>
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
**4.** Getters turn into computed values automatically (setters remain as is):
|
|
330
|
-
|
|
331
|
-
```html
|
|
332
|
-
<div id="x-plus-y">
|
|
333
|
-
<span :text="x">x</span> + <span :text="y">y</span> = <span :text="z">z</span>
|
|
334
|
-
</div>
|
|
335
|
-
|
|
336
|
-
<script type="module">
|
|
337
|
-
import sprae from 'sprae';
|
|
338
|
-
let state = sprae(document, { x:1, y:1, get z() { return this.x + this.y } })
|
|
339
|
-
|
|
340
|
-
state.x = 2, state.y = 2
|
|
341
|
-
state.z // 4
|
|
342
|
-
</script>
|
|
343
|
-
```
|
|
261
|
+
Sandbox can be extended via `Object.assign(sprae.globals, { BigInt, window, document })` etc.
|
|
344
262
|
|
|
345
263
|
## Examples
|
|
346
264
|
|