sprae 10.10.6 → 10.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/readme.md CHANGED
@@ -105,13 +105,13 @@ Set style value.
105
105
 
106
106
  ```html
107
107
  <!-- extends style -->
108
- <div style="foo: bar" :style="'baz-baz: qux'">
108
+ <div style="foo: bar" :style="'bar-baz: qux'">
109
109
 
110
110
  <!-- object -->
111
- <div :style="{bazBaz: 'qux'}"></div>
111
+ <div :style="{barBaz: 'qux'}"></div>
112
112
 
113
113
  <!-- CSS variable -->
114
- <div :style="{'--baz-baz': qux}"></div>
114
+ <div :style="{'--bar-baz': qux}"></div>
115
115
  ```
116
116
 
117
117
  #### `:value="value"`
@@ -163,8 +163,8 @@ Expose element with `name`.
163
163
  <textarea :ref="text" placeholder="Enter text..."></textarea>
164
164
 
165
165
  <!-- iterable items -->
166
- <li :each="item in items" :ref="item">
167
- <input :onfocus..onblur="e => (item.classList.add('editing'), e => item.classList.remove('editing'))"/>
166
+ <li :each="item in items" :ref="li">
167
+ <input :onfocus..onblur="e => (li.classList.add('editing'), e => li.classList.remove('editing'))"/>
168
168
  </li>
169
169
  ```
170
170
 
@@ -176,7 +176,7 @@ Run effect, not changing any attribute.
176
176
  <div :fx="a.value ? foo() : bar()" />
177
177
 
178
178
  <!-- cleanup function -->
179
- <div :fx="id = setInterval(tick, interval), () => clearInterval(tick)" />
179
+ <div :fx="id = setInterval(tick, 1000), () => clearInterval(id)" />
180
180
  ```
181
181
 
182
182
  #### `:on<event>="handler"`, `:on<in>..on<out>="handler"`
@@ -304,7 +304,7 @@ name.value = 'Dolly';
304
304
 
305
305
  Provider | Size | Feature
306
306
  :---|:---|:---
307
- [`ulive`](https://ghub.io/ulive) (default) | 350b | Minimal implementation, basic performance, good for small states.
307
+ [`ulive`](https://ghub.io/ulive) | 350b | Minimal implementation, basic performance, good for small states.
308
308
  [`@webreflection/signal`](https://ghub.io/@webreflection/signal) | 531b | Class-based, better performance, good for small-medium states.
309
309
  [`usignal`](https://ghub.io/usignal) | 850b | Class-based with optimizations, good for medium states.
310
310
  [`@preact/signals-core`](https://ghub.io/@preact/signals-core) | 1.47kb | Best performance, good for any states, industry standard.
@@ -373,8 +373,10 @@ sprae.use({ compile })
373
373
  * Properties prefixed with `_` are untracked: `let state = sprae(el, {_x:2}); state._x++; // no effect`.
374
374
  * To destroy state and detach sprae handlers, call `element[Symbol.dispose]()`.
375
375
  * State getters/setters work as computed effects, eg. `sprae(el, { x:1, get x2(){ return this.x * 2} })`.
376
- * `this` keyword is not used, to get access to current element use `<input :ref="el" :text="el.value"/>`.
377
- * Async/await is not supported in attributes, it's a strong indicator you need to put these methods into state.
376
+ * `this` is not used, to get access to current element use `<input :ref="el" :text="el.value"/>`.
377
+ * `event` is not used, `:on*` attributes expect a function with event object as first argument `:onevt="event => handle()"`, see [#46](https://github.com/dy/sprae/issues/46).
378
+ * `key` is not used, `:each` uses direct list mapping instead of dom diffing.
379
+ * `await` is not supported in attributes, it’s a strong indicator you need to put these methods into state.
378
380
 
379
381
  ## Justification
380
382
 
package/signal.js CHANGED
@@ -1,5 +1,59 @@
1
+ // ulive copy, stable minimal implementation
2
+ let current, batched;
3
+
4
+ export let signal = (v, s, obs = new Set) => (
5
+ s = {
6
+ get value() {
7
+ current?.deps.push(obs.add(current));
8
+ return v
9
+ },
10
+ set value(val) {
11
+ if (val === v) return
12
+ v = val;
13
+ for (let sub of obs) batched ? batched.add(sub) : sub(); // notify effects
14
+ },
15
+ peek() { return v },
16
+ },
17
+ s.toJSON = s.then = s.toString = s.valueOf = () => s.value,
18
+ s
19
+ ),
20
+ effect = (fn, teardown, fx, deps) => (
21
+ fx = (prev) => {
22
+ teardown?.call?.();
23
+ prev = current, current = fx;
24
+ try { teardown = fn(); } finally { current = prev; }
25
+ },
26
+ deps = fx.deps = [],
27
+
28
+ fx(),
29
+ (dep) => { teardown?.call?.(); while (dep = deps.pop()) dep.delete(fx); }
30
+ ),
31
+ computed = (fn, s = signal(), c, e) => (
32
+ c = {
33
+ get value() {
34
+ e ||= effect(() => s.value = fn());
35
+ return s.value
36
+ },
37
+ peek: s.peek
38
+ },
39
+ c.toJSON = c.then = c.toString = c.valueOf = () => c.value,
40
+ c
41
+ ),
42
+ batch = (fn) => {
43
+ let fxs = batched;
44
+ if (!fxs) batched = new Set;
45
+ try { fn(); }
46
+ finally {
47
+ if (!fxs) {
48
+ fxs = batched;
49
+ batched = null;
50
+ for (const fx of fxs) fx();
51
+ }
52
+ }
53
+ },
54
+ untracked = (fn, prev, v) => (prev = current, current = null, v = fn(), current = prev, v);
55
+
1
56
  // signals adapter - allows switching signals implementation and not depend on core
2
- export let signal, effect, untracked, batch, computed;
3
57
 
4
58
  export function use(s) {
5
59
  signal = s.signal
package/sprae.js CHANGED
@@ -1,7 +1,5 @@
1
1
  import sprae from './core.js'
2
2
 
3
- import * as signals from 'ulive'
4
-
5
3
  // default directives
6
4
  import './directive/if.js'
7
5
  import './directive/each.js'
@@ -15,9 +13,6 @@ import './directive/value.js'
15
13
  import './directive/fx.js'
16
14
  import './directive/default.js'
17
15
 
18
- // default signals
19
- sprae.use(signals)
20
-
21
16
  // default compiler (indirect new Function to avoid detector)
22
17
  sprae.use({ compile: expr => sprae.constructor(`with (arguments[0]) { return ${expr} };`) })
23
18