sprae 11.6.0 → 12.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/core.js +229 -90
- package/directive/class.js +9 -13
- package/directive/default.js +2 -154
- package/directive/each.js +79 -75
- package/directive/else.js +22 -0
- package/directive/fx.js +2 -2
- package/directive/if.js +40 -34
- package/directive/ref.js +8 -7
- package/directive/scope.js +17 -0
- package/directive/spread.js +3 -0
- package/directive/style.js +9 -7
- package/directive/text.js +4 -4
- package/directive/value.js +39 -40
- package/dist/sprae.js +3 -495
- package/dist/sprae.js.map +4 -4
- package/dist/sprae.umd.js +3 -640
- package/dist/sprae.umd.js.map +4 -4
- package/micro.js +2 -0
- package/package.json +17 -14
- package/readme.md +432 -205
- package/signal.js +41 -40
- package/sprae.js +127 -18
- package/store.js +109 -96
- package/directive/aria.js +0 -6
- package/directive/data.js +0 -3
- package/directive/with.js +0 -12
- package/dist/sprae.auto.js +0 -662
- package/dist/sprae.auto.js.map +0 -7
- package/dist/sprae.auto.min.js +0 -5
- package/dist/sprae.auto.min.js.map +0 -7
- package/dist/sprae.min.js +0 -5
- package/dist/sprae.min.js.map +0 -7
- package/dist/sprae.umd.min.js +0 -5
- package/dist/sprae.umd.min.js.map +0 -7
package/signal.js
CHANGED
|
@@ -1,53 +1,54 @@
|
|
|
1
|
-
//
|
|
2
|
-
let current;
|
|
1
|
+
// preact-signals minimal implementation
|
|
2
|
+
let current, depth = 0, batched;
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
// default signals impl
|
|
5
|
+
|
|
6
|
+
export const signal = (v, _s, _obs = new Set, _v = () => _s.value) => (
|
|
7
|
+
_s = {
|
|
6
8
|
get value() {
|
|
7
|
-
current?.deps.push(
|
|
9
|
+
current?.deps.push(_obs.add(current));
|
|
8
10
|
return v
|
|
9
11
|
},
|
|
10
12
|
set value(val) {
|
|
11
13
|
if (val === v) return
|
|
12
14
|
v = val;
|
|
13
|
-
for (let sub of
|
|
15
|
+
for (let sub of _obs) batched ? batched.add(sub) : sub(); // notify effects
|
|
14
16
|
},
|
|
15
17
|
peek() { return v },
|
|
18
|
+
toJSON: _v, then: _v, toString: _v, valueOf: _v
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
export const effect = (fn, _teardown, _fx, _deps, __tmp) => (
|
|
23
|
+
_fx = (prev) => {
|
|
24
|
+
__tmp = _teardown;
|
|
25
|
+
_teardown = null; // we null _teardown to avoid repeated call in case of recursive update
|
|
26
|
+
__tmp?.call?.();
|
|
27
|
+
prev = current, current = _fx
|
|
28
|
+
if (depth++ > 10) throw 'Cycle detected';
|
|
29
|
+
try { _teardown = fn(); } finally { current = prev; depth-- }
|
|
16
30
|
},
|
|
17
|
-
|
|
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 = [],
|
|
31
|
+
_deps = _fx.deps = [],
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
peek: s.peek
|
|
33
|
+
_fx(),
|
|
34
|
+
(dep) => { _teardown?.call?.(); while (dep = _deps.pop()) dep.delete(_fx); }
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
export const computed = (fn, _s = signal(), _c, _e, _v = () => _c.value) => (
|
|
38
|
+
_c = {
|
|
39
|
+
get value() {
|
|
40
|
+
_e ||= effect(() => _s.value = fn());
|
|
41
|
+
return _s.value
|
|
38
42
|
},
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
peek: _s.peek,
|
|
44
|
+
toJSON: _v, then: _v, toString: _v, valueOf: _v
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
export const batch = (fn, _first = !batched) => {
|
|
49
|
+
batched ??= new Set;
|
|
50
|
+
try { fn(); }
|
|
51
|
+
finally { if (_first) { for (const fx of batched) fx(); batched = null } }
|
|
52
|
+
}
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
use = (s) => (
|
|
48
|
-
signal = s.signal,
|
|
49
|
-
effect = s.effect,
|
|
50
|
-
computed = s.computed,
|
|
51
|
-
batch = s.batch || batch,
|
|
52
|
-
untracked = s.untracked || untracked
|
|
53
|
-
)
|
|
54
|
+
export const untracked = (fn, _prev, _v) => (_prev = current, current = null, _v = fn(), current = _prev, _v)
|
package/sprae.js
CHANGED
|
@@ -1,20 +1,129 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import store from "./store.js";
|
|
2
|
+
import { batch, computed, effect, signal, untracked } from './signal.js';
|
|
3
|
+
import sprae, { use, directive, modifier, start, throttle, debounce, _add, _off, _state, _on, _dispose } from './core.js';
|
|
4
|
+
|
|
5
|
+
import _if from "./directive/if.js";
|
|
6
|
+
import _else from "./directive/else.js";
|
|
7
|
+
import _text from "./directive/text.js";
|
|
8
|
+
import _class from "./directive/class.js";
|
|
9
|
+
import _style from "./directive/style.js";
|
|
10
|
+
import _fx from "./directive/fx.js";
|
|
11
|
+
import _value from "./directive/value.js";
|
|
12
|
+
import _ref from "./directive/ref.js";
|
|
13
|
+
import _scope from "./directive/scope.js";
|
|
14
|
+
import _each from "./directive/each.js";
|
|
15
|
+
import _default from "./directive/default.js";
|
|
16
|
+
import _spread from "./directive/spread.js";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
Object.assign(directive, {
|
|
20
|
+
// :x="x"
|
|
21
|
+
'*': _default,
|
|
22
|
+
|
|
23
|
+
// :="{a,b,c}"
|
|
24
|
+
'': _spread,
|
|
25
|
+
|
|
26
|
+
// :class="[a, b, c]"
|
|
27
|
+
class: _class,
|
|
28
|
+
|
|
29
|
+
// :text="..."
|
|
30
|
+
text: _text,
|
|
31
|
+
|
|
32
|
+
// :style="..."
|
|
33
|
+
style: _style,
|
|
34
|
+
|
|
35
|
+
// :fx="..."
|
|
36
|
+
fx: _fx,
|
|
37
|
+
|
|
38
|
+
// :value - 2 way binding like x-model
|
|
39
|
+
value: _value,
|
|
40
|
+
|
|
41
|
+
// :ref="..."
|
|
42
|
+
ref: _ref,
|
|
43
|
+
|
|
44
|
+
// :scope creates variables scope for a subtree
|
|
45
|
+
scope: _scope,
|
|
46
|
+
|
|
47
|
+
if: _if,
|
|
48
|
+
else: _else,
|
|
49
|
+
|
|
50
|
+
// :each="v,k in src"
|
|
51
|
+
each: _each
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
Object.assign(modifier, {
|
|
55
|
+
debounce: (fn,
|
|
56
|
+
_how = 250,
|
|
57
|
+
_schedule = _how === "tick" ? queueMicrotask : _how === "raf" ? requestAnimationFrame : _how === "idle" ? requestIdleCallback : ((fn) => setTimeout(fn, _how)),
|
|
58
|
+
_count = 0
|
|
59
|
+
) =>
|
|
60
|
+
debounce(fn, _schedule),
|
|
61
|
+
|
|
62
|
+
throttle: (fn, _how = 250, _schedule = _how === "tick" ? queueMicrotask : _how === "raf" ? requestAnimationFrame : ((fn) => setTimeout(fn, _how))) => (
|
|
63
|
+
throttle(fn, _schedule)
|
|
64
|
+
),
|
|
65
|
+
|
|
66
|
+
once: (fn, _done, _fn) => Object.assign((e) => !_done && (_done = 1, fn(e)), { once: true }),
|
|
67
|
+
|
|
68
|
+
// event modifiers
|
|
69
|
+
// actions
|
|
70
|
+
prevent: (fn) => (e) => (e?.preventDefault(), fn(e)),
|
|
71
|
+
stop: (fn) => (e) => (e?.stopPropagation(), fn(e)),
|
|
72
|
+
immediate: (fn) => (e) => (e?.stopImmediatePropagation(), fn(e)),
|
|
73
|
+
|
|
74
|
+
// options
|
|
75
|
+
passive: fn => (fn.passive = true, fn),
|
|
76
|
+
capture: fn => (fn.capture = true, fn),
|
|
77
|
+
|
|
78
|
+
// target
|
|
79
|
+
window: fn => (fn.target = window, fn),
|
|
80
|
+
document: fn => (fn.target = document, fn),
|
|
81
|
+
parent: fn => (fn.target = fn.target.parentNode, fn),
|
|
82
|
+
|
|
83
|
+
// test
|
|
84
|
+
self: (fn) => (e) => (e.target === fn.target && fn(e)),
|
|
85
|
+
|
|
86
|
+
outside: (fn) => (e, _target) => (
|
|
87
|
+
_target = fn.target,
|
|
88
|
+
!_target.contains(e.target) && e.target.isConnected && (_target.offsetWidth || _target.offsetHeight)
|
|
89
|
+
),
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// key testers
|
|
93
|
+
const keys = {
|
|
94
|
+
ctrl: e => e.ctrlKey || e.key === "Control" || e.key === "Ctrl",
|
|
95
|
+
shift: e => e.shiftKey || e.key === "Shift",
|
|
96
|
+
alt: e => e.altKey || e.key === "Alt",
|
|
97
|
+
meta: e => e.metaKey || e.key === "Meta" || e.key === "Command",
|
|
98
|
+
arrow: e => e.key.startsWith("Arrow"),
|
|
99
|
+
enter: e => e.key === "Enter",
|
|
100
|
+
esc: e => e.key.startsWith("Esc"),
|
|
101
|
+
tab: e => e.key === "Tab",
|
|
102
|
+
space: e => e.key === " " || e.key === "Space" || e.key === " ",
|
|
103
|
+
delete: e => e.key === "Delete" || e.key === "Backspace",
|
|
104
|
+
digit: e => /^\d$/.test(e.key),
|
|
105
|
+
letter: e => /^\p{L}$/gu.test(e.key),
|
|
106
|
+
char: e => /^\S$/.test(e.key),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// augment modifiers with key testers
|
|
110
|
+
for (let k in keys) modifier[k] = (fn, ...params) => (e) => keys[k](e) && params.every(k => keys[k]?.(e) ?? e.key === k) && fn(e)
|
|
111
|
+
|
|
112
|
+
use({
|
|
113
|
+
compile: expr => {
|
|
114
|
+
return sprae.constructor(`with (arguments[0]) { ${expr} }`)
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// signals
|
|
118
|
+
signal, effect, computed, batch, untracked
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// expose for runtime config
|
|
122
|
+
sprae.use = use
|
|
123
|
+
sprae.store = store
|
|
124
|
+
sprae.directive = directive
|
|
125
|
+
sprae.modifier = modifier
|
|
126
|
+
sprae.start = start
|
|
19
127
|
|
|
20
128
|
export default sprae
|
|
129
|
+
export { sprae, store, signal, effect, computed, batch, untracked, start, use }
|
package/store.js
CHANGED
|
@@ -1,139 +1,152 @@
|
|
|
1
1
|
// signals-based proxy
|
|
2
|
-
import { signal, computed, batch } from './
|
|
3
|
-
import { parse } from './core.js';
|
|
2
|
+
import { signal, computed, batch, untracked } from './core.js'
|
|
4
3
|
|
|
4
|
+
|
|
5
|
+
// _signals allows both storing signals and checking instance, which would be difficult with WeakMap
|
|
5
6
|
export const _signals = Symbol('signals'),
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
7
|
+
_change = Symbol('change'),
|
|
8
|
+
_set = Symbol('set')
|
|
9
|
+
|
|
10
|
+
// object store is not lazy
|
|
11
|
+
// parent defines parent scope or sandbox
|
|
12
|
+
export const store = (values, parent = globalThis) => {
|
|
13
|
+
if (!values) return values
|
|
14
|
+
|
|
15
|
+
// ignore globals
|
|
16
|
+
if (values[Symbol.toStringTag]) return values;
|
|
17
|
+
|
|
18
|
+
// bypass existing store
|
|
19
|
+
if (values[_signals]) return values
|
|
20
|
+
|
|
21
|
+
// non-objects: for array redirect to list
|
|
22
|
+
if (values.constructor !== Object) return Array.isArray(values) ? list(values) : values
|
|
23
|
+
|
|
24
|
+
// _change stores total number of keys to track new props
|
|
25
|
+
// NOTE: be careful
|
|
26
|
+
let keyCount = Object.keys(values).length,
|
|
27
|
+
signals = { }
|
|
28
|
+
|
|
29
|
+
// proxy conducts prop access to signals
|
|
30
|
+
let state = new Proxy(Object.assign(signals, {[_change]: signal(keyCount), [_signals]: signals}), {
|
|
31
|
+
get: (_, k) => (k in signals ? (signals[k] ? signals[k].valueOf() : signals[k]) : parent[k]),
|
|
32
|
+
set: (_, k, v, _s) => (k in signals ? set(signals, k, v) : (create(signals, k, v), signals[_change].value = ++keyCount), 1), // bump length for new signal
|
|
33
|
+
// FIXME: try to avild calling Symbol.dispose here
|
|
34
|
+
deleteProperty: (_, k) => (k in signals && (k[0] != '_' && signals[k]?.[Symbol.dispose]?.(), delete signals[k], signals[_change].value = --keyCount), 1),
|
|
35
|
+
// subscribe to length when object is spread
|
|
36
|
+
ownKeys: () => (signals[_change].value, Reflect.ownKeys(signals)),
|
|
37
|
+
has: _ => 1 // sandbox prevents writing to global
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
// init signals for values
|
|
41
|
+
descs = Object.getOwnPropertyDescriptors(values)
|
|
42
|
+
|
|
43
|
+
for (let k in values) {
|
|
44
|
+
// getter turns into computed
|
|
45
|
+
if (descs[k]?.get)
|
|
46
|
+
// stash setter
|
|
47
|
+
(signals[k] = computed(descs[k].get.bind(state)))[_set] = descs[k].set?.bind(state);
|
|
48
|
+
|
|
49
|
+
// init blank signal - make sure we don't take prototype one
|
|
50
|
+
else create(signals, k, values[k])
|
|
51
|
+
}
|
|
33
52
|
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
return state
|
|
54
|
+
}
|
|
36
55
|
|
|
37
|
-
|
|
38
|
-
// getter turns into computed
|
|
39
|
-
if (descs[k]?.get)
|
|
40
|
-
// stash setter
|
|
41
|
-
(signals[k] = computed(descs[k].get.bind(state)))._set = descs[k].set?.bind(state);
|
|
56
|
+
const mut = ['push', 'pop', 'shift', 'unshift', 'splice']
|
|
42
57
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
signals[k] = null, set(signals, k, values[k]);
|
|
46
|
-
}
|
|
58
|
+
// array store - signals are lazy since arrays can be very large & expensive
|
|
59
|
+
const list = (values, parent = globalThis) => {
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
// gotta fill with null since proto methods like .reduce may fail
|
|
62
|
+
let signals = Array(values.length).fill(null),
|
|
50
63
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// track last accessed property to find out if .length was directly accessed from expression or via .push/etc method
|
|
54
|
-
let lastProp,
|
|
64
|
+
// if .length was accessed from mutator (.push/etc) method
|
|
65
|
+
isMut = false,
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
// since array mutator methods read .length internally only once, we disable it on the moment of call, allowing rest of operations to be reactive
|
|
68
|
+
mut = fn => function () {isMut = true; return fn.apply(this, arguments); },
|
|
58
69
|
|
|
59
|
-
|
|
60
|
-
signals = Array(values.length).fill(),
|
|
70
|
+
length = signal(values.length),
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
// proxy conducts prop access to signals
|
|
73
|
+
state = new Proxy(
|
|
74
|
+
Object.assign(signals, {
|
|
75
|
+
[_change]: length,
|
|
76
|
+
[_signals]: signals,
|
|
77
|
+
push: mut(signals.push),
|
|
78
|
+
pop: mut(signals.pop),
|
|
79
|
+
shift: mut(signals.shift),
|
|
80
|
+
unshift: mut(signals.unshift),
|
|
81
|
+
splice: mut(signals.splice),
|
|
82
|
+
}),
|
|
83
|
+
{
|
|
64
84
|
get(_, k) {
|
|
65
|
-
//
|
|
66
|
-
if (typeof k === 'symbol') return k === _change ? _len : k === _signals ? signals : signals[k]
|
|
85
|
+
// console.log('GET', k, isMut)
|
|
67
86
|
|
|
68
|
-
// if .length is read within
|
|
69
|
-
|
|
87
|
+
// if .length is read within mutators - peek signal to avoid recursive subscription
|
|
88
|
+
// we need to ignore it only once and keep for the rest of the mutator call
|
|
89
|
+
if (k === 'length') return isMut ? (isMut = false, signals.length) : length.value;
|
|
70
90
|
|
|
71
|
-
|
|
91
|
+
// non-numeric
|
|
92
|
+
if (typeof k === 'symbol' || isNaN(k)) return signals[k]?.valueOf() ?? parent[k];
|
|
72
93
|
|
|
73
94
|
// create signal (lazy)
|
|
74
95
|
// NOTE: if you decide to unlazy values, think about large arrays - init upfront can be costly
|
|
75
|
-
return (signals[k]
|
|
96
|
+
return (signals[k] ??= signal(store(values[k]))).valueOf()
|
|
76
97
|
},
|
|
77
98
|
|
|
78
99
|
set(_, k, v) {
|
|
100
|
+
// console.log('SET', k, v)
|
|
101
|
+
|
|
79
102
|
// .length
|
|
80
103
|
if (k === 'length') {
|
|
81
104
|
// force cleaning up tail
|
|
82
105
|
for (let i = v; i < signals.length; i++) delete state[i]
|
|
83
106
|
// .length = N directly
|
|
84
|
-
|
|
107
|
+
length.value = signals.length = v;
|
|
85
108
|
}
|
|
86
|
-
else {
|
|
87
|
-
set(signals, k, v)
|
|
88
109
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
110
|
+
// force changing length, if eg. a=[]; a[1]=1 - need to come after setting the item
|
|
111
|
+
else if (k >= signals.length) create(signals, k, v), state.length = +k + 1
|
|
112
|
+
|
|
113
|
+
// existing signal
|
|
114
|
+
else signals[k] ? set(signals, k, v) : create(signals, k, v)
|
|
92
115
|
|
|
93
116
|
return 1
|
|
94
117
|
},
|
|
95
118
|
|
|
119
|
+
// dispose notifies any signal deps, like :each
|
|
96
120
|
deleteProperty: (_, k) => (signals[k]?.[Symbol.dispose]?.(), delete signals[k], 1),
|
|
97
121
|
})
|
|
98
122
|
|
|
99
|
-
|
|
100
|
-
|
|
123
|
+
return state
|
|
124
|
+
}
|
|
101
125
|
|
|
102
|
-
//
|
|
103
|
-
const
|
|
126
|
+
// create signal value, skip untracked
|
|
127
|
+
const create = (signals, k, v) => (signals[k] = k[0] == '_' || v?.peek ? v : signal(store(v)))
|
|
104
128
|
|
|
105
129
|
// set/update signal value
|
|
106
|
-
const set = (signals, k, v) => {
|
|
107
|
-
let s = signals[k], cur
|
|
108
|
-
|
|
109
|
-
// untracked
|
|
110
|
-
if (k[0] === '_') signals[k] = v
|
|
111
|
-
// new property. preserve signal value as is
|
|
112
|
-
else if (!s) signals[k] = s = v?.peek ? v : signal(store(v))
|
|
130
|
+
const set = (signals, k, v, _s, _v) => {
|
|
113
131
|
// skip unchanged (although can be handled by last condition - we skip a few checks this way)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
return k[0] === '_' ? (signals[k] = v) :
|
|
133
|
+
(v !== (_v = (_s = signals[k]).peek())) && (
|
|
134
|
+
// stashed _set for value with getter/setter
|
|
135
|
+
_s[_set] ? _s[_set](v) :
|
|
136
|
+
// patch array
|
|
137
|
+
Array.isArray(v) && Array.isArray(_v) ?
|
|
138
|
+
// if we update plain array (stored in signal) - take over value instead
|
|
139
|
+
// since input value can be store, we have to make sure we don't subscribe to its length or values
|
|
140
|
+
// FIXME: generalize to objects
|
|
141
|
+
_change in _v ? untracked(() => batch(() => {
|
|
142
|
+
for (let i = 0; i < v.length; i++) _v[i] = v[i]
|
|
143
|
+
_v.length = v.length // forces deleting tail signals
|
|
144
|
+
})) : _s.value = v :
|
|
145
|
+
// .x = y
|
|
146
|
+
(_s.value = store(v))
|
|
147
|
+
)
|
|
128
148
|
}
|
|
129
149
|
|
|
130
|
-
// create expression setter, reflecting value back to state
|
|
131
|
-
export const setter = (expr, set = parse(`${expr}=${_stash}`)) => (
|
|
132
|
-
(state, value) => (
|
|
133
|
-
state[_stash] = value, // save value to stash
|
|
134
|
-
set(state)
|
|
135
|
-
)
|
|
136
|
-
)
|
|
137
150
|
|
|
138
151
|
// make sure state contains first element of path, eg. `a` from `a.b[c]`
|
|
139
152
|
// NOTE: we don't need since we force proxy sandbox
|
package/directive/aria.js
DELETED
package/directive/data.js
DELETED
package/directive/with.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import sprae, { dir } from "../core.js";
|
|
2
|
-
import { untracked } from "../signal.js";
|
|
3
|
-
import store, { _signals } from '../store.js';
|
|
4
|
-
|
|
5
|
-
dir('with', (el, rootState, state) => (
|
|
6
|
-
state=null,
|
|
7
|
-
values => !state ?
|
|
8
|
-
// NOTE: we force untracked because internal directives can eval outside of effects (like ref etc) that would cause unwanted subscribe
|
|
9
|
-
// FIXME: since this can be async effect, we should create & sprae it in advance.
|
|
10
|
-
untracked(() => sprae(el, state = store(values, rootState))) :
|
|
11
|
-
sprae(el, values)
|
|
12
|
-
))
|