sprae 12.2.4 → 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 CHANGED
@@ -1,5 +1,4 @@
1
1
  import store, { _change, _signals } from "./store.js";
2
- import pkg from './package.json' with { type: 'json' };
3
2
 
4
3
  export const _dispose = (Symbol.dispose ||= Symbol("dispose")),
5
4
  _state = Symbol("state"),
@@ -7,7 +6,6 @@ export const _dispose = (Symbol.dispose ||= Symbol("dispose")),
7
6
  _off = Symbol('off'),
8
7
  _add = Symbol('init');
9
8
 
10
-
11
9
  export let prefix = ':', signal, effect, computed, batch = (fn) => fn(), untracked = batch;
12
10
 
13
11
  export let directive = {}, modifier = {}
@@ -42,7 +40,7 @@ const sprae = (el = document.body, state) => {
42
40
  el[_dispose] ||= () => (el[_off](), el[_off] = el[_on] = el[_dispose] = el[_add] = el[_state] = null)
43
41
 
44
42
  const add = el[_add] = (el) => {
45
- let _attrs = el.attributes, fn;
43
+ let _attrs = el.attributes, start;
46
44
 
47
45
  // we iterate live collection (subsprae can init args)
48
46
  if (_attrs) for (let i = 0; i < _attrs.length;) {
@@ -51,8 +49,10 @@ const sprae = (el = document.body, state) => {
51
49
  if (name.startsWith(prefix)) {
52
50
  el.removeAttribute(name)
53
51
 
52
+ currentDir = name;
53
+
54
54
  // directive initializer can be redefined
55
- if (fn = initDirective(el, name, value, state)) fx.push(fn), offs.push(fn())
55
+ fx.push(start = dir(el, name.slice(prefix.length), value, state)), offs.push(start())
56
56
 
57
57
  // stop after subsprae like :each, :if, :scope etc.
58
58
  if (_state in el) return
@@ -74,122 +74,8 @@ const sprae = (el = document.body, state) => {
74
74
  return state;
75
75
  }
76
76
 
77
- sprae.version = pkg.version;
78
-
79
-
80
- /**
81
- * Initializes directive (defined by sprae build), returns "on" function that enables it
82
- * Multiprop sequences initializer, eg. :a:b..c:d
83
- * @type {(el: HTMLElement, name:string, value:string, state:Object) => Function}
84
- * */
85
- const initDirective = (el, dirName, expr, state) => {
86
- let cur, // current step callback
87
- off // current step disposal
88
-
89
- let steps = dirName.slice(prefix.length).split('..').map((step, i, { length }) => (
90
- // multiple attributes like :id:for=""
91
- step.split(prefix).reduce((prev, str) => {
92
- let [name, ...mods] = str.split('.');
93
- let evaluate = parse(expr, directive[currentDir = name]?.parse)
94
-
95
- // a hack, but events have no signal-effects and can be sequenced
96
- // FIXME: events are molded into core, but should be an optional directive
97
- if (name.startsWith('on')) {
98
- let type = name.slice(2),
99
- fn = applyMods(
100
- sx(
101
- // single event vs chain
102
- length == 1 ? e => evaluate(state, (fn) => call(fn, e)) :
103
- (e => (cur = (!i ? e => call(evaluate(state), e) : cur)(e), off(), off = steps[(i + 1) % length]())),
104
- { target: el }
105
- ),
106
- mods);
107
-
108
- return (_poff) => (_poff = prev?.(), fn.target.addEventListener(type, fn, fn), () => (_poff?.(), fn.target.removeEventListener(type, fn)))
109
- }
110
-
111
- let fn, dispose, change, count;
112
-
113
- if (mods.length) {
114
- change = signal(-1), // signal authorized to trigger effect: 0 = init; >0 = trigger
115
- count = -1 // called effect count
116
-
117
- // effect applier - first time it applies the effect, next times effect is triggered by change signal
118
- fn = applyMods(sx(throttle(() => {
119
- if (++change.value) return // all calls except for the first one are handled by effect
120
- dispose = effect(() => update && (
121
- change.value == count ? fn() : // plan update: separate tick (via throttle) makes sure planner effect call is finished before eval call
122
- (count = change.value, evaluate(state, update)) // if changed more than effect called - call it
123
- ));
124
- }), {target: el}), mods)
125
- }
126
- else {
127
- fn = sx(() => dispose = effect(() => evaluate(state, update)), {target: el })
128
- }
129
-
130
- // props have no sequences and can be sync
131
- // it's nice to see directive as taking some part of current context and returning new or updated context
132
- let update = (directive[name] || directive['*'])(fn.target, state, expr, name)
133
-
134
- // some directives are effect-less
135
- if (!update) return
136
-
137
- // take over state if directive created it (mainly :scope)
138
- if (el[_state]) state = el[_state]
139
-
140
- return (_poff) => (
141
- _poff = prev?.(),
142
- // console.log('ON', name),
143
- fn(),
144
- () => (
145
- // console.log('OFF', name, el),
146
- _poff?.(), dispose?.(), change && (change.value = -1, count = dispose = null)
147
- )
148
- )
149
- }, null)
150
- ));
151
-
152
- // off can be changed on the go
153
- return () => (off = steps[0]?.())
154
- }
155
-
156
-
157
- /**
158
- * Configure sprae
159
- */
160
- export const use = (s) => (
161
- s.compile && (compile = s.compile),
162
- s.prefix && (prefix = s.prefix),
163
- s.signal && (signal = s.signal),
164
- s.effect && (effect = s.effect),
165
- s.computed && (computed = s.computed),
166
- s.batch && (batch = s.batch),
167
- s.untracked && (untracked = s.untracked)
168
- )
169
-
170
-
171
- /**
172
- * Lifecycle hanger: spraes automatically any new nodes
173
- */
174
- export const start = (root = document.body, values) => {
175
- const state = store(values)
176
- sprae(root, state);
177
- const mo = new MutationObserver(mutations => {
178
- for (const m of mutations) {
179
- for (const el of m.addedNodes) {
180
- // el can be spraed or removed by subsprae (like within :each/:if)
181
- if (el.nodeType === 1 && el[_state] === undefined && root.contains(el)) {
182
- // even if element has no spraeable attrs, some of its children can have
183
- root[_add](el)
184
- }
185
- }
186
- // for (const el of m.removedNodes) el[Symbol.dispose]?.()
187
- }
188
- });
189
- mo.observe(root, { childList: true, subtree: true });
190
- return state
191
- }
192
-
77
+ // directive initializer
78
+ export let dir
193
79
 
194
80
  /**
195
81
  * Compiles an expression into an evaluator function.
@@ -203,14 +89,14 @@ export let compile
203
89
  * @param {string} expr The expression to parse and compile into a function.
204
90
  * @returns {Function} The compiled evaluator function for the expression.
205
91
  */
206
- export const parse = (expr, prepare, _fn) => {
207
- if (_fn = parse.cache[expr]) return _fn
92
+ export const parse = (expr) => {
93
+ let fn = cache[expr=expr.trim()]
94
+ if (fn) return fn
208
95
 
209
- let _expr = expr.trim() || 'undefined'
210
- if (prepare) _expr = prepare(_expr)
96
+ let _expr = expr || 'undefined'
211
97
 
212
98
  // if, const, let - no return
213
- if (/^(if|let|const)\b/.test(_expr) || /;(?![^{]*})/.test(_expr)) ;
99
+ if (/^(if|let|const)\b/.test(_expr) || /;(?![^{]*})/.test(_expr));
214
100
  else _expr = `return ${_expr}`
215
101
 
216
102
  // async expression
@@ -218,37 +104,54 @@ export const parse = (expr, prepare, _fn) => {
218
104
 
219
105
  // static time errors
220
106
  try {
221
- _fn = compile(_expr)
222
- Object.defineProperty(_fn, "name", {value: `∴ ${expr}`})
223
- } catch (e) { console.error(`∴ ${e}\n\n${prefix + currentDir}="${expr}"`) }
107
+ fn = compile(_expr)
108
+ // Object.defineProperty(fn, "name", { value: `∴ ${expr}` })
109
+ } catch (e) { console.error(`∴ ${e}\n\n${currentDir}="${expr}"`) }
224
110
 
225
111
  // run time errors
226
- return parse.cache[expr] = (state, cb, _out) => {
112
+ return cache[expr] = function (state, cb, _out) {
227
113
  try {
228
- let result = _fn?.(state)
229
- // if cb is given (to handle asyncs) - call it with result and return function that returns last cb result - needed for effect cleanup
230
- if (cb) return result?.then ? result.then(v => _out = cb(v)) : _out = cb(result), () => call(_out)
114
+ let result = fn?.call(this, state)
115
+ // if cb is given (to handle async/await exprs, usually directive update) - call it with result and return a cleanup function
116
+ if (cb) return result?.then ? (result.then(v => _out = cb(v)), () => _out && call(_out)) : cb(result)
231
117
  else return result
232
118
  } catch (e) {
233
- console.error(`∴ ${e}\n\n${prefix + currentDir}="${expr}"`)
119
+ console.error(`∴ ${e}\n\n${currentDir}="${expr}"`)
234
120
  }
235
121
  }
236
122
  }
237
- parse.cache = {};
123
+ const cache = {};
124
+
238
125
 
239
126
 
240
- // apply modifiers to context (from the end due to nature of wrapping ctx.call)
241
- const applyMods = (fn, mods) => {
127
+ /**
128
+ * Configure sprae
129
+ */
130
+ export const use = (s) => (
131
+ s.compile && (compile = s.compile),
132
+ s.prefix && (prefix = s.prefix),
133
+ s.signal && (signal = s.signal),
134
+ s.effect && (effect = s.effect),
135
+ s.computed && (computed = s.computed),
136
+ s.batch && (batch = s.batch),
137
+ s.untracked && (untracked = s.untracked),
138
+ s.dir && (dir = s.dir)
139
+ )
140
+
141
+ // modifier applier
142
+ export const decorate = (fn, mods) => {
242
143
  while (mods.length) {
243
- let [name, ...params] = mods.pop().split('-')
244
- fn = sx(modifier[name]?.(fn, ...params) ?? fn, fn)
144
+ let [name, ...params] = mods.pop().split('-'), mod = modifier[name], wrapFn
145
+ if (mod) {
146
+ if ((wrapFn = mod(fn, ...params)) !== fn) {
147
+ for (let k in fn) wrapFn[k] ??= fn[k];
148
+ fn = wrapFn
149
+ }
150
+ }
245
151
  }
246
152
  return fn
247
153
  }
248
154
 
249
- // soft-extend missing props and ignoring signals
250
- const sx = (a, b) => { if (a != b) for (let k in b) (a[k] ??= b[k]); return a }
251
-
252
155
  // instantiated <template> fragment holder, like persisting fragment but with minimal API surface
253
156
  export const frag = (tpl) => {
254
157
  if (!tpl.nodeType) return tpl // existing tpl
@@ -292,16 +195,17 @@ export const clsx = (c, _out = []) => !c ? '' : typeof c === 'string' ? c : (
292
195
 
293
196
  // throttle function to (once per tick or other custom scheduler)
294
197
  export const throttle = (fn, schedule = queueMicrotask) => {
295
- let _planned = 0;
198
+ let _planned = 0, arg;
296
199
  const throttled = (e) => {
297
- if (!_planned++) fn(e), schedule((_dirty = _planned > 1) => (
298
- _planned = 0, _dirty && throttled(e)
200
+ arg = e
201
+ if (!_planned++) fn(arg), schedule((_dirty = _planned > 1) => (
202
+ _planned = 0, _dirty && throttled(arg)
299
203
  ));
300
204
  }
301
205
  return throttled;
302
206
  }
303
207
 
304
- export const debounce = (fn, schedule = queueMicrotask, _count = 0) => (arg, _planned=++_count) => schedule(() => (_planned == _count && fn(arg)))
208
+ export const debounce = (fn, schedule = queueMicrotask, _count = 0) => (arg, _planned = ++_count) => schedule(() => (_planned == _count && fn(arg)))
305
209
 
306
210
  export * from './store.js';
307
211
 
package/directive/_.js ADDED
@@ -0,0 +1,3 @@
1
+ import { attr, call } from "../core.js";
2
+
3
+ export default (el, st, ex, name) => v => attr(el, name, v && call(v, el.getAttribute(name)))
@@ -1,11 +1,15 @@
1
- import { clsx, call } from "../core.js";
1
+ import { clsx, call, decorate } from "../core.js";
2
2
 
3
- export default (el, _cur, _new) => (
4
- _cur = new Set,
5
- (v) => {
3
+ export default (el, st, ex, name) => {
4
+ let _cur = new Set, _new
5
+
6
+ // redefine target, if modifiers have one
7
+ name.includes('.') && (el = decorate({target:el}, name.split('.').slice(1)).target ?? el)
8
+
9
+ return (v) => {
6
10
  _new = new Set
7
11
  if (v) clsx(call(v, el.className)).split(' ').map(c => c && _new.add(c))
8
12
  for (let c of _cur) if (_new.has(c)) _new.delete(c); else el.classList.remove(c);
9
13
  for (let c of _cur = _new) el.classList.add(c)
10
14
  }
11
- )
15
+ }
package/directive/each.js CHANGED
@@ -1,7 +1,9 @@
1
- import sprae, { store, _state, effect, _change, _signals, frag, throttle } from "../core.js";
1
+ import sprae, { store, parse, _state, effect, _change, _signals, frag, throttle, debounce } from "../core.js";
2
2
 
3
- const each = (tpl, state, expr) => {
4
- let [itemVar, idxVar = "$"] = expr.split(/\bin\b/)[0].trim().replace(/\(|\)/g, '').split(/\s*,\s*/);
3
+ export default (tpl, state, expr) => {
4
+ const [lhs, rhs] = expr.split(/\bin\b/)
5
+
6
+ let [itemVar, idxVar = "$"] = lhs.trim().replace(/\(|\)/g, '').split(/\s*,\s*/);
5
7
 
6
8
  // we need :if to be able to replace holder instead of tpl for :if :each case
7
9
  let holder = document.createTextNode("");
@@ -19,6 +21,7 @@ const each = (tpl, state, expr) => {
19
21
  cur = null, prevl = 0
20
22
  }
21
23
 
24
+
22
25
  // delete
23
26
  if (newl < prevl) cur.length = newl
24
27
 
@@ -65,7 +68,7 @@ const each = (tpl, state, expr) => {
65
68
  tpl.replaceWith(holder);
66
69
  tpl[_state] = null // mark as fake-spraed, to preserve :-attribs for template
67
70
 
68
- return value => {
71
+ return Object.assign(value => {
69
72
  // resolve new items
70
73
  keys = null
71
74
  if (typeof value === "number") items = Array.from({ length: value }, (_, i) => i + 1)
@@ -74,16 +77,11 @@ const each = (tpl, state, expr) => {
74
77
 
75
78
  // whenever list changes, we rebind internal change effect
76
79
  return effect(() => {
77
- // subscribe to items change (.length) - we do it every time (not just in update) since preact unsubscribes unused signals
80
+ // subscribe to items change (.length) - we do it every time (not just in update) since preact signals unsubscribes unused signals
78
81
  items[_change]?.value
79
82
 
80
83
  // make first render immediately, debounce subsequent renders
81
84
  update()
82
85
  })
83
- }
86
+ }, {eval:parse(rhs)})
84
87
  }
85
-
86
- // :each directive skips v, k
87
- each.parse = (str) => str.split(/\bin\b/)[1].trim()
88
-
89
- export default each
package/directive/else.js CHANGED
@@ -2,9 +2,9 @@ import { _on, _off, _state, frag } from '../core.js';
2
2
 
3
3
 
4
4
  // NOTE: we can reach :else counterpart whereas prev :else :if is on hold
5
- export default (el, state, _el, _, _prev=el) => {
5
+ export default (el) => {
6
+ let _el, _prev = el
6
7
 
7
- // console.log(':else init', el)
8
8
  _el = el.content ? frag(el) : el
9
9
 
10
10
  // find holder
@@ -0,0 +1,17 @@
1
+ import { call, parse, decorate } from "../core.js"
2
+
3
+ export default (el, state, expr, name) => {
4
+ // wrap inline cb into function
5
+ // if (!/^(?:[\w$]+|\([^()]*\))\s*=>/.test(expr) && !/^function\b/.test(expr)) expr = `()=>{${expr}}`;
6
+
7
+ const [type, ...mods] = name.slice(2).split('.'),
8
+ evaluate = parse(expr).bind(el),
9
+ trigger = decorate(Object.assign(e => evaluate(state, (fn) => fn && call(fn, e)), { target: el }), mods);
10
+
11
+ trigger.target.addEventListener(type, trigger, trigger)
12
+ return {
13
+ [Symbol.dispose]() {
14
+ trigger.target.removeEventListener(type, trigger)
15
+ }
16
+ }
17
+ }
package/directive/if.js CHANGED
@@ -2,9 +2,10 @@
2
2
  import sprae, { throttle, _on, _off, _state, frag } from '../core.js';
3
3
 
4
4
  // :if="a"
5
- export default (el, state, _holder, _el, _match) => {
5
+ export default (el, state) => {
6
+ let _holder, _el, _match
7
+
6
8
  // new element :if
7
- // console.log(':if init', el)
8
9
  if (!el._holder) {
9
10
  // mark el as fake-spraed to delay init, since we sprae rest when branch matches, both :if and :else :if
10
11
  el[_state] ??= null
@@ -19,10 +20,8 @@ export default (el, state, _holder, _el, _match) => {
19
20
 
20
21
  _holder.update = throttle(() => {
21
22
  let match = _holder._clauses.find(([, s]) => s)
22
- // console.group(':if update clauses', ..._holder._clauses)
23
23
 
24
24
  if (match != _match) {
25
- // console.log(':if match', match)
26
25
  _match?.[0].remove()
27
26
  _match?.[0][_off]?.()
28
27
  if (_match = match) {
@@ -31,7 +30,6 @@ export default (el, state, _holder, _el, _match) => {
31
30
  !_match[0][_state] ? (delete _match[0][_state], sprae(_match[0], state)) : _match[0][_on]?.()
32
31
  }
33
32
  }
34
- // console.groupEnd()
35
33
  })
36
34
  }
37
35
  // :else :if needs to be spraed all over to have clean list of offable effects
@@ -40,7 +38,6 @@ export default (el, state, _holder, _el, _match) => {
40
38
  // :else may have children to init which is called after :if
41
39
  // or preact can schedule :else after :if, so we ensure order of call by next tick
42
40
  return value => {
43
- // console.log(':if update', _el, value)
44
41
  _el._clause[1] = value
45
42
  _el._holder.update()
46
43
  }
package/directive/ref.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { parse } from "../core.js"
2
2
  // import { setter } from "./value.js"
3
3
 
4
- export default (el, state, expr, name, _prev, _set) => {
5
- // FIXME: we call eval twice here - once to check if it's fn, second for update (from core)
6
- if (typeof parse(expr)(state) == 'function') return v => (v(el))
4
+ export default (el, state, expr) => {
5
+ let fn = parse(expr)(state)
6
+
7
+ if (typeof fn == 'function') return {[Symbol.dispose]:fn(el)}
7
8
 
8
9
  // NOTE: we have to set element statically (outside of effect) to avoid parasitic sub - multiple els with same :ref can cause recursion (eg. :each :ref="x")
9
- // (setter(expr)(state, el))
10
- Object.defineProperty(state, expr, { value: el, configurable: true })
10
+ // FIXME: do via (setter(expr)(state, el))
11
+ else Object.defineProperty(state, expr, { value: el, configurable: true })
11
12
  }
@@ -3,27 +3,27 @@ import sprae, { store, call, untracked, _state, _signals, signal } from '../core
3
3
  export default (el, rootState) => {
4
4
  // 0 run pre-creates state to provide scope for the first effect - it can write vars in it, so we should already have it
5
5
  // el[_state] even replaces own :scope effect state
6
- let subscope = el[_state] = store({}, rootState), init = false;
6
+ let state = el[_state] = store({}, rootState), init = false;
7
7
 
8
8
  // 1st run spraes subtree with values from scope - it can be postponed by modifiers (we isolate reads from parent effect)
9
9
  // 2nd+ runs update subscope
10
10
  return values => {
11
- values = call(values, subscope);
11
+ values = call(values, state);
12
12
 
13
13
  // we bind to subscope to alleviate friction using scope method directly
14
14
  // also returned props should force-create signals in subscope, not overwriting parent
15
- if (values !== subscope) {
15
+ if (values !== state) {
16
16
  for (let k in values) {
17
17
  // _add forces new prop, instead of checking parent
18
- let v = typeof values[k] === 'function' ? values[k].bind(subscope) : values[k]
18
+ let v = typeof values[k] === 'function' ? values[k].bind(state) : values[k]
19
19
  // update
20
- if (k in subscope[_signals]) subscope[k] = v
20
+ if (k in state[_signals]) state[k] = v
21
21
  // create
22
- else (subscope[_signals][k] = (k[0] == '_' || v?.peek) ? v : signal(store(v)))
22
+ else (state[_signals][k] = (k[0] == '_' || v?.peek) ? v : signal(store(v)))
23
23
  }
24
24
  }
25
25
 
26
26
  // Object.assign(subscope, call(values, subscope))
27
- return !init && (init = true, delete el[_state], untracked(() => sprae(el, subscope)))
27
+ return !init && (init = true, delete el[_state], untracked(() => sprae(el, state)))
28
28
  }
29
29
  }
@@ -0,0 +1,35 @@
1
+ // events directive with enabled aliases and sequences like :onclick.ctrl.once..keyup.enter
2
+ import { _dispose, call, parse, decorate } from "../core.js"
3
+
4
+ export default (el, state, expr, names) => {
5
+ let cur, // current step callback
6
+ off // current step disposal
7
+
8
+ let steps = names.split('..').map((step, i, { length }) => step.split(':').reduce(
9
+ (prev, str) => {
10
+ const [name, ...mods] = str.slice(2).split('.')
11
+
12
+ const evaluate = parse(expr).bind(el)
13
+
14
+ const trigger = decorate(Object.assign(
15
+ e => (!i ? evaluate(state, (fn) => cur = fn && call(fn, e)) : (cur = cur(e)), off(), off = steps[(i + 1) % length]()),
16
+ { target: el }
17
+ ), mods)
18
+
19
+
20
+ return (_poff) => (
21
+ _poff = prev?.(),
22
+ trigger.target.addEventListener(name, trigger, trigger),
23
+ () => (_poff?.(), trigger.target.removeEventListener(name, trigger))
24
+ )
25
+ }, null)
26
+ )
27
+
28
+ off = steps[0]()
29
+
30
+ return {
31
+ [Symbol.dispose]() {
32
+ off?.()
33
+ }
34
+ }
35
+ }
@@ -1,9 +1,14 @@
1
- import { call, attr } from "../core.js";
1
+ import { call, attr, decorate } from "../core.js";
2
2
 
3
- export default (el, _static) => (
4
- _static = el.getAttribute("style"),
5
- v => {
6
- v = call(v, el.style)
3
+ export default (el, st, ex, name) => {
4
+ let _static;
5
+
6
+ // redefine target, if modifiers have one
7
+ if (name.includes('.')) el = decorate({target:el}, name.split('.').slice(1)).target ?? el;
8
+
9
+ return v => {
10
+ if (!_static) { _static = el.getAttribute("style") }
11
+ if (v) v = call(v, el.style)
7
12
  if (typeof v === "string") attr(el, "style", _static + '; ' + v);
8
13
  else {
9
14
  if (_static) attr(el, "style", _static);
@@ -11,4 +16,4 @@ export default (el, _static) => (
11
16
  for (let k in v) k[0] == '-' ? el.style.setProperty(k, v[k]) : k[0] > 'A' && (el.style[k] = v[k])
12
17
  }
13
18
  }
14
- )
19
+ }
package/directive/text.js CHANGED
@@ -3,5 +3,5 @@ import { frag, call } from "../core.js"
3
3
  export default el => (
4
4
  // <template :text="a"/> or previously initialized template
5
5
  el.content && el.replaceWith(el = frag(el).childNodes[0]),
6
- v => (v = call(v, el.textContent), el.textContent = v == null ? "" : v)
6
+ v => (v = v && call(v, el.textContent), el.textContent = v == null ? "" : v)
7
7
  )
@@ -7,7 +7,7 @@ export const setter = (expr, _set = parse(`${expr}=__`)) => (target, value) => {
7
7
  target.__ = value; _set(target), delete target.__
8
8
  }
9
9
 
10
- export default (el, state, expr, name) => {
10
+ export default (el, state, expr) => {
11
11
  // bind back to value, but some values can be not bindable, eg. `:value="7"`
12
12
  try {
13
13
  const set = setter(expr)
package/dist/sprae.js CHANGED
@@ -1,5 +1,5 @@
1
- var ne={name:"sprae",description:"DOM microhydration",version:"12.2.3",main:"./sprae.js",module:"./sprae.js","umd:main":"dist/sprae.umd.js",unpkg:"dist/sprae.umd.js",types:"dist/sprae.d.ts",type:"module",files:["core.js","sprae.js","store.js","signal.js","micro.js","directive","dist"],devDependencies:{"@preact/signals":"^2.0.4","@preact/signals-core":"^1.8.0","@webreflection/signal":"^2.1.2","es-module-shims":"^1.10.0",esbuild:"^0.23.0","esbuild-plugin-umd-wrapper":"^2.0.3",hyperf:"^1.7.0",jsdom:"^27.0.0",requestidlecallback:"^0.3.0","signal-polyfill":"^0.1.1",subscript:"^9.1.0",tst:"^7.2.0",ulive:"^1.0.7",usignal:"^0.9.0","wait-please":"^3.1.0"},scripts:{test:"node -r ./test/register.cjs test/test.js",build:"node .esbuild.js"},repository:{type:"git",url:"git+https://github.com/dy/sprae.git"},keywords:["hydration","progressive","progressive enhancement","signals","directives","preact-signals","reactive","template-parts","petit-vue","alpinejs","templating"],author:"Dmitry Iv <df.creative@gmail.com>",license:"MIT",bugs:{url:"https://github.com/dy/sprae/issues"},homepage:"https://github.com/dy/sprae#readme"};var J=Symbol.dispose||(Symbol.dispose=Symbol("dispose")),u=Symbol("state"),H=Symbol("on"),K=Symbol("off"),G=Symbol("init"),q=":",A,v,U,X=e=>e(),R=X,W={},V={},Q=null,Y=(e=document.body,r)=>{if(e[u])return Object.assign(e[u],r);r=F(r||{});let t=[],o=[];e[H]=()=>!o&&(o=t.map(i=>i())),e[K]=()=>(o?.map(i=>i()),o=null),e[J]||(e[J]=()=>(e[K](),e[K]=e[H]=e[J]=e[G]=e[u]=null));let s=e[G]=i=>{let n=i.attributes,a;if(n)for(let c=0;c<n.length;){let{name:p,value:y}=n[c];if(p.startsWith(q)){if(i.removeAttribute(p),(a=Me(i,p,y,r))&&(t.push(a),o.push(a())),u in i)return}else c++}for(let c of[...i.childNodes])c.nodeType==1&&s(c)};return s(e),e[u]===void 0&&(e[u]=r),r};Y.version=ne.version;var Me=(e,r,t,o)=>{let s,i,n=r.slice(q.length).split("..").map((a,c,{length:p})=>a.split(q).reduce((y,l)=>{let[m,...g]=l.split("."),D=S(t,W[Q=m]?.parse);if(m.startsWith("on")){let L=m.slice(2),I=ae(B(p==1?P=>D(o,z=>d(z,P)):P=>(s=(c?s:z=>d(D(o),z))(P),i(),i=n[(c+1)%p]()),{target:e}),g);return P=>(P=y?.(),I.target.addEventListener(L,I,I),()=>(P?.(),I.target.removeEventListener(L,I)))}let k,h,w,b;g.length?(w=A(-1),b=-1,k=ae(B(T(()=>{++w.value||(h=v(()=>M&&(w.value==b?k():(b=w.value,D(o,M)))))}),{target:e}),g)):k=B(()=>h=v(()=>D(o,M)),{target:e});let M=(W[m]||W["*"])(k.target,o,t,m);if(M)return e[u]&&(o=e[u]),L=>(L=y?.(),k(),()=>(L?.(),h?.(),w&&(w.value=-1,b=h=null)))},null));return()=>i=n[0]?.()},_=e=>(e.compile&&(le=e.compile),e.prefix&&(q=e.prefix),e.signal&&(A=e.signal),e.effect&&(v=e.effect),e.computed&&(U=e.computed),e.batch&&(X=e.batch),e.untracked&&(R=e.untracked)),ce=(e=document.body,r)=>{let t=F(r);return Y(e,t),new MutationObserver(s=>{for(let i of s)for(let n of i.addedNodes)n.nodeType===1&&n[u]===void 0&&e.contains(n)&&e[G](n)}).observe(e,{childList:!0,subtree:!0}),t},le,S=(e,r,t)=>{if(t=S.cache[e])return t;let o=e.trim()||"undefined";r&&(o=r(o)),/^(if|let|const)\b/.test(o)||/;(?![^{]*})/.test(o)||(o=`return ${o}`),/\bawait\s/.test(o)&&(o=`return (async()=>{ ${o} })()`);try{t=le(o),Object.defineProperty(t,"name",{value:`\u2234 ${e}`})}catch(s){console.error(`\u2234 ${s}
1
+ var ke=Object.defineProperty;var Ne=(e,r)=>{for(var t in r)ke(e,t,{get:r[t],enumerable:!0})};var T=Symbol.dispose||(Symbol.dispose=Symbol("dispose")),p=Symbol("state"),V=Symbol("on"),M=Symbol("off"),J=Symbol("init"),Z=":",y,P,B,q=e=>e(),v=q,K={},I={},z=null,Te=(e=document.body,r)=>{if(e[p])return Object.assign(e[p],r);r=R(r||{});let t=[],o=[];e[V]=()=>!o&&(o=t.map(i=>i())),e[M]=()=>(o?.map(i=>i()),o=null),e[T]||(e[T]=()=>(e[M](),e[M]=e[V]=e[T]=e[J]=e[p]=null));let s=e[J]=i=>{let n=i.attributes,a;if(n)for(let l=0;l<n.length;){let{name:c,value:m}=n[l];if(c.startsWith(Z)){if(i.removeAttribute(c),z=c,t.push(a=te(i,c.slice(Z.length),m,r)),o.push(a()),p in i)return}else l++}for(let l of[...i.childNodes])l.nodeType==1&&s(l)};return s(e),e[p]===void 0&&(e[p]=r),r},te,re,g=e=>{let r=ee[e=e.trim()];if(r)return r;let t=e||"undefined";/^(if|let|const)\b/.test(t)||/;(?![^{]*})/.test(t)||(t=`return ${t}`),/\bawait\s/.test(t)&&(t=`return (async()=>{ ${t} })()`);try{r=re(t)}catch(o){console.error(`\u2234 ${o}
2
2
 
3
- ${q+Q}="${e}"`)}return S.cache[e]=(s,i,n)=>{try{let a=t?.(s);return i?(a?.then?a.then(c=>n=i(c)):n=i(a),()=>d(n)):a}catch(a){console.error(`\u2234 ${a}
3
+ ${z}="${e}"`)}return ee[e]=function(o,s,i){try{let n=r?.call(this,o);return s?n?.then?(n.then(a=>i=s(a)),()=>i&&f(i)):s(n):n}catch(n){console.error(`\u2234 ${n}
4
4
 
5
- ${q+Q}="${e}"`)}}};S.cache={};var ae=(e,r)=>{for(;r.length;){let[t,...o]=r.pop().split("-");e=B(V[t]?.(e,...o)??e,e)}return e},B=(e,r)=>{if(e!=r)for(let t in r)e[t]??(e[t]=r[t]);return e},N=e=>{if(!e.nodeType)return e;let r=e.content.cloneNode(!0),t=[...e.attributes],o=document.createTextNode(""),s=(r.append(o),[...r.childNodes]);return{childNodes:s,content:r,remove:()=>r.append(...s),replaceWith(i){i!==o&&(o.before(i),r.append(...s))},attributes:t,removeAttribute(i){t.splice(t.findIndex(n=>n.name===i),1)}}},d=(e,r)=>typeof e=="function"?e(r):e,ue=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(r,t)=>(t?"-":"")+r.toLowerCase()),x=(e,r,t)=>t==null||t===!1?e.removeAttribute(r):e.setAttribute(r,t===!0?"":t),ee=(e,r=[])=>e?typeof e=="string"?e:(Array.isArray(e)?e.map(ee):Object.entries(e).reduce((t,[o,s])=>s?[...t,o]:t,[])).join(" "):"",T=(e,r=queueMicrotask)=>{let t=0,o=s=>{t++||(e(s),r((i=t>1)=>(t=0,i&&o(s))))};return o},pe=(e,r=queueMicrotask,t=0)=>(o,s=++t)=>r(()=>s==t&&e(o)),f=Y;var j=Symbol("signals"),O=Symbol("change"),re=Symbol("set"),te=!0,C=(e,r)=>{if(!e||e[Symbol.toStringTag]||e[j])return e;if(e.constructor!==Object)return Array.isArray(e)?Pe(e):e;let t=Object.keys(e).length,o={},s=new Proxy(Object.assign(o,{[O]:A(t),[j]:o}),{get:(n,a)=>a in o?o[a]?o[a].valueOf():o[a]:r?r[a]:globalThis[a],set:(n,a,c,p)=>a in o?(fe(o,a,c),1):(te=!1,r&&a in r?r[a]=c:(Z(o,a,c),o[O].value=++t),te=!0,1),deleteProperty:(n,a)=>(a in o&&(a[0]!="_"&&o[a]?.[Symbol.dispose]?.(),delete o[a],o[O].value=--t),1),ownKeys:()=>(o[O].value,Reflect.ownKeys(o)),has:(n,a)=>a in o?!0:r?a in r:te}),i=Object.getOwnPropertyDescriptors(e);for(let n in e)i[n]?.get?(o[n]=U(i[n].get.bind(s)))[re]=i[n].set?.bind(s):Z(o,n,e[n]);return s},Pe=(e,r=globalThis)=>{let t=Array(e.length).fill(null),o=!1,s=a=>function(){return o=!0,a.apply(this,arguments)},i=A(e.length),n=new Proxy(Object.assign(t,{[O]:i,[j]:t,push:s(t.push),pop:s(t.pop),shift:s(t.shift),unshift:s(t.unshift),splice:s(t.splice)}),{get(a,c){return c==="length"?o?(o=!1,t.length):i.value:typeof c=="symbol"||isNaN(c)?t[c]?.valueOf()??r[c]:(t[c]??(t[c]=A(C(e[c])))).valueOf()},set(a,c,p){if(c==="length"){for(let y=p;y<t.length;y++)delete n[y];i.value=t.length=p}else c>=t.length?(Z(t,c,p),n.length=+c+1):t[c]?fe(t,c,p):Z(t,c,p);return 1},deleteProperty:(a,c)=>(t[c]?.[Symbol.dispose]?.(),delete t[c],1)});return n},Z=(e,r,t)=>e[r]=r[0]=="_"||t?.peek?t:A(C(t)),fe=(e,r,t,o,s)=>r[0]==="_"?e[r]=t:t!==(s=(o=e[r]).peek())&&(o[re]?o[re](t):Array.isArray(t)&&Array.isArray(s)?O in s?R(()=>X(()=>{for(let i=0;i<t.length;i++)s[i]=t[i];s.length=t.length})):o.value=t:o.value=C(t)),F=C;var $,de=0,E,oe=(e,r,t=new Set,o=()=>r.value)=>r={get value(){return $?.deps.push(t.add($)),e},set value(s){if(s!==e){e=s;for(let i of t)E?E.add(i):i()}},peek(){return e},toJSON:o,then:o,toString:o,valueOf:o},se=(e,r,t,o,s)=>(t=i=>{if(s=r,r=null,s?.call?.(),i=$,$=t,de++>10)throw"Cycle detected";try{r=e()}finally{$=i,de--}},o=t.deps=[],t(),i=>{for(r?.call?.();i=o.pop();)i.delete(t)}),me=(e,r=oe(),t,o,s=()=>t.value)=>t={get value(){return o||(o=se(()=>r.value=e())),r.value},peek:r.peek,toJSON:s,then:s,toString:s,valueOf:s},ye=(e,r=!E)=>{E??(E=new Set);try{e()}finally{if(r){for(let t of E)t();E=null}}},ge=(e,r,t)=>(r=$,$=null,t=e(),$=r,t);var he=(e,r,t,o,s)=>{var i;return e._holder?f(o=e,r):(e[i=u]??(e[i]=null),o=e.content?N(e):e,e.replaceWith(t=document.createTextNode("")),o._holder=t._holder=t,t._clauses=[o._clause=[o,!1]],t.update=T(()=>{let n=t._clauses.find(([,a])=>a);n!=s&&(s?.[0].remove(),s?.[0][K]?.(),(s=n)&&(t.before(s[0].content||s[0]),s[0][u]?s[0][H]?.():(delete s[0][u],f(s[0],r))))})),n=>{o._clause[1]=n,o._holder.update()}};var be=(e,r,t,o,s=e)=>{for(t=e.content?N(e):e;s&&!(t._holder=s._holder);)s=s.previousSibling;return e.remove(),e[u]=null,t._holder._clauses.push(t._clause=[t,!0]),t._holder.update};var xe=e=>(e.content&&e.replaceWith(e=N(e).childNodes[0]),r=>(r=d(r,e.textContent),e.textContent=r??""));var je=(e,r,t)=>(r=new Set,o=>{t=new Set,o&&ee(d(o,e.className)).split(" ").map(s=>s&&t.add(s));for(let s of r)t.has(s)?t.delete(s):e.classList.remove(s);for(let s of r=t)e.classList.add(s)});var Se=(e,r)=>(r=e.getAttribute("style"),t=>{if(t=d(t,e.style),typeof t=="string")x(e,"style",r+"; "+t);else{r&&x(e,"style",r);for(let o in t)o[0]=="-"?e.style.setProperty(o,t[o]):o[0]>"A"&&(e.style[o]=t[o])}});var Ae=()=>d;var We=(e,r=S(`${e}=__`))=>(t,o)=>{t.__=o,r(t),delete t.__},Oe=(e,r,t,o)=>{try{let s=We(t),i=e.type==="checkbox"?()=>s(r,e.checked):e.type==="select-multiple"?()=>s(r,[...e.selectedOptions].map(n=>n.value)):()=>s(r,e.selectedIndex<0?null:isNaN(e.valueAsNumber)?e.value:e.valueAsNumber);e.oninput=e.onchange=i,e.type?.startsWith("select")&&(new MutationObserver(i).observe(e,{childList:!0,subtree:!0,attributes:!0}),f(e,r)),S(t)(r)??i()}catch{}return e.type==="text"||e.type===""||e.tagName==="TEXTAREA"?(s,i,n)=>(i=e.selectionStart,n=e.selectionEnd,e.setAttribute("value",e.value=s??""),i&&e.setSelectionRange(i,n)):e.type==="checkbox"?s=>(e.checked=s,x(e,"checked",s)):e.type==="radio"?s=>e.value===s&&(e.checked=s,x(e,"checked",s)):e.type==="select-one"?s=>{for(let i of e.options)i.value==s?i.setAttribute("selected",""):i.removeAttribute("selected");e.value=s}:e.type==="select-multiple"?s=>{for(let i of e.options)i.removeAttribute("selected");for(let i of s)e.querySelector(`[value="${i}"]`).setAttribute("selected","")}:s=>e.value=s};var ke=(e,r,t,o,s,i)=>{if(typeof S(t)(r)=="function")return n=>n(e);Object.defineProperty(r,t,{value:e,configurable:!0})};var we=(e,r)=>{let t=e[u]=C({},r),o=!1;return s=>{if(s=d(s,t),s!==t)for(let i in s){let n=typeof s[i]=="function"?s[i].bind(t):s[i];i in t[j]?t[i]=n:t[j][i]=i[0]=="_"||n?.peek?n:A(C(n))}return!o&&(o=!0,delete e[u],R(()=>f(e,t)))}};var Ne=(e,r,t)=>{let[o,s="$"]=t.split(/\bin\b/)[0].trim().replace(/\(|\)/g,"").split(/\s*,\s*/),i=document.createTextNode(""),n,a,c,p=0,y=T(()=>{var D,k;let l=0,m=c,g=m.length;if(n&&!n[O]){for(let h of n[j]||[])h[Symbol.dispose]();n=null,p=0}if(g<p)n.length=g;else{if(!n)n=m;else for(;l<p;)n[l]=m[l++];for(;l<g;l++){n[l]=m[l];let h=l,w=Object.create(r,{[o]:{get:()=>n[h]},[s]:{value:a?a[h]:h}}),b=e.content?N(e):e.cloneNode(!0);i.before(b.content||b),f(b,w);let M=((k=n[D=j]||(n[D]=[]))[l]||(k[l]={}))[Symbol.dispose];n[j][l][Symbol.dispose]=()=>{M?.(),b[Symbol.dispose]?.(),b.remove()}}}p=g});return e.replaceWith(i),e[u]=null,l=>(a=null,typeof l=="number"?c=Array.from({length:l},(m,g)=>g+1):l?.constructor===Object?(a=Object.keys(l),c=Object.values(l)):c=l||[],v(()=>{c[O]?.value,y()}))};Ne.parse=e=>e.split(/\bin\b/)[1].trim();var $e=Ne;var De=(e,r,t,o)=>s=>x(e,o,d(s,e.getAttribute(o)));var Te=e=>r=>{for(let t in r)x(e,ue(t),r[t])};Object.assign(W,{"*":De,"":Te,class:je,text:xe,style:Se,fx:Ae,value:Oe,ref:ke,scope:we,if:he,else:be,each:$e});Object.assign(V,{debounce:(e,r=250,t=r==="tick"?queueMicrotask:r==="raf"?requestAnimationFrame:r==="idle"?requestIdleCallback:s=>setTimeout(s,r),o=0)=>pe(e,t),throttle:(e,r=250,t=r==="tick"?queueMicrotask:r==="raf"?requestAnimationFrame:o=>setTimeout(o,r))=>T(e,t),once:(e,r,t)=>Object.assign(o=>!r&&(r=1,e(o)),{once:!0}),prevent:e=>r=>(r?.preventDefault(),e(r)),stop:e=>r=>(r?.stopPropagation(),e(r)),immediate:e=>r=>(r?.stopImmediatePropagation(),e(r)),passive:e=>(e.passive=!0,e),capture:e=>(e.capture=!0,e),window:e=>(e.target=e.target.ownerDocument.defaultView,e),document:e=>(e.target=e.target.ownerDocument,e),root:e=>(e.target=e.target.ownerDocument.documentElement,e),body:e=>(e.target=e.target.ownerDocument.body,e),parent:e=>(e.target=e.target.parentNode,e),self:e=>r=>r.target===e.target&&e(r),outside:e=>(r,t)=>(t=e.target,!t.contains(r.target)&&r.target.isConnected&&(t.offsetWidth||t.offsetHeight))});var ie={ctrl:e=>e.ctrlKey||e.key==="Control"||e.key==="Ctrl",shift:e=>e.shiftKey||e.key==="Shift",alt:e=>e.altKey||e.key==="Alt",meta:e=>e.metaKey||e.key==="Meta"||e.key==="Command",arrow:e=>e.key.startsWith("Arrow"),enter:e=>e.key==="Enter",esc:e=>e.key.startsWith("Esc"),tab:e=>e.key==="Tab",space:e=>e.key==="\xA0"||e.key==="Space"||e.key===" ",delete:e=>e.key==="Delete"||e.key==="Backspace",digit:e=>/^\d$/.test(e.key),letter:e=>/^\p{L}$/gu.test(e.key),char:e=>/^\S$/.test(e.key)};for(let e in ie)V[e]=(r,...t)=>o=>ie[e](o)&&t.every(s=>ie[s]?.(o)??o.key===s)&&r(o);_({compile:e=>f.constructor(`with (arguments[0]) { ${e} }`),signal:oe,effect:se,computed:me,batch:ye,untracked:ge});f.use=_;f.store=F;f.directive=W;f.modifier=V;f.start=ce;var It=f;export{ye as batch,me as computed,It as default,se as effect,oe as signal,f as sprae,ce as start,F as store,ge as untracked,_ as use};
5
+ ${z}="${e}"`)}}},ee={},F=e=>(e.compile&&(re=e.compile),e.prefix&&(Z=e.prefix),e.signal&&(y=e.signal),e.effect&&(P=e.effect),e.computed&&(B=e.computed),e.batch&&(q=e.batch),e.untracked&&(v=e.untracked),e.dir&&(te=e.dir)),b=(e,r)=>{for(;r.length;){let[t,...o]=r.pop().split("-"),s=I[t],i;if(s&&(i=s(e,...o))!==e){for(let n in e)i[n]??(i[n]=e[n]);e=i}}return e},O=e=>{if(!e.nodeType)return e;let r=e.content.cloneNode(!0),t=[...e.attributes],o=document.createTextNode(""),s=(r.append(o),[...r.childNodes]);return{childNodes:s,content:r,remove:()=>r.append(...s),replaceWith(i){i!==o&&(o.before(i),r.append(...s))},attributes:t,removeAttribute(i){t.splice(t.findIndex(n=>n.name===i),1)}}},f=(e,r)=>typeof e=="function"?e(r):e,oe=e=>e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(r,t)=>(t?"-":"")+r.toLowerCase()),x=(e,r,t)=>t==null||t===!1?e.removeAttribute(r):e.setAttribute(r,t===!0?"":t),G=(e,r=[])=>e?typeof e=="string"?e:(Array.isArray(e)?e.map(G):Object.entries(e).reduce((t,[o,s])=>s?[...t,o]:t,[])).join(" "):"",$=(e,r=queueMicrotask)=>{let t=0,o,s=i=>{o=i,t++||(e(o),r((n=t>1)=>(t=0,n&&s(o))))};return s},se=(e,r=queueMicrotask,t=0)=>(o,s=++t)=>r(()=>s==t&&e(o)),d=Te;var _=Symbol("signals"),j=Symbol("change"),U=Symbol("set"),Q=!0,D=(e,r)=>{if(!e||e[Symbol.toStringTag]||e[_])return e;if(e.constructor!==Object)return Array.isArray(e)?$e(e):e;let t=Object.keys(e).length,o={},s=new Proxy(Object.assign(o,{[j]:y(t),[_]:o}),{get:(n,a)=>a in o?o[a]?o[a].valueOf():o[a]:r?r[a]:globalThis[a],set:(n,a,l,c)=>a in o?(ie(o,a,l),1):(Q=!1,r&&a in r?r[a]=l:(H(o,a,l),o[j].value=++t),Q=!0,1),deleteProperty:(n,a)=>(a in o&&(a[0]!="_"&&o[a]?.[Symbol.dispose]?.(),delete o[a],o[j].value=--t),1),ownKeys:()=>(o[j].value,Reflect.ownKeys(o)),has:(n,a)=>a in o?!0:r?a in r:Q}),i=Object.getOwnPropertyDescriptors(e);for(let n in e)i[n]?.get?(o[n]=B(i[n].get.bind(s)))[U]=i[n].set?.bind(s):H(o,n,e[n]);return s},$e=(e,r=globalThis)=>{let t=Array(e.length).fill(null),o=!1,s=a=>function(){return o=!0,a.apply(this,arguments)},i=y(e.length),n=new Proxy(Object.assign(t,{[j]:i,[_]:t,push:s(t.push),pop:s(t.pop),shift:s(t.shift),unshift:s(t.unshift),splice:s(t.splice)}),{get(a,l){return l==="length"?o?(o=!1,t.length):i.value:typeof l=="symbol"||isNaN(l)?t[l]?.valueOf()??r[l]:(t[l]??(t[l]=y(D(e[l])))).valueOf()},set(a,l,c){if(l==="length"){for(let m=c;m<t.length;m++)delete n[m];i.value=t.length=c}else l>=t.length?(H(t,l,c),n.length=+l+1):t[l]?ie(t,l,c):H(t,l,c);return 1},deleteProperty:(a,l)=>(t[l]?.[Symbol.dispose]?.(),delete t[l],1)});return n},H=(e,r,t)=>e[r]=r[0]=="_"||t?.peek?t:y(D(t)),ie=(e,r,t,o,s)=>r[0]==="_"?e[r]=t:t!==(s=(o=e[r]).peek())&&(o[U]?o[U](t):Array.isArray(t)&&Array.isArray(s)?j in s?v(()=>q(()=>{for(let i=0;i<t.length;i++)s[i]=t[i];s.length=t.length})):o.value=t:o.value=D(t)),R=D;var Y={};Ne(Y,{batch:()=>ve,computed:()=>De,effect:()=>le,signal:()=>ae,untracked:()=>Ce});var k,ne=0,C,ae=(e,r,t=new Set,o=()=>r.value)=>r={get value(){return k?.deps.add(t.add(k)),e},set value(s){if(s!==e){e=s;for(let i of t)C?C.add(i):i()}},peek(){return e},toJSON:o,toString:o,valueOf:o},le=(e,r,t,o)=>(t=s=>{let i=r;if(r=null,i?.call?.(),s=k,k=t,ne++>10)throw"Cycle detected";try{r=e()}finally{k=s,ne--}},t.fn=e,o=t.deps=new Set,t(),s=>{r?.call?.();for(s of o)s.delete(t);o.clear()}),De=(e,r=ae(),t,o,s=()=>t.value)=>t={get value(){return o||(o=le(()=>r.value=e())),r.value},peek:r.peek,toJSON:s,toString:s,valueOf:s},ve=(e,r=!C,t)=>{C??(C=new Set);try{e()}finally{if(r){[C,t]=[null,C];for(let o of t)o()}}},Ce=(e,r,t)=>(r=k,k=null,t=e(),k=r,t);var ce={name:"sprae",description:"DOM microhydration",version:"12.3.0",main:"./sprae.js",module:"./sprae.js","umd:main":"dist/sprae.umd.js",unpkg:"dist/sprae.umd.js",types:"dist/sprae.d.ts",type:"module",files:["core.js","sprae.js","store.js","signal.js","micro.js","directive","dist"],devDependencies:{"@preact/signals":"^2.0.4","@preact/signals-core":"^1.8.0","@webreflection/signal":"^2.1.2","es-module-shims":"^1.10.0",esbuild:"^0.23.0","esbuild-plugin-umd-wrapper":"^2.0.3","esbuild-plugin-version-injector":"^1.2.1",hyperf:"^1.7.0",jsdom:"^27.0.0",requestidlecallback:"^0.3.0","signal-polyfill":"^0.1.1",subscript:"^9.1.0",tst:"^8.0.2",ulive:"^1.0.7",usignal:"^0.9.0","wait-please":"^3.1.0"},scripts:{test:"node -r ./test/register.cjs test/test.js",build:"node .esbuild.js"},repository:{type:"git",url:"git+https://github.com/dy/sprae.git"},keywords:["hydration","progressive","progressive enhancement","signals","directives","preact-signals","reactive","template-parts","petit-vue","alpinejs","templating"],author:"Dmitry Iv <df.creative@gmail.com>",license:"MIT",bugs:{url:"https://github.com/dy/sprae/issues"},homepage:"https://github.com/dy/sprae#readme"};var ue=(e,r)=>{var i;let t,o,s;return e._holder?d(o=e,r):(e[i=p]??(e[i]=null),o=e.content?O(e):e,e.replaceWith(t=document.createTextNode("")),o._holder=t._holder=t,t._clauses=[o._clause=[o,!1]],t.update=$(()=>{let n=t._clauses.find(([,a])=>a);n!=s&&(s?.[0].remove(),s?.[0][M]?.(),(s=n)&&(t.before(s[0].content||s[0]),s[0][p]?s[0][V]?.():(delete s[0][p],d(s[0],r))))})),n=>{o._clause[1]=n,o._holder.update()}};var pe=e=>{let r,t=e;for(r=e.content?O(e):e;t&&!(r._holder=t._holder);)t=t.previousSibling;return e.remove(),e[p]=null,r._holder._clauses.push(r._clause=[r,!0]),r._holder.update};var de=e=>(e.content&&e.replaceWith(e=O(e).childNodes[0]),r=>(r=r&&f(r,e.textContent),e.textContent=r??""));var fe=(e,r,t,o)=>{let s=new Set,i;return o.includes(".")&&(e=b({target:e},o.split(".").slice(1)).target??e),n=>{i=new Set,n&&G(f(n,e.className)).split(" ").map(a=>a&&i.add(a));for(let a of s)i.has(a)?i.delete(a):e.classList.remove(a);for(let a of s=i)e.classList.add(a)}};var me=(e,r,t,o)=>{let s;return o.includes(".")&&(e=b({target:e},o.split(".").slice(1)).target??e),i=>{if(s||(s=e.getAttribute("style")),i&&(i=f(i,e.style)),typeof i=="string")x(e,"style",s+"; "+i);else{s&&x(e,"style",s);for(let n in i)n[0]=="-"?e.style.setProperty(n,i[n]):n[0]>"A"&&(e.style[n]=i[n])}}};var ge=()=>f;var Le=(e,r=g(`${e}=__`))=>(t,o)=>{t.__=o,r(t),delete t.__},he=(e,r,t)=>{try{let o=Le(t),s=e.type==="checkbox"?()=>o(r,e.checked):e.type==="select-multiple"?()=>o(r,[...e.selectedOptions].map(i=>i.value)):()=>o(r,e.selectedIndex<0?null:isNaN(e.valueAsNumber)?e.value:e.valueAsNumber);e.oninput=e.onchange=s,e.type?.startsWith("select")&&(new MutationObserver(s).observe(e,{childList:!0,subtree:!0,attributes:!0}),d(e,r)),g(t)(r)??s()}catch{}return e.type==="text"||e.type===""||e.tagName==="TEXTAREA"?(o,s,i)=>(s=e.selectionStart,i=e.selectionEnd,e.setAttribute("value",e.value=o??""),s&&e.setSelectionRange(s,i)):e.type==="checkbox"?o=>(e.checked=o,x(e,"checked",o)):e.type==="radio"?o=>e.value===o&&(e.checked=o,x(e,"checked",o)):e.type==="select-one"?o=>{for(let s of e.options)s.value==o?s.setAttribute("selected",""):s.removeAttribute("selected");e.value=o}:e.type==="select-multiple"?o=>{for(let s of e.options)s.removeAttribute("selected");for(let s of o)e.querySelector(`[value="${s}"]`).setAttribute("selected","")}:o=>e.value=o};var ye=(e,r,t)=>{let o=g(t)(r);if(typeof o=="function")return{[Symbol.dispose]:o(e)};Object.defineProperty(r,t,{value:e,configurable:!0})};var be=(e,r)=>{let t=e[p]=D({},r),o=!1;return s=>{if(s=f(s,t),s!==t)for(let i in s){let n=typeof s[i]=="function"?s[i].bind(t):s[i];i in t[_]?t[i]=n:t[_][i]=i[0]=="_"||n?.peek?n:y(D(n))}return!o&&(o=!0,delete e[p],v(()=>d(e,t)))}};var xe=(e,r,t)=>{let[o,s]=t.split(/\bin\b/),[i,n="$"]=o.trim().replace(/\(|\)/g,"").split(/\s*,\s*/),a=document.createTextNode(""),l,c,m,w=0,S=$(()=>{var A,E;let u=0,N=m,h=N.length;if(l&&!l[j]){for(let L of l[_]||[])L[Symbol.dispose]();l=null,w=0}if(h<w)l.length=h;else{if(!l)l=N;else for(;u<w;)l[u]=N[u++];for(;u<h;u++){l[u]=N[u];let L=u,Ae=Object.create(r,{[i]:{get:()=>l[L]},[n]:{value:c?c[L]:L}}),W=e.content?O(e):e.cloneNode(!0);a.before(W.content||W),d(W,Ae);let Oe=((E=l[A=_]||(l[A]=[]))[u]||(E[u]={}))[Symbol.dispose];l[_][u][Symbol.dispose]=()=>{Oe?.(),W[Symbol.dispose]?.(),W.remove()}}}w=h});return e.replaceWith(a),e[p]=null,Object.assign(u=>(c=null,typeof u=="number"?m=Array.from({length:u},(N,h)=>h+1):u?.constructor===Object?(c=Object.keys(u),m=Object.values(u)):m=u||[],P(()=>{m[j]?.value,S()})),{eval:g(s)})};var _e=(e,r,t,o)=>s=>x(e,o,s&&f(s,e.getAttribute(o)));var Se=e=>r=>{for(let t in r)x(e,oe(t),r[t])};var je=(e,r,t,o)=>{let[s,...i]=o.slice(2).split("."),n=g(t).bind(e),a=b(Object.assign(l=>n(r,c=>c&&f(c,l)),{target:e}),i);return a.target.addEventListener(s,a,a),{[Symbol.dispose](){a.target.removeEventListener(s,a)}}};var we=(e,r,t,o)=>{let s,i,n=o.split("..").map((a,l,{length:c})=>a.split(":").reduce((m,w)=>{let[S,...u]=w.slice(2).split("."),N=g(t).bind(e),h=b(Object.assign(A=>(l?s=s(A):N(r,E=>s=E&&f(E,A)),i(),i=n[(l+1)%c]()),{target:e}),u);return A=>(A=m?.(),h.target.addEventListener(S,h,h),()=>(A?.(),h.target.removeEventListener(S,h)))},null));return i=n[0](),{[Symbol.dispose](){i?.()}}};Object.assign(K,{_:(e,r,t,o)=>(o.startsWith("on")?je:_e)(e,r,t,o),"":Se,class:fe,text:de,style:me,fx:ge,value:he,ref:ye,scope:be,if:ue,else:pe,each:xe});var We=(e,r,t,o)=>{let[s,...i]=r.split("."),n=K[s]||K._;return()=>{let a=n(e,o,t,r);if(!a?.call)return a?.[T];let l=b(Object.assign($(()=>c.value++),{target:e}),i),c=y(0),m=0,w=a.eval??g(t).bind(e),S,u=()=>(S&&f(S),S=null);return o=e[p]??o,P(()=>(c.value==m?l():(m=c.value,S=w(o,a)),u))}};Object.assign(I,{debounce:(e,r=250)=>se(e,(r||(r=0),t=>setTimeout(t,r))),throttle:(e,r=250)=>$(e,(r||(r=0),t=>setTimeout(t,r))),tick:e=>r=>queueMicrotask(()=>e(r)),raf:e=>r=>requestAnimationFrame(()=>e(r)),once:(e,r,t)=>(t=o=>!r&&(r=1,e(o)),t.once=!0,t),window:e=>(e.target=e.target.ownerDocument.defaultView,e),document:e=>(e.target=e.target.ownerDocument,e),root:e=>(e.target=e.target.ownerDocument.documentElement,e),body:e=>(e.target=e.target.ownerDocument.body,e),parent:e=>(e.target=e.target.parentNode,e),self:e=>r=>r.target===e.target&&e(r),outside:e=>(r,t)=>(t=e.target,!t.contains(r.target)&&r.target.isConnected&&(t.offsetWidth||t.offsetHeight)),prevent:e=>r=>(r?.preventDefault(),e(r)),stop:e=>r=>(r?.stopPropagation(),e(r)),immediate:e=>r=>(r?.stopImmediatePropagation(),e(r)),passive:e=>(e.passive=!0,e),capture:e=>(e.capture=!0,e)});var X={ctrl:e=>e.ctrlKey||e.key==="Control"||e.key==="Ctrl",shift:e=>e.shiftKey||e.key==="Shift",alt:e=>e.altKey||e.key==="Alt",meta:e=>e.metaKey||e.key==="Meta",cmd:e=>e.metaKey||e.key==="Command",arrow:e=>e.key.startsWith("Arrow"),enter:e=>e.key==="Enter",esc:e=>e.key.startsWith("Esc"),tab:e=>e.key==="Tab",space:e=>e.key==="\xA0"||e.key==="Space"||e.key===" ",delete:e=>e.key==="Delete"||e.key==="Backspace",digit:e=>/^\d$/.test(e.key),letter:e=>/^\p{L}$/gu.test(e.key),char:e=>/^\S$/.test(e.key)};for(let e in X)I[e]=(r,t,o)=>s=>X[e](s)&&(!t||X[t]?.(s))&&(!o||X[o]?.(s))&&r(s);F({compile:e=>d.constructor(`with (arguments[0]) { ${e} }`),dir:(e,r,t,o)=>r.includes("..")?()=>we(e,o,t,r)[T]:r.split(":").reduce((s,i)=>{let n=We(e,i,t,o);return s?(a,l)=>(a=s(),l=n(),()=>{a(),l()}):n},null),...Y});d.use=F;d.store=R;d.directive=K;d.modifier=I;d.version=ce.version;var Ht=d.start=(e=document.body,r)=>{let t=R(r);return d(e,t),new MutationObserver(s=>{for(let i of s)for(let n of i.addedNodes)n.nodeType===1&&n[p]===void 0&&e.contains(n)&&e[J](n)}).observe(e,{childList:!0,subtree:!0}),t};d.version="12.3.0";var Xt=d;export{q as batch,B as computed,Xt as default,P as effect,y as signal,d as sprae,Ht as start,R as store,v as untracked,F as use};