ripple 0.3.2 → 0.3.4

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 (128) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/package.json +2 -2
  3. package/src/compiler/identifier-utils.js +0 -2
  4. package/src/compiler/phases/1-parse/index.js +101 -195
  5. package/src/compiler/phases/2-analyze/index.js +82 -174
  6. package/src/compiler/phases/2-analyze/prune.js +2 -2
  7. package/src/compiler/phases/3-transform/client/index.js +174 -264
  8. package/src/compiler/phases/3-transform/segments.js +0 -22
  9. package/src/compiler/phases/3-transform/server/index.js +185 -42
  10. package/src/compiler/types/index.d.ts +14 -33
  11. package/src/compiler/utils.js +32 -20
  12. package/src/runtime/index-client.js +0 -17
  13. package/src/runtime/internal/client/bindings.js +118 -7
  14. package/src/runtime/internal/client/render.js +5 -1
  15. package/src/runtime/internal/client/runtime.js +1 -1
  16. package/src/runtime/internal/client/types.d.ts +4 -0
  17. package/tests/client/array/array.copy-within.test.ripple +7 -7
  18. package/tests/client/array/array.derived.test.ripple +24 -24
  19. package/tests/client/array/array.iteration.test.ripple +7 -7
  20. package/tests/client/array/array.mutations.test.ripple +17 -17
  21. package/tests/client/array/array.to-methods.test.ripple +4 -4
  22. package/tests/client/async-suspend.test.ripple +3 -3
  23. package/tests/client/basic/basic.attributes.test.ripple +31 -31
  24. package/tests/client/basic/basic.collections.test.ripple +6 -6
  25. package/tests/client/basic/basic.components.test.ripple +8 -8
  26. package/tests/client/basic/basic.errors.test.ripple +31 -34
  27. package/tests/client/basic/basic.events.test.ripple +11 -11
  28. package/tests/client/basic/basic.get-set.test.ripple +18 -18
  29. package/tests/client/basic/basic.reactivity.test.ripple +36 -36
  30. package/tests/client/basic/basic.rendering.test.ripple +7 -7
  31. package/tests/client/basic/basic.utilities.test.ripple +4 -4
  32. package/tests/client/boundaries.test.ripple +7 -7
  33. package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +24 -0
  34. package/tests/client/compiler/compiler.assignments.test.ripple +12 -10
  35. package/tests/client/compiler/compiler.basic.test.ripple +58 -60
  36. package/tests/client/compiler/compiler.tracked-access.test.ripple +14 -8
  37. package/tests/client/compiler/compiler.typescript.test.ripple +31 -0
  38. package/tests/client/composite/composite.dynamic-components.test.ripple +6 -6
  39. package/tests/client/composite/composite.props.test.ripple +9 -9
  40. package/tests/client/composite/composite.reactivity.test.ripple +23 -23
  41. package/tests/client/composite/composite.render.test.ripple +52 -4
  42. package/tests/client/computed-properties.test.ripple +3 -3
  43. package/tests/client/context.test.ripple +3 -3
  44. package/tests/client/css/global-additional-cases.test.ripple +5 -2
  45. package/tests/client/css/style-identifier.test.ripple +40 -49
  46. package/tests/client/date.test.ripple +39 -39
  47. package/tests/client/dynamic-elements.test.ripple +37 -37
  48. package/tests/client/events.test.ripple +25 -25
  49. package/tests/client/for.test.ripple +8 -8
  50. package/tests/client/head.test.ripple +7 -7
  51. package/tests/client/html.test.ripple +2 -2
  52. package/tests/client/input-value.test.ripple +376 -177
  53. package/tests/client/lazy-destructuring.test.ripple +185 -0
  54. package/tests/client/map.test.ripple +20 -20
  55. package/tests/client/media-query.test.ripple +4 -4
  56. package/tests/client/object.test.ripple +5 -5
  57. package/tests/client/portal.test.ripple +4 -4
  58. package/tests/client/ref.test.ripple +3 -3
  59. package/tests/client/return.test.ripple +17 -17
  60. package/tests/client/set.test.ripple +10 -10
  61. package/tests/client/svg.test.ripple +6 -5
  62. package/tests/client/switch.test.ripple +10 -10
  63. package/tests/client/tracked-expression.test.ripple +3 -1
  64. package/tests/client/try.test.ripple +4 -4
  65. package/tests/client/url/url.derived.test.ripple +6 -7
  66. package/tests/client/url/url.parsing.test.ripple +9 -9
  67. package/tests/client/url/url.partial-removal.test.ripple +9 -9
  68. package/tests/client/url/url.reactivity.test.ripple +16 -16
  69. package/tests/client/url/url.serialization.test.ripple +3 -3
  70. package/tests/client/url-search-params/url-search-params.derived.test.ripple +7 -8
  71. package/tests/client/url-search-params/url-search-params.initialization.test.ripple +6 -4
  72. package/tests/client/url-search-params/url-search-params.iteration.test.ripple +12 -12
  73. package/tests/client/url-search-params/url-search-params.mutation.test.ripple +18 -18
  74. package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +16 -16
  75. package/tests/client/url-search-params/url-search-params.serialization.test.ripple +4 -4
  76. package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +3 -3
  77. package/tests/hydration/build-components.js +4 -10
  78. package/tests/hydration/compiled/client/basic.js +4 -4
  79. package/tests/hydration/compiled/client/events.js +2 -0
  80. package/tests/hydration/compiled/client/for.js +2 -0
  81. package/tests/hydration/compiled/client/head.js +13 -11
  82. package/tests/hydration/compiled/client/hmr.js +4 -2
  83. package/tests/hydration/compiled/client/html.js +82 -95
  84. package/tests/hydration/compiled/client/if-children.js +8 -9
  85. package/tests/hydration/compiled/client/if.js +2 -0
  86. package/tests/hydration/compiled/client/mixed-control-flow.js +4 -2
  87. package/tests/hydration/compiled/client/portal.js +1 -1
  88. package/tests/hydration/compiled/client/reactivity.js +2 -0
  89. package/tests/hydration/compiled/client/return.js +2 -0
  90. package/tests/hydration/compiled/client/switch.js +2 -0
  91. package/tests/hydration/compiled/server/composite.js +2 -2
  92. package/tests/hydration/compiled/server/events.js +2 -0
  93. package/tests/hydration/compiled/server/for.js +2 -0
  94. package/tests/hydration/compiled/server/head.js +13 -11
  95. package/tests/hydration/compiled/server/hmr.js +2 -0
  96. package/tests/hydration/compiled/server/html.js +2 -0
  97. package/tests/hydration/compiled/server/if-children.js +2 -0
  98. package/tests/hydration/compiled/server/if.js +2 -0
  99. package/tests/hydration/compiled/server/mixed-control-flow.js +2 -0
  100. package/tests/hydration/compiled/server/portal.js +1 -1
  101. package/tests/hydration/compiled/server/reactivity.js +2 -0
  102. package/tests/hydration/compiled/server/return.js +2 -0
  103. package/tests/hydration/compiled/server/switch.js +2 -0
  104. package/tests/hydration/components/composite.ripple +1 -1
  105. package/tests/hydration/components/events.ripple +10 -8
  106. package/tests/hydration/components/for.ripple +22 -20
  107. package/tests/hydration/components/head.ripple +8 -6
  108. package/tests/hydration/components/hmr.ripple +3 -1
  109. package/tests/hydration/components/html.ripple +3 -1
  110. package/tests/hydration/components/if-children.ripple +9 -7
  111. package/tests/hydration/components/if.ripple +7 -5
  112. package/tests/hydration/components/mixed-control-flow.ripple +5 -3
  113. package/tests/hydration/components/portal.ripple +2 -2
  114. package/tests/hydration/components/reactivity.ripple +11 -9
  115. package/tests/hydration/components/return.ripple +13 -11
  116. package/tests/hydration/components/switch.ripple +6 -4
  117. package/tests/server/__snapshots__/compiler.test.ripple.snap +22 -0
  118. package/tests/server/await.test.ripple +2 -2
  119. package/tests/server/basic.attributes.test.ripple +21 -19
  120. package/tests/server/basic.components.test.ripple +5 -4
  121. package/tests/server/basic.test.ripple +21 -20
  122. package/tests/server/compiler.test.ripple +36 -5
  123. package/tests/server/composite.props.test.ripple +7 -6
  124. package/tests/server/context.test.ripple +3 -1
  125. package/tests/server/dynamic-elements.test.ripple +24 -24
  126. package/tests/server/head.test.ripple +7 -5
  127. package/tests/server/style-identifier.test.ripple +95 -16
  128. package/types/index.d.ts +4 -1
