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.
- package/CHANGELOG.md +85 -0
- package/package.json +2 -2
- package/src/compiler/identifier-utils.js +0 -2
- package/src/compiler/phases/1-parse/index.js +101 -195
- package/src/compiler/phases/2-analyze/index.js +82 -174
- package/src/compiler/phases/2-analyze/prune.js +2 -2
- package/src/compiler/phases/3-transform/client/index.js +174 -264
- package/src/compiler/phases/3-transform/segments.js +0 -22
- package/src/compiler/phases/3-transform/server/index.js +185 -42
- package/src/compiler/types/index.d.ts +14 -33
- package/src/compiler/utils.js +32 -20
- package/src/runtime/index-client.js +0 -17
- package/src/runtime/internal/client/bindings.js +118 -7
- package/src/runtime/internal/client/render.js +5 -1
- package/src/runtime/internal/client/runtime.js +1 -1
- package/src/runtime/internal/client/types.d.ts +4 -0
- package/tests/client/array/array.copy-within.test.ripple +7 -7
- package/tests/client/array/array.derived.test.ripple +24 -24
- package/tests/client/array/array.iteration.test.ripple +7 -7
- package/tests/client/array/array.mutations.test.ripple +17 -17
- package/tests/client/array/array.to-methods.test.ripple +4 -4
- package/tests/client/async-suspend.test.ripple +3 -3
- package/tests/client/basic/basic.attributes.test.ripple +31 -31
- package/tests/client/basic/basic.collections.test.ripple +6 -6
- package/tests/client/basic/basic.components.test.ripple +8 -8
- package/tests/client/basic/basic.errors.test.ripple +31 -34
- package/tests/client/basic/basic.events.test.ripple +11 -11
- package/tests/client/basic/basic.get-set.test.ripple +18 -18
- package/tests/client/basic/basic.reactivity.test.ripple +36 -36
- package/tests/client/basic/basic.rendering.test.ripple +7 -7
- package/tests/client/basic/basic.utilities.test.ripple +4 -4
- package/tests/client/boundaries.test.ripple +7 -7
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +24 -0
- package/tests/client/compiler/compiler.assignments.test.ripple +12 -10
- package/tests/client/compiler/compiler.basic.test.ripple +58 -60
- package/tests/client/compiler/compiler.tracked-access.test.ripple +14 -8
- package/tests/client/compiler/compiler.typescript.test.ripple +31 -0
- package/tests/client/composite/composite.dynamic-components.test.ripple +6 -6
- package/tests/client/composite/composite.props.test.ripple +9 -9
- package/tests/client/composite/composite.reactivity.test.ripple +23 -23
- package/tests/client/composite/composite.render.test.ripple +52 -4
- package/tests/client/computed-properties.test.ripple +3 -3
- package/tests/client/context.test.ripple +3 -3
- package/tests/client/css/global-additional-cases.test.ripple +5 -2
- package/tests/client/css/style-identifier.test.ripple +40 -49
- package/tests/client/date.test.ripple +39 -39
- package/tests/client/dynamic-elements.test.ripple +37 -37
- package/tests/client/events.test.ripple +25 -25
- package/tests/client/for.test.ripple +8 -8
- package/tests/client/head.test.ripple +7 -7
- package/tests/client/html.test.ripple +2 -2
- package/tests/client/input-value.test.ripple +376 -177
- package/tests/client/lazy-destructuring.test.ripple +185 -0
- package/tests/client/map.test.ripple +20 -20
- package/tests/client/media-query.test.ripple +4 -4
- package/tests/client/object.test.ripple +5 -5
- package/tests/client/portal.test.ripple +4 -4
- package/tests/client/ref.test.ripple +3 -3
- package/tests/client/return.test.ripple +17 -17
- package/tests/client/set.test.ripple +10 -10
- package/tests/client/svg.test.ripple +6 -5
- package/tests/client/switch.test.ripple +10 -10
- package/tests/client/tracked-expression.test.ripple +3 -1
- package/tests/client/try.test.ripple +4 -4
- package/tests/client/url/url.derived.test.ripple +6 -7
- package/tests/client/url/url.parsing.test.ripple +9 -9
- package/tests/client/url/url.partial-removal.test.ripple +9 -9
- package/tests/client/url/url.reactivity.test.ripple +16 -16
- package/tests/client/url/url.serialization.test.ripple +3 -3
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +7 -8
- package/tests/client/url-search-params/url-search-params.initialization.test.ripple +6 -4
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +12 -12
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +18 -18
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +16 -16
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +4 -4
- package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +3 -3
- package/tests/hydration/build-components.js +4 -10
- package/tests/hydration/compiled/client/basic.js +4 -4
- package/tests/hydration/compiled/client/events.js +2 -0
- package/tests/hydration/compiled/client/for.js +2 -0
- package/tests/hydration/compiled/client/head.js +13 -11
- package/tests/hydration/compiled/client/hmr.js +4 -2
- package/tests/hydration/compiled/client/html.js +82 -95
- package/tests/hydration/compiled/client/if-children.js +8 -9
- package/tests/hydration/compiled/client/if.js +2 -0
- package/tests/hydration/compiled/client/mixed-control-flow.js +4 -2
- package/tests/hydration/compiled/client/portal.js +1 -1
- package/tests/hydration/compiled/client/reactivity.js +2 -0
- package/tests/hydration/compiled/client/return.js +2 -0
- package/tests/hydration/compiled/client/switch.js +2 -0
- package/tests/hydration/compiled/server/composite.js +2 -2
- package/tests/hydration/compiled/server/events.js +2 -0
- package/tests/hydration/compiled/server/for.js +2 -0
- package/tests/hydration/compiled/server/head.js +13 -11
- package/tests/hydration/compiled/server/hmr.js +2 -0
- package/tests/hydration/compiled/server/html.js +2 -0
- package/tests/hydration/compiled/server/if-children.js +2 -0
- package/tests/hydration/compiled/server/if.js +2 -0
- package/tests/hydration/compiled/server/mixed-control-flow.js +2 -0
- package/tests/hydration/compiled/server/portal.js +1 -1
- package/tests/hydration/compiled/server/reactivity.js +2 -0
- package/tests/hydration/compiled/server/return.js +2 -0
- package/tests/hydration/compiled/server/switch.js +2 -0
- package/tests/hydration/components/composite.ripple +1 -1
- package/tests/hydration/components/events.ripple +10 -8
- package/tests/hydration/components/for.ripple +22 -20
- package/tests/hydration/components/head.ripple +8 -6
- package/tests/hydration/components/hmr.ripple +3 -1
- package/tests/hydration/components/html.ripple +3 -1
- package/tests/hydration/components/if-children.ripple +9 -7
- package/tests/hydration/components/if.ripple +7 -5
- package/tests/hydration/components/mixed-control-flow.ripple +5 -3
- package/tests/hydration/components/portal.ripple +2 -2
- package/tests/hydration/components/reactivity.ripple +11 -9
- package/tests/hydration/components/return.ripple +13 -11
- package/tests/hydration/components/switch.ripple +6 -4
- package/tests/server/__snapshots__/compiler.test.ripple.snap +22 -0
- package/tests/server/await.test.ripple +2 -2
- package/tests/server/basic.attributes.test.ripple +21 -19
- package/tests/server/basic.components.test.ripple +5 -4
- package/tests/server/basic.test.ripple +21 -20
- package/tests/server/compiler.test.ripple +36 -5
- package/tests/server/composite.props.test.ripple +7 -6
- package/tests/server/context.test.ripple +3 -1
- package/tests/server/dynamic-elements.test.ripple +24 -24
- package/tests/server/head.test.ripple +7 -5
- package/tests/server/style-identifier.test.ripple +95 -16
- 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
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
select.
|
|
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 "
|
|
849
|
+
'Assignments or updates to tracked values are not allowed during computed "track(() => ...)" evaluation',
|
|
850
850
|
);
|
|
851
851
|
}
|
|
852
852
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { flushSync,
|
|
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 =
|
|
8
|
-
let thirdItem =
|
|
9
|
-
let fourthItem =
|
|
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 =
|
|
53
|
-
let thirdItem =
|
|
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 =
|
|
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,
|
|
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 =
|
|
8
|
-
let filtered =
|
|
9
|
-
let reduced =
|
|
10
|
-
let includes =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
95
|
-
let foundIndex =
|
|
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 =
|
|
129
|
-
let foundLastIndex =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
483
|
-
let atNegative1 =
|
|
484
|
-
let atNegative2 =
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
87
|
+
let sum = track(0);
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
effect(() => {
|
|
90
90
|
@sum = 0;
|
|
91
91
|
for (const item of items) {
|
|
92
|
-
|
|
92
|
+
untrack(() => {
|
|
93
93
|
@sum += item;
|
|
94
94
|
});
|
|
95
95
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { flushSync,
|
|
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 =
|
|
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 =
|
|
38
|
-
let lastItem =
|
|
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 =
|
|
77
|
-
let firstItem =
|
|
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> =
|
|
116
|
-
let middleItem =
|
|
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 =
|
|
145
|
-
let secondItem =
|
|
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 =
|
|
171
|
-
let firstItem =
|
|
172
|
-
let lastItem =
|
|
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 =
|
|
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 =
|
|
292
|
-
let secondItem =
|
|
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 =
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
19
|
+
let count = track(0);
|
|
20
20
|
|
|
21
21
|
try {
|
|
22
22
|
<Child {count} />
|