sigmx 0.1.0 → 0.2.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.
Files changed (308) hide show
  1. package/README.md +54 -43
  2. package/dist/cli.js +3 -1
  3. package/dist/cli.js.map +2 -2
  4. package/dist/kernel/compile.d.ts +8 -9
  5. package/dist/kernel/compile.js +102 -67
  6. package/dist/kernel/compile.js.map +2 -2
  7. package/dist/kernel/contracts.d.ts +12 -13
  8. package/dist/kernel/index.d.ts +11 -12
  9. package/dist/kernel/index.js +14 -12
  10. package/dist/kernel/index.js.map +3 -3
  11. package/dist/kernel/precompile.d.ts +8 -12
  12. package/dist/kernel/precompile.js +33 -76
  13. package/dist/kernel/precompile.js.map +2 -2
  14. package/dist/kernel/precompiled.d.ts +7 -4
  15. package/dist/kernel/precompiled.js +5 -5
  16. package/dist/kernel/precompiled.js.map +2 -2
  17. package/dist/kernel/reactive.d.ts +13 -11
  18. package/dist/kernel/reactive.js +96 -71
  19. package/dist/kernel/reactive.js.map +3 -3
  20. package/dist/kernel/runtime.js +85 -63
  21. package/dist/kernel/runtime.js.map +3 -3
  22. package/dist/kernel/scan.d.ts +2 -11
  23. package/dist/kernel/scan.js +26 -9
  24. package/dist/kernel/scan.js.map +2 -2
  25. package/dist/kernel/state.d.ts +5 -8
  26. package/dist/kernel/state.js +114 -76
  27. package/dist/kernel/state.js.map +2 -2
  28. package/dist/kernel/strict-csp.d.ts +0 -5
  29. package/dist/kernel/strict-csp.js +2 -2
  30. package/dist/kernel/strict-csp.js.map +2 -2
  31. package/dist/lib/casing.d.ts +4 -1
  32. package/dist/lib/casing.js +8 -1
  33. package/dist/lib/casing.js.map +2 -2
  34. package/dist/lib/objects.d.ts +5 -4
  35. package/dist/lib/objects.js +13 -5
  36. package/dist/lib/objects.js.map +2 -2
  37. package/dist/lib/schedule.d.ts +3 -5
  38. package/dist/lib/schedule.js +12 -10
  39. package/dist/lib/schedule.js.map +2 -2
  40. package/dist/lib/sse.d.ts +10 -1
  41. package/dist/lib/sse.js +32 -28
  42. package/dist/lib/sse.js.map +2 -2
  43. package/dist/plugins/def.d.ts +5 -0
  44. package/dist/plugins/def.js +22 -0
  45. package/dist/plugins/def.js.map +7 -0
  46. package/dist/plugins/directives/attribute-sync.js +8 -12
  47. package/dist/plugins/directives/attribute-sync.js.map +2 -2
  48. package/dist/plugins/directives/boost.d.ts +1 -1
  49. package/dist/plugins/directives/boost.js +34 -30
  50. package/dist/plugins/directives/boost.js.map +2 -2
  51. package/dist/plugins/directives/busy-flag.js +13 -16
  52. package/dist/plugins/directives/busy-flag.js.map +2 -2
  53. package/dist/plugins/directives/class-toggle.js +17 -16
  54. package/dist/plugins/directives/class-toggle.js.map +2 -2
  55. package/dist/plugins/directives/cloak.js +2 -7
  56. package/dist/plugins/directives/cloak.js.map +2 -2
  57. package/dist/plugins/directives/collapse.js +36 -37
  58. package/dist/plugins/directives/collapse.js.map +2 -2
  59. package/dist/plugins/directives/declare.js +5 -8
  60. package/dist/plugins/directives/declare.js.map +2 -2
  61. package/dist/plugins/directives/derive.js +9 -15
  62. package/dist/plugins/directives/derive.js.map +2 -2
  63. package/dist/plugins/directives/element-ref.js +8 -8
  64. package/dist/plugins/directives/element-ref.js.map +2 -2
  65. package/dist/plugins/directives/event-listener.js +18 -23
  66. package/dist/plugins/directives/event-listener.js.map +2 -2
  67. package/dist/plugins/directives/frame-loop.js +9 -14
  68. package/dist/plugins/directives/frame-loop.js.map +2 -2
  69. package/dist/plugins/directives/html.js +6 -7
  70. package/dist/plugins/directives/html.js.map +2 -2
  71. package/dist/plugins/directives/inline-style.js +17 -20
  72. package/dist/plugins/directives/inline-style.js.map +2 -2
  73. package/dist/plugins/directives/mask.js +19 -23
  74. package/dist/plugins/directives/mask.js.map +2 -2
  75. package/dist/plugins/directives/media-query.d.ts +4 -1
  76. package/dist/plugins/directives/media-query.js +13 -12
  77. package/dist/plugins/directives/media-query.js.map +2 -2
  78. package/dist/plugins/directives/on-mount.js +4 -9
  79. package/dist/plugins/directives/on-mount.js.map +2 -2
  80. package/dist/plugins/directives/patch-listener.js +24 -19
  81. package/dist/plugins/directives/patch-listener.js.map +2 -2
  82. package/dist/plugins/directives/remove-me.js +7 -8
  83. package/dist/plugins/directives/remove-me.js.map +2 -2
  84. package/dist/plugins/directives/scroll-to.d.ts +4 -1
  85. package/dist/plugins/directives/scroll-to.js +8 -14
  86. package/dist/plugins/directives/scroll-to.js.map +2 -2
  87. package/dist/plugins/directives/size-watch.js +7 -12
  88. package/dist/plugins/directives/size-watch.js.map +2 -2
  89. package/dist/plugins/directives/state-dump.js +6 -10
  90. package/dist/plugins/directives/state-dump.js.map +2 -2
  91. package/dist/plugins/directives/storage-sync.js +13 -9
  92. package/dist/plugins/directives/storage-sync.js.map +2 -2
  93. package/dist/plugins/directives/teleport.js +8 -14
  94. package/dist/plugins/directives/teleport.js.map +2 -2
  95. package/dist/plugins/directives/text-content.js +6 -7
  96. package/dist/plugins/directives/text-content.js.map +2 -2
  97. package/dist/plugins/directives/timer.js +7 -13
  98. package/dist/plugins/directives/timer.js.map +2 -2
  99. package/dist/plugins/directives/transition.d.ts +1 -2
  100. package/dist/plugins/directives/transition.js +32 -34
  101. package/dist/plugins/directives/transition.js.map +2 -2
  102. package/dist/plugins/directives/tween.d.ts +2 -2
  103. package/dist/plugins/directives/tween.js +34 -50
  104. package/dist/plugins/directives/tween.js.map +2 -2
  105. package/dist/plugins/directives/two-way-bind.d.ts +1 -1
  106. package/dist/plugins/directives/two-way-bind.js +70 -67
  107. package/dist/plugins/directives/two-way-bind.js.map +2 -2
  108. package/dist/plugins/directives/url-params.js +36 -59
  109. package/dist/plugins/directives/url-params.js.map +3 -3
  110. package/dist/plugins/directives/url-replace.js +6 -7
  111. package/dist/plugins/directives/url-replace.js.map +2 -2
  112. package/dist/plugins/directives/validity.js +6 -9
  113. package/dist/plugins/directives/validity.js.map +2 -2
  114. package/dist/plugins/directives/viewport.js +18 -23
  115. package/dist/plugins/directives/viewport.js.map +2 -2
  116. package/dist/plugins/directives/visibility.js +9 -14
  117. package/dist/plugins/directives/visibility.js.map +2 -2
  118. package/dist/plugins/directives/watch.d.ts +0 -1
  119. package/dist/plugins/directives/watch.js +2 -8
  120. package/dist/plugins/directives/watch.js.map +2 -2
  121. package/dist/plugins/functions/bulk-set.js +10 -7
  122. package/dist/plugins/functions/bulk-set.js.map +2 -2
  123. package/dist/plugins/functions/bulk-toggle.js +10 -7
  124. package/dist/plugins/functions/bulk-toggle.js.map +2 -2
  125. package/dist/plugins/functions/confirm.js +2 -2
  126. package/dist/plugins/functions/confirm.js.map +2 -2
  127. package/dist/plugins/functions/copy-text.js +5 -5
  128. package/dist/plugins/functions/copy-text.js.map +2 -2
  129. package/dist/plugins/functions/dispatch.js +5 -5
  130. package/dist/plugins/functions/dispatch.js.map +2 -2
  131. package/dist/plugins/functions/locale-format.d.ts +4 -1
  132. package/dist/plugins/functions/locale-format.js +9 -16
  133. package/dist/plugins/functions/locale-format.js.map +2 -2
  134. package/dist/plugins/functions/range-map.js +6 -6
  135. package/dist/plugins/functions/range-map.js.map +2 -2
  136. package/dist/plugins/functions/request.d.ts +7 -3
  137. package/dist/plugins/functions/request.js +85 -80
  138. package/dist/plugins/functions/request.js.map +2 -2
  139. package/dist/plugins/functions/untracked-read.js +3 -2
  140. package/dist/plugins/functions/untracked-read.js.map +2 -2
  141. package/dist/plugins/functions/websocket.d.ts +3 -3
  142. package/dist/plugins/functions/websocket.js +18 -25
  143. package/dist/plugins/functions/websocket.js.map +2 -2
  144. package/dist/plugins/index.d.ts +34 -36
  145. package/dist/plugins/index.js +31 -35
  146. package/dist/plugins/index.js.map +2 -2
  147. package/dist/plugins/server-events/apply-elements.d.ts +1 -1
  148. package/dist/plugins/server-events/apply-elements.js +41 -40
  149. package/dist/plugins/server-events/apply-elements.js.map +2 -2
  150. package/dist/plugins/server-events/apply-state.js +9 -12
  151. package/dist/plugins/server-events/apply-state.js.map +2 -2
  152. package/dist/plugins/server-events/morph.d.ts +0 -2
  153. package/dist/plugins/server-events/morph.js +58 -55
  154. package/dist/plugins/server-events/morph.js.map +3 -3
  155. package/dist/presets/all.d.ts +0 -1
  156. package/dist/presets/all.js +22 -26
  157. package/dist/presets/all.js.map +2 -2
  158. package/dist/presets/essentials.d.ts +0 -1
  159. package/dist/presets/essentials.js +27 -9
  160. package/dist/presets/essentials.js.map +2 -2
  161. package/dist/presets/minimal.d.ts +0 -1
  162. package/dist/presets/minimal.js +2 -2
  163. package/dist/presets/minimal.js.map +2 -2
  164. package/dist/server.d.ts +108 -0
  165. package/dist/server.js +218 -0
  166. package/dist/server.js.map +7 -0
  167. package/dist/sigmx.standalone.js +1 -1
  168. package/dist/standalone.js.map +2 -2
  169. package/dist/vite.d.ts +2 -2
  170. package/dist/vite.js +48 -15
  171. package/dist/vite.js.map +2 -2
  172. package/package.json +21 -2
  173. package/dist/auto.d.ts +0 -1
  174. package/dist/auto.js +0 -7
  175. package/dist/auto.js.map +0 -7
  176. package/dist/core/csp.d.ts +0 -7
  177. package/dist/core/csp.js +0 -20
  178. package/dist/core/csp.js.map +0 -7
  179. package/dist/core/engine.d.ts +0 -10
  180. package/dist/core/engine.js +0 -200
  181. package/dist/core/engine.js.map +0 -7
  182. package/dist/core/expr.d.ts +0 -12
  183. package/dist/core/expr.js +0 -94
  184. package/dist/core/expr.js.map +0 -7
  185. package/dist/core/index.d.ts +0 -16
  186. package/dist/core/index.js +0 -46
  187. package/dist/core/index.js.map +0 -7
  188. package/dist/core/signals.d.ts +0 -42
  189. package/dist/core/signals.js +0 -195
  190. package/dist/core/signals.js.map +0 -7
  191. package/dist/core/store.d.ts +0 -32
  192. package/dist/core/store.js +0 -185
  193. package/dist/core/store.js.map +0 -7
  194. package/dist/core/types.d.ts +0 -101
  195. package/dist/core/types.js +0 -1
  196. package/dist/core/types.js.map +0 -7
  197. package/dist/plugins/actions/clipboard.d.ts +0 -2
  198. package/dist/plugins/actions/clipboard.js +0 -11
  199. package/dist/plugins/actions/clipboard.js.map +0 -7
  200. package/dist/plugins/actions/fit.d.ts +0 -2
  201. package/dist/plugins/actions/fit.js +0 -14
  202. package/dist/plugins/actions/fit.js.map +0 -7
  203. package/dist/plugins/actions/intl.d.ts +0 -2
  204. package/dist/plugins/actions/intl.js +0 -21
  205. package/dist/plugins/actions/intl.js.map +0 -7
  206. package/dist/plugins/actions/peek.d.ts +0 -2
  207. package/dist/plugins/actions/peek.js +0 -6
  208. package/dist/plugins/actions/peek.js.map +0 -7
  209. package/dist/plugins/actions/setAll.d.ts +0 -2
  210. package/dist/plugins/actions/setAll.js +0 -11
  211. package/dist/plugins/actions/setAll.js.map +0 -7
  212. package/dist/plugins/actions/toggleAll.d.ts +0 -2
  213. package/dist/plugins/actions/toggleAll.js +0 -11
  214. package/dist/plugins/actions/toggleAll.js.map +0 -7
  215. package/dist/plugins/attributes/attr.d.ts +0 -2
  216. package/dist/plugins/attributes/attr.js +0 -20
  217. package/dist/plugins/attributes/attr.js.map +0 -7
  218. package/dist/plugins/attributes/bind.d.ts +0 -6
  219. package/dist/plugins/attributes/bind.js +0 -81
  220. package/dist/plugins/attributes/bind.js.map +0 -7
  221. package/dist/plugins/attributes/class.d.ts +0 -2
  222. package/dist/plugins/attributes/class.js +0 -22
  223. package/dist/plugins/attributes/class.js.map +0 -7
  224. package/dist/plugins/attributes/computed.d.ts +0 -2
  225. package/dist/plugins/attributes/computed.js +0 -20
  226. package/dist/plugins/attributes/computed.js.map +0 -7
  227. package/dist/plugins/attributes/customValidity.d.ts +0 -2
  228. package/dist/plugins/attributes/customValidity.js +0 -14
  229. package/dist/plugins/attributes/customValidity.js.map +0 -7
  230. package/dist/plugins/attributes/effect.d.ts +0 -2
  231. package/dist/plugins/attributes/effect.js +0 -12
  232. package/dist/plugins/attributes/effect.js.map +0 -7
  233. package/dist/plugins/attributes/indicator.d.ts +0 -2
  234. package/dist/plugins/attributes/indicator.js +0 -20
  235. package/dist/plugins/attributes/indicator.js.map +0 -7
  236. package/dist/plugins/attributes/init.d.ts +0 -2
  237. package/dist/plugins/attributes/init.js +0 -14
  238. package/dist/plugins/attributes/init.js.map +0 -7
  239. package/dist/plugins/attributes/jsonSignals.d.ts +0 -2
  240. package/dist/plugins/attributes/jsonSignals.js +0 -15
  241. package/dist/plugins/attributes/jsonSignals.js.map +0 -7
  242. package/dist/plugins/attributes/matchMedia.d.ts +0 -2
  243. package/dist/plugins/attributes/matchMedia.js +0 -19
  244. package/dist/plugins/attributes/matchMedia.js.map +0 -7
  245. package/dist/plugins/attributes/on.d.ts +0 -5
  246. package/dist/plugins/attributes/on.js +0 -28
  247. package/dist/plugins/attributes/on.js.map +0 -7
  248. package/dist/plugins/attributes/onIntersect.d.ts +0 -2
  249. package/dist/plugins/attributes/onIntersect.js +0 -28
  250. package/dist/plugins/attributes/onIntersect.js.map +0 -7
  251. package/dist/plugins/attributes/onInterval.d.ts +0 -2
  252. package/dist/plugins/attributes/onInterval.js +0 -18
  253. package/dist/plugins/attributes/onInterval.js.map +0 -7
  254. package/dist/plugins/attributes/onRaf.d.ts +0 -1
  255. package/dist/plugins/attributes/onRaf.js +0 -19
  256. package/dist/plugins/attributes/onRaf.js.map +0 -7
  257. package/dist/plugins/attributes/onResize.d.ts +0 -1
  258. package/dist/plugins/attributes/onResize.js +0 -17
  259. package/dist/plugins/attributes/onResize.js.map +0 -7
  260. package/dist/plugins/attributes/onSignalPatch.d.ts +0 -5
  261. package/dist/plugins/attributes/onSignalPatch.js +0 -35
  262. package/dist/plugins/attributes/onSignalPatch.js.map +0 -7
  263. package/dist/plugins/attributes/persist.d.ts +0 -6
  264. package/dist/plugins/attributes/persist.js +0 -16
  265. package/dist/plugins/attributes/persist.js.map +0 -7
  266. package/dist/plugins/attributes/queryString.d.ts +0 -5
  267. package/dist/plugins/attributes/queryString.js +0 -54
  268. package/dist/plugins/attributes/queryString.js.map +0 -7
  269. package/dist/plugins/attributes/ref.d.ts +0 -2
  270. package/dist/plugins/attributes/ref.js +0 -13
  271. package/dist/plugins/attributes/ref.js.map +0 -7
  272. package/dist/plugins/attributes/replaceUrl.d.ts +0 -1
  273. package/dist/plugins/attributes/replaceUrl.js +0 -11
  274. package/dist/plugins/attributes/replaceUrl.js.map +0 -7
  275. package/dist/plugins/attributes/scrollIntoView.d.ts +0 -2
  276. package/dist/plugins/attributes/scrollIntoView.js +0 -19
  277. package/dist/plugins/attributes/scrollIntoView.js.map +0 -7
  278. package/dist/plugins/attributes/show.d.ts +0 -2
  279. package/dist/plugins/attributes/show.js +0 -19
  280. package/dist/plugins/attributes/show.js.map +0 -7
  281. package/dist/plugins/attributes/signals.d.ts +0 -2
  282. package/dist/plugins/attributes/signals.js +0 -13
  283. package/dist/plugins/attributes/signals.js.map +0 -7
  284. package/dist/plugins/attributes/style.d.ts +0 -2
  285. package/dist/plugins/attributes/style.js +0 -25
  286. package/dist/plugins/attributes/style.js.map +0 -7
  287. package/dist/plugins/attributes/text.d.ts +0 -1
  288. package/dist/plugins/attributes/text.js +0 -13
  289. package/dist/plugins/attributes/text.js.map +0 -7
  290. package/dist/plugins/attributes/viewTransition.d.ts +0 -1
  291. package/dist/plugins/attributes/viewTransition.js +0 -11
  292. package/dist/plugins/attributes/viewTransition.js.map +0 -7
  293. package/dist/plugins/directives/transition-name.d.ts +0 -1
  294. package/dist/plugins/directives/transition-name.js +0 -11
  295. package/dist/plugins/directives/transition-name.js.map +0 -7
  296. package/dist/plugins/directives/trap.d.ts +0 -5
  297. package/dist/plugins/directives/trap.js +0 -48
  298. package/dist/plugins/directives/trap.js.map +0 -7
  299. package/dist/sigmx.auto.js +0 -5
  300. package/dist/utils/object.d.ts +0 -9
  301. package/dist/utils/object.js +0 -26
  302. package/dist/utils/object.js.map +0 -7
  303. package/dist/utils/text.d.ts +0 -7
  304. package/dist/utils/text.js +0 -15
  305. package/dist/utils/text.js.map +0 -7
  306. package/dist/utils/timing.d.ts +0 -14
  307. package/dist/utils/timing.js +0 -58
  308. package/dist/utils/timing.js.map +0 -7