@@ -30,6 +30,15 @@ function not_set_function_type_error(name) {
30
30
  );
31
31
  }
32
32
 
33
+ /**
34
+ * @returns {TypeError}
35
+ */
36
+ function invalid_select_multiple_value_error() {
37
+ return new TypeError(
38
+ 'Reactive bound value of a `<select multiple>` element should be an array, but it received a non-array value.',
39
+ );
40
+ }
41
+
33
42
  /**
34
43
  * @param {string} name
35
44
  * @param {unknown} maybe_tracked
@@ -149,6 +158,10 @@ function is_numberlike_input(input) {
149
158
 
150
159
  /** @param {HTMLOptionElement} option */
151
160
  function get_option_value(option) {
161
+ if ('__value' in option) {
162
+ return option.__value;
163
+ }
164
+
152
165
  return option.value;
153
166
  }
154
167
 
@@ -168,7 +181,7 @@ function select_option(select, value, mounting = false) {
168
181
 
169
182
  // If not an array, warn and keep the selection as is
170
183
  if (!is_array(value)) {
171
- // TODO
184
+ throw invalid_select_multiple_value_error();
172
185
  }
173
186
 
174
187
  // Otherwise, update the selection
@@ -192,6 +205,88 @@ function select_option(select, value, mounting = false) {
192
205
  }
193
206
  }
