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/readme.md CHANGED
@@ -1,8 +1,8 @@
1
- # [∴](https://dy.github.io/sprae) sprae [![tests](https://github.com/dy/sprae/actions/workflows/node.js.yml/badge.svg)](https://github.com/dy/sprae/actions/workflows/node.js.yml) ![size](https://img.shields.io/badge/size-~5kb-white) [![npm](https://img.shields.io/npm/v/sprae?color=white)](https://www.npmjs.com/package/sprae)
1
+ # [∴](https://dy.github.io/sprae) sprae [![tests](https://github.com/dy/sprae/actions/workflows/node.js.yml/badge.svg)](https://github.com/dy/sprae/actions/workflows/node.js.yml) ![size](https://img.shields.io/badge/size-~8kb-white) [![npm](https://img.shields.io/npm/v/sprae?color=white)](https://www.npmjs.com/package/sprae)
2
2
 
3
- > Microhydration for HTML/JSX tree.
3
+ > Reactive sprinkles for HTML/JSX.
4
4
 
5
- Open & minimal PE framework with signals-based reactivity.
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
- ~5kb script that adds reactivity to HTML via `:attribute="expression"`. No build step, no new syntax.
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
- 3x lighter, pluggable signals, prop modifiers, event chains. Faster in [benchmarks](https://krausest.github.io/js-framework-benchmark/).
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 [safe evaluator](#csp-safe-evaluator).
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
- It is used by a few SaaS systems and landing pages of big guys.
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, _s, _obs = new Set, _v = () => _s.value) => (
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, _s = signal(), _c, _e, _v = () => _c.value) => (
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, _v) => (_prev = current, current = null, _v = fn(), current = _prev, _v)
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, name, expr, state) => {
69
- let [dirName, ...mods] = name.split('.'), create = directive[dirName] || directive._
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).bind(el),
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 (name.includes('..')) return () => _seq(el, state, expr, name)[_dispose]
236
- return name.split(':').reduce((prev, str) => {
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 = str.startsWith('on') ? () => _event(el, state, expr, str)[_dispose]
241
- : obs?.observer ? () => obs(el, state, expr, str)[_dispose]
242
- : dir(el, str, expr, state)
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
- mut = fn => function () { isMut = true; return fn.apply(this, arguments); },
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(signals.splice),
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
- // force cleaning up tail
190
- for (let i = v; i < signals.length; i++) delete state[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] ? set(signals, k, v, shallow) : create(signals, k, v, shallow)
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
- let ver = signal(0)
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 : (ver.value, t[k]),
228
- set: (t, k, val) => { let prev = t[k]; t[k] = val; if (prev !== val) ver.value++; return 1 },
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<T_1 extends Function>(fn: T_1, ms?: number | Function): T_1;
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../core.js"],"names":[],"mappings":"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"}
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":"AAuBe;;;;EAqHd;;qBA5I6F,YAAY"}
1
+ {"version":3,"file":"each.d.ts","sourceRoot":"","sources":["../../directive/each.js"],"names":[],"mappings":"AAiBe;;;;EAuJd;;qBAxKgH,YAAY"}
@@ -1,3 +1,4 @@
1
1
  declare function _default(el: Element | HTMLTemplateElement, state: any): (value: any) => void;
2
2
  export default _default;
3
+ export function _else(el: Element | HTMLTemplateElement): () => void;
3
4
  //# sourceMappingURL=if.d.ts.map
@@ -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, _s: any, _obs?: Set<any>, _v?: () => any): import("./core.js").Signal<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, _s: import("./core.js").Signal<any>, _c: any, _e: any, _v?: () => any): import("./core.js").Signal<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, _v: any): T;
5
+ export function untracked<T>(fn: () => T, _prev: any): T;
6
6
  //# sourceMappingURL=signal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../signal.js"],"names":[],"mappings":"AAmBO,uBAJM,CAAC,KACH,CAAC,6CACC,OAAO,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAgBzC;AAOM,2BAHI,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,yCACvB,MAAM,IAAI,CAsBtB;AAQM,yBAJM,CAAC,MACH,MAAM,CAAC,0EACL,OAAO,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAWzC;AAQM,sBAJM,CAAC,MACH,MAAM,CAAC,gCACL,CAAC,CAMb;AAQM,0BAJM,CAAC,MACH,MAAM,CAAC,wBACL,CAAC,CAE+F"}
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"}
@@ -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;AA2PhI,4BAFL,OAAO,OAEsC"}
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>;
@@ -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,3 +0,0 @@
1
- declare function _default(el: Element | HTMLTemplateElement): () => void;
2
- export default _default;
3
- //# sourceMappingURL=else.d.ts.map
@@ -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"}