sprae 12.2.5 → 12.3.0
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 +47 -140
- package/directive/_.js +3 -0
- package/directive/class.js +9 -5
- package/directive/each.js +9 -11
- package/directive/else.js +2 -2
- package/directive/event.js +17 -0
- package/directive/if.js +3 -6
- package/directive/ref.js +6 -5
- package/directive/scope.js +7 -7
- package/directive/sequence.js +35 -0
- package/directive/style.js +11 -6
- package/directive/text.js +1 -1
- package/directive/value.js +1 -1
- package/dist/sprae.js +3 -3
- package/dist/sprae.js.map +4 -4
- package/dist/sprae.micro.js +5 -0
- package/dist/sprae.micro.js.map +7 -0
- package/dist/sprae.umd.js +3 -3
- package/dist/sprae.umd.js.map +4 -4
- package/micro.js +55 -1
- package/package.json +2 -2
- package/readme.md +7 -4
- package/signal.js +12 -11
- package/sprae.js +80 -37
- package/store.js +1 -1
- package/directive/default.js +0 -3
package/sprae.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import store from "./store.js";
|
|
2
|
-
import { batch, computed, effect, signal, untracked } from './
|
|
3
|
-
import
|
|
2
|
+
import { batch, computed, effect, signal, untracked } from './core.js';
|
|
3
|
+
import * as signals from './signal.js';
|
|
4
|
+
import sprae, { use, decorate, directive, modifier, parse, throttle, debounce, _off, _state, _on, _dispose, _add, call } from './core.js';
|
|
5
|
+
import pkg from './package.json' with { type: 'json' };
|
|
4
6
|
|
|
5
7
|
import _if from "./directive/if.js";
|
|
6
8
|
import _else from "./directive/else.js";
|
|
@@ -12,55 +14,64 @@ import _value from "./directive/value.js";
|
|
|
12
14
|
import _ref from "./directive/ref.js";
|
|
13
15
|
import _scope from "./directive/scope.js";
|
|
14
16
|
import _each from "./directive/each.js";
|
|
15
|
-
import _default from "./directive/
|
|
17
|
+
import _default from "./directive/_.js";
|
|
16
18
|
import _spread from "./directive/spread.js";
|
|
19
|
+
import _event from "./directive/event.js";
|
|
20
|
+
import _seq from "./directive/sequence.js";
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
Object.assign(directive, {
|
|
20
|
-
|
|
21
|
-
'*': _default,
|
|
22
|
-
|
|
23
|
-
// FIXME
|
|
24
|
-
// 'on*': _on,
|
|
25
|
-
|
|
26
|
-
// :="{a,b,c}"
|
|
24
|
+
_: (el, state, expr, name) => (name.startsWith('on') ? _event : _default)(el, state, expr, name),
|
|
27
25
|
'': _spread,
|
|
28
|
-
|
|
29
|
-
// :class="[a, b, c]"
|
|
30
26
|
class: _class,
|
|
31
|
-
|
|
32
|
-
// :text="..."
|
|
33
27
|
text: _text,
|
|
34
|
-
|
|
35
|
-
// :style="..."
|
|
36
28
|
style: _style,
|
|
37
|
-
|
|
38
|
-
// :fx="..."
|
|
39
29
|
fx: _fx,
|
|
40
|
-
|
|
41
|
-
// :value - 2 way binding like x-model
|
|
42
30
|
value: _value,
|
|
43
|
-
|
|
44
|
-
// :ref="..."
|
|
45
31
|
ref: _ref,
|
|
46
|
-
|
|
47
|
-
// :scope creates variables scope for a subtree
|
|
48
32
|
scope: _scope,
|
|
49
|
-
|
|
50
33
|
if: _if,
|
|
51
34
|
else: _else,
|
|
52
|
-
|
|
53
|
-
// :each="v,k in src"
|
|
54
35
|
each: _each
|
|
55
36
|
})
|
|
56
37
|
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Directive initializer (with modifiers support)
|
|
41
|
+
* @type {(el: HTMLElement, name:string, value:string, state:Object) => Function}
|
|
42
|
+
* */
|
|
43
|
+
const dir = (target, name, expr, state) => {
|
|
44
|
+
let [dirName, ...mods] = name.split('.'), create = directive[dirName] || directive._
|
|
45
|
+
|
|
46
|
+
return () => {
|
|
47
|
+
let update = create(target, state, expr, name)
|
|
48
|
+
|
|
49
|
+
if (!update?.call) return update?.[_dispose]
|
|
50
|
+
|
|
51
|
+
// throttle prevents multiple updates within one tick as well as isolates stack for each update
|
|
52
|
+
let trigger = decorate(Object.assign(throttle(() => change.value++), { target }), mods),
|
|
53
|
+
change = signal(0), // signal authorized to trigger effect: 0 = init; >0 = trigger
|
|
54
|
+
count = 0, // called effect count
|
|
55
|
+
evaluate = update.eval ?? parse(expr).bind(target),
|
|
56
|
+
_out, out = () => (_out && call(_out), _out=null) // effect trigger and invoke may happen in the same tick, so it will be effect-within-effect call - we need to store output of evaluate to return from trigger effect
|
|
57
|
+
|
|
58
|
+
state = target[_state] ?? state
|
|
59
|
+
|
|
60
|
+
return effect(() => (
|
|
61
|
+
// if planned count is same as actual count - plan new update, else update right away
|
|
62
|
+
change.value == count ? (trigger()) : (count = change.value, _out = evaluate(state, update)),
|
|
63
|
+
out
|
|
64
|
+
))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
Object.assign(modifier, {
|
|
58
69
|
// timing
|
|
59
70
|
debounce: (fn, _how = 250) => debounce(fn, (_how ||= 0, (fn) => setTimeout(fn, _how))),
|
|
60
71
|
throttle: (fn, _how = 250) => throttle(fn, (_how ||= 0, (fn) => setTimeout(fn, _how))),
|
|
61
|
-
tick: (fn) => (e) => queueMicrotask(() => fn(e)),
|
|
72
|
+
tick: (fn) => (e) => (queueMicrotask(() => fn(e))),
|
|
62
73
|
raf: (fn) => (e) => requestAnimationFrame(() => fn(e)),
|
|
63
|
-
once: (fn, _done, _fn) =>
|
|
74
|
+
once: (fn, _done, _fn) => (_fn = (e) => !_done && (_done = 1, fn(e)), _fn.once = true, _fn),
|
|
64
75
|
|
|
65
76
|
// target
|
|
66
77
|
window: fn => (fn.target = fn.target.ownerDocument.defaultView, fn),
|
|
@@ -87,7 +98,8 @@ const keys = {
|
|
|
87
98
|
ctrl: e => e.ctrlKey || e.key === "Control" || e.key === "Ctrl",
|
|
88
99
|
shift: e => e.shiftKey || e.key === "Shift",
|
|
89
100
|
alt: e => e.altKey || e.key === "Alt",
|
|
90
|
-
meta: e => e.metaKey || e.key === "Meta"
|
|
101
|
+
meta: e => e.metaKey || e.key === "Meta",
|
|
102
|
+
cmd: e => e.metaKey || e.key === "Command",
|
|
91
103
|
arrow: e => e.key.startsWith("Arrow"),
|
|
92
104
|
enter: e => e.key === "Enter",
|
|
93
105
|
esc: e => e.key.startsWith("Esc"),
|
|
@@ -100,23 +112,54 @@ const keys = {
|
|
|
100
112
|
};
|
|
101
113
|
|
|
102
114
|
// augment modifiers with key testers
|
|
103
|
-
for (let k in keys) modifier[k] = (fn,
|
|
115
|
+
for (let k in keys) modifier[k] = (fn, a, b) => (e) => keys[k](e) && (!a || keys[a]?.(e)) && (!b || keys[b]?.(e)) && fn(e)
|
|
116
|
+
|
|
104
117
|
|
|
105
118
|
use({
|
|
106
|
-
compile: expr => {
|
|
107
|
-
|
|
119
|
+
compile: expr => sprae.constructor(`with (arguments[0]) { ${expr} }`),
|
|
120
|
+
dir: (el, name, expr, state) => {
|
|
121
|
+
// sequences shortcut
|
|
122
|
+
if (name.includes('..')) return () => _seq(el, state, expr, name)[_dispose]
|
|
123
|
+
return name.split(':').reduce((prev, str) => {
|
|
124
|
+
let start = dir(el, str, expr, state)
|
|
125
|
+
return !prev ? start : (p, s) => (p = prev(), s = start(), () => { p(); s() })
|
|
126
|
+
}, null)
|
|
108
127
|
},
|
|
109
|
-
|
|
110
|
-
// signals
|
|
111
|
-
signal, effect, computed, batch, untracked
|
|
128
|
+
...signals
|
|
112
129
|
})
|
|
113
130
|
|
|
131
|
+
|
|
114
132
|
// expose for runtime config
|
|
115
133
|
sprae.use = use
|
|
116
134
|
sprae.store = store
|
|
117
135
|
sprae.directive = directive
|
|
118
136
|
sprae.modifier = modifier
|
|
119
|
-
sprae.
|
|
137
|
+
sprae.version = pkg.version;
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Lifecycle hanger: spraes automatically any new nodes
|
|
142
|
+
*/
|
|
143
|
+
const start = sprae.start = (root = document.body, values) => {
|
|
144
|
+
const state = store(values)
|
|
145
|
+
sprae(root, state);
|
|
146
|
+
const mo = new MutationObserver(mutations => {
|
|
147
|
+
for (const m of mutations) {
|
|
148
|
+
for (const el of m.addedNodes) {
|
|
149
|
+
// el can be spraed or removed by subsprae (like within :each/:if)
|
|
150
|
+
if (el.nodeType === 1 && el[_state] === undefined && root.contains(el)) {
|
|
151
|
+
// even if element has no spraeable attrs, some of its children can have
|
|
152
|
+
root[_add](el)
|
|
153
|
+
// sprae(el, state, root);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// for (const el of m.removedNodes) el[Symbol.dispose]?.()
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
mo.observe(root, { childList: true, subtree: true });
|
|
160
|
+
return state
|
|
161
|
+
}
|
|
162
|
+
|
|
120
163
|
|
|
121
164
|
// version placeholder for bundler
|
|
122
165
|
sprae.version = "[VI]{{inject}}[/VI]"
|
package/store.js
CHANGED
|
@@ -43,7 +43,7 @@ export const store = (values, parent) => {
|
|
|
43
43
|
},
|
|
44
44
|
|
|
45
45
|
set: (_, k, v, _s) => {
|
|
46
|
-
// console.group('SET', k, v
|
|
46
|
+
// console.group('SET', k, v)
|
|
47
47
|
if (k in signals) return set(signals, k, v), 1
|
|
48
48
|
|
|
49
49
|
// turn off sandbox to check if parents have the prop - we don't want to create new prop in global scope
|
package/directive/default.js
DELETED