sprae 9.1.1 → 10.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 +66 -83
- package/directive/aria.js +2 -1
- package/directive/class.js +6 -5
- package/directive/data.js +4 -3
- package/directive/default.js +14 -16
- package/directive/each.js +84 -47
- package/directive/fx.js +2 -1
- package/directive/if.js +10 -8
- package/directive/ref.js +7 -7
- package/directive/style.js +4 -3
- package/directive/text.js +4 -3
- package/directive/value.js +2 -1
- package/directive/with.js +16 -0
- package/dist/sprae.js +326 -180
- package/dist/sprae.min.js +1 -1
- package/package.json +5 -4
- package/readme.md +67 -97
- package/signal.js +9 -42
- package/sprae.js +2 -3
- package/store.js +156 -0
- package/directive/scope.js +0 -10
package/core.js
CHANGED
|
@@ -1,97 +1,93 @@
|
|
|
1
|
+
import { effect, untracked, use } from "./signal.js";
|
|
2
|
+
import store, { _signals } from './store.js';
|
|
3
|
+
|
|
1
4
|
// polyfill
|
|
2
5
|
const _dispose = (Symbol.dispose ||= Symbol("dispose"));
|
|
3
6
|
|
|
4
7
|
// mark
|
|
5
8
|
const SPRAE = `∴`
|
|
6
9
|
|
|
7
|
-
// signals impl
|
|
8
|
-
export let signal, effect, batch, computed, untracked
|
|
9
|
-
|
|
10
10
|
// reserved directives - order matters!
|
|
11
11
|
export const directive = {};
|
|
12
12
|
|
|
13
13
|
// sprae element: apply directives
|
|
14
14
|
const memo = new WeakMap();
|
|
15
15
|
|
|
16
|
-
export default function sprae(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// repeated call can be caused by :each with new objects with old keys needs an update
|
|
20
|
-
if (memo.has(container)) {
|
|
21
|
-
const [state, effects] = memo.get(container)
|
|
22
|
-
// we rewrite signals instead of update, because user should have what he provided
|
|
23
|
-
for (let k in values) { state[k] = values[k] }
|
|
24
|
-
// since we call direct updates here, we have to make sure
|
|
25
|
-
// we don't subscribe outer effect, as in case of :each
|
|
26
|
-
untracked(() => { for (let fx of effects) fx() })
|
|
27
|
-
}
|
|
16
|
+
export default function sprae(els, values) {
|
|
17
|
+
let state
|
|
28
18
|
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (attr.name[0] === ':') {
|
|
41
|
-
el.removeAttribute(attr.name);
|
|
42
|
-
|
|
43
|
-
// multiple attributes like :id:for=""
|
|
44
|
-
let names = attr.name.slice(1).split(':')
|
|
45
|
-
|
|
46
|
-
// NOTE: secondary directives don't stop flow nor extend state, so no need to check
|
|
47
|
-
for (let name of names) {
|
|
48
|
-
let dir = directive[name] || directive.default
|
|
49
|
-
let evaluate = (dir.parse || parse)(attr.value, parse)
|
|
50
|
-
let update = dir(el, evaluate, state, name);
|
|
51
|
-
if (update) {
|
|
52
|
-
update[_dispose] = effect(update);
|
|
53
|
-
effects.push(update);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// stop if element was spraed by directive or skipped (detached) like in case of :if or :each
|
|
58
|
-
if (memo.has(el)) return;
|
|
59
|
-
if (el.parentNode !== parent) return false;
|
|
60
|
-
} else i++;
|
|
19
|
+
// make multiple items
|
|
20
|
+
if (!els?.[Symbol.iterator]) els = [els]
|
|
21
|
+
|
|
22
|
+
for (let el of els) {
|
|
23
|
+
// text nodes, comments etc - but collections are fine
|
|
24
|
+
if (el?.children) {
|
|
25
|
+
// repeated call can be caused by :each with new objects with old keys needs an update
|
|
26
|
+
if (memo.has(el)) {
|
|
27
|
+
// we rewrite signals instead of update, because user should have what he provided
|
|
28
|
+
Object.assign(memo.get(el), values)
|
|
61
29
|
}
|
|
62
|
-
|
|
30
|
+
else {
|
|
31
|
+
// take over existing state instead of creating clone
|
|
32
|
+
state ||= store(values || {});
|
|
63
33
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
34
|
+
init(el, state);
|
|
35
|
+
|
|
36
|
+
// if element was spraed by :with or :each instruction - skip, otherwise save
|
|
37
|
+
if (!memo.has(el)) memo.set(el, state);
|
|
38
|
+
}
|
|
67
39
|
}
|
|
68
40
|
};
|
|
69
41
|
|
|
70
|
-
|
|
42
|
+
return state;
|
|
43
|
+
}
|
|
71
44
|
|
|
72
|
-
|
|
73
|
-
|
|
45
|
+
// init directives on a single element
|
|
46
|
+
function init(el, state, parent = el.parentNode, effects = []) {
|
|
47
|
+
if (el.attributes) {
|
|
48
|
+
// init generic-name attributes second
|
|
49
|
+
for (let i = 0; i < el.attributes.length;) {
|
|
50
|
+
let attr = el.attributes[i];
|
|
51
|
+
|
|
52
|
+
if (attr.name[0] === ':') {
|
|
53
|
+
el.removeAttribute(attr.name);
|
|
54
|
+
|
|
55
|
+
// multiple attributes like :id:for=""
|
|
56
|
+
let names = attr.name.slice(1).split(':')
|
|
57
|
+
|
|
58
|
+
// NOTE: secondary directives don't stop flow nor extend state, so no need to check
|
|
59
|
+
for (let name of names) {
|
|
60
|
+
let dir = directive[name] || directive.default
|
|
61
|
+
let evaluate = (dir.parse || parse)(attr.value, parse)
|
|
62
|
+
let dispose = dir(el, evaluate, state, name);
|
|
63
|
+
if (dispose) effects.push(dispose);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// stop if element was spraed by internal directive
|
|
67
|
+
if (memo.has(el)) return;
|
|
68
|
+
|
|
69
|
+
// stop if element is skipped (detached) like in case of :if or :each
|
|
70
|
+
if (el.parentNode !== parent) return;
|
|
71
|
+
} else i++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
memo.set(container, [state, effects]);
|
|
77
|
-
container.classList?.add(SPRAE); // mark spraed element
|
|
75
|
+
for (let child of [...el.children]) init(child, state, el)
|
|
78
76
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
// mark spraed element
|
|
78
|
+
el.classList?.add(SPRAE);
|
|
79
|
+
el[_dispose] = () => {
|
|
80
|
+
while (effects.length) effects.pop()();
|
|
81
|
+
el.classList.remove(SPRAE);
|
|
82
|
+
memo.delete(el);
|
|
84
83
|
// NOTE: each child disposes own children etc.
|
|
85
|
-
let els =
|
|
84
|
+
let els = el.getElementsByClassName(SPRAE);
|
|
86
85
|
while (els.length) els[0][_dispose]?.()
|
|
87
86
|
}
|
|
87
|
+
};
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// default compiler
|
|
89
|
+
// compiler
|
|
93
90
|
const evalMemo = {};
|
|
94
|
-
|
|
95
91
|
const parse = (expr, dir, fn) => {
|
|
96
92
|
if (fn = evalMemo[expr = expr.trim()]) return fn
|
|
97
93
|
|
|
@@ -99,28 +95,15 @@ const parse = (expr, dir, fn) => {
|
|
|
99
95
|
try { fn = compile(expr); }
|
|
100
96
|
catch (e) { throw Object.assign(e, { message: `∴ ${e.message}\n\n${dir}${expr ? `="${expr}"\n\n` : ""}`, expr }) }
|
|
101
97
|
|
|
102
|
-
fn.expr = expr
|
|
103
|
-
|
|
104
98
|
// runtime errors
|
|
105
99
|
return evalMemo[expr] = fn
|
|
106
100
|
}
|
|
107
101
|
|
|
108
|
-
// compiler
|
|
109
102
|
export let compile
|
|
110
103
|
|
|
111
|
-
// DOM swapper
|
|
112
|
-
export let swap
|
|
113
|
-
|
|
114
104
|
// configure signals/compile/differ
|
|
115
105
|
// it's more compact than using sprae.signal = signal etc.
|
|
116
106
|
sprae.use = s => {
|
|
117
|
-
s.signal && (
|
|
118
|
-
|
|
119
|
-
effect = s.effect,
|
|
120
|
-
computed = s.computed,
|
|
121
|
-
batch = s.batch || (fn => fn()),
|
|
122
|
-
untracked = s.untracked || batch
|
|
123
|
-
);
|
|
124
|
-
s.swap && (swap = s.swap)
|
|
125
|
-
s.compile && (compile = s.compile)
|
|
107
|
+
s.signal && use(s);
|
|
108
|
+
s.compile && (compile = s.compile);
|
|
126
109
|
}
|
package/directive/aria.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
2
|
import { attr, dashcase } from './default.js'
|
|
3
|
+
import { effect } from "../signal.js";
|
|
3
4
|
|
|
4
5
|
directive['aria'] = (el, evaluate, state) => {
|
|
5
6
|
const update = (value) => {
|
|
6
7
|
for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
|
|
7
8
|
}
|
|
8
|
-
return () => update(evaluate(state)
|
|
9
|
+
return effect(() => update(evaluate(state)))
|
|
9
10
|
}
|
package/directive/class.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
2
|
import { ipol } from './default.js';
|
|
3
|
+
import { effect } from "../signal.js";
|
|
3
4
|
|
|
4
5
|
directive.class = (el, evaluate, state) => {
|
|
5
6
|
let cur = new Set
|
|
6
|
-
return () => {
|
|
7
|
+
return effect(() => {
|
|
7
8
|
let v = evaluate(state);
|
|
8
9
|
let clsx = new Set;
|
|
9
10
|
if (v) {
|
|
10
|
-
if (typeof v === "string") ipol(v
|
|
11
|
-
else if (Array.isArray(v)) v.map(v => (v = ipol(v
|
|
12
|
-
else Object.entries(v).map(([k, v]) => v
|
|
11
|
+
if (typeof v === "string") ipol(v, state).split(' ').map(cls => clsx.add(cls));
|
|
12
|
+
else if (Array.isArray(v)) v.map(v => (v = ipol(v, state)) && clsx.add(v));
|
|
13
|
+
else Object.entries(v).map(([k, v]) => v && clsx.add(k));
|
|
13
14
|
}
|
|
14
15
|
for (let cls of cur) if (clsx.has(cls)) clsx.delete(cls); else el.classList.remove(cls);
|
|
15
16
|
for (let cls of cur = clsx) el.classList.add(cls)
|
|
16
|
-
};
|
|
17
|
+
});
|
|
17
18
|
};
|
package/directive/data.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
|
+
import { effect } from "../signal.js";
|
|
2
3
|
|
|
3
4
|
directive['data'] = (el, evaluate, state) => {
|
|
4
|
-
return () => {
|
|
5
|
-
let value = evaluate(state)
|
|
5
|
+
return effect(() => {
|
|
6
|
+
let value = evaluate(state)
|
|
6
7
|
for (let key in value) el.dataset[key] = value[key];
|
|
7
|
-
}
|
|
8
|
+
})
|
|
8
9
|
}
|
package/directive/default.js
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
|
+
import { effect } from "../signal.js";
|
|
2
3
|
|
|
3
4
|
// set generic property directive
|
|
4
5
|
directive.default = (el, evaluate, state, name) => {
|
|
5
|
-
let evt = name.startsWith("on") && name.slice(2)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (name) attr(el, name, ipol(value, state))
|
|
18
|
-
else for (let key in value) attr(el, dashcase(key), ipol(value[key], state));
|
|
19
|
-
};
|
|
6
|
+
let evt = name.startsWith("on") && name.slice(2), off
|
|
7
|
+
return effect(
|
|
8
|
+
evt ?
|
|
9
|
+
() => (
|
|
10
|
+
off?.(), // intermediate teardown
|
|
11
|
+
off = on(el, evt, evaluate(state))
|
|
12
|
+
) :
|
|
13
|
+
() => {
|
|
14
|
+
let value = evaluate(state);
|
|
15
|
+
if (name) attr(el, name, ipol(value, state))
|
|
16
|
+
else for (let key in value) attr(el, dashcase(key), ipol(value[key], state));
|
|
17
|
+
});
|
|
20
18
|
};
|
|
21
19
|
|
|
22
20
|
|
|
@@ -148,5 +146,5 @@ export const dashcase = (str) => {
|
|
|
148
146
|
|
|
149
147
|
// interpolate a$<b> fields from context
|
|
150
148
|
export const ipol = (v, state) => {
|
|
151
|
-
return v?.replace ? v.replace(/\$<([^>]+)>/g, (match, field) => state[field]
|
|
149
|
+
return v?.replace ? v.replace(/\$<([^>]+)>/g, (match, field) => state[field] ?? '') : v
|
|
152
150
|
};
|
package/directive/each.js
CHANGED
|
@@ -1,59 +1,96 @@
|
|
|
1
|
-
import sprae, { directive
|
|
1
|
+
import sprae, { directive } from "../core.js";
|
|
2
|
+
import { _change, _signals } from "../store.js";
|
|
3
|
+
import { effect, untracked, computed } from '../signal.js';
|
|
2
4
|
|
|
3
|
-
export const _each = Symbol(":each");
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
+
export const _each = Symbol(":each");
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
(directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
|
|
8
|
+
directive.each = (tpl, [itemVar, idxVar, evaluate], state) => {
|
|
9
9
|
// we need :if to be able to replace holder instead of tpl for :if :each case
|
|
10
|
-
const holder = (tpl[_each] = document.createTextNode(""))
|
|
10
|
+
const holder = (tpl[_each] = document.createTextNode(""));
|
|
11
11
|
tpl.replaceWith(holder);
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
13
|
+
// we re-create items any time new items are produced
|
|
14
|
+
let cur, keys, prevl = 0
|
|
15
|
+
|
|
16
|
+
// separate computed effect reduces number of needed updates for the effect
|
|
17
|
+
const items = computed(() => {
|
|
18
|
+
keys = null
|
|
19
|
+
let items = evaluate(state)
|
|
20
|
+
if (typeof items === "number") items = Array.from({ length: items }, (_, i) => i + 1)
|
|
21
|
+
if (items?.constructor === Object) keys = Object.keys(items), items = Object.values(items)
|
|
22
|
+
return items || []
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const update = () => {
|
|
26
|
+
// NOTE: untracked avoids rerendering full list whenever internal items or props change
|
|
27
|
+
untracked(() => {
|
|
28
|
+
let i = 0, newItems = items.value, newl = newItems.length
|
|
29
|
+
|
|
30
|
+
// plain array update, not store (signal with array) - updates full list
|
|
31
|
+
if (cur && !(cur[_change])) {
|
|
32
|
+
for (let s of cur[_signals] || []) { s[Symbol.dispose]() }
|
|
33
|
+
cur = null, prevl = 0
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// delete
|
|
37
|
+
if (newl < prevl) {
|
|
38
|
+
cur.length = newl
|
|
39
|
+
}
|
|
40
|
+
// update, append, init
|
|
41
|
+
else {
|
|
42
|
+
// init
|
|
43
|
+
if (!cur) {
|
|
44
|
+
cur = newItems
|
|
45
|
+
}
|
|
46
|
+
// update
|
|
47
|
+
else {
|
|
48
|
+
for (; i < prevl; i++) {
|
|
49
|
+
cur[i] = newItems[i]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// append
|
|
54
|
+
for (; i < newl; i++) {
|
|
55
|
+
cur[i] = newItems[i]
|
|
56
|
+
let idx = i,
|
|
57
|
+
scope = Object.create(state, {
|
|
58
|
+
[itemVar]: { get() { return cur[idx] } },
|
|
59
|
+
[idxVar]: { value: keys ? keys[idx] : idx },
|
|
60
|
+
}),
|
|
61
|
+
el = (tpl.content || tpl).cloneNode(true), // single element or fragment
|
|
62
|
+
els = tpl.content ? [...el.childNodes] : [el] // total added elements
|
|
63
|
+
|
|
64
|
+
holder.before(el);
|
|
65
|
+
sprae(els, scope);
|
|
66
|
+
|
|
67
|
+
// signal/holder disposal removes element
|
|
68
|
+
((cur[_signals] ||= [])[i] ||= {})[Symbol.dispose] = () => {
|
|
69
|
+
for (let el of els) el[Symbol.dispose](), el.remove()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
prevl = newl
|
|
75
|
+
})
|
|
76
|
+
}
|
|
47
77
|
|
|
48
|
-
|
|
78
|
+
let planned = 0
|
|
79
|
+
return effect(() => {
|
|
80
|
+
// subscribe to items change (.length)
|
|
81
|
+
if (!cur) items.value[_change]?.value
|
|
82
|
+
|
|
83
|
+
// make first render immediately, debounce subsequent renders
|
|
84
|
+
if (!planned) {
|
|
85
|
+
update()
|
|
86
|
+
queueMicrotask(() => (planned && update(), planned = 0))
|
|
87
|
+
} else planned++
|
|
88
|
+
})
|
|
89
|
+
}
|
|
49
90
|
|
|
50
|
-
// document fragment
|
|
51
|
-
if (el.nodeType === 11) els.push(...el.childNodes); else els.push(el);
|
|
52
|
-
}
|
|
53
91
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}).parse = (expr, parse) => {
|
|
92
|
+
// redefine parser to exclude `[a in] b`
|
|
93
|
+
directive.each.parse = (expr, parse) => {
|
|
57
94
|
let [leftSide, itemsExpr] = expr.split(/\s+in\s+/);
|
|
58
95
|
let [itemVar, idxVar = "$"] = leftSide.split(/\s*,\s*/);
|
|
59
96
|
|
package/directive/fx.js
CHANGED
package/directive/if.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import sprae, { directive
|
|
1
|
+
import sprae, { directive } from "../core.js";
|
|
2
2
|
import { _each } from './each.js';
|
|
3
|
+
import { effect } from "../signal.js";
|
|
3
4
|
|
|
4
5
|
// :if is interchangeable with :each depending on order, :if :each or :each :if have different meanings
|
|
5
|
-
// as for :if :
|
|
6
|
-
// we consider :
|
|
6
|
+
// as for :if :with - :if must init first, since it is lazy, to avoid initializing component ahead of time by :with
|
|
7
|
+
// we consider :with={x} :if={x} case insignificant
|
|
7
8
|
const _prevIf = Symbol("if");
|
|
8
9
|
directive.if = (ifEl, evaluate, state) => {
|
|
9
10
|
let parent = ifEl.parentNode,
|
|
@@ -25,14 +26,15 @@ directive.if = (ifEl, evaluate, state) => {
|
|
|
25
26
|
else next.remove(), elses = next.content ? [...next.content.childNodes] : [next];
|
|
26
27
|
} else elses = none
|
|
27
28
|
|
|
28
|
-
return () => {
|
|
29
|
-
const newEls = evaluate(state)
|
|
29
|
+
return effect(() => {
|
|
30
|
+
const newEls = evaluate(state) ? ifs : ifEl[_prevIf] ? none : elses;
|
|
30
31
|
if (next) next[_prevIf] = newEls === ifs
|
|
31
32
|
if (cur != newEls) {
|
|
32
33
|
// :if :each
|
|
33
34
|
if (cur[0]?.[_each]) cur = [cur[0][_each]]
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
for (let el of cur) el.remove();
|
|
36
|
+
cur = newEls;
|
|
37
|
+
for (let el of cur) parent.insertBefore(el, holder), sprae(el, state);
|
|
36
38
|
}
|
|
37
|
-
};
|
|
39
|
+
});
|
|
38
40
|
};
|
package/directive/ref.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
|
+
import { _change, _signals } from "../store.js";
|
|
2
3
|
import { ipol } from './default.js';
|
|
3
4
|
|
|
4
5
|
// ref must be last within primaries, since that must be skipped by :each, but before secondaries
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}).parse = expr => expr
|
|
6
|
+
directive.ref = (el, expr, state) => {
|
|
7
|
+
// defining prop is needed for inherited scope, like :each or :with, since el cannot be signal
|
|
8
|
+
Object.defineProperty(state, ipol(expr, state), { value: el })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
directive.ref.parse = expr => expr
|
package/directive/style.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
2
|
import { ipol } from './default.js';
|
|
3
|
+
import { effect } from "../signal.js";
|
|
3
4
|
|
|
4
5
|
directive.style = (el, evaluate, state) => {
|
|
5
6
|
let initStyle = el.getAttribute("style") || "";
|
|
6
7
|
if (!initStyle.endsWith(";")) initStyle += "; ";
|
|
7
8
|
|
|
8
|
-
return () => {
|
|
9
|
-
let v = evaluate(state)
|
|
9
|
+
return effect(() => {
|
|
10
|
+
let v = evaluate(state);
|
|
10
11
|
if (typeof v === "string") el.setAttribute("style", initStyle + ipol(v, state));
|
|
11
12
|
else {
|
|
12
13
|
el.setAttribute("style", initStyle);
|
|
13
14
|
for (let k in v) el.style.setProperty(k, ipol(v[k], state));
|
|
14
15
|
}
|
|
15
|
-
};
|
|
16
|
+
});
|
|
16
17
|
};
|
package/directive/text.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
|
+
import { effect } from "../signal.js";
|
|
2
3
|
|
|
3
4
|
// set text content
|
|
4
5
|
directive.text = (el, evaluate, state) => {
|
|
5
6
|
if (el.content) el.replaceWith(el = document.createTextNode('')) // <template :text="abc"/>
|
|
6
7
|
|
|
7
|
-
return () => {
|
|
8
|
-
let value = evaluate(state)
|
|
8
|
+
return effect(() => {
|
|
9
|
+
let value = evaluate(state);
|
|
9
10
|
el.textContent = value == null ? "" : value;
|
|
10
|
-
};
|
|
11
|
+
});
|
|
11
12
|
};
|
package/directive/value.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { directive } from "../core.js";
|
|
2
2
|
import { attr } from './default.js';
|
|
3
|
+
import { effect } from "../signal.js";
|
|
3
4
|
|
|
4
5
|
// connect expr to element value
|
|
5
6
|
directive.value = (el, evaluate, state) => {
|
|
@@ -25,5 +26,5 @@ directive.value = (el, evaluate, state) => {
|
|
|
25
26
|
}
|
|
26
27
|
: (value) => (el.value = value);
|
|
27
28
|
|
|
28
|
-
return () => (update(evaluate(state)
|
|
29
|
+
return effect(() => (update(evaluate(state))));
|
|
29
30
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import sprae, { directive } from "../core.js";
|
|
2
|
+
import store, { _signals } from '../store.js';
|
|
3
|
+
import { effect } from "../signal.js";
|
|
4
|
+
|
|
5
|
+
directive.with = (el, evaluate, rootState) => {
|
|
6
|
+
let state, values
|
|
7
|
+
return effect(() => {
|
|
8
|
+
values = evaluate(rootState);
|
|
9
|
+
Object.assign(state ||= sprae(el,
|
|
10
|
+
store(
|
|
11
|
+
values,
|
|
12
|
+
Object.create(rootState[_signals])
|
|
13
|
+
)
|
|
14
|
+
), values)
|
|
15
|
+
})
|
|
16
|
+
};
|