@@ -5,19 +5,15 @@ let flushing = false;
5
5
  const queue = /* @__PURE__ */ new Set();
6
6
  const settled = /* @__PURE__ */ new Set();
7
7
  class Signal {
8
- /** @internal */
9
- a;
10
- /** @internal */
11
- e = 0;
12
- /** @internal */
13
- f = /* @__PURE__ */ new Set();
8
+ d = 0;
9
+ e = /* @__PURE__ */ new Set();
14
10
  constructor(v) {
15
11
  this.a = v;
16
12
  }
17
13
  get value() {
18
14
  if (active) {
19
- active.b.set(this, this.e);
20
- this.f.add(active);
15
+ active.b.set(this, this.d);
16
+ this.e.add(active);
21
17
  }
22
18
  return this.a;
23
19
  }
@@ -27,28 +23,20 @@ class Signal {
27
23
  this.bump();
28
24
  }
29
25
  }
30
- /** Read without subscribing. */
31
26
  peek() {
32
27
  return this.a;
33
28
  }
34
29
  /** Notify subscribers without replacing the value (after mutating an array or object in place). */
35
30
  bump() {
36
- this.e++;
37
- for (const s of this.f) s.h();
38
- if (!depth) flush();
31
+ this.d++;
32
+ for (const s of this.e) s.g();
33
+ depth || flush();
39
34
  }
