ripple 0.3.68 → 0.3.69

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 (182) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +2 -2
  4. package/src/runtime/element.js +1 -1
  5. package/src/runtime/index-client.js +11 -11
  6. package/src/runtime/index-server.js +7 -4
  7. package/src/runtime/internal/client/bindings.js +1 -1
  8. package/src/runtime/internal/client/blocks.js +13 -4
  9. package/src/runtime/internal/client/component.js +55 -0
  10. package/src/runtime/internal/client/composite.js +4 -2
  11. package/src/runtime/internal/client/expression.js +65 -7
  12. package/src/runtime/internal/client/hmr.js +54 -43
  13. package/src/runtime/internal/client/index.js +5 -1
  14. package/src/runtime/internal/client/portal.js +70 -69
  15. package/src/runtime/internal/client/render.js +3 -0
  16. package/src/runtime/internal/server/index.js +92 -8
  17. package/tests/client/__snapshots__/html.test.tsrx.snap +3 -3
  18. package/tests/client/array/array.copy-within.test.tsrx +33 -31
  19. package/tests/client/array/array.derived.test.tsrx +186 -169
  20. package/tests/client/array/array.iteration.test.tsrx +40 -37
  21. package/tests/client/array/array.mutations.test.tsrx +113 -101
  22. package/tests/client/array/array.static.test.tsrx +119 -101
  23. package/tests/client/array/array.to-methods.test.tsrx +24 -21
  24. package/tests/client/async-suspend.test.tsrx +247 -246
  25. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +0 -1
  26. package/tests/client/basic/basic.attributes.test.tsrx +428 -423
  27. package/tests/client/basic/basic.collections.test.tsrx +109 -102
  28. package/tests/client/basic/basic.components.test.tsrx +323 -205
  29. package/tests/client/basic/basic.errors.test.tsrx +91 -91
  30. package/tests/client/basic/basic.events.test.tsrx +114 -115
  31. package/tests/client/basic/basic.get-set.test.tsrx +97 -87
  32. package/tests/client/basic/basic.hmr.test.tsrx +19 -16
  33. package/tests/client/basic/basic.reactivity.test.tsrx +199 -191
  34. package/tests/client/basic/basic.rendering.test.tsrx +272 -182
  35. package/tests/client/basic/basic.styling.test.tsrx +23 -22
  36. package/tests/client/basic/basic.utilities.test.tsrx +10 -8
  37. package/tests/client/boundaries.test.tsrx +26 -26
  38. package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +5 -5
  39. package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +5 -5
  40. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -81
  41. package/tests/client/compiler/compiler.attributes.test.tsrx +15 -15
  42. package/tests/client/compiler/compiler.basic.test.tsrx +322 -314
  43. package/tests/client/compiler/compiler.regex.test.tsrx +44 -47
  44. package/tests/client/compiler/compiler.tracked-access.test.tsrx +38 -38
  45. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  46. package/tests/client/compiler/compiler.typescript.test.tsrx +2 -2
  47. package/tests/client/composite/composite.dynamic-components.test.tsrx +47 -48
  48. package/tests/client/composite/composite.generics.test.tsrx +168 -192
  49. package/tests/client/composite/composite.props.test.tsrx +97 -81
  50. package/tests/client/composite/composite.reactivity.test.tsrx +177 -147
  51. package/tests/client/composite/composite.render.test.tsrx +122 -105
  52. package/tests/client/computed-properties.test.tsrx +28 -28
  53. package/tests/client/context.test.tsrx +21 -21
  54. package/tests/client/css/global-additional-cases.test.tsrx +58 -58
  55. package/tests/client/css/global-advanced-selectors.test.tsrx +16 -16
  56. package/tests/client/css/global-at-rules.test.tsrx +10 -10
  57. package/tests/client/css/global-basic.test.tsrx +14 -14
  58. package/tests/client/css/global-classes-ids.test.tsrx +14 -14
  59. package/tests/client/css/global-combinators.test.tsrx +10 -10
  60. package/tests/client/css/global-complex-nesting.test.tsrx +14 -14
  61. package/tests/client/css/global-edge-cases.test.tsrx +18 -18
  62. package/tests/client/css/global-keyframes.test.tsrx +12 -12
  63. package/tests/client/css/global-nested.test.tsrx +10 -10
  64. package/tests/client/css/global-pseudo.test.tsrx +12 -12
  65. package/tests/client/css/global-scoping.test.tsrx +20 -20
  66. package/tests/client/css/style-identifier.test.tsrx +143 -291
  67. package/tests/client/date.test.tsrx +146 -133
  68. package/tests/client/dynamic-elements.test.tsrx +398 -365
  69. package/tests/client/events.test.tsrx +292 -290
  70. package/tests/client/for.test.tsrx +156 -153
  71. package/tests/client/head.test.tsrx +105 -96
  72. package/tests/client/html.test.tsrx +122 -26
  73. package/tests/client/input-value.test.tsrx +1361 -1314
  74. package/tests/client/lazy-array.test.tsrx +16 -13
  75. package/tests/client/lazy-destructuring.test.tsrx +257 -213
  76. package/tests/client/map.test.tsrx +65 -60
  77. package/tests/client/media-query.test.tsrx +22 -20
  78. package/tests/client/object.test.tsrx +87 -81
  79. package/tests/client/portal.test.tsrx +57 -51
  80. package/tests/client/ref.test.tsrx +233 -202
  81. package/tests/client/return.test.tsrx +71 -2560
  82. package/tests/client/set.test.tsrx +54 -45
  83. package/tests/client/svg.test.tsrx +216 -186
  84. package/tests/client/switch.test.tsrx +194 -193
  85. package/tests/client/track-async-hydration.test.tsrx +18 -14
  86. package/tests/client/tracked-index-access.test.tsrx +28 -18
  87. package/tests/client/try.test.tsrx +675 -548
  88. package/tests/client/tsx.test.tsrx +373 -311
  89. package/tests/client/typescript-generics.test.tsrx +145 -145
  90. package/tests/client/url/url.derived.test.tsrx +33 -28
  91. package/tests/client/url/url.parsing.test.tsrx +61 -51
  92. package/tests/client/url/url.partial-removal.test.tsrx +56 -48
  93. package/tests/client/url/url.reactivity.test.tsrx +142 -125
  94. package/tests/client/url/url.serialization.test.tsrx +13 -11
  95. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +34 -29
  96. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +25 -21
  97. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +50 -45
  98. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +111 -99
  99. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +49 -43
  100. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +14 -12
  101. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +16 -14
  102. package/tests/hydration/basic.test.js +3 -3
  103. package/tests/hydration/compiled/client/basic.js +586 -651
  104. package/tests/hydration/compiled/client/composite.js +79 -104
  105. package/tests/hydration/compiled/client/events.js +140 -148
  106. package/tests/hydration/compiled/client/for.js +1005 -1018
  107. package/tests/hydration/compiled/client/head.js +124 -134
  108. package/tests/hydration/compiled/client/hmr.js +41 -48
  109. package/tests/hydration/compiled/client/html-in-template.js +38 -41
  110. package/tests/hydration/compiled/client/html.js +970 -1314
  111. package/tests/hydration/compiled/client/if-children.js +234 -249
  112. package/tests/hydration/compiled/client/if.js +182 -189
  113. package/tests/hydration/compiled/client/mixed-control-flow.js +347 -303
  114. package/tests/hydration/compiled/client/nested-control-flow.js +1084 -832
  115. package/tests/hydration/compiled/client/portal.js +65 -85
  116. package/tests/hydration/compiled/client/reactivity.js +84 -90
  117. package/tests/hydration/compiled/client/return.js +38 -1939
  118. package/tests/hydration/compiled/client/switch.js +218 -224
  119. package/tests/hydration/compiled/client/track-async-serialization.js +250 -259
  120. package/tests/hydration/compiled/client/try.js +123 -132
  121. package/tests/hydration/compiled/server/basic.js +773 -831
  122. package/tests/hydration/compiled/server/composite.js +166 -191
  123. package/tests/hydration/compiled/server/events.js +170 -184
  124. package/tests/hydration/compiled/server/for.js +851 -909
  125. package/tests/hydration/compiled/server/head.js +206 -216
  126. package/tests/hydration/compiled/server/hmr.js +64 -72
  127. package/tests/hydration/compiled/server/html-in-template.js +42 -76
  128. package/tests/hydration/compiled/server/html.js +1362 -1667
  129. package/tests/hydration/compiled/server/if-children.js +419 -445
  130. package/tests/hydration/compiled/server/if.js +194 -208
  131. package/tests/hydration/compiled/server/mixed-control-flow.js +249 -257
  132. package/tests/hydration/compiled/server/nested-control-flow.js +491 -515
  133. package/tests/hydration/compiled/server/portal.js +152 -160
  134. package/tests/hydration/compiled/server/reactivity.js +94 -106
  135. package/tests/hydration/compiled/server/return.js +28 -2172
  136. package/tests/hydration/compiled/server/switch.js +274 -286
  137. package/tests/hydration/compiled/server/track-async-serialization.js +340 -358
  138. package/tests/hydration/compiled/server/try.js +167 -185
  139. package/tests/hydration/components/basic.tsrx +320 -272
  140. package/tests/hydration/components/composite.tsrx +44 -32
  141. package/tests/hydration/components/events.tsrx +101 -91
  142. package/tests/hydration/components/for.tsrx +510 -452
  143. package/tests/hydration/components/head.tsrx +87 -80
  144. package/tests/hydration/components/hmr.tsrx +22 -17
  145. package/tests/hydration/components/html-in-template.tsrx +22 -17
  146. package/tests/hydration/components/html.tsrx +525 -443
  147. package/tests/hydration/components/if-children.tsrx +158 -148
  148. package/tests/hydration/components/if.tsrx +109 -95
  149. package/tests/hydration/components/mixed-control-flow.tsrx +100 -96
  150. package/tests/hydration/components/nested-control-flow.tsrx +215 -203
  151. package/tests/hydration/components/portal.tsrx +41 -34
  152. package/tests/hydration/components/reactivity.tsrx +37 -27
  153. package/tests/hydration/components/return.tsrx +12 -556
  154. package/tests/hydration/components/switch.tsrx +120 -114
  155. package/tests/hydration/components/track-async-serialization.tsrx +107 -91
  156. package/tests/hydration/components/try.tsrx +55 -40
  157. package/tests/hydration/html.test.js +4 -4
  158. package/tests/hydration/return.test.js +13 -532
  159. package/tests/server/await.test.tsrx +3 -3
  160. package/tests/server/basic.attributes.test.tsrx +264 -195
  161. package/tests/server/basic.components.test.tsrx +296 -169
  162. package/tests/server/basic.test.tsrx +300 -198
  163. package/tests/server/compiler.test.tsrx +62 -60
  164. package/tests/server/composite.props.test.tsrx +77 -63
  165. package/tests/server/composite.test.tsrx +168 -192
  166. package/tests/server/context.test.tsrx +18 -12
  167. package/tests/server/dynamic-elements.test.tsrx +197 -180
  168. package/tests/server/for.test.tsrx +85 -78
  169. package/tests/server/head.test.tsrx +50 -43
  170. package/tests/server/html-nesting-validation.test.tsrx +8 -8
  171. package/tests/server/if.test.tsrx +57 -51
  172. package/tests/server/lazy-destructuring.test.tsrx +366 -294
  173. package/tests/server/return.test.tsrx +76 -1355
  174. package/tests/server/streaming-ssr.test.tsrx +4 -75
  175. package/tests/server/style-identifier.test.tsrx +169 -148
  176. package/tests/server/switch.test.tsrx +91 -85
  177. package/tests/server/track-async-serialization.test.tsrx +105 -85
  178. package/tests/server/try.test.tsrx +374 -280
  179. package/tests/utils/compiler-compat-config.test.js +2 -2
  180. package/tests/utils/runtime-imports.test.js +10 -0
  181. package/types/index.d.ts +8 -0
  182. package/tests/client/__snapshots__/html.test.rsrx.snap +0 -40
