sprae 12.2.5 → 12.3.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 +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 +9 -5
- package/signal.js +12 -11
- package/sprae.js +90 -43
- 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,68 @@ 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
|
-
// timing
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
// timing (lodash-like)
|
|
70
|
+
// FIXME: add immediate param
|
|
71
|
+
debounce: (fn, _how) => debounce(fn, (_how ||= 0, !_how ? undefined : _how === 'raf' ? requestAnimationFrame : (fn) => setTimeout(fn, _how))),
|
|
72
|
+
throttle: (fn, _how) => throttle(fn, (_how ||= 0, !_how ? undefined : _how === 'raf' ? requestAnimationFrame : (fn) => setTimeout(fn, _how))),
|
|
73
|
+
delay: (fn, ms) => !ms ? (e) => (queueMicrotask(() => fn(e))) : (e) => setTimeout(() => fn(e), ms),
|
|
74
|
+
|
|
75
|
+
tick: (fn) => (console.warn('Deprecated'), (e) => (queueMicrotask(() => fn(e)))),
|
|
76
|
+
raf: (fn) => (console.warn('Deprecated'), (e) => requestAnimationFrame(() => fn(e))),
|
|
77
|
+
|
|
78
|
+
once: (fn, _done, _fn) => (_fn = (e) => !_done && (_done = 1, fn(e)), _fn.once = true, _fn),
|
|
64
79
|
|
|
65
80
|
// target
|
|
66
81
|
window: fn => (fn.target = fn.target.ownerDocument.defaultView, fn),
|
|
@@ -76,8 +91,8 @@ Object.assign(modifier, {
|
|
|
76
91
|
|
|
77
92
|
// events
|
|
78
93
|
prevent: (fn) => (e) => (e?.preventDefault(), fn(e)),
|
|
79
|
-
stop: (fn) => (e) => (e?.stopPropagation(), fn(e)),
|
|
80
|
-
immediate: (fn) => (e) => (e?.stopImmediatePropagation(), fn(e)),
|
|
94
|
+
stop: (fn, _how) => (e) => (_how?.[0] === 'i' ? e?.stopImmediatePropagation() : e?.stopPropagation(), fn(e)),
|
|
95
|
+
immediate: (fn) => (console.warn('Deprecated'), (e) => (e?.stopImmediatePropagation(), fn(e))),
|
|
81
96
|
passive: fn => (fn.passive = true, fn),
|
|
82
97
|
capture: fn => (fn.capture = true, fn),
|
|
83
98
|
})
|
|
@@ -87,7 +102,8 @@ const keys = {
|
|
|
87
102
|
ctrl: e => e.ctrlKey || e.key === "Control" || e.key === "Ctrl",
|
|
88
103
|
shift: e => e.shiftKey || e.key === "Shift",
|
|
89
104
|
alt: e => e.altKey || e.key === "Alt",
|
|
90
|
-
meta: e => e.metaKey || e.key === "Meta"
|
|
105
|
+
meta: e => e.metaKey || e.key === "Meta",
|
|
106
|
+
cmd: e => e.metaKey || e.key === "Command",
|
|
91
107
|
arrow: e => e.key.startsWith("Arrow"),
|
|
92
108
|
enter: e => e.key === "Enter",
|
|
93
109
|
esc: e => e.key.startsWith("Esc"),
|
|
@@ -100,23 +116,54 @@ const keys = {
|
|
|
100
116
|
};
|
|
101
117
|
|
|
102
118
|
// augment modifiers with key testers
|
|
103
|
-
for (let k in keys) modifier[k] = (fn,
|
|
119
|
+
for (let k in keys) modifier[k] = (fn, a, b) => (e) => keys[k](e) && (!a || keys[a]?.(e)) && (!b || keys[b]?.(e)) && fn(e)
|
|
120
|
+
|
|
104
121
|
|
|
105
122
|
use({
|
|
106
|
-
compile: expr => {
|
|
107
|
-
|
|
123
|
+
compile: expr => sprae.constructor(`with (arguments[0]) { ${expr} }`),
|
|
124
|
+
dir: (el, name, expr, state) => {
|
|
125
|
+
// sequences shortcut
|
|
126
|
+
if (name.includes('..')) return () => _seq(el, state, expr, name)[_dispose]
|
|
127
|
+
return name.split(':').reduce((prev, str) => {
|
|
128
|
+
let start = dir(el, str, expr, state)
|
|
129
|
+
return !prev ? start : (p, s) => (p = prev(), s = start(), () => { p(); s() })
|
|
130
|
+
}, null)
|
|
108
131
|
},
|
|
109
|
-
|
|
110
|
-
// signals
|
|
111
|
-
signal, effect, computed, batch, untracked
|
|
132
|
+
...signals
|
|
112
133
|
})
|
|
113
134
|
|
|
135
|
+
|
|
114
136
|
// expose for runtime config
|
|
115
137
|
sprae.use = use
|
|
116
138
|
sprae.store = store
|
|
117
139
|
sprae.directive = directive
|
|
118
140
|
sprae.modifier = modifier
|
|
119
|
-
sprae.
|
|
141
|
+
sprae.version = pkg.version;
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Lifecycle hanger: spraes automatically any new nodes
|
|
146
|
+
*/
|
|
147
|
+
const start = sprae.start = (root = document.body, values) => {
|
|
148
|
+
const state = store(values)
|
|
149
|
+
sprae(root, state);
|
|
150
|
+
const mo = new MutationObserver(mutations => {
|
|
151
|
+
for (const m of mutations) {
|
|
152
|
+
for (const el of m.addedNodes) {
|
|
153
|
+
// el can be spraed or removed by subsprae (like within :each/:if)
|
|
154
|
+
if (el.nodeType === 1 && el[_state] === undefined && root.contains(el)) {
|
|
155
|
+
// even if element has no spraeable attrs, some of its children can have
|
|
156
|
+
root[_add](el)
|
|
157
|
+
// sprae(el, state, root);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// for (const el of m.removedNodes) el[Symbol.dispose]?.()
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
mo.observe(root, { childList: true, subtree: true });
|
|
164
|
+
return state
|
|
165
|
+
}
|
|
166
|
+
|
|
120
167
|
|
|
121
168
|
// version placeholder for bundler
|
|
122
169
|
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