40
35
  }
41
36
  const release = (t) => {
42
- for (const d of t.b.keys()) d.f.delete(t);
37
+ for (const d of t.b.keys()) d.e.delete(t);
43
38
  t.b.clear();
44
39
  };
45
- const stale = (t) => {
46
- for (const [d, seen] of t.b) {
47
- if (d instanceof Computed) d.i();
48
- if (d.e !== seen) return true;
49
- }
50
- return false;
51
- };
52
40
  const capture = (t, fn) => {
53
41
  release(t);
54
42
  const prev = active;
@@ -59,85 +47,93 @@ const capture = (t, fn) => {
59
47
  active = prev;
60
48
  }
61
49
  };
50
+ const stale = (t) => {
51
+ if (!t.b.size) return true;
52
+ for (const [d, seen] of t.b) {
53
+ if (d instanceof Computed) d.l();
54
+ if (d.d !== seen) return true;
55
+ }
56
+ return false;
57
+ };
62
58
  class Computed extends Signal {
63
59
  b = /* @__PURE__ */ new Map();
64
- /** @internal */
65
- g = true;
66
- /** @internal */
67
- c;
60
+ c = true;
68
61
  constructor(fn) {
69
62
  super(void 0);
70
- this.c = fn;
71
- }
72
- /** @internal */
73
- i() {
74
- if (!this.g) return;
75
- this.g = false;
76
- if (this.b.size && !stale(this)) return;
77
- const x = capture(this, this.c);
63
+ this.h = fn;
64
+ }
65
+ l() {
66
+ if (!this.c) return;
67
+ this.c = false;
68
+ if (!stale(this)) return;
69
+ const x = capture(this, this.h);
78
70
  if (!Object.is(x, this.a)) {
79
71
  this.a = x;
80
- this.e++;
72
+ this.d++;
81
73
  }
82
74
  }
83
75
  get value() {
84
- this.i();
76
+ this.l();
85
77
  return super.value;
86
78
  }
87
79
  set value(_) {
88
- throw new Error("computed signals are read-only");
80
+ throw new Error("computed is read-only");
89
81
  }
90
- peek() {
91
- this.i();
92
- return this.a;
93
- }
94
- h() {
95
- if (!this.g) {
96
- this.g = true;
97
- for (const s of this.f) s.h();
82
+ g() {
83
+ if (!this.c) {
84
+ this.c = true;
85
+ for (const s of this.e) s.g();
98
86
  }
99
87
  }
88
+ /** Unsubscribe from every dependency; the computed is no longer recalculated. Public: the store calls it. */
89
+ dispose() {
90
+ release(this);
91
+ this.c = false;
92
+ }
100
93
  }
101
94
  class Effect {
102
95
  b = /* @__PURE__ */ new Map();
103
- j = false;
104
- k = false;
105
- d = /* @__PURE__ */ new Set();
106
- c;
107
- l;
96
+ f = false;
97
+ i = false;
98
+ j = /* @__PURE__ */ new Set();
108
99
  constructor(fn, onError) {
109
- this.c = fn;
110
- this.l = onError;
100
+ this.h = fn;
101
+ this.m = onError;
111
102
  }
112
- h() {
113
- if (!this.k && !this.j) {
114
- this.j = true;
103
+ g() {
104
+ if (!this.i && !this.f) {
105
+ this.f = true;
115
106
  queue.add(this);
116
107
  }
117
108
  }
118
109
  n() {
119
- this.j = false;
120
- if (this.k || this.b.size && !stale(this)) return;
121
- for (const c of this.d) c.m();
122
- this.d.clear();
110
+ this.f = false;
111
+ if (this.i) return;
123
112
  const prevOwner = owner;
124
113
  owner = this;
125
114
  depth++;
126
115
  try {
127
- capture(this, this.c);
116
+ if (stale(this)) {
117
+ this.o();
118
+ capture(this, this.h);
119
+ }
128
120
  } catch (e) {
129
- if (!this.l) throw e;
130
- this.l(e);
121
+ if (!this.m) throw e;
122
+ this.m(e);
131
123
  } finally {
132
124
  depth--;
133
125
  owner = prevOwner;
134
126
  }
135
127
  }
136
- m() {
137
- this.k = true;
128
+ o() {
129
+ for (const c of this.j) c.k();
130
+ this.j.clear();
131
+ }
132
+ k() {
133
+ this.i = true;
138
134
  release(this);
139
- for (const c of this.d) c.m();
140
- this.d.clear();
135
+ if (active === this) active = void 0;
136
+ this.o();
141
137
  queue.delete(this);
142
138
  }
143
139
  }
@@ -145,17 +141,31 @@ const signal = (value) => new Signal(value);
145
141
  const computed = (fn) => new Computed(fn);
146
142
  const effect = (fn, onError) => {
147
143
  const e = new Effect(fn, onError);
148
- owner?.d.add(e);
149
- e.n();
150
- if (!depth) flush();
151
- return () => e.m();
144
+ owner?.j.add(e);
145
+ try {
146
+ e.n();
147
+ depth || flush();
148
+ } catch (err) {
149
+ e.k();
150
+ throw err;
151
+ }
152
+ return () => e.k();
153
+ };
154
+ const rootEffect = (fn, onError) => {
155
+ const prev = owner;
156
+ owner = void 0;
157
+ try {
158
+ return effect(fn, onError);
159
+ } finally {
160
+ owner = prev;
161
+ }
152
162
  };
153
163
  const batch = (fn) => {
154
164
  depth++;
155
165
  try {
156
166
  return fn();
157
167
  } finally {
158
- if (!--depth) flush();
168
+ --depth || flush();
159
169
  }
160
170
  };
161
171
  const untracked = (fn) => {
@@ -174,18 +184,32 @@ const onSettled = (fn) => {
174
184
  const flush = () => {
175
185
  if (flushing || depth) return;
176
186
  flushing = true;
187
+ let thrown;
188
+ let failed = false;
177
189
  try {
178
190
  let guard = 0;
179
191
  while (queue.size) {
180
- if (++guard > 1e5) throw new Error("effect loop");
192
+ if (++guard > 1e5) {
193
+ for (const e2 of queue) e2.f = false;
194
+ queue.clear();
195
+ throw new Error("effect loop");
196
+ }
181
197
  const e = queue.values().next().value;
182
198
  queue.delete(e);
183
- e.n();
199
+ try {
200
+ e.n();
201
+ } catch (err) {
202
+ if (!failed) {
203
+ failed = true;
204
+ thrown = err;
205
+ }
206
+ }
184
207
  }
185
208
  } finally {
186
209
  flushing = false;
187
210
  }
188
211
  for (const fn of settled) fn();
212
+ if (failed) throw thrown;
189
213
  };
190
214
  export {
191
215
  Computed,
@@ -195,6 +219,7 @@ export {
195
219
  effect,
196
220
  flush,
197
221
  onSettled,
222
+ rootEffect,
198
223
  signal,
199
224
  untracked
200
225
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/kernel/reactive.ts"],
4
- "sourcesContent": ["// Reactive primitives: push invalidation, pull recomputation, version-checked effects.\n// No DOM dependency, so this module is unit-testable in plain Node.\n// Members prefixed with `_` are internal and get mangled by the build.\n\ninterface Tracker {\n _deps: Map<Signal<any>, number>\n _invalidate(): void\n}\n\nlet active: Tracker | undefined\nlet owner: Effect | undefined\nlet depth = 0\nlet flushing = false\nconst queue = new Set<Effect>()\nconst settled = new Set<() => void>()\n\nexport class Signal<T> {\n /** @internal */ _v: T\n /** @internal */ _ver = 0\n /** @internal */ _subs = new Set<Tracker>()\n constructor(v: T) {\n this._v = v\n }\n get value(): T {\n if (active) {\n active._deps.set(this, this._ver)\n this._subs.add(active)\n }\n return this._v\n }\n set value(x: T) {\n if (!Object.is(x, this._v)) {\n this._v = x\n this.bump()\n }\n }\n /** Read without subscribing. */\n peek(): T {\n return this._v\n }\n /** Notify subscribers without replacing the value (after mutating an array or object in place). */\n bump(): void {\n this._ver++\n for (const s of this._subs) s._invalidate()\n if (!depth) flush()\n }\n}\n\nconst release = (t: Tracker): void => {\n for (const d of t._deps.keys()) d._subs.delete(t)\n t._deps.clear()\n}\n\n/** True when any dependency's version moved since the tracker last ran. Refreshes computeds on the way. */\nconst stale = (t: Tracker): boolean => {\n for (const [d, seen] of t._deps) {\n if (d instanceof Computed) d._refresh()\n if (d._ver !== seen) return true\n }\n return false\n}\n\nconst capture = <R>(t: Tracker, fn: () => R): R => {\n release(t)\n const prev = active\n active = t\n try {\n return fn()\n } finally {\n active = prev\n }\n}\n\nexport class Computed<T> extends Signal<T> implements Tracker {\n _deps = new Map<Signal<any>, number>()\n /** @internal */ _dirty = true\n /** @internal */ _fn: () => T\n constructor(fn: () => T) {\n super(undefined as T)\n this._fn = fn\n }\n /** @internal */ _refresh(): void {\n if (!this._dirty) return\n this._dirty = false\n if (this._deps.size && !stale(this)) return\n const x = capture(this, this._fn)\n if (!Object.is(x, this._v)) {\n this._v = x\n this._ver++\n }\n }\n override get value(): T {\n this._refresh()\n return super.value\n }\n override set value(_: T) {\n throw new Error('computed signals are read-only')\n }\n override peek(): T {\n this._refresh()\n return this._v\n }\n _invalidate(): void {\n if (!this._dirty) {\n this._dirty = true\n for (const s of this._subs) s._invalidate()\n }\n }\n}\n\nclass Effect implements Tracker {\n _deps = new Map<Signal<any>, number>()\n _queued = false\n _dead = false\n _kids = new Set<Effect>()\n _fn: () => void\n _onError?: (e: unknown) => void\n constructor(fn: () => void, onError?: (e: unknown) => void) {\n this._fn = fn\n this._onError = onError\n }\n _invalidate(): void {\n if (!this._dead && !this._queued) {\n this._queued = true\n queue.add(this)\n }\n }\n _exec(): void {\n this._queued = false\n if (this._dead || (this._deps.size && !stale(this))) return\n for (const c of this._kids) c._dispose()\n this._kids.clear()\n const prevOwner = owner\n owner = this\n depth++\n try {\n capture(this, this._fn)\n } catch (e) {\n if (!this._onError) throw e\n this._onError(e)\n } finally {\n depth--\n owner = prevOwner\n }\n }\n _dispose(): void {\n this._dead = true\n release(this)\n for (const c of this._kids) c._dispose()\n this._kids.clear()\n queue.delete(this)\n }\n}\n\nexport const signal = <T>(value: T): Signal<T> => new Signal(value)\nexport const computed = <T>(fn: () => T): Computed<T> => new Computed(fn)\n\n/**\n * Run `fn` now and again whenever a signal it read changes. Effects created inside another\n * effect are disposed when the parent re-runs. Returns a disposer.\n */\nexport const effect = (fn: () => void, onError?: (e: unknown) => void): (() => void) => {\n const e = new Effect(fn, onError)\n owner?._kids.add(e)\n e._exec()\n if (!depth) flush()\n return () => e._dispose()\n}\n\n/** Coalesce many writes into one round of effect runs. */\nexport const batch = <R>(fn: () => R): R => {\n depth++\n try {\n return fn()\n } finally {\n if (!--depth) flush()\n }\n}\n\n/** Read signals inside `fn` without subscribing the current effect to them. */\nexport const untracked = <R>(fn: () => R): R => {\n const prev = active\n active = undefined\n try {\n return fn()\n } finally {\n active = prev\n }\n}\n\n/** Called after each flush once every queued effect has run. */\nexport const onSettled = (fn: () => void): (() => void) => {\n settled.add(fn)\n return () => settled.delete(fn)\n}\n\nexport const flush = (): void => {\n if (flushing || depth) return\n flushing = true\n try {\n let guard = 0\n while (queue.size) {\n if (++guard > 1e5) throw new Error('effect loop')\n const e: Effect = queue.values().next().value!\n queue.delete(e)\n e._exec()\n }\n } finally {\n flushing = false\n }\n for (const fn of settled) fn()\n}\n"],
5
- "mappings": "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",
6
- "names": ["_v", "_ver", "_subs", "_deps", "_invalidate", "_refresh", "_dirty", "_fn", "_queued", "_dead", "_kids", "_onError", "_exec", "_dispose"]
4
+ "sourcesContent": ["// Members prefixed with `_` are internal and get mangled by the build.\n\ninterface Tracker {\n _deps: Map<Signal<any>, number>;\n _invalidate(): void;\n}\n\nlet active: Tracker | undefined;\nlet owner: Effect | undefined;\nlet depth = 0;\nlet flushing = false;\nconst queue = new Set<Effect>();\nconst settled = new Set<() => void>();\n\nexport class Signal<T> {\n declare _v: T;\n _ver = 0;\n _subs = new Set<Tracker>();\n constructor(v: T) {\n this._v = v;\n }\n get value(): T {\n if (active) {\n active._deps.set(this, this._ver);\n this._subs.add(active);\n }\n return this._v;\n }\n set value(x: T) {\n if (!Object.is(x, this._v)) {\n this._v = x;\n this.bump();\n }\n }\n peek(): T {\n return this._v;\n }\n /** Notify subscribers without replacing the value (after mutating an array or object in place). */\n bump(): void {\n this._ver++;\n for (const s of this._subs) s._invalidate();\n depth || flush();\n }\n}\n\n/** Drop `t`'s subscriptions. */\nconst release = (t: Tracker): void => {\n for (const d of t._deps.keys()) d._subs.delete(t);\n t._deps.clear();\n};\n\n/** Drop `t`'s subscriptions, then run `fn` with `t` as the active tracker so its reads re-subscribe. */\nconst capture = <R>(t: Tracker, fn: () => R): R => {\n release(t);\n const prev = active;\n active = t;\n try {\n return fn();\n } finally {\n active = prev;\n }\n};\n\n/** True when `t` has never run or any dependency's version moved since. Refreshes computeds on the way. */\nconst stale = (t: Tracker): boolean => {\n if (!t._deps.size) return true;\n for (const [d, seen] of t._deps) {\n if (d instanceof Computed) d._refresh();\n if (d._ver !== seen) return true;\n }\n return false;\n};\n\nexport class Computed<T> extends Signal<T> implements Tracker {\n declare _fn: () => T;\n _deps = new Map<Signal<any>, number>();\n _dirty = true;\n constructor(fn: () => T) {\n super(undefined as T);\n this._fn = fn;\n }\n _refresh(): void {\n if (!this._dirty) return;\n this._dirty = false;\n if (!stale(this)) return;\n const x = capture(this, this._fn);\n if (!Object.is(x, this._v)) {\n this._v = x;\n this._ver++;\n }\n }\n override get value(): T {\n this._refresh();\n return super.value;\n }\n override set value(_: T) {\n throw new Error('computed is read-only');\n }\n _invalidate(): void {\n if (!this._dirty) {\n this._dirty = true;\n for (const s of this._subs) s._invalidate();\n }\n }\n /** Unsubscribe from every dependency; the computed is no longer recalculated. Public: the store calls it. */\n dispose(): void {\n release(this);\n this._dirty = false;\n }\n}\n\nclass Effect implements Tracker {\n _deps = new Map<Signal<any>, number>();\n _queued = false;\n _dead = false;\n _kids = new Set<Effect>();\n declare _fn: () => void;\n declare _onError?: (e: unknown) => void;\n constructor(fn: () => void, onError?: (e: unknown) => void) {\n this._fn = fn;\n this._onError = onError;\n }\n _invalidate(): void {\n if (!this._dead && !this._queued) {\n this._queued = true;\n queue.add(this);\n }\n }\n _exec(): void {\n this._queued = false;\n if (this._dead) return;\n const prevOwner = owner;\n owner = this;\n depth++;\n try {\n // `stale` refreshes computeds, which may throw: that belongs to this effect's error handling.\n if (stale(this)) {\n this._drop();\n capture(this, this._fn);\n }\n } catch (e) {\n if (!this._onError) throw e;\n this._onError(e);\n } finally {\n depth--;\n owner = prevOwner;\n }\n }\n _drop(): void {\n for (const c of this._kids) c._dispose();\n this._kids.clear();\n }\n _dispose(): void {\n this._dead = true;\n release(this);\n if (active === this) active = undefined; // disposed from inside its own run: stop subscribing\n this._drop();\n queue.delete(this);\n }\n}\n\nexport const signal = <T>(value: T): Signal<T> => new Signal(value);\nexport const computed = <T>(fn: () => T): Computed<T> => new Computed(fn);\n\n/**\n * Run `fn` now and again whenever a signal it read changes. Effects created inside another\n * effect are disposed when the parent re-runs. Returns a disposer.\n */\nexport const effect = (fn: () => void, onError?: (e: unknown) => void): (() => void) => {\n const e = new Effect(fn, onError);\n owner?._kids.add(e);\n try {\n e._exec();\n depth || flush();\n } catch (err) {\n e._dispose(); // a first run that throws (or loops) without a handler leaves nothing subscribed\n throw err;\n }\n return () => e._dispose();\n};\n\n/**\n * Like `effect`, but never owned by the effect that happens to be running: for long-lived effects\n * such as mounted attributes, which must not die when an unrelated parent effect re-runs.\n */\nexport const rootEffect = (fn: () => void, onError?: (e: unknown) => void): (() => void) => {\n const prev = owner;\n owner = undefined;\n try {\n return effect(fn, onError);\n } finally {\n owner = prev;\n }\n};\n\nexport const batch = <R>(fn: () => R): R => {\n depth++;\n try {\n return fn();\n } finally {\n --depth || flush();\n }\n};\n\nexport const untracked = <R>(fn: () => R): R => {\n const prev = active;\n active = undefined;\n try {\n return fn();\n } finally {\n active = prev;\n }\n};\n\nexport const onSettled = (fn: () => void): (() => void) => {\n settled.add(fn);\n return () => settled.delete(fn);\n};\n\nexport const flush = (): void => {\n if (flushing || depth) return;\n flushing = true;\n let thrown: unknown;\n let failed = false;\n try {\n let guard = 0;\n while (queue.size) {\n if (++guard > 1e5) {\n // Leave nothing behind, or every later flush would trip the same guard; the effects stay\n // subscribed and run again on their next change.\n for (const e of queue) e._queued = false;\n queue.clear();\n throw new Error('effect loop');\n }\n const e = queue.values().next().value as Effect;\n queue.delete(e);\n try {\n e._exec();\n } catch (err) {\n // One throwing effect (no onError) must not starve the others; rethrow after the flush.\n if (!failed) {\n failed = true;\n thrown = err;\n }\n }\n }\n } finally {\n flushing = false;\n }\n for (const fn of settled) fn();\n if (failed) throw thrown;\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["_ver", "_subs", "_v", "_deps", "_invalidate", "_refresh", "_dirty", "_fn", "_queued", "_dead", "_kids", "_onError", "_exec", "_drop", "_dispose", "e"]
7
7
  }
@@ -1,66 +1,59 @@
1
+ import { recase } from "../lib/casing.js";
1
2
  import { functionCompiler } from "./compile.js";
2
- import { effect } from "./reactive.js";
3
+ import { rootEffect } from "./reactive.js";
3
4
  import { createStore } from "./state.js";
4
- import { recase } from "../lib/casing.js";
5
- const isEl = (n) => n instanceof HTMLElement || n instanceof SVGElement || n instanceof MathMLElement;
6
- const tree = (n) => isEl(n) ? [n, ...n.querySelectorAll("*")] : n instanceof ShadowRoot ? [...n.querySelectorAll("*")] : [];
7
- const parsed = /* @__PURE__ */ new Map();
5
+ const isEl = (n) => n.nodeType === 1;
6
+ const tree = (n) => n.querySelectorAll ? [...isEl(n) ? [n] : [], ...n.querySelectorAll("*")] : [];
8
7
  const parseAttr = (raw) => {
9
- let p = parsed.get(raw);
10
- if (!p) {
11
- const [head, ...modParts] = raw.split("__");
12
- const i = head.indexOf(":");
13
- const mods = /* @__PURE__ */ new Map();
14
- for (const m of modParts) {
15
- const [name, ...args] = m.split(".");
16
- mods.set(name, args);
17
- }
18
- p = { plugin: i < 0 ? head : head.slice(0, i), key: i < 0 ? void 0 : head.slice(i + 1), mods };
19
- parsed.set(raw, p);
20
- }
21
- return p;
8
+ const [head, ...modParts] = raw.split("__");
9
+ const [, plugin, key] = /^([^:]*)(?::(.*))?$/.exec(head);
10
+ return {
11
+ plugin,
12
+ key,
13
+ mods: new Map(
14
+ modParts.map((m) => {
15
+ const [name, ...args] = m.split(".");
16
+ return [name, args];
17
+ })
18
+ )
19
+ };
20
+ };
21
+ const cut = (list, s) => {
22
+ for (const p of list) if (s.startsWith(p)) return s.slice(p.length);
22
23
  };
23
- const fail = (message, info) => Object.assign(new Error(message), { info });
24
24
  const createRuntime = (options) => {
25
25
  const prefixes = [].concat(options.prefix ?? "data-");
26
26
  const eventPrefixes = [].concat(options.eventPrefix ?? "sigmx-");
27
27
  const store = options.store ?? createStore();
28
- const compiler = options.compile ?? functionCompiler;
29
28
  const { expressions } = options;
30
29
  const onError = options.onError ?? ((e, info) => console.error(e, info));
31
30
  const attributes = /* @__PURE__ */ Object.create(null);
32
- const actions = /* @__PURE__ */ Object.create(null);
33
- const handlers = /* @__PURE__ */ Object.create(null);
34
31
  const runtime = {
35
32
  prefixes,
36
33
  attr: (name) => prefixes[0] + name,
37
34
  store,
38
- compiler,
35
+ compiler: options.compile ?? functionCompiler,
39
36
  emit: (type, detail) => document.dispatchEvent(new CustomEvent(`sigmx-${type}`, { detail })),
40
37
  call: (name, ctx, args) => {
41
- const a = actions[name];
38
+ const a = runtime.actions[name];
42
39
  if (!a) throw ctx.error(`unknown action @${name}`);
43
40
  return a.call(ctx, ...args);
44
41
  },
45
42
  eventPrefixes,
46
43
  handle: (event, data) => {
47
- const p = eventPrefixes.find((p2) => event.startsWith(p2));
48
- const h = handlers[p ? event.slice(p.length) : event];
44
+ const h = runtime.handlers[cut(eventPrefixes, event) ?? event];
49
45
  h?.handle(runtime, data);
50
46
  return !!h;
51
47
  },
52
48
  attributes,
53
- actions,
54
- handlers
49
+ actions: /* @__PURE__ */ Object.create(null),
50
+ handlers: /* @__PURE__ */ Object.create(null)
55
51
  };
56
52
  const mounted = /* @__PURE__ */ new Map();
57
53
  const roots = /* @__PURE__ */ new Set();
58
- const ignoreSelf = prefixes.map((p) => `[${p}ignore__self]`).join();
59
54
  const ignoreAny = prefixes.map((p) => `[${p}ignore]`).join();
60
- const ignored = (el) => el.matches(ignoreSelf) || !!el.closest(ignoreAny);
61
- const strip = (attr) => {
62
- for (const p of prefixes) if (attr.startsWith(p)) return attr.slice(p.length);
63
- };
55
+ const ignored = (el) => !!el.closest(ignoreAny);
56
+ let destroyed = false;
64
57
  const unmount = (els) => {
65
58
  for (const el of els) {
66
59
  const m = mounted.get(el);
@@ -72,20 +65,30 @@ const createRuntime = (options) => {
72
65
  m?.get(attr)?.();
73
66
  m?.delete(attr);
74
67
  };
75
- const actionsFor = (el, evt, error, cleanup) => {
76
- const ctx = { el, evt, store, runtime, error, cleanup };
77
- return new Proxy({}, { get: (_, name) => (...args) => runtime.call(name, ctx, args) });
78
- };
79
68
  const mount = (el, attr, raw, value, only) => {
80
69
  const { plugin: name, key, mods } = parseAttr(raw);
81
70
  const plugin = attributes[name];
82
71
  if (!plugin || only && !only.has(name)) return;
83
72
  unmountAttr(el, attr);
84
73
  const disposers = [];
74
+ const cleanup = (f) => {
75
+ disposers.push(f);
76
+ return () => {
77
+ const i = disposers.indexOf(f);
78
+ if (i >= 0) disposers.splice(i, 1);
79
+ };
80
+ };
85
81
  const info = { plugin: name, el, attr };
86
- const error = (message, extra) => fail(`${prefixes[0]}${name}: ${message}`, { ...info, ...extra });
82
+ const error = (message, extra) => Object.assign(new Error(`${prefixes[0]}${name}: ${message}`), { info: { ...info, ...extra } });
87
83
  const report = (e) => onError(e, info);
88
84
  let fn;
85
+ const watched = /* @__PURE__ */ new WeakSet();
86
+ const watch = (r) => {
87
+ if (r instanceof Promise && !watched.has(r)) {
88
+ watched.add(r);
89
+ r.catch(report);
90
+ }
91
+ };
89
92
  const ctx = {
90
93
  el,
91
94
  plugin: name,
@@ -95,10 +98,27 @@ const createRuntime = (options) => {
95
98
  mods,
96
99
  cased: (style = "camel") => recase(key ?? "", mods.get("case")?.[0] || style),
97
100
  evaluate: (evt, ...args) => {
98
- fn ??= expressions(value, ["el", "evt", ...plugin.args ?? []], plugin.returns ?? true);
99
- return fn(store, actionsFor(el, evt, error, ctx.cleanup), el, evt, ...args);
101
+ if (plugin.literal && !mods.has("dynamic")) return value;
102
+ fn ??= expressions(value, ["el", "evt", ...plugin.args ?? []]);
103
+ const actx = { el, evt, store, runtime, error, cleanup, report };
104
+ const actions = new Proxy(
105
+ {},
106
+ {
107
+ get: (_, name2) => (...args2) => {
108
+ const r2 = runtime.call(name2, actx, args2);
109
+ watch(r2);
110
+ return r2;
111
+ }
112
+ }
113
+ );
114
+ const r = fn(store, actions, el, evt, ...args);
115
+ watch(r);
116
+ return r;
117
+ },
118
+ // Root-owned: an attribute mounted from inside another effect must outlive that effect's re-runs.
119
+ effect: (f) => {
120
+ cleanup(rootEffect(f, report));
100
121
  },
101
- effect: (f) => disposers.push(effect(f, report)),
102
122
  listen: (target, type, f, opts) => {
103
123
  const h = (e) => {
104
124
  try {
@@ -108,25 +128,33 @@ const createRuntime = (options) => {
108
128
  }
109
129
  };
110
130
  target.addEventListener(type, h, opts);
111
- disposers.push(() => target.removeEventListener(type, h, opts));
131
+ cleanup(() => target.removeEventListener(type, h, opts));
112
132
  },
113
- cleanup: (f) => disposers.push(f),
133
+ cleanup,
114
134
  error,
135
+ report,
115
136
  store,
116
137
  runtime
117
138
  };
118
139
  let m = mounted.get(el);
119
- if (!m) mounted.set(el, m = /* @__PURE__ */ new Map());
140
+ if (!m) {
141
+ m = /* @__PURE__ */ new Map();
142
+ mounted.set(el, m);
143
+ }
120
144
  m.set(attr, () => {
121
145
  for (const d of disposers.splice(0)) d();
122
146
  });
123
147
  try {
124
- if (plugin.key === "required" && !key) throw error("needs a key");
125
- if (plugin.key === "forbidden" && key) throw error("takes no key");
126
- if (plugin.value === "required" && !value) throw error("needs a value");
127
- if (plugin.value === "forbidden" && value) throw error("takes no value");
148
+ for (const [k, v] of [
149
+ ["key", key],
150
+ ["value", value]
151
+ ]) {
152
+ const rule = plugin[k];
153
+ if (rule && rule === "required" === !v) throw error(`${rule === "required" ? "needs a" : "takes no"} ${k}`);
154
+ }
128
155
  const r = plugin.mount(ctx);
129
- if (typeof r === "function") disposers.push(r);
156
+ if (typeof r === "function") cleanup(r);
157
+ else watch(r);
130
158
  } catch (e) {
131
159
  report(e);
132
160
  }
@@ -135,18 +163,18 @@ const createRuntime = (options) => {
135
163
  for (const el of els) {
136
164
  if (ignored(el)) continue;
137
165
  for (const { name, value } of [...el.attributes]) {
138
- const raw = strip(name);
139
- if (raw) mount(el, name, raw, value, only);
166
+ const raw = cut(prefixes, name);
167
+ if (raw && !mounted.get(el)?.has(name)) mount(el, name, raw, value, only);
140
168
  }
141
169
  }
142
170
  };
143
171
  const observer = new MutationObserver((records) => {
144
172
  for (const { type, target, attributeName, addedNodes, removedNodes } of records) {
145
173
  if (type === "childList") {
146
- for (const n of removedNodes) unmount(tree(n));
174
+ for (const n of removedNodes) if (!n.isConnected) unmount(tree(n));
147
175
  for (const n of addedNodes) mountEls(tree(n));
148
176
  } else if (attributeName && isEl(target) && !ignored(target)) {
149
- const raw = strip(attributeName);
177
+ const raw = cut(prefixes, attributeName);
150
178
  if (!raw) continue;
151
179
  const value = target.getAttribute(attributeName);
152
180
  if (value === null) unmountAttr(target, attributeName);
@@ -154,26 +182,19 @@ const createRuntime = (options) => {
154
182
  }
155
183
  }
156
184
  });
157
- let ready = false;
158
185
  const apply = (root = document.documentElement, observe = true, only) => {
186
+ if (destroyed) return;
159
187
  mountEls(tree(root), only);
160
188
  if (observe && !roots.has(root)) {
161
189
  observer.observe(root, { subtree: true, childList: true, attributes: true });
162
190
  roots.add(root);
163
191
  }
164
- if (!ready && roots.has(document.documentElement)) {
165
- ready = true;
166
- runtime.emit("ready");
167
- }
168
192
  };
169
193
  const use = (...plugins) => {
170
194
  const added = /* @__PURE__ */ new Set();
171
195
  for (const p of plugins) {
172
- if (p.type === "attribute") {
173
- attributes[p.name] = p;
174
- added.add(p.name);
175
- } else if (p.type === "action") actions[p.name] = p;
176
- else handlers[p.name] = p;
196
+ runtime[`${p.type}s`][p.name] = p;
197
+ if (p.type === "attribute") added.add(p.name);
177
198
  }
178
199
  if (added.size) for (const r of roots) apply(r, false, added);
179
200
  };
@@ -188,6 +209,7 @@ const createRuntime = (options) => {
188
209
  apply: (root, observe) => apply(root, observe),
189
210
  use,
190
211
  destroy: () => {
212
+ destroyed = true;
191
213
  observer.disconnect();
192
214
  stopPatches();
193
215
  unmount([...mounted.keys()]);