@@ -3,20 +3,21 @@ import { effect, flushSync, on, track } from 'ripple';
3
3
 
4
4
  describe('on() event handler', () => {
5
5
  it('should attach multiple handlers via onClick attribute (delegated)', () => {
6
- component Basic() {
7
- let &[count1] = track(0);
8
- let &[count2] = track(0);
9
-
10
- <button
11
- onClick={() => {
12
- count1++;
13
- count2++;
14
- }}
15
- >
16
- {'Click me'}
17
- </button>
18
- <div class="count1">{count1}</div>
19
- <div class="count2">{count2}</div>
6
+ function Basic() {
7
+ return <>
8
+ let &[count1] = track(0);
9
+ let &[count2] = track(0);
10
+ <button
11
+ onClick={() => {
12
+ count1++;
13
+ count2++;
14
+ }}
15
+ >
16
+ {'Click me'}
17
+ </button>
18
+ <div class="count1">{count1}</div>
19
+ <div class="count2">{count2}</div>
20
+ </>;
20
21
  }
21
22
 
22
23
  render(Basic);
@@ -35,17 +36,18 @@ describe('on() event handler', () => {
35
36
  });
36
37
 
37
38
  it('should attach and remove a single event handler', () => {
38
- component Basic() {
39
- let &[count] = track(0);
40
-
41
- const setupListener = (node: HTMLButtonElement) => {
42
- const remove = on(node, 'click', () => {
43
- count++;
44
- });
45
- return remove;
46
- };
47
- <button {ref setupListener}>{'Click me'}</button>
48
- <div class="count">{count}</div>
39
+ function Basic() {
40
+ return <>
41
+ let &[count] = track(0);
42
+ const setupListener = (node: HTMLButtonElement) => {
43
+ const remove = on(node, 'click', () => {
44
+ count++;
45
+ });
46
+ return remove;
47
+ };
48
+ <button ref={setupListener}>{'Click me'}</button>
49
+ <div class="count">{count}</div>
50
+ </>;
49
51
  }
50
52
 
51
53
  render(Basic);
@@ -66,25 +68,26 @@ describe('on() event handler', () => {
66
68
  });
67
69
 
68
70
  it('should handle multiple different event types on same element', () => {
69
- component Basic() {
70
- let &[clickCount] = track(0);
71
- let &[mousedownCount] = track(0);
72
-
73
- const setupListeners = (node: HTMLButtonElement) => {
74
- const remove1 = on(node, 'click', () => {
75
- clickCount++;
76
- });
77
- const remove2 = on(node, 'mousedown', () => {
78
- mousedownCount++;
79
- });
80
- return () => {
81
- remove1();
82
- remove2();
71
+ function Basic() {
72
+ return <>
73
+ let &[clickCount] = track(0);
74
+ let &[mousedownCount] = track(0);
75
+ const setupListeners = (node: HTMLButtonElement) => {
76
+ const remove1 = on(node, 'click', () => {
77
+ clickCount++;
78
+ });
79
+ const remove2 = on(node, 'mousedown', () => {
80
+ mousedownCount++;
81
+ });
82
+ return () => {
83
+ remove1();
84
+ remove2();
85
+ };
83
86
  };
84
- };
85
- <button {ref setupListeners}>{'Test'}</button>
86
- <div class="click-count">{clickCount}</div>
87
- <div class="mousedown-count">{mousedownCount}</div>
87
+ <button ref={setupListeners}>{'Test'}</button>
88
+ <div class="click-count">{clickCount}</div>
89
+ <div class="mousedown-count">{mousedownCount}</div>
90
+ </>;
88
91
  }
89
92
 
90
93
  render(Basic);
@@ -115,27 +118,28 @@ describe('on() event handler', () => {
115
118
  });
116
119
 
117
120
  it('should handle multiple handlers for same event type on same element', () => {
118
- component Basic() {
119
- let &[callOrder] = track<number[]>([]);
120
-
121
- const setupListeners = (node: HTMLButtonElement) => {
122
- const remove1 = on(node, 'click', () => {
123
- callOrder = [...callOrder, 1];
124
- });
125
- const remove2 = on(node, 'click', () => {
126
- callOrder = [...callOrder, 2];
127
- });
128
- const remove3 = on(node, 'click', () => {
129
- callOrder = [...callOrder, 3];
130
- });
131
- return () => {
132
- remove1();
133
- remove2();
134
- remove3();
121
+ function Basic() {
122
+ return <>
123
+ let &[callOrder] = track<number[]>([]);
124
+ const setupListeners = (node: HTMLButtonElement) => {
125
+ const remove1 = on(node, 'click', () => {
126
+ callOrder = [...callOrder, 1];
127
+ });
128
+ const remove2 = on(node, 'click', () => {
129
+ callOrder = [...callOrder, 2];
130
+ });
131
+ const remove3 = on(node, 'click', () => {
132
+ callOrder = [...callOrder, 3];
133
+ });
134
+ return () => {
135
+ remove1();
136
+ remove2();
137
+ remove3();
138
+ };
135
139
  };
136
- };
137
- <button {ref setupListeners}>{'Click me'}</button>
138
- <div class="order">{callOrder.join(',')}</div>
140
+ <button ref={setupListeners}>{'Click me'}</button>
141
+ <div class="order">{callOrder.join(',')}</div>
142
+ </>;
139
143
  }
140
144
 
141
145
  render(Basic);
@@ -157,43 +161,44 @@ describe('on() event handler', () => {
157
161
  });
158
162
 
159
163
  it('should remove specific handler without affecting others', () => {
160
- component Basic() {
161
- let &[handler1Called] = track(0);
162
- let &[handler2Called] = track(0);
163
- let &[handler3Called] = track(0);
164
- let removeHandler2: OnEventListenerRemover | undefined;
165
-
166
- const setupListeners = (node: HTMLButtonElement) => {
167
- const remove1 = on(node, 'click', () => {
168
- handler1Called++;
169
- });
170
- removeHandler2 = on(node, 'click', () => {
171
- handler2Called++;
172
- });
173
- const remove3 = on(node, 'click', () => {
174
- handler3Called++;
175
- });
176
- return () => {
177
- remove1();
178
- removeHandler2?.();
179
- remove3();
180
- };
181
- };
182
- <div>
183
- <button class="test-btn" {ref setupListeners}>{'Click me'}</button>
184
- <button
185
- class="remove-btn"
186
- onClick={() => {
164
+ function Basic() {
165
+ return <>
166
+ let &[handler1Called] = track(0);
167
+ let &[handler2Called] = track(0);
168
+ let &[handler3Called] = track(0);
169
+ let removeHandler2: OnEventListenerRemover | undefined;
170
+ const setupListeners = (node: HTMLButtonElement) => {
171
+ const remove1 = on(node, 'click', () => {
172
+ handler1Called++;
173
+ });
174
+ removeHandler2 = on(node, 'click', () => {
175
+ handler2Called++;
176
+ });
177
+ const remove3 = on(node, 'click', () => {
178
+ handler3Called++;
179
+ });
180
+ return () => {
181
+ remove1();
187
182
  removeHandler2?.();
188
- removeHandler2 = undefined;
189
- }}
190
- >
191
- {'Remove handler 2'}
192
- </button>
193
- <div class="h1">{handler1Called}</div>
194
- <div class="h2">{handler2Called}</div>
195
- <div class="h3">{handler3Called}</div>
196
- </div>
183
+ remove3();
184
+ };
185
+ };
186
+ <div>
187
+ <button class="test-btn" ref={setupListeners}>{'Click me'}</button>
188
+ <button
189
+ class="remove-btn"
190
+ onClick={() => {
191
+ removeHandler2?.();
192
+ removeHandler2 = undefined;
193
+ }}
194
+ >
195
+ {'Remove handler 2'}
196
+ </button>
197
+ <div class="h1">{handler1Called}</div>
198
+ <div class="h2">{handler2Called}</div>
199
+ <div class="h3">{handler3Called}</div>
200
+ </div>
201
+ </>;
197
202
  }
198
203
 
199
204
  render(Basic);
@@ -234,30 +239,31 @@ describe('on() event handler', () => {
234
239
  it(
235
240
  'should handle change event with multiple handlers (like bindChecked and bindIndeterminate)',
236
241
  () => {
237
- component Basic() {
238
- let &[checked] = track(false);
239
- let &[indeterminate] = track(true);
240
-
241
- const setupListeners = (node: HTMLInputElement) => {
242
- node.indeterminate = indeterminate;
243
- node.checked = checked;
244
-
245
- const remove1 = on(node, 'change', () => {
246
- checked = node.checked;
247
- });
248
- const remove2 = on(node, 'change', () => {
249
- indeterminate = node.indeterminate;
250
- });
251
- return () => {
252
- remove1();
253
- remove2();
242
+ function Basic() {
243
+ return <>
244
+ let &[checked] = track(false);
245
+ let &[indeterminate] = track(true);
246
+ const setupListeners = (node: HTMLInputElement) => {
247
+ node.indeterminate = indeterminate;
248
+ node.checked = checked;
249
+
250
+ const remove1 = on(node, 'change', () => {
251
+ checked = node.checked;
252
+ });
253
+ const remove2 = on(node, 'change', () => {
254
+ indeterminate = node.indeterminate;
255
+ });
256
+ return () => {
257
+ remove1();
258
+ remove2();
259
+ };
254
260
  };
255
- };
256
- <div>
257
- <input type="checkbox" {ref setupListeners} />
258
- <div class="checked">{checked ? 'true' : 'false'}</div>
259
- <div class="indeterminate">{indeterminate ? 'true' : 'false'}</div>
260
- </div>
261
+ <div>
262
+ <input type="checkbox" ref={setupListeners} />
263
+ <div class="checked">{checked ? 'true' : 'false'}</div>
264
+ <div class="indeterminate">{indeterminate ? 'true' : 'false'}</div>
265
+ </div>
266
+ </>;
261
267
  }
262
268
 
263
269
  render(Basic);
@@ -282,18 +288,18 @@ describe('on() event handler', () => {
282
288
  );
283
289
 
284
290
  it('should support non-delegated events', () => {
285
- component Basic() {
286
- let &[focusCount] = track(0);
287
-
288
- const setupListener = (node: HTMLInputElement) => {
289
- const remove = on(node, 'focus', () => {
290
- focusCount++;
291
- });
292
- return remove;
293
- };
294
-
295
- <input {ref setupListener} />
296
- <div class="focus-count">{focusCount}</div>
291
+ function Basic() {
292
+ return <>
293
+ let &[focusCount] = track(0);
294
+ const setupListener = (node: HTMLInputElement) => {
295
+ const remove = on(node, 'focus', () => {
296
+ focusCount++;
297
+ });
298
+ return remove;
299
+ };
300
+ <input ref={setupListener} />
301
+ <div class="focus-count">{focusCount}</div>
302
+ </>;
297
303
  }
298
304
 
299
305
  render(Basic);
@@ -314,43 +320,44 @@ describe('on() event handler', () => {
314
320
  });
315
321
 
316
322
  it('should handle removal of all handlers for same event type', () => {
317
- component Basic() {
318
- let &[count] = track(0);
319
- let remove1: OnEventListenerRemover | undefined;
320
- let remove2: OnEventListenerRemover | undefined;
321
- let remove3: OnEventListenerRemover | undefined;
322
-
323
- const setupListeners = (node: HTMLButtonElement) => {
324
- remove1 = on(node, 'click', () => {
325
- count++;
326
- });
327
- remove2 = on(node, 'click', () => {
328
- count += 10;
329
- });
330
- remove3 = on(node, 'click', () => {
331
- count += 100;
332
- });
333
- return () => {
334
- remove1?.();
335
- remove2?.();
336
- remove3?.();
337
- };
338
- };
339
- <div>
340
- <button class="test-btn" {ref setupListeners}>{'Click me'}</button>
341
- <button
342
- class="remove-all"
343
- onClick={() => {
323
+ function Basic() {
324
+ return <>
325
+ let &[count] = track(0);
326
+ let remove1: OnEventListenerRemover | undefined;
327
+ let remove2: OnEventListenerRemover | undefined;
328
+ let remove3: OnEventListenerRemover | undefined;
329
+ const setupListeners = (node: HTMLButtonElement) => {
330
+ remove1 = on(node, 'click', () => {
331
+ count++;
332
+ });
333
+ remove2 = on(node, 'click', () => {
334
+ count += 10;
335
+ });
336
+ remove3 = on(node, 'click', () => {
337
+ count += 100;
338
+ });
339
+ return () => {
344
340
  remove1?.();
345
341
  remove2?.();
346
342
  remove3?.();
347
- remove1 = remove2 = remove3 = undefined;
348
- }}
349
- >
350
- {'Remove all'}
351
- </button>
352
- <div class="count">{count}</div>
353
- </div>
343
+ };
344
+ };
345
+ <div>
346
+ <button class="test-btn" ref={setupListeners}>{'Click me'}</button>
347
+ <button
348
+ class="remove-all"
349
+ onClick={() => {
350
+ remove1?.();
351
+ remove2?.();
352
+ remove3?.();
353
+ remove1 = remove2 = remove3 = undefined;
354
+ }}
355
+ >
356
+ {'Remove all'}
357
+ </button>
358
+ <div class="count">{count}</div>
359
+ </div>
360
+ </>;
354
361
  }
355
362
 
356
363
  render(Basic);
@@ -378,28 +385,27 @@ describe('on() event handler', () => {
378
385
  });
379
386
 
380
387
  it('should not add duplicate handlers when same handler is attached multiple times', () => {
381
- component Basic() {
382
- let &[count] = track(0);
383
-
384
- const sharedHandler = () => {
385
- count++;
386
- };
387
-
388
- const setupListeners = (node: HTMLButtonElement) => {
389
- // Attach the same handler multiple times
390
- const remove1 = on(node, 'click', sharedHandler);
391
- const remove2 = on(node, 'click', sharedHandler);
392
- const remove3 = on(node, 'click', sharedHandler);
393
-
394
- return () => {
395
- remove1?.();
396
- remove2?.();
397
- remove3?.();
388
+ function Basic() {
389
+ return <>
390
+ let &[count] = track(0);
391
+ const sharedHandler = () => {
392
+ count++;
398
393
  };
399
- };
394
+ const setupListeners = (node: HTMLButtonElement) => {
395
+ // Attach the same handler multiple times
396
+ const remove1 = on(node, 'click', sharedHandler);
397
+ const remove2 = on(node, 'click', sharedHandler);
398
+ const remove3 = on(node, 'click', sharedHandler);
400
399
 
401
- <button {ref setupListeners}>{'Click me'}</button>
402
- <div class="count">{count}</div>
400
+ return () => {
401
+ remove1?.();
402
+ remove2?.();
403
+ remove3?.();
404
+ };
405
+ };
406
+ <button ref={setupListeners}>{'Click me'}</button>
407
+ <div class="count">{count}</div>
408
+ </>;
403
409
  }
404
410
 
405
411
  render(Basic);
@@ -421,28 +427,27 @@ describe('on() event handler', () => {
421
427
  });
422
428
 
423
429
  it('should allow duplicate handlers when delegated is false (no deduplication)', () => {
424
- component Basic() {
425
- let &[count] = track(0);
426
-
427
- const sharedHandler = () => {
428
- count++;
429
- };
430
-
431
- const setupListeners = (node: HTMLButtonElement) => {
432
- // Attach the same handler multiple times with delegated: false
433
- const remove1 = on(node, 'click', sharedHandler, { delegated: false });
434
- const remove2 = on(node, 'click', sharedHandler, { delegated: false });
435
- const remove3 = on(node, 'click', sharedHandler, { delegated: false });
436
-
437
- return () => {
438
- remove1?.();
439
- remove2?.();
440
- remove3?.();
430
+ function Basic() {
431
+ return <>
432
+ let &[count] = track(0);
433
+ const sharedHandler = () => {
434
+ count++;
441
435
  };
442
- };
436
+ const setupListeners = (node: HTMLButtonElement) => {
437
+ // Attach the same handler multiple times with delegated: false
438
+ const remove1 = on(node, 'click', sharedHandler, { delegated: false });
439
+ const remove2 = on(node, 'click', sharedHandler, { delegated: false });
440
+ const remove3 = on(node, 'click', sharedHandler, { delegated: false });
443
441
 
444
- <button {ref setupListeners}>{'Click me'}</button>
445
- <div class="count">{count}</div>
442
+ return () => {
443
+ remove1?.();
444
+ remove2?.();
445
+ remove3?.();
446
+ };
447
+ };
448
+ <button ref={setupListeners}>{'Click me'}</button>
449
+ <div class="count">{count}</div>
450
+ </>;
446
451
  }
447
452
 
448
453
  render(Basic);
@@ -465,29 +470,26 @@ describe('on() event handler', () => {
465
470
  });
466
471
 
467
472
  it('should fire capture event on parent before bubbling event on child', () => {
468
- component Basic() {
469
- let &[callOrder] = track<string[]>([]);
470
-
471
- const parentCaptureHandler = () => {
472
- callOrder = [...callOrder, 'parent-capture'];
473
- };
474
-
475
- const childBubbleHandler = () => {
476
- callOrder = [...callOrder, 'child-bubble'];
477
- };
478
-
479
- const setupParent = (node: HTMLDivElement) => {
480
- return on(node, 'clickCapture', parentCaptureHandler);
481
- };
482
-
483
- const setupChild = (node: HTMLButtonElement) => {
484
- return on(node, 'click', childBubbleHandler);
485
- };
486
-
487
- <div {ref setupParent} class="parent">
488
- <button {ref setupChild} class="child">{'Click me'}</button>
489
- </div>
490
- <div class="order">{callOrder.join(',')}</div>
473
+ function Basic() {
474
+ return <>
475
+ let &[callOrder] = track<string[]>([]);
476
+ const parentCaptureHandler = () => {
477
+ callOrder = [...callOrder, 'parent-capture'];
478
+ };
479
+ const childBubbleHandler = () => {
480
+ callOrder = [...callOrder, 'child-bubble'];
481
+ };
482
+ const setupParent = (node: HTMLDivElement) => {
483
+ return on(node, 'clickCapture', parentCaptureHandler);
484
+ };
485
+ const setupChild = (node: HTMLButtonElement) => {
486
+ return on(node, 'click', childBubbleHandler);
487
+ };
488
+ <div ref={setupParent} class="parent">
489
+ <button ref={setupChild} class="child">{'Click me'}</button>
490
+ </div>
491
+ <div class="order">{callOrder.join(',')}</div>
492
+ </>;
491
493
  }
492
494
 
493
495
  render(Basic);
@@ -510,28 +512,28 @@ describe('on() event handler', () => {
510
512
  });
511
513
 
512
514
  it('should fire handler only once when once option is true', () => {
513
- component Basic() {
514
- let &[count] = track(0);
515
- let &[permanentCount] = track(0);
516
-
517
- const setupListeners = (node: HTMLButtonElement) => {
518
- const onceHandler = on(node, 'click', () => {
519
- count++;
520
- }, { once: true });
521
-
522
- const permanentHandler = on(node, 'click', () => {
523
- permanentCount++;
524
- });
515
+ function Basic() {
516
+ return <>
517
+ let &[count] = track(0);
518
+ let &[permanentCount] = track(0);
519
+ const setupListeners = (node: HTMLButtonElement) => {
520
+ const onceHandler = on(node, 'click', () => {
521
+ count++;
522
+ }, { once: true });
523
+
524
+ const permanentHandler = on(node, 'click', () => {
525
+ permanentCount++;
526
+ });
525
527
 
526
- return () => {
527
- onceHandler?.();
528
- permanentHandler?.();
528
+ return () => {
529
+ onceHandler?.();
530
+ permanentHandler?.();
531
+ };
529
532
  };
530
- };
531
-
532
- <button {ref setupListeners}>{'Click me'}</button>
533
- <div class="once-count">{count}</div>
534
- <div class="permanent-count">{permanentCount}</div>
533
+ <button ref={setupListeners}>{'Click me'}</button>
534
+ <div class="once-count">{count}</div>
535
+ <div class="permanent-count">{permanentCount}</div>
536
+ </>;
535
537
  }
536
538
 
537
539
  render(Basic);
@@ -564,20 +566,20 @@ describe('on() event handler', () => {
564
566
  });
565
567
 
566
568
  it('should handle click events on window', () => {
567
- component Basic() {
568
- let &[windowClickCount] = track(0);
569
-
570
- effect(() => {
571
- const removeWindowListener = on(window, 'click', () => {
572
- windowClickCount++;
569
+ function Basic() {
570
+ return <>
571
+ let &[windowClickCount] = track(0);
572
+ effect(() => {
573
+ const removeWindowListener = on(window, 'click', () => {
574
+ windowClickCount++;
575
+ });
576
+ return removeWindowListener;
573
577
  });
574
- return removeWindowListener;
575
- });
576
-
577
- <div>
578
- <button class="test-btn">{'Click me'}</button>
579
- <div class="window-count">{windowClickCount}</div>
580
- </div>
578
+ <div>
579
+ <button class="test-btn">{'Click me'}</button>
580
+ <div class="window-count">{windowClickCount}</div>
581
+ </div>
582
+ </>;
581
583
  }
582
584
 
583
585
  render(Basic);
@@ -600,20 +602,20 @@ describe('on() event handler', () => {
600
602
  });
601
603
 
602
604
  it('should handle click events on document', () => {
603
- component Basic() {
604
- let &[documentClickCount] = track(0);
605
-
606
- effect(() => {
607
- const removeDocumentListener = on(document, 'click', () => {
608
- documentClickCount++;
605
+ function Basic() {
606
+ return <>
607
+ let &[documentClickCount] = track(0);
608
+ effect(() => {
609
+ const removeDocumentListener = on(document, 'click', () => {
610
+ documentClickCount++;
611
+ });
612
+ return removeDocumentListener;
609
613
  });
610
- return removeDocumentListener;
611
- });
612
-
613
- <div>
614
- <button class="test-btn">{'Click me'}</button>
615
- <div class="document-count">{documentClickCount}</div>
616
- </div>
614
+ <div>
615
+ <button class="test-btn">{'Click me'}</button>
616
+ <div class="document-count">{documentClickCount}</div>
617
+ </div>
618
+ </>;
617
619
  }
618
620
 
619
621
  render(Basic);
@@ -636,20 +638,20 @@ describe('on() event handler', () => {
636
638
  });
637
639
 
638
640
  it('should handle click events on body', () => {
639
- component Basic() {
640
- let &[bodyClickCount] = track(0);
641
-
642
- effect(() => {
643
- const removeBodyListener = on(document.body, 'click', () => {
644
- bodyClickCount++;
641
+ function Basic() {
642
+ return <>
643
+ let &[bodyClickCount] = track(0);
644
+ effect(() => {
645
+ const removeBodyListener = on(document.body, 'click', () => {
646
+ bodyClickCount++;
647
+ });
648
+ return removeBodyListener;
645
649
  });
646
- return removeBodyListener;
647
- });
648
-
649
- <div>
650
- <button class="test-btn">{'Click me'}</button>
651
- <div class="body-count">{bodyClickCount}</div>
652
- </div>
650
+ <div>
651
+ <button class="test-btn">{'Click me'}</button>
652
+ <div class="body-count">{bodyClickCount}</div>
653
+ </div>
654
+ </>;
653
655
  }
654
656
 
655
657
  render(Basic);