ripple 0.3.121 → 0.3.123
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 +24 -0
- package/package.json +3 -3
- package/src/runtime/internal/client/for.js +4 -4
- package/tests/client/for.test.tsrx +72 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# ripple
|
|
2
2
|
|
|
3
|
+
## 0.3.123
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1432](https://github.com/Ripple-TS/ripple/pull/1432)
|
|
8
|
+
[`8b5abd7`](https://github.com/Ripple-TS/ripple/commit/8b5abd7021a23b7651608fb26ff7e59ed5b4a18c)
|
|
9
|
+
Thanks [@chenzylab](https://github.com/chenzylab)! - Fix insertion order when a
|
|
10
|
+
keyed or ref-based `@for` inserts multiple new items in the middle of the list.
|
|
11
|
+
The pure-insert reconciliation path resolved the DOM anchor per new item by
|
|
12
|
+
indexing the old blocks with a new-list index, so the anchor drifted into the
|
|
13
|
+
matched suffix and later items landed after it (e.g. `[A, C, D]` →
|
|
14
|
+
`[A, B1, B2, C, D]` rendered as `A, B1, C, B2, D`). The anchor is now resolved
|
|
15
|
+
once, at the start of the matched suffix, and reused for the whole run of
|
|
16
|
+
inserts.
|
|
17
|
+
|
|
18
|
+
## 0.3.122
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
[[`481d934`](https://github.com/Ripple-TS/ripple/commit/481d934aa17a275aa588d945b4c65b421076f89c)]:
|
|
24
|
+
- @tsrx/core@0.1.60
|
|
25
|
+
- @tsrx/ripple@0.1.61
|
|
26
|
+
|
|
3
27
|
## 0.3.121
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.3.
|
|
6
|
+
"version": "0.3.123",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"clsx": "^2.1.1",
|
|
74
74
|
"devalue": "^5.8.1",
|
|
75
75
|
"esm-env": "^1.2.2",
|
|
76
|
-
"@tsrx/core": "0.1.
|
|
77
|
-
"@tsrx/ripple": "0.1.
|
|
76
|
+
"@tsrx/core": "0.1.60",
|
|
77
|
+
"@tsrx/ripple": "0.1.61"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@types/estree": "^1.0.8",
|
|
@@ -479,10 +479,10 @@ function reconcile_by_key(
|
|
|
479
479
|
|
|
480
480
|
if (j > a_end) {
|
|
481
481
|
if (j <= b_end) {
|
|
482
|
+
var insert_target = block_start(a_blocks, a_end + 1, a_length, anchor);
|
|
482
483
|
while (j <= b_end) {
|
|
483
484
|
b_val = b[j];
|
|
484
|
-
|
|
485
|
-
b_blocks[j] = create_item(target, b_val, j, render_fn, is_indexed, true);
|
|
485
|
+
b_blocks[j] = create_item(insert_target, b_val, j, render_fn, is_indexed, true);
|
|
486
486
|
j++;
|
|
487
487
|
}
|
|
488
488
|
}
|
|
@@ -766,10 +766,10 @@ function reconcile_by_ref(anchor, block, b, render_fn, is_controlled, is_indexed
|
|
|
766
766
|
|
|
767
767
|
if (j > a_end) {
|
|
768
768
|
if (j <= b_end) {
|
|
769
|
+
var insert_target = block_start(a_blocks, a_end + 1, a_length, anchor);
|
|
769
770
|
while (j <= b_end) {
|
|
770
771
|
b_val = b[j];
|
|
771
|
-
|
|
772
|
-
b_blocks[j] = create_item(target, b_val, j, render_fn, is_indexed, false);
|
|
772
|
+
b_blocks[j] = create_item(insert_target, b_val, j, render_fn, is_indexed, false);
|
|
773
773
|
j++;
|
|
774
774
|
}
|
|
775
775
|
}
|
|
@@ -234,6 +234,78 @@ describe('for statements', () => {
|
|
|
234
234
|
expect(container.querySelectorAll('.item').length).toBe(2);
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
+
it('keyed for inserts multiple new items in the middle in correct order', () => {
|
|
238
|
+
function App() @{
|
|
239
|
+
let &[items] = track([
|
|
240
|
+
{ id: 'a', text: 'A' },
|
|
241
|
+
{ id: 'c', text: 'C' },
|
|
242
|
+
{ id: 'd', text: 'D' },
|
|
243
|
+
]);
|
|
244
|
+
<>
|
|
245
|
+
@for (const item of items; key item.id) {
|
|
246
|
+
<div class="item">{item.text}</div>
|
|
247
|
+
}
|
|
248
|
+
<button
|
|
249
|
+
onClick={() => {
|
|
250
|
+
items = [
|
|
251
|
+
{ id: 'a', text: 'A' },
|
|
252
|
+
{ id: 'b1', text: 'B1' },
|
|
253
|
+
{ id: 'b2', text: 'B2' },
|
|
254
|
+
{ id: 'c', text: 'C' },
|
|
255
|
+
{ id: 'd', text: 'D' },
|
|
256
|
+
];
|
|
257
|
+
}}
|
|
258
|
+
>{'Insert'}</button>
|
|
259
|
+
</>
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
render(App);
|
|
263
|
+
|
|
264
|
+
const getTexts = () => Array.from(container.querySelectorAll('.item')).map(
|
|
265
|
+
(el) => el.textContent,
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
expect(getTexts()).toEqual(['A', 'C', 'D']);
|
|
269
|
+
|
|
270
|
+
container.querySelector('button').click();
|
|
271
|
+
flushSync();
|
|
272
|
+
|
|
273
|
+
expect(getTexts()).toEqual(['A', 'B1', 'B2', 'C', 'D']);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('ref-based for inserts multiple new items in the middle in correct order', () => {
|
|
277
|
+
const a = { text: 'A' };
|
|
278
|
+
const c = { text: 'C' };
|
|
279
|
+
const d = { text: 'D' };
|
|
280
|
+
|
|
281
|
+
function App() @{
|
|
282
|
+
let &[items] = track([a, c, d]);
|
|
283
|
+
<>
|
|
284
|
+
@for (const item of items) {
|
|
285
|
+
<div class="item">{item.text}</div>
|
|
286
|
+
}
|
|
287
|
+
<button
|
|
288
|
+
onClick={() => {
|
|
289
|
+
items = [a, { text: 'B1' }, { text: 'B2' }, c, d];
|
|
290
|
+
}}
|
|
291
|
+
>{'Insert'}</button>
|
|
292
|
+
</>
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
render(App);
|
|
296
|
+
|
|
297
|
+
const getTexts = () => Array.from(container.querySelectorAll('.item')).map(
|
|
298
|
+
(el) => el.textContent,
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
expect(getTexts()).toEqual(['A', 'C', 'D']);
|
|
302
|
+
|
|
303
|
+
container.querySelector('button').click();
|
|
304
|
+
flushSync();
|
|
305
|
+
|
|
306
|
+
expect(getTexts()).toEqual(['A', 'B1', 'B2', 'C', 'D']);
|
|
307
|
+
});
|
|
308
|
+
|
|
237
309
|
it('keyed for with 32+ items: full reversal updates values via Map path', () => {
|
|
238
310
|
function App() @{
|
|
239
311
|
let &[items] = track(Array.from({ length: 40 }, (_, i) => ({ id: i, text: `Item ${i}` })));
|