sprae 13.3.7 → 13.4.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 -22
- package/directive/each.js +58 -30
- package/directive/if.js +23 -0
- package/dist/sprae-csp.js +11 -11
- package/dist/sprae-csp.js.map +4 -4
- package/dist/sprae-csp.umd.js +11 -11
- package/dist/sprae-csp.umd.js.map +4 -4
- package/dist/sprae-preact.js +4 -4
- package/dist/sprae-preact.js.map +4 -4
- package/dist/sprae-preact.umd.js +4 -4
- package/dist/sprae-preact.umd.js.map +4 -4
- package/dist/sprae.js +4 -4
- package/dist/sprae.js.map +4 -4
- package/dist/sprae.umd.js +4 -4
- package/dist/sprae.umd.js.map +4 -4
- package/package.json +1 -1
- package/readme.md +7 -7
- package/signal.js +33 -26
- package/sprae.js +26 -19
- package/store.js +36 -10
- package/types/core.d.ts +4 -20
- package/types/core.d.ts.map +1 -1
- package/types/directive/each.d.ts.map +1 -1
- package/types/directive/if.d.ts +1 -0
- package/types/directive/if.d.ts.map +1 -1
- package/types/signal.d.ts +3 -3
- package/types/signal.d.ts.map +1 -1
- package/types/sprae.d.ts.map +1 -1
- package/types/store.d.ts +2 -0
- package/types/store.d.ts.map +1 -1
- package/directive/else.js +0 -24
- package/types/directive/else.d.ts +0 -3
- package/types/directive/else.d.ts.map +0 -1
package/readme.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# [∴](https://dy.github.io/sprae) sprae [](https://github.com/dy/sprae/actions/workflows/node.js.yml)  sprae [](https://github.com/dy/sprae/actions/workflows/node.js.yml)  [](https://www.npmjs.com/package/sprae)
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Reactive sprinkles for HTML/JSX.
|
|
4
4
|
|
|
5
|
-
Open & minimal
|
|
5
|
+
Open & minimal microhydration framework with signals-based reactivity.
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
## Usage
|
|
@@ -511,13 +511,13 @@ Works with [define-element](https://github.com/dy/define-element), Lit, or any C
|
|
|
511
511
|
## FAQ
|
|
512
512
|
|
|
513
513
|
**What is sprae?**<br>
|
|
514
|
-
~
|
|
514
|
+
~8kb script that adds reactivity to HTML via `:attribute="expression"`. No build step, no new syntax.
|
|
515
515
|
|
|
516
516
|
**Learning curve?**<br>
|
|
517
517
|
If you know HTML and JS, you know sprae. Just `:attribute="expression"`.
|
|
518
518
|
|
|
519
519
|
**How does it compare to Alpine?**<br>
|
|
520
|
-
|
|
520
|
+
~2× lighter and ~2× faster — [measured](https://dy.github.io/sprae/compare). Pluggable signals, built-in modifiers, event chains, full-JS [CSP build](https://dy.github.io/sprae/csp).
|
|
521
521
|
|
|
522
522
|
**How does it compare to React/Vue?**<br>
|
|
523
523
|
No build step, no virtual DOM. Can inject into [JSX](#jsx--nextjs) for server components without framework overhead.
|
|
@@ -526,7 +526,7 @@ No build step, no virtual DOM. Can inject into [JSX](#jsx--nextjs) for server co
|
|
|
526
526
|
Signals are the emerging [standard](https://github.com/tc39/proposal-signals) for reactivity. Pluggable — first to support native signals when browsers ship.
|
|
527
527
|
|
|
528
528
|
**Is new Function unsafe?**<br>
|
|
529
|
-
No more than inline `onclick` handlers. For strict CSP, use the [
|
|
529
|
+
No more than inline `onclick` handlers. For strict CSP, use the [CSP build](https://dy.github.io/sprae/csp).
|
|
530
530
|
|
|
531
531
|
**Components?**<br>
|
|
532
532
|
Use [define-element](https://github.com/dy/define-element) for declarative web components, or any CE library. For simpler cases, [manage duplication](https://tailwindcss.com/docs/styling-with-utility-classes#managing-duplication) with templates/includes.
|
|
@@ -541,7 +541,7 @@ Any browser with [Proxy](https://caniuse.com/proxy) (all modern browsers, no IE)
|
|
|
541
541
|
State is plain reactive objects — scales as far as your data model does. Use [store](#store) with computed getters and methods for complex apps.
|
|
542
542
|
|
|
543
543
|
**Is it production-ready?**<br>
|
|
544
|
-
|
|
544
|
+
3+ years, ~200 [npm versions](https://www.npmjs.com/package/sprae?activeTab=versions), 0 open issues, 0 dependencies, full test suite incl. the CSP build.
|
|
545
545
|
|
|
546
546
|
**Is it backed by a company?**<br>
|
|
547
547
|
Indie project. [Support it](https://github.com/sponsors/dy).
|
package/signal.js
CHANGED
|
@@ -11,27 +11,31 @@ let depth = 0
|
|
|
11
11
|
/** @type {Set<import('./core.js').EffectFn> | null} */
|
|
12
12
|
let batched;
|
|
13
13
|
|
|
14
|
+
// class keeps instances light: prototype accessors share one shape, subscribers Set allocates lazily
|
|
15
|
+
class Signal {
|
|
16
|
+
constructor(v) { this.v = v; this.o = null }
|
|
17
|
+
get value() {
|
|
18
|
+
if (current) current.deps.add((this.o ??= new Set).add(current))
|
|
19
|
+
return this.v
|
|
20
|
+
}
|
|
21
|
+
set value(val) {
|
|
22
|
+
if (val === this.v) return
|
|
23
|
+
this.v = val
|
|
24
|
+
if (this.o) for (let sub of this.o) batched ? batched.add(sub) : sub() // notify effects
|
|
25
|
+
}
|
|
26
|
+
peek() { return this.v }
|
|
27
|
+
valueOf() { return this.value }
|
|
28
|
+
toString() { return this.value }
|
|
29
|
+
toJSON() { return this.value }
|
|
30
|
+
}
|
|
31
|
+
|
|
14
32
|
/**
|
|
15
33
|
* Creates a reactive signal.
|
|
16
34
|
* @template T
|
|
17
35
|
* @param {T} v - Initial value
|
|
18
36
|
* @returns {import('./core.js').Signal<T>}
|
|
19
37
|
*/
|
|
20
|
-
export const signal = (v
|
|
21
|
-
_s = {
|
|
22
|
-
get value() {
|
|
23
|
-
current?.deps.add(_obs.add(current));
|
|
24
|
-
return v
|
|
25
|
-
},
|
|
26
|
-
set value(val) {
|
|
27
|
-
if (val === v) return
|
|
28
|
-
v = val;
|
|
29
|
-
for (let sub of _obs) batched ? batched.add(sub) : sub(); // notify effects
|
|
30
|
-
},
|
|
31
|
-
peek() { return v },
|
|
32
|
-
toJSON: _v, toString: _v, valueOf: _v
|
|
33
|
-
}
|
|
34
|
-
)
|
|
38
|
+
export const signal = (v) => new Signal(v)
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
41
|
* Creates a reactive effect that re-runs when dependencies change.
|
|
@@ -60,22 +64,22 @@ export const effect = (fn, _teardown, _fx, _deps) => (
|
|
|
60
64
|
(dep) => { _teardown?.call?.(); _teardown = fn = _fx.fn = null; for (dep of _deps) dep.delete(_fx); _deps.clear() }
|
|
61
65
|
)
|
|
62
66
|
|
|
67
|
+
// a computed is a signal with a lazy producer effect keeping it current
|
|
68
|
+
class Computed extends Signal {
|
|
69
|
+
constructor(fn) { super(); this.fn = fn; this.e = null }
|
|
70
|
+
get value() {
|
|
71
|
+
this.e ||= effect(() => super.value = this.fn())
|
|
72
|
+
return super.value
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
63
76
|
/**
|
|
64
77
|
* Creates a computed signal derived from other signals.
|
|
65
78
|
* @template T
|
|
66
79
|
* @param {() => T} fn - Computation function
|
|
67
80
|
* @returns {import('./core.js').Signal<T>}
|
|
68
81
|
*/
|
|
69
|
-
export const computed = (fn
|
|
70
|
-
_c = {
|
|
71
|
-
get value() {
|
|
72
|
-
_e ||= effect(() => _s.value = fn());
|
|
73
|
-
return _s.value
|
|
74
|
-
},
|
|
75
|
-
peek: _s.peek,
|
|
76
|
-
toJSON: _v, toString: _v, valueOf: _v
|
|
77
|
-
}
|
|
78
|
-
)
|
|
82
|
+
export const computed = (fn) => new Computed(fn)
|
|
79
83
|
|
|
80
84
|
/**
|
|
81
85
|
* Batches multiple signal updates into a single notification.
|
|
@@ -95,4 +99,7 @@ export const batch = (fn, _first = !batched, _list) => {
|
|
|
95
99
|
* @param {() => T} fn - Function to run untracked
|
|
96
100
|
* @returns {T}
|
|
97
101
|
*/
|
|
98
|
-
export const untracked = (fn, _prev
|
|
102
|
+
export const untracked = (fn, _prev) => {
|
|
103
|
+
_prev = current, current = null
|
|
104
|
+
try { return fn() } finally { current = _prev }
|
|
105
|
+
}
|
package/sprae.js
CHANGED
|
@@ -8,8 +8,7 @@ import { batch, computed, effect, signal, untracked } from './core.js';
|
|
|
8
8
|
import * as signals from './signal.js';
|
|
9
9
|
import sprae, { use, decorate, directive, modifier, parse, throttle, debounce, _off, _state, _on, _dispose, _add, start, isCE } from './core.js';
|
|
10
10
|
|
|
11
|
-
import _if from "./directive/if.js";
|
|
12
|
-
import _else from "./directive/else.js";
|
|
11
|
+
import _if, { _else } from "./directive/if.js";
|
|
13
12
|
import _text from "./directive/text.js";
|
|
14
13
|
import _class from "./directive/class.js";
|
|
15
14
|
import _style from "./directive/style.js";
|
|
@@ -65,8 +64,8 @@ Object.assign(directive, {
|
|
|
65
64
|
* @param {Object} state - Reactive state object
|
|
66
65
|
* @returns {() => (() => void) | void} Initializer function that returns a disposer
|
|
67
66
|
*/
|
|
68
|
-
const dir = (target,
|
|
69
|
-
let
|
|
67
|
+
const dir = (target, dirName, mods, expr, state) => {
|
|
68
|
+
let create = directive[dirName] || directive._
|
|
70
69
|
let hasMods = mods.length > 0
|
|
71
70
|
|
|
72
71
|
return () => {
|
|
@@ -75,7 +74,7 @@ const dir = (target, name, expr, state) => {
|
|
|
75
74
|
if (hasMods) {
|
|
76
75
|
// modifiers can retarget the update or schedule it, so they keep the trigger indirection
|
|
77
76
|
change = signal(0)
|
|
78
|
-
trigger = decorate(Object.assign(() => change.value++, { target }), mods)
|
|
77
|
+
trigger = decorate(Object.assign(() => change.value++, { target }), mods.slice())
|
|
79
78
|
el = trigger.target ?? target
|
|
80
79
|
}
|
|
81
80
|
|
|
@@ -83,7 +82,7 @@ const dir = (target, name, expr, state) => {
|
|
|
83
82
|
|
|
84
83
|
if (!update?.call) return update?.[_dispose]
|
|
85
84
|
|
|
86
|
-
let evaluate = update.eval ?? parse(expr)
|
|
85
|
+
let evaluate = update.eval ?? parse(expr),
|
|
87
86
|
_out, out = () => (typeof _out === 'function' && _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
|
|
88
87
|
|
|
89
88
|
// use element's own state for expression evaluation, unless it's a custom element
|
|
@@ -91,15 +90,24 @@ const dir = (target, name, expr, state) => {
|
|
|
91
90
|
if (!isCE(el)) state = el[_state] ?? state
|
|
92
91
|
|
|
93
92
|
let off = hasMods ? effect(() => {
|
|
94
|
-
change.value == count ? trigger() : (count = change.value, _out = evaluate(state, update))
|
|
93
|
+
change.value == count ? trigger() : (count = change.value, _out = evaluate.call(el, state, update))
|
|
95
94
|
return out
|
|
96
|
-
}) : effect(() => (_out = evaluate(state, update), out))
|
|
95
|
+
}) : effect(() => (_out = evaluate.call(el, state, update), out))
|
|
97
96
|
if (!(_state in el)) return off
|
|
98
97
|
let _d = 0
|
|
99
98
|
return () => { if (_d) return; _d = 1; off(); update[_off] ? update[_off]() : el[_dispose]?.() }
|
|
100
99
|
}
|
|
101
100
|
}
|
|
102
101
|
|
|
102
|
+
// per-name parse memo: the same few attr names repeat across every :each row
|
|
103
|
+
const recipes = {}
|
|
104
|
+
const recipe = (name) => recipes[name] ??=
|
|
105
|
+
name.includes('..') ? 0 : // sequence marker
|
|
106
|
+
name.split(':').map(str => {
|
|
107
|
+
let [dirName, ...mods] = str.split('.')
|
|
108
|
+
return { str, dirName, mods, on: str.startsWith('on') }
|
|
109
|
+
})
|
|
110
|
+
|
|
103
111
|
// Parses time string to ms: 100, 100ms, 1s, 1m
|
|
104
112
|
const parseTime = (t) => !t ? 0 : typeof t === 'number' ? t :
|
|
105
113
|
(([, n, u] = t.match(/^(\d+)(ms|s|m)?$/) || []) => (n = +n, u === 's' ? n * 1000 : u === 'm' ? n * 60000 : n))()
|
|
@@ -127,10 +135,6 @@ Object.assign(modifier, {
|
|
|
127
135
|
throttle: (fn, a) => throttle(fn, scheduler(a)),
|
|
128
136
|
/** Runs callback after delay. Supports: tick (default), raf, idle, N, Nms, Ns, Nm. */
|
|
129
137
|
delay: (fn, a) => ((sched = scheduler(a)) => (e) => sched(() => fn(e)))(),
|
|
130
|
-
/** Shortcut for delay-tick (next microtask). */
|
|
131
|
-
tick: (fn) => (e) => queueMicrotask(() => fn(e)),
|
|
132
|
-
/** Shortcut for delay-raf (next animation frame). */
|
|
133
|
-
raf: (fn) => (e) => requestAnimationFrame(() => fn(e)),
|
|
134
138
|
|
|
135
139
|
/** Calls handler only once. */
|
|
136
140
|
once: (fn, _done, _fn) => (_fn = (e) => !_done && (_done = 1, fn(e)), _fn.once = true, _fn),
|
|
@@ -168,6 +172,9 @@ Object.assign(modifier, {
|
|
|
168
172
|
})
|
|
169
173
|
/** Alias for .away modifier */
|
|
170
174
|
modifier.outside = modifier.away
|
|
175
|
+
/** Shortcuts for .delay-tick / .delay-raf */
|
|
176
|
+
modifier.tick = fn => modifier.delay(fn)
|
|
177
|
+
modifier.raf = fn => modifier.delay(fn, 'raf')
|
|
171
178
|
|
|
172
179
|
/**
|
|
173
180
|
* Key testers for keyboard event modifiers.
|
|
@@ -231,15 +238,15 @@ use({
|
|
|
231
238
|
},
|
|
232
239
|
// these 2 exceptions might look inconsistent, but arguably that's the cleanest way to avoid coupling
|
|
233
240
|
dir: (el, name, expr, state) => {
|
|
241
|
+
let segs = recipe(name)
|
|
234
242
|
// sequences: handle own modifiers, return dispose
|
|
235
|
-
if (
|
|
236
|
-
return
|
|
237
|
-
let dirName = str.split('.')[0]
|
|
243
|
+
if (!segs) return () => _seq(el, state, expr, name)[_dispose]
|
|
244
|
+
return segs.reduce((prev, seg) => {
|
|
238
245
|
// events and observers handle own modifiers, return dispose
|
|
239
|
-
let obs = directive[dirName]
|
|
240
|
-
let start =
|
|
241
|
-
: obs?.observer ? () => obs(el, state, expr, str)[_dispose]
|
|
242
|
-
: dir(el,
|
|
246
|
+
let obs = directive[seg.dirName]
|
|
247
|
+
let start = seg.on ? () => _event(el, state, expr, seg.str)[_dispose]
|
|
248
|
+
: obs?.observer ? () => obs(el, state, expr, seg.str)[_dispose]
|
|
249
|
+
: dir(el, seg.dirName, seg.mods, expr, state)
|
|
243
250
|
return !prev ? start : (p, s) => (p = prev(), s = start(), () => { p(); s() })
|
|
244
251
|
}, null)
|
|
245
252
|
},
|
package/store.js
CHANGED
|
@@ -11,6 +11,9 @@ export const _signals = Symbol('signals')
|
|
|
11
11
|
/** Symbol for the change signal that tracks object keys or array length */
|
|
12
12
|
export const _change = Symbol('change')
|
|
13
13
|
|
|
14
|
+
/** Symbol for list index/content bumps (swap, splice, index writes) */
|
|
15
|
+
export const _touch = Symbol('touch')
|
|
16
|
+
|
|
14
17
|
/** Symbol for stashed setter on computed values */
|
|
15
18
|
export const _set = Symbol('set')
|
|
16
19
|
|
|
@@ -150,21 +153,31 @@ const list = (values, parent = globalThis) => {
|
|
|
150
153
|
isMut = false,
|
|
151
154
|
|
|
152
155
|
// since array mutator methods read .length internally only once, we disable it on the moment of call, allowing rest of operations to be reactive
|
|
153
|
-
|
|
156
|
+
// batch: a single splice/push writes many index signals — notify subscribers once, not per index
|
|
157
|
+
mut = fn => function () { isMut = true; let r; batch(() => r = fn.apply(this, arguments)); return r },
|
|
154
158
|
|
|
155
159
|
length = signal(values.length),
|
|
156
160
|
|
|
161
|
+
// _touch bumps notify keyed :each of index/content changes (swap, splice) in O(1)
|
|
162
|
+
// instead of forcing :each to subscribe to all N index signals
|
|
163
|
+
touch = signal(0),
|
|
164
|
+
bump = () => { touch.value++ },
|
|
165
|
+
|
|
166
|
+
// capture native array mutators before they're shadowed on signals[]
|
|
167
|
+
asplice = signals.splice,
|
|
168
|
+
|
|
157
169
|
// proxy passes prop access to signals
|
|
158
170
|
state = new Proxy(
|
|
159
171
|
Object.assign(signals, {
|
|
160
172
|
[_change]: length,
|
|
173
|
+
[_touch]: touch,
|
|
161
174
|
[_signals]: signals,
|
|
162
|
-
// patch mutators
|
|
175
|
+
// patch mutators — `this` must be the list proxy so set traps fire reactively
|
|
163
176
|
push: mut(signals.push),
|
|
164
177
|
pop: mut(signals.pop),
|
|
165
178
|
shift: mut(signals.shift),
|
|
166
179
|
unshift: mut(signals.unshift),
|
|
167
|
-
splice: mut(
|
|
180
|
+
splice: mut(function () { let r = asplice.apply(this, arguments); bump(); return r }),
|
|
168
181
|
}),
|
|
169
182
|
{
|
|
170
183
|
get(_, k) {
|
|
@@ -186,8 +199,8 @@ const list = (values, parent = globalThis) => {
|
|
|
186
199
|
|
|
187
200
|
// .length
|
|
188
201
|
if (k === 'length') {
|
|
189
|
-
//
|
|
190
|
-
for (let i = v; i < signals.length; i++)
|
|
202
|
+
// clean up tail directly — proxy delete per index is pure trap overhead
|
|
203
|
+
for (let i = v; i < signals.length; i++) signals[i]?.[Symbol.dispose]?.()
|
|
191
204
|
// .length = N directly
|
|
192
205
|
length.value = signals.length = v;
|
|
193
206
|
}
|
|
@@ -195,8 +208,12 @@ const list = (values, parent = globalThis) => {
|
|
|
195
208
|
// force changing length, if eg. a=[]; a[1]=1 - need to come after setting the item
|
|
196
209
|
else if (k >= signals.length) create(signals, k, v, shallow), state.length = +k + 1
|
|
197
210
|
|
|
198
|
-
// existing signal
|
|
199
|
-
else signals[k]
|
|
211
|
+
// existing signal — bump for :each index tracking (swap)
|
|
212
|
+
else if (signals[k]) {
|
|
213
|
+
let s = signals[k], prev = s.peek?.() ?? s.valueOf()
|
|
214
|
+
set(signals, k, v, shallow)
|
|
215
|
+
if ((s.peek?.() ?? s.valueOf()) !== prev) bump()
|
|
216
|
+
} else create(signals, k, v, shallow)
|
|
200
217
|
|
|
201
218
|
return 1
|
|
202
219
|
},
|
|
@@ -222,10 +239,19 @@ const create = (signals, k, v, wrap = store) => (signals[k] = (k[0] == '_' || v?
|
|
|
222
239
|
const shallow = (v) => {
|
|
223
240
|
if (!v || typeof v !== 'object' || v.constructor !== Object) return v
|
|
224
241
|
if (v[_change]) return v // already reactive (store or shallow proxy)
|
|
225
|
-
|
|
242
|
+
// per-key version signals: writing one key notifies only its readers, not the whole item
|
|
243
|
+
let sigs = {}, ver // ver tracks key set (adds/deletes), created on demand
|
|
226
244
|
return new Proxy(v, {
|
|
227
|
-
get: (t, k) => k === _signals ? t : k === _change ? ver : (
|
|
228
|
-
set: (t, k, val) => {
|
|
245
|
+
get: (t, k) => k === _signals ? t : k === _change ? (ver ??= signal(0)) : typeof k === 'symbol' ? t[k] : ((sigs[k] ??= signal(0)).value, t[k]),
|
|
246
|
+
set: (t, k, val) => {
|
|
247
|
+
if (t[k] !== val) {
|
|
248
|
+
let fresh = !(k in t)
|
|
249
|
+
t[k] = val
|
|
250
|
+
sigs[k] && sigs[k].value++
|
|
251
|
+
if (fresh && ver) ver.value++
|
|
252
|
+
}
|
|
253
|
+
return 1
|
|
254
|
+
},
|
|
229
255
|
has: () => true
|
|
230
256
|
})
|
|
231
257
|
}
|
package/types/core.d.ts
CHANGED
|
@@ -86,7 +86,7 @@ export function frag(tpl: HTMLTemplateElement | FragmentLike): FragmentLike;
|
|
|
86
86
|
export function dashcase(str: string): string;
|
|
87
87
|
export function attr(el: any, name: any, v: any): any;
|
|
88
88
|
export function clsx(c: string | string[] | Record<string, boolean> | null | undefined): string;
|
|
89
|
-
export function throttle
|
|
89
|
+
export function throttle(fn: any, ms: any): (e: any) => void;
|
|
90
90
|
export function debounce<T_1 extends Function>(fn: T_1, ms?: number | Function, immediate?: boolean): T_1;
|
|
91
91
|
export * from "./store.js";
|
|
92
92
|
export default sprae;
|
|
@@ -202,32 +202,16 @@ export type FragmentLike = {
|
|
|
202
202
|
*/
|
|
203
203
|
removeAttribute: (name: string) => void;
|
|
204
204
|
};
|
|
205
|
-
/**
|
|
206
|
-
* @callback DirectiveHandler
|
|
207
|
-
* @param {Element} el - Target element
|
|
208
|
-
* @param {Object} state - Reactive state object
|
|
209
|
-
* @param {string} expr - Expression string
|
|
210
|
-
* @param {string} [name] - Directive name with modifiers
|
|
211
|
-
* @returns {((value: any) => void | (() => void)) | { [Symbol.dispose]: () => void } | void}
|
|
212
|
-
*/
|
|
213
|
-
/**
|
|
214
|
-
* @callback ModifierHandler
|
|
215
|
-
* @param {Function} fn - Function to modify
|
|
216
|
-
* @param {...string} args - Modifier arguments (from dash-separated values)
|
|
217
|
-
* @returns {Function}
|
|
218
|
-
*/
|
|
219
|
-
/**
|
|
220
|
-
* @typedef {Object} SpraeState
|
|
221
|
-
* @property {Record<string, Signal>} [_signals] - Internal signals map
|
|
222
|
-
*/
|
|
223
205
|
/**
|
|
224
206
|
* Applies directives to an HTML element and manages its reactive state.
|
|
225
207
|
*
|
|
226
208
|
* @param {Element} [el=document.body] - The target HTML element to apply directives to.
|
|
227
209
|
* @param {Object} [state] - Initial state values to populate the element's reactive state.
|
|
210
|
+
* @param {Element} [master] - Internal: clone source (eg. :each template) — first clone records
|
|
211
|
+
* its directive scan on the master, later clones replay it without touching attributes.
|
|
228
212
|
* @returns {SpraeState & Object} The reactive state object associated with the element.
|
|
229
213
|
*/
|
|
230
|
-
declare function sprae(root?: HTMLElement, state?: any): SpraeState & any;
|
|
214
|
+
declare function sprae(root?: HTMLElement, state?: any, master?: Element): SpraeState & any;
|
|
231
215
|
declare namespace sprae {
|
|
232
216
|
let version: any;
|
|
233
217
|
}
|
package/types/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../core.js"],"names":[],"mappings":"AAIA,uEAAuE;AACvE,2BAA8D;AAE9D,oDAAoD;AACpD,mCAAqC;AAErC,0CAA0C;AAC1C,gCAA+B;AAE/B,2CAA2C;AAC3C,iCAAiC;AAEjC,yCAAyC;AACzC,iCAAkC;AAElC,sCAAsC;AACtC,0BAAwB;AAGjB,mCAAgD;AAEvD;;;;;;;;;GASG;AAEH;;;;;GAKG;AAEH;;;;GAIG;AACH,mBAFU,CAAC,GAAC,EAAE,KAAK,EAAE,GAAC,KAAK,MAAM,CAAC,GAAC,CAAC,CAElB;AAElB;;;GAGG;AACH,mBAFU,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,MAAM,IAAI,CAErC;AAElB;;;;GAIG;AACH,qBAFU,CAAC,GAAC,EAAE,EAAE,EAAE,MAAM,GAAC,KAAK,MAAM,CAAC,GAAC,CAAC,CAEnB;AAEpB;;;;GAIG;AACH,kBAFU,CAAC,GAAC,EAAE,EAAE,EAAE,MAAM,GAAC,KAAK,GAAC,CAEC;AAEhC;;;;GAIG;AACH,sBAFU,CAAC,GAAC,EAAE,EAAE,EAAE,MAAM,GAAC,KAAK,GAAC,CAEF;AAE7B;;;GAGG;AACH,sBAFU,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAEhB;AAE1B;;;GAGG;AACH,qBAFU,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAEjB;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../core.js"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"each.d.ts","sourceRoot":"","sources":["../../directive/each.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"each.d.ts","sourceRoot":"","sources":["../../directive/each.js"],"names":[],"mappings":"AAiBe;;;;EAuJd;;qBAxKgH,YAAY"}
|
package/types/directive/if.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"if.d.ts","sourceRoot":"","sources":["../../directive/if.js"],"names":[],"mappings":"AASe,8BAJJ,OAAO,GAAG,mBAAmB,eAE3B,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CA+ChC"}
|
|
1
|
+
{"version":3,"file":"if.d.ts","sourceRoot":"","sources":["../../directive/if.js"],"names":[],"mappings":"AASe,8BAJJ,OAAO,GAAG,mBAAmB,eAE3B,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CA+ChC;;AAQM,0BAHI,OAAO,GAAG,mBAAmB,GAC3B,MAAM,IAAI,CAiBtB"}
|
package/types/signal.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export function signal<T>(v: T
|
|
1
|
+
export function signal<T>(v: T): import("./core.js").Signal<T>;
|
|
2
2
|
export function effect(fn: () => void | (() => void), _teardown: any, _fx: any, _deps: any): () => void;
|
|
3
|
-
export function computed<T>(fn: () => T
|
|
3
|
+
export function computed<T>(fn: () => T): import("./core.js").Signal<T>;
|
|
4
4
|
export function batch<T>(fn: () => T, _first: boolean, _list: any): T;
|
|
5
|
-
export function untracked<T>(fn: () => T, _prev: any
|
|
5
|
+
export function untracked<T>(fn: () => T, _prev: any): T;
|
|
6
6
|
//# sourceMappingURL=signal.d.ts.map
|
package/types/signal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../signal.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../signal.js"],"names":[],"mappings":"AAqCO,uBAJM,CAAC,KACH,CAAC,GACC,OAAO,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAEA;AAOnC,2BAHI,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,yCACvB,MAAM,IAAI,CAsBtB;AAiBM,yBAJM,CAAC,MACH,MAAM,CAAC,GACL,OAAO,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAEM;AAQzC,sBAJM,CAAC,MACH,MAAM,CAAC,gCACL,CAAC,CAMb;AAQM,0BAJM,CAAC,MACH,MAAM,CAAC,eACL,CAAC,CAKb"}
|
package/types/sprae.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sprae.d.ts","sourceRoot":"","sources":["../sprae.js"],"names":[],"mappings":";kBAQqI,WAAW;kBAH9H,YAAY;uBAC6B,WAAW;uBAAX,WAAW;yBAAX,WAAW;sBAAX,WAAW;0BAAX,WAAW;sBAE+D,WAAW;oBAAX,WAAW;yBAAX,WAAW;yBAAX,WAAW;
|
|
1
|
+
{"version":3,"file":"sprae.d.ts","sourceRoot":"","sources":["../sprae.js"],"names":[],"mappings":";kBAQqI,WAAW;kBAH9H,YAAY;uBAC6B,WAAW;uBAAX,WAAW;yBAAX,WAAW;sBAAX,WAAW;0BAAX,WAAW;sBAE+D,WAAW;oBAAX,WAAW;yBAAX,WAAW;yBAAX,WAAW;AAkQhI,4BAFL,OAAO,OAEsC"}
|
package/types/store.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export const _signals: unique symbol;
|
|
3
3
|
/** Symbol for the change signal that tracks object keys or array length */
|
|
4
4
|
export const _change: unique symbol;
|
|
5
|
+
/** Symbol for list index/content bumps (swap, splice, index writes) */
|
|
6
|
+
export const _touch: unique symbol;
|
|
5
7
|
/** Symbol for stashed setter on computed values */
|
|
6
8
|
export const _set: unique symbol;
|
|
7
9
|
export function store<T extends unknown>(values: T, parent?: any): ReactiveStore<T>;
|
package/types/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../store.js"],"names":[],"mappings":"AAOA,oDAAoD;AACpD,qCAAyC;AAEzC,2EAA2E;AAC3E,oCAAuC;AAEvC,mDAAmD;AACnD,iCAAiC;AA6B1B,sBAVe,CAAC,0BACZ,CAAC,iBAEC,aAAa,CAAC,CAAC,CAAC,CAkG5B;;;;;0BA9GY,CAAC,IACD,CAAC,GAAG;IAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;CAAE"}
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../store.js"],"names":[],"mappings":"AAOA,oDAAoD;AACpD,qCAAyC;AAEzC,2EAA2E;AAC3E,oCAAuC;AAEvC,uEAAuE;AACvE,mCAAqC;AAErC,mDAAmD;AACnD,iCAAiC;AA6B1B,sBAVe,CAAC,0BACZ,CAAC,iBAEC,aAAa,CAAC,CAAC,CAAC,CAkG5B;;;;;0BA9GY,CAAC,IACD,CAAC,GAAG;IAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;CAAE"}
|
package/directive/else.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { _on, _off, _state, frag } from '../core.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Else directive - conditional branch following :if.
|
|
5
|
-
* Can be used as `:else` or `:else :if="condition"`.
|
|
6
|
-
* @param {Element | HTMLTemplateElement} el - Element with directive
|
|
7
|
-
* @returns {() => void} Update function
|
|
8
|
-
*/
|
|
9
|
-
export default (el) => {
|
|
10
|
-
let _el, _prev = el
|
|
11
|
-
|
|
12
|
-
_el = el.content ? frag(el) : el
|
|
13
|
-
_el[_state] ??= null // mark _el (frag) as needing sprae
|
|
14
|
-
|
|
15
|
-
// find holder
|
|
16
|
-
while (_prev && !(_el._holder = _prev._holder)) _prev = _prev.previousSibling
|
|
17
|
-
|
|
18
|
-
el.remove()
|
|
19
|
-
el[_state] = null // mark as fake-spraed to stop further init, to lazy-sprae when branch matches
|
|
20
|
-
|
|
21
|
-
_el._holder._clauses.push(_el._clause = [_el, true])
|
|
22
|
-
|
|
23
|
-
return _el._holder.update
|
|
24
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"else.d.ts","sourceRoot":"","sources":["../../directive/else.js"],"names":[],"mappings":"AAQe,8BAHJ,OAAO,GAAG,mBAAmB,GAC3B,MAAM,IAAI,CAiBtB"}
|