194
207
 
208
+ /** @type {MutationObserver | undefined} */
209
+ var select_mutation_observer;
210
+ /** @type {Set<HTMLSelectElement> | undefined} */
211
+ var observed_selects;
212
+ var select_observer_options = {
213
+ childList: true,
214
+ subtree: true,
215
+ attributes: true,
216
+ attributeFilter: ['value'],
217
+ };
218
+
219
+ /**
220
+ * @param {MutationRecord[]} entries
221
+ * @returns {void}
222
+ */
223
+ function process_select_mutation_entries(entries) {
224
+ var selects = new Set();
225
+
226
+ for (const entry of entries) {
227
+ const target = /** @type {HTMLElement} */ (entry.target);
228
+ const select = /** @type {HTMLSelectElement | null} */ (
229
+ target.nodeName === 'SELECT' ? target : target.closest('select')
230
+ );
231
+
232
+ if (!select || selects.has(select)) {
233
+ continue;
234
+ }
235
+
236
+ if (observed_selects?.has(select)) {
237
+ selects.add(select);
238
+ select_option(select, select.__value);
239
+ }
240
+ }
241
+ }
242
+
243
+ /**
244
+ * @param {HTMLSelectElement} select
245
+ * @returns {void}
246
+ */
247
+ function observe_select(select) {
248
+ select_mutation_observer ??= new MutationObserver((entries) => {
249
+ process_select_mutation_entries(entries);
250
+ });
251
+
252
+ observed_selects ??= new Set();
253
+ observed_selects.add(select);
254
+ select_mutation_observer.observe(select, select_observer_options);
255
+ }
256
+
257
+ /**
258
+ * @param {HTMLSelectElement} select
259
+ * @returns {void}
260
+ */
261
+ function unobserve_select(select) {
262
+ if (!observed_selects?.delete(select)) {
263
+ return;
264
+ }
265
+
266
+ if (select_mutation_observer) {
267
+ process_select_mutation_entries(select_mutation_observer.takeRecords());
268
+ }
269
+
270
+ select_mutation_observer?.disconnect();
271
+
272
+ for (const current_select of observed_selects) {
273
+ select_mutation_observer?.observe(current_select, select_observer_options);
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Re-applies the current bound selection when option children change after mount.
279
+ * @param {HTMLSelectElement} select
280
+ * @returns {() => void}
281
+ */
282
+ function init_select(select) {
283
+ observe_select(select);
284
+
285
+ return () => {
286
+ unobserve_select(select);
287
+ };
288
+ }
289
+
195
290
  /**
196
291
  * @param {unknown} maybe_tracked
197
292
  * @param {SetFunction | undefined} set_func
@@ -201,11 +296,13 @@ export function bindValue(maybe_tracked, set_func = undefined) {
201
296
  var { getter, setter } = get_bind_get_set('bindValue()', maybe_tracked, set_func);
202
297
 
203
298
  return (node) => {
299
+ /** @type {undefined | (() => void)} */
204
300
  var clear_event;
205
301
 
206
302
  if (node.tagName === 'SELECT') {
207
303
  var select = /** @type {HTMLSelectElement} */ (node);
208
304
  var mounting = true;
305
+ var clear_observer = init_select(select);
209
306
 
210
307
  clear_event = on(select, 'change', async () => {
211
308
  var query = ':checked';
@@ -225,27 +322,41 @@ export function bindValue(maybe_tracked, set_func = undefined) {
225
322
  value = selected_option && get_option_value(selected_option);
226
323
  }
227
324
 
325
+ select.__value = value;
228
326
  setter(value);
229
327
  });
230
328
 
231
329
  effect(() => {
232
330
  var value = getter();
233
331
  select_option(select, value, mounting);
332
+ select.__value = value;
234
333
 
235
334
  // Mounting and value undefined -> take selection from dom
236
335
  if (mounting && value === undefined) {
237
- /** @type {HTMLOptionElement | null} */
238
- var selected_option = /** @type {HTMLOptionElement | null} */ (
239
- select.querySelector(':checked')
240
- );
241
- if (selected_option !== null) {
242
- value = get_option_value(selected_option);
336
+ if (select.multiple) {
337
+ value = [].map.call(select.querySelectorAll(':checked'), get_option_value);
338
+ select.__value = value;
243
339
  setter(value);
340
+ } else {
341
+ /** @type {HTMLOptionElement | null} */
342
+ var selected_option = /** @type {HTMLOptionElement | null} */ (
343
+ select.querySelector(':checked')
344
+ );
345
+ if (selected_option !== null) {
346
+ value = get_option_value(selected_option);
347
+ select.__value = value;
348
+ setter(value);
349
+ }
244
350
  }
245
351
  }
246
352
 
247
353
  mounting = false;
248
354
  });
355
+
356
+ return () => {
357
+ clear_event?.();
358
+ clear_observer();
359
+ };
249
360
  } else {
250
361
  var input = /** @type {HTMLInputElement} */ (node);
251
362
 
@@ -181,13 +181,17 @@ export function set_class(dom, value, hash, is_html = true) {
181
181
  }
182
182
 
183
183
  /**
184
- * @param {HTMLInputElement | HTMLProgressElement} element
184
+ * @param {HTMLInputElement | HTMLProgressElement | HTMLOptionElement} element
185
185
  * @param {any} value
186
186
  * @returns {void}
187
187
  */
188
188
  export function set_value(element, value) {
189
189
  var attributes = (element.__attributes ??= {});
190
190
 
191
+ if (element.nodeName === 'OPTION') {
192
+ /** @type {HTMLOptionElement & { __value?: any }} */ (element).__value = value;
193
+ }
194
+
191
195
  if (
192
196
  attributes.value ===
193
197
  (attributes.value =
@@ -846,7 +846,7 @@ export function public_set(tracked, value) {
846
846
  export function set(tracked, value) {
847
847
  if (!is_mutating_allowed) {
848
848
  throw new Error(
849
- 'Assignments or updates to tracked values are not allowed during computed "#ripple.track(() => ...)" evaluation',
849
+ 'Assignments or updates to tracked values are not allowed during computed "track(() => ...)" evaluation',
850
850
  );
851
851
  }
852
852
 
@@ -77,6 +77,10 @@ declare global {
77
77
  __root?: EventTarget;
78
78
  }
79
79
 
80
+ interface HTMLSelectElement {
81
+ __value?: unknown;
82
+ }
83
+
80
84
  interface Text {
81
85
  __t?: string | null;
82
86
  }
@@ -1,12 +1,12 @@
1
- import { flushSync, RippleArray } from 'ripple';
1
+ import { RippleArray, flushSync, track } from 'ripple';
2
2
 
3
3
  describe('RippleArray copyWithin', () => {
4
4
  it('handles copyWithin operation with reactivity', () => {
5
5
  component ArrayTest() {
6
6
  let items = new RippleArray(1, 2, 3, 4, 5);
7
- let firstItem = #ripple.track(() => items[0]);
8
- let thirdItem = #ripple.track(() => items[2]);
9
- let fourthItem = #ripple.track(() => items[3]);
7
+ let firstItem = track(() => items[0]);
8
+ let thirdItem = track(() => items[2]);
9
+ let fourthItem = track(() => items[3]);
10
10
 
11
11
  <button onClick={() => items.copyWithin(0, 3)}>{'copy end to start'}</button>
12
12
  <button onClick={() => items.copyWithin(2, 0, 2)}>{'copy start to middle'}</button>
@@ -49,8 +49,8 @@ describe('RippleArray copyWithin', () => {
49
49
  it('handles copyWithin with negative indexes and reactivity', () => {
50
50
  component ArrayTest() {
51
51
  let items = new RippleArray(1, 2, 3, 4, 5);
52
- let secondItem = #ripple.track(() => items[1]);
53
- let thirdItem = #ripple.track(() => items[2]);
52
+ let secondItem = track(() => items[1]);
53
+ let thirdItem = track(() => items[2]);
54
54
 
55
55
  <button onClick={() => items.copyWithin(-4, -2)}>{'copy with negative indexes'}</button>
56
56
  <pre>{JSON.stringify(items)}</pre>
@@ -80,7 +80,7 @@ describe('RippleArray copyWithin', () => {
80
80
  it('handles copyWithin with overlapping ranges', () => {
81
81
  component ArrayTest() {
82
82
  let items = new RippleArray(1, 2, 3, 4, 5);
83
- let entries = #ripple.track(() => Array.from(items.entries()));
83
+ let entries = track(() => Array.from(items.entries()));
84
84
 
85
85
  <button onClick={() => items.copyWithin(2, 1, 4)}>{'copy with overlap'}</button>
86
86
  <pre>{JSON.stringify(items)}</pre>
@@ -1,13 +1,13 @@
1
- import { flushSync, RippleArray } from 'ripple';
1
+ import { RippleArray, flushSync, track } from 'ripple';
2
2
 
3
3
  describe('RippleArray > derived', () => {
4
4
  it('handles array methods that return values (map, filter, etc.)', () => {
5
5
  component ArrayTest() {
6
6
  let items = new RippleArray(1, 2, 3, 4, 5);
7
- let doubled = #ripple.track(() => items.map((x) => x * 2));
8
- let filtered = #ripple.track(() => items.filter((x) => x % 2 === 0));
9
- let reduced = #ripple.track(() => items.reduce((acc, val) => acc + val, 0));
10
- let includes = #ripple.track(() => items.includes(3));
7
+ let doubled = track(() => items.map((x) => x * 2));
8
+ let filtered = track(() => items.filter((x) => x % 2 === 0));
9
+ let reduced = track(() => items.reduce((acc, val) => acc + val, 0));
10
+ let includes = track(() => items.includes(3));
11
11
 
12
12
  <button onClick={() => items.push(6)}>{'add item'}</button>
13
13
  <pre>{JSON.stringify(@doubled)}</pre>
@@ -39,7 +39,7 @@ describe('RippleArray > derived', () => {
39
39
  it('handles concat method with reactivity', () => {
40
40
  component ArrayTest() {
41
41
  let items = new RippleArray(1, 2, 3);
42
- let concatenated = #ripple.track(() => items.concat([4, 5], 6, [7, 8]));
42
+ let concatenated = track(() => items.concat([4, 5], 6, [7, 8]));
43
43
 
44
44
  <button onClick={() => items.push(3.5)}>{'add to original'}</button>
45
45
  <pre>{JSON.stringify(items)}</pre>
@@ -65,7 +65,7 @@ describe('RippleArray > derived', () => {
65
65
  it('handles array slice method with reactivity', () => {
66
66
  component ArrayTest() {
67
67
  let items = new RippleArray(1, 2, 3, 4, 5);
68
- let sliced = #ripple.track(() => items.slice(1, 4));
68
+ let sliced = track(() => items.slice(1, 4));
69
69
 
70
70
  <button onClick={() => (items[2] = 30)}>{'change middle'}</button>
71
71
  <pre>{JSON.stringify(items)}</pre>
@@ -91,8 +91,8 @@ describe('RippleArray > derived', () => {
91
91
  it('handles find and findIndex methods with reactivity', () => {
92
92
  component ArrayTest() {
93
93
  let items = new RippleArray(5, 10, 15, 20, 25);
94
- let found = #ripple.track(() => items.find((x) => x > 12));
95
- let foundIndex = #ripple.track(() => items.findIndex((x) => x > 12));
94
+ let found = track(() => items.find((x) => x > 12));
95
+ let foundIndex = track(() => items.findIndex((x) => x > 12));
96
96
 
97
97
  <button
98
98
  onClick={() => {
@@ -125,8 +125,8 @@ describe('RippleArray > derived', () => {
125
125
  it('handles findLast and findLastIndex methods with reactivity', () => {
126
126
  component ArrayTest() {
127
127
  let items = new RippleArray(5, 15, 10, 20, 15);
128
- let foundLast = #ripple.track(() => items.findLast((x) => x === 15));
129
- let foundLastIndex = #ripple.track(() => items.findLastIndex((x) => x === 15));
128
+ let foundLast = track(() => items.findLast((x) => x === 15));
129
+ let foundLastIndex = track(() => items.findLastIndex((x) => x === 15));
130
130
 
131
131
  <button
132
132
  onClick={() => {
@@ -159,7 +159,7 @@ describe('RippleArray > derived', () => {
159
159
  it('handles every method with reactivity', () => {
160
160
  component ArrayTest() {
161
161
  let items = new RippleArray(2, 4, 6, 8);
162
- let allEven = #ripple.track(() => items.every((x) => x % 2 === 0));
162
+ let allEven = track(() => items.every((x) => x % 2 === 0));
163
163
 
164
164
  <button onClick={() => items.push(3)}>{'add odd'}</button>
165
165
  <button
@@ -195,7 +195,7 @@ describe('RippleArray > derived', () => {
195
195
  it('handles flat method with reactivity', () => {
196
196
  component ArrayTest() {
197
197
  let items = new RippleArray<number | number[]>([1, 2], [3, 4], 5);
198
- let flattened = #ripple.track(() => items.flat());
198
+ let flattened = track(() => items.flat());
199
199
 
200
200
  <button onClick={() => (items[0] = [6, 7, 8])}>{'change nested'}</button>
201
201
  <pre>{JSON.stringify(items)}</pre>
@@ -221,7 +221,7 @@ describe('RippleArray > derived', () => {
221
221
  it('handles flatMap method with reactivity', () => {
222
222
  component ArrayTest() {
223
223
  let items = new RippleArray(1, 2, 3);
224
- let flatMapped = #ripple.track(() => items.flatMap((x) => [x, x * 2]));
224
+ let flatMapped = track(() => items.flatMap((x) => [x, x * 2]));
225
225
 
226
226
  <button onClick={() => items.push(4)}>{'add item'}</button>
227
227
  <pre>{JSON.stringify(items)}</pre>
@@ -247,7 +247,7 @@ describe('RippleArray > derived', () => {
247
247
  it('handles join method with reactivity', () => {
248
248
  component ArrayTest() {
249
249
  let items = new RippleArray('apple', 'banana', 'cherry');
250
- let joined = #ripple.track(() => items.join(', '));
250
+ let joined = track(() => items.join(', '));
251
251
 
252
252
  <button onClick={() => items.push('date')}>{'add item'}</button>
253
253
  <pre>{JSON.stringify(items)}</pre>
@@ -275,7 +275,7 @@ describe('RippleArray > derived', () => {
275
275
  it('handles lastIndexOf method with reactivity', () => {
276
276
  component ArrayTest() {
277
277
  let items = new RippleArray(1, 2, 3, 2, 1);
278
- let lastIndex = #ripple.track(() => items.lastIndexOf(2));
278
+ let lastIndex = track(() => items.lastIndexOf(2));
279
279
 
280
280
  <button
281
281
  onClick={() => {
@@ -307,7 +307,7 @@ describe('RippleArray > derived', () => {
307
307
  it('handles reduceRight method with reactivity', () => {
308
308
  component ArrayTest() {
309
309
  let items = new RippleArray('a', 'b', 'c');
310
- let reduced = #ripple.track(() => items.reduceRight((acc, val) => acc + val, ''));
310
+ let reduced = track(() => items.reduceRight((acc, val) => acc + val, ''));
311
311
 
312
312
  <button onClick={() => items.push('d')}>{'add item'}</button>
313
313
  <pre>{JSON.stringify(items)}</pre>
@@ -333,7 +333,7 @@ describe('RippleArray > derived', () => {
333
333
  it('handles some method with reactivity', () => {
334
334
  component ArrayTest() {
335
335
  let items = new RippleArray(1, 3, 5, 7);
336
- let hasEven = #ripple.track(() => items.some((x) => x % 2 === 0));
336
+ let hasEven = track(() => items.some((x) => x % 2 === 0));
337
337
 
338
338
  <button onClick={() => items.push(2)}>{'add even'}</button>
339
339
  <button
@@ -369,7 +369,7 @@ describe('RippleArray > derived', () => {
369
369
  it('handles toLocaleString method with reactivity', () => {
370
370
  component ArrayTest() {
371
371
  let items = new RippleArray(1000, 2000, 3000);
372
- let localized = #ripple.track(() => items.toLocaleString('en-US'));
372
+ let localized = track(() => items.toLocaleString('en-US'));
373
373
 
374
374
  <button
375
375
  onClick={() => {
@@ -401,7 +401,7 @@ describe('RippleArray > derived', () => {
401
401
  it('handles toString method with reactivity', () => {
402
402
  component ArrayTest() {
403
403
  let items = new RippleArray(1, 2, 3);
404
- let string = #ripple.track(() => items.toString());
404
+ let string = track(() => items.toString());
405
405
 
406
406
  <button onClick={() => items.push(4)}>{'add item'}</button>
407
407
  <pre>{JSON.stringify(items)}</pre>
@@ -431,7 +431,7 @@ describe('RippleArray > derived', () => {
431
431
 
432
432
  component ArrayTest() {
433
433
  let items = new RippleArray(1, 2, 3, 4);
434
- let withReplaced = #ripple.track(() => items.with(2, 30));
434
+ let withReplaced = track(() => items.with(2, 30));
435
435
 
436
436
  <button onClick={() => (items[2] = 50)}>{'change original'}</button>
437
437
  <pre>{JSON.stringify(items)}</pre>
@@ -479,9 +479,9 @@ describe('RippleArray > derived', () => {
479
479
  it('handles at method with reactivity', () => {
480
480
  component ArrayTest() {
481
481
  let items = new RippleArray(10, 20, 30, 40, 50);
482
- let atIndex2 = #ripple.track(() => items.at(2));
483
- let atNegative1 = #ripple.track(() => items.at(-1));
484
- let atNegative2 = #ripple.track(() => items.at(-2));
482
+ let atIndex2 = track(() => items.at(2));
483
+ let atNegative1 = track(() => items.at(-1));
484
+ let atNegative2 = track(() => items.at(-2));
485
485
 
486
486
  <button onClick={() => (items[2] = 300)}>{'change index 2'}</button>
487
487
  <button onClick={() => (items[items.length - 1] = 500)}>{'change last'}</button>
@@ -1,10 +1,10 @@
1
- import { flushSync, RippleArray } from 'ripple';
1
+ import { RippleArray, effect, flushSync, track, untrack } from 'ripple';
2
2
 
3
3
  describe('RippleArray > iteration', () => {
4
4
  it('handles entries method with reactivity', () => {
5
5
  component ArrayTest() {
6
6
  let items = new RippleArray('a', 'b', 'c');
7
- let entries = #ripple.track(() => Array.from(items.entries()));
7
+ let entries = track(() => Array.from(items.entries()));
8
8
 
9
9
  <button onClick={() => items.push('d')}>{'add item'}</button>
10
10
  <pre>{JSON.stringify(items)}</pre>
@@ -32,7 +32,7 @@ describe('RippleArray > iteration', () => {
32
32
  it('handles keys method with reactivity', () => {
33
33
  component ArrayTest() {
34
34
  let items = new RippleArray('a', 'b', 'c');
35
- let keys = #ripple.track(() => Array.from(items.keys()));
35
+ let keys = track(() => Array.from(items.keys()));
36
36
 
37
37
  <button onClick={() => items.push('d')}>{'add item'}</button>
38
38
  <pre>{JSON.stringify(items)}</pre>
@@ -58,7 +58,7 @@ describe('RippleArray > iteration', () => {
58
58
  it('handles values method with reactivity', () => {
59
59
  component ArrayTest() {
60
60
  let items = new RippleArray('a', 'b', 'c');
61
- let values = #ripple.track(() => Array.from(items.values()));
61
+ let values = track(() => Array.from(items.values()));
62
62
 
63
63
  <button onClick={() => items.push('d')}>{'add item'}</button>
64
64
  <pre>{JSON.stringify(items)}</pre>
@@ -84,12 +84,12 @@ describe('RippleArray > iteration', () => {
84
84
  it('handles Symbol.iterator with reactivity', () => {
85
85
  component ArrayTest() {
86
86
  let items = new RippleArray(1, 2, 3);
87
- let sum = #ripple.track(0);
87
+ let sum = track(0);
88
88
 
89
- #ripple.effect(() => {
89
+ effect(() => {
90
90
  @sum = 0;
91
91
  for (const item of items) {
92
- #ripple.untrack(() => {
92
+ untrack(() => {
93
93
  @sum += item;
94
94
  });
95
95
  }
@@ -1,9 +1,9 @@
1
- import { flushSync, RippleArray } from 'ripple';
1
+ import { RippleArray, flushSync, track } from 'ripple';
2
2
 
3
3
  describe('RippleArray > mutations', () => {
4
4
  it('handles direct assignment and length tracking', () => {
5
5
  component ArrayTest() {
6
- let items = #ripple[1, 2, 3];
6
+ let items = new RippleArray(1, 2, 3);
7
7
 
8
8
  <button onClick={() => (items[items.length] = items.length + 1)}>{'increment'}</button>
9
9
 
@@ -34,8 +34,8 @@ describe('RippleArray > mutations', () => {
34
34
 
35
35
  it('handles push and pop operations with reactivity', () => {
36
36
  component ArrayTest() {
37
- let items = #ripple[1, 2, 3];
38
- let lastItem = #ripple.track(() => items[items.length - 1]);
37
+ let items = new RippleArray(1, 2, 3);
38
+ let lastItem = track(() => items[items.length - 1]);
39
39
 
40
40
  <button onClick={() => items.push(4)}>{'push'}</button>
41
41
  <button onClick={() => items.pop()}>{'pop'}</button>
@@ -73,8 +73,8 @@ describe('RippleArray > mutations', () => {
73
73
 
74
74
  it('handles shift and unshift operations with reactivity', () => {
75
75
  component ArrayTest() {
76
- let items = #ripple[2, 3, 4];
77
- let firstItem = #ripple.track(() => items[0]);
76
+ let items = new RippleArray(2, 3, 4);
77
+ let firstItem = track(() => items[0]);
78
78
 
79
79
  <button onClick={() => items.unshift(1)}>{'unshift'}</button>
80
80
  <button onClick={() => items.shift()}>{'shift'}</button>
@@ -112,8 +112,8 @@ describe('RippleArray > mutations', () => {
112
112
 
113
113
  it('handles splice operation with reactivity', () => {
114
114
  component ArrayTest() {
115
- let items: RippleArray<number | string> = #ripple[1, 2, 3, 4, 5];
116
- let middleItem = #ripple.track(() => items[2]);
115
+ let items: RippleArray<number | string> = new RippleArray(1, 2, 3, 4, 5);
116
+ let middleItem = track(() => items[2]);
117
117
 
118
118
  <button onClick={() => items.splice(1, 2, 'a', 'b')}>{'splice'}</button>
119
119
  <pre>{JSON.stringify(items)}</pre>
@@ -141,8 +141,8 @@ describe('RippleArray > mutations', () => {
141
141
 
142
142
  it('handles fill operation with reactivity', () => {
143
143
  component ArrayTest() {
144
- let items = #ripple[1, 2, 3, 4, 5];
145
- let secondItem = #ripple.track(() => items[1]);
144
+ let items = new RippleArray(1, 2, 3, 4, 5);
145
+ let secondItem = track(() => items[1]);
146
146
 
147
147
  <button onClick={() => items.fill(0, 1, 4)}>{'fill'}</button>
148
148
  <pre>{JSON.stringify(items)}</pre>
@@ -167,9 +167,9 @@ describe('RippleArray > mutations', () => {
167
167
 
168
168
  it('handles reverse operation with reactivity', () => {
169
169
  component ArrayTest() {
170
- let items = #ripple[1, 2, 3, 4, 5];
171
- let firstItem = #ripple.track(() => items[0]);
172
- let lastItem = #ripple.track(() => items[4]);
170
+ let items = new RippleArray(1, 2, 3, 4, 5);
171
+ let firstItem = track(() => items[0]);
172
+ let lastItem = track(() => items[4]);
173
173
 
174
174
  <button onClick={() => items.reverse()}>{'reverse'}</button>
175
175
  <pre>{JSON.stringify(items)}</pre>
@@ -198,7 +198,7 @@ describe('RippleArray > mutations', () => {
198
198
  it('handles sort operation with reactivity', () => {
199
199
  component ArrayTest() {
200
200
  let items = new RippleArray(5, 3, 1, 4, 2);
201
- let secondItem = #ripple.track(() => items[1]);
201
+ let secondItem = track(() => items[1]);
202
202
 
203
203
  <button onClick={() => items.sort()}>{'sort ascending'}</button>
204
204
  <button onClick={() => items.sort((a, b) => b - a)}>{'sort descending'}</button>
@@ -288,8 +288,8 @@ describe('RippleArray > mutations', () => {
288
288
  it('handles array index access with reactivity', () => {
289
289
  component ArrayTest() {
290
290
  let items = new RippleArray(10, 20, 30);
291
- let firstItem = #ripple.track(() => items[0]);
292
- let secondItem = #ripple.track(() => items[1]);
291
+ let firstItem = track(() => items[0]);
292
+ let secondItem = track(() => items[1]);
293
293
 
294
294
  <button onClick={() => (items[0] = 100)}>{'change first'}</button>
295
295
  <pre>{@firstItem}</pre>
@@ -321,7 +321,7 @@ describe('RippleArray > mutations', () => {
321
321
  it('handles length property for reactivity', () => {
322
322
  component ArrayTest() {
323
323
  let items = new RippleArray(1, 2, 3);
324
- let length = #ripple.track(() => items.length);
324
+ let length = track(() => items.length);
325
325
 
326
326
  <button onClick={() => (items.length = 5)}>{'expand'}</button>
327
327
  <button onClick={() => (items.length = 2)}>{'shrink'}</button>
@@ -1,4 +1,4 @@
1
- import { flushSync, RippleArray } from 'ripple';
1
+ import { RippleArray, flushSync, track } from 'ripple';
2
2
 
3
3
  describe('RippleArray > to* methods', () => {
4
4
  it('handles toReversed method with reactivity', (context) => {
@@ -8,7 +8,7 @@ describe('RippleArray > to* methods', () => {
8
8
 
9
9
  component ArrayTest() {
10
10
  let items = new RippleArray(1, 2, 3, 4);
11
- let reversed = #ripple.track(() => items.toReversed());
11
+ let reversed = track(() => items.toReversed());
12
12
 
13
13
  <button onClick={() => items.push(5)}>{'add item'}</button>
14
14
  <pre>{JSON.stringify(items)}</pre>
@@ -38,7 +38,7 @@ describe('RippleArray > to* methods', () => {
38
38
 
39
39
  component ArrayTest() {
40
40
  let items = new RippleArray(3, 1, 4, 2);
41
- let sorted = #ripple.track(() => items.toSorted());
41
+ let sorted = track(() => items.toSorted());
42
42
 
43
43
  <button onClick={() => items.push(0)}>{'add item'}</button>
44
44
  <pre>{JSON.stringify(items)}</pre>
@@ -68,7 +68,7 @@ describe('RippleArray > to* methods', () => {
68
68
 
69
69
  component ArrayTest() {
70
70
  let items = new RippleArray<string | number>(1, 2, 3, 4, 5);
71
- let spliced = #ripple.track(() => items.toSpliced(1, 2, 'a', 'b'));
71
+ let spliced = track(() => items.toSpliced(1, 2, 'a', 'b'));
72
72
 
73
73
  <button onClick={() => (items[2] = 30)}>{'change item'}</button>
74
74
  <pre>{JSON.stringify(items)}</pre>
@@ -1,11 +1,11 @@
1
- import { flushSync } from 'ripple';
1
+ import { flushSync, track } from 'ripple';
2
2
 
3
3
  describe('async suspense', () => {
4
4
  it('hides child content during re-suspension when tracked dependency changes', async () => {
5
5
  let resolve_fn: (() => void) | null = null;
6
6
 
7
7
  component Child({ count }: { count: any }) {
8
- await #ripple.track(() => {
8
+ await track(() => {
9
9
  @count;
10
10
  return new Promise<void>((resolve) => {
11
11
  resolve_fn = resolve;
@@ -16,7 +16,7 @@ describe('async suspense', () => {
16
16
  }
17
17
 
18
18
  component App() {
19
- let count = #ripple.track(0);
19
+ let count = track(0);
20
20
 
21
21
  try {
22
22
  <Child {count} />