ripple 0.3.14 → 0.3.15
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 +14 -0
- package/package.json +3 -3
- package/tests/client/basic/basic.components.test.rsrx +103 -1
- package/tests/client/compiler/compiler.basic.test.rsrx +38 -1
- package/tests/server/basic.components.test.rsrx +114 -0
- package/tests/server/compiler.test.rsrx +38 -1
- package/types/index.d.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# ripple
|
|
2
2
|
|
|
3
|
+
## 0.3.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`a14097a`](https://github.com/Ripple-TS/ripple/commit/a14097a688ad85c236a6619cef527c78787ab367)
|
|
8
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Fix children prop precedence
|
|
9
|
+
when invoking components so that template children always win over an explicit
|
|
10
|
+
`children=` attribute, while still respecting JSX-like ordering between explicit
|
|
11
|
+
props and spreads when no template children are present.
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
[[`a14097a`](https://github.com/Ripple-TS/ripple/commit/a14097a688ad85c236a6619cef527c78787ab367)]:
|
|
15
|
+
- ripple@0.3.15
|
|
16
|
+
|
|
3
17
|
## 0.3.14
|
|
4
18
|
|
|
5
19
|
### 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.15",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -83,9 +83,9 @@
|
|
|
83
83
|
"@volar/language-core": "~2.4.28",
|
|
84
84
|
"vscode-languageserver-types": "^3.17.5",
|
|
85
85
|
"@tsrx/core": "0.0.2",
|
|
86
|
-
"@tsrx/ripple": "0.0.
|
|
86
|
+
"@tsrx/ripple": "0.0.3"
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
|
-
"ripple": "0.3.
|
|
89
|
+
"ripple": "0.3.15"
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Tracked,
|
|
3
|
-
Props,
|
|
4
3
|
PropsWithChildren,
|
|
5
4
|
PropsWithExtras,
|
|
6
5
|
Component,
|
|
@@ -414,4 +413,107 @@ describe('basic client > components & composition', () => {
|
|
|
414
413
|
button.click();
|
|
415
414
|
}).not.toThrow();
|
|
416
415
|
});
|
|
416
|
+
|
|
417
|
+
it('renders explicit children prop without spread', () => {
|
|
418
|
+
component Card(props: PropsWithChildren<{}>) {
|
|
419
|
+
<div class="card">{props.children}</div>
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
component App() {
|
|
423
|
+
<Card children="fallback text" />
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
render(App);
|
|
427
|
+
expect(container.querySelector('.card').textContent).toBe('fallback text');
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('renders explicit children before spread', () => {
|
|
431
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
432
|
+
<div class="card">{props.children}</div>
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
component App() {
|
|
436
|
+
const extra = { id: '1' };
|
|
437
|
+
<Card children="fallback text" {...extra} />
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
render(App);
|
|
441
|
+
expect(container.querySelector('.card').textContent).toBe('fallback text');
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it('renders spread before explicit children', () => {
|
|
445
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
446
|
+
<div class="card">{props.children}</div>
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
component App() {
|
|
450
|
+
const extra = { id: '1' };
|
|
451
|
+
<Card {...extra} children="fallback text" />
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
render(App);
|
|
455
|
+
expect(container.querySelector('.card').textContent).toBe('fallback text');
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it('template children override explicit children before spread', () => {
|
|
459
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
460
|
+
<div class="card">{props.children}</div>
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
component App() {
|
|
464
|
+
const extra = { id: '1' };
|
|
465
|
+
<Card children="fallback text" {...extra}>
|
|
466
|
+
<span>{'template content'}</span>
|
|
467
|
+
</Card>
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
render(App);
|
|
471
|
+
expect(container.querySelector('.card span').textContent).toBe('template content');
|
|
472
|
+
expect(container.querySelector('.card').textContent).toBe('template content');
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it('template children override explicit children after spread', () => {
|
|
476
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
477
|
+
<div class="card">{props.children}</div>
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
component App() {
|
|
481
|
+
const extra = { id: '1' };
|
|
482
|
+
<Card {...extra} children="fallback text">
|
|
483
|
+
<span>{'template content'}</span>
|
|
484
|
+
</Card>
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
render(App);
|
|
488
|
+
expect(container.querySelector('.card span').textContent).toBe('template content');
|
|
489
|
+
expect(container.querySelector('.card').textContent).toBe('template content');
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it('spread can override explicit children when no template children', () => {
|
|
493
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
494
|
+
<div class="card">{props.children}</div>
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
component App() {
|
|
498
|
+
const extra = { id: '1', children: 'from spread' };
|
|
499
|
+
<Card children="explicit" {...extra} />
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
render(App);
|
|
503
|
+
expect(container.querySelector('.card').textContent).toBe('from spread');
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it('explicit children overrides spread children when it comes after', () => {
|
|
507
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
508
|
+
<div class="card">{props.children}</div>
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
component App() {
|
|
512
|
+
const extra = { id: '1', children: 'from spread' };
|
|
513
|
+
<Card {...extra} children="explicit" />
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
render(App);
|
|
517
|
+
expect(container.querySelector('.card').textContent).toBe('explicit');
|
|
518
|
+
});
|
|
417
519
|
});
|
|
@@ -535,8 +535,9 @@ export component App() {
|
|
|
535
535
|
|
|
536
536
|
const result = compile(source, 'test.ripple', { mode: 'client' }).js.code;
|
|
537
537
|
|
|
538
|
+
// Template children should take precedence - explicit children prop should be removed
|
|
538
539
|
expect((result.match(/children:/g) || []).length).toBe(1);
|
|
539
|
-
expect(result).toContain('children: _$_.
|
|
540
|
+
expect(result).toContain('children: _$_.ripple_element(');
|
|
540
541
|
});
|
|
541
542
|
|
|
542
543
|
it('should not error on `this` MemberExpression with a UpdateExpression', () => {
|
|
@@ -654,4 +655,40 @@ export component App() {}`;
|
|
|
654
655
|
|
|
655
656
|
expect(result).toContain('class StringMap extends Map<string, string> {}');
|
|
656
657
|
});
|
|
658
|
+
|
|
659
|
+
it('wraps children in normalize_children for explicit children prop passed to component', () => {
|
|
660
|
+
const source = `
|
|
661
|
+
component Card(props) {
|
|
662
|
+
<div>{props.children}</div>
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
export component App() {
|
|
666
|
+
const content = 'hello';
|
|
667
|
+
|
|
668
|
+
<Card children={content} />
|
|
669
|
+
}
|
|
670
|
+
`;
|
|
671
|
+
|
|
672
|
+
const result = compile(source, 'test.ripple', { mode: 'client' }).js.code;
|
|
673
|
+
|
|
674
|
+
expect(result).toContain('_$_.normalize_children(');
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
it('uses spread_props for spreads that may contain children', () => {
|
|
678
|
+
const source = `
|
|
679
|
+
component Card(props) {
|
|
680
|
+
<div>{props.children}</div>
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
export component App() {
|
|
684
|
+
const props = { children: 'hello' };
|
|
685
|
+
|
|
686
|
+
<Card {...props} />
|
|
687
|
+
}
|
|
688
|
+
`;
|
|
689
|
+
|
|
690
|
+
const result = compile(source, 'test.ripple', { mode: 'client' }).js.code;
|
|
691
|
+
|
|
692
|
+
expect(result).toContain('_$_.spread_props(');
|
|
693
|
+
});
|
|
657
694
|
});
|
|
@@ -235,4 +235,118 @@ describe('basic server > components & composition', () => {
|
|
|
235
235
|
|
|
236
236
|
expect(document.querySelector('div')).toBeNull();
|
|
237
237
|
});
|
|
238
|
+
|
|
239
|
+
it('renders explicit children prop without spread', async () => {
|
|
240
|
+
component Card(props: PropsWithChildren<{}>) {
|
|
241
|
+
<div class="card">{props.children}</div>
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
component App() {
|
|
245
|
+
<Card children="fallback text" />
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const { body } = await render(App);
|
|
249
|
+
const { document } = parseHtml(body);
|
|
250
|
+
expect(document.querySelector('.card').textContent).toBe('fallback text');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('renders explicit children before spread', async () => {
|
|
254
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
255
|
+
<div class="card">{props.children}</div>
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
component App() {
|
|
259
|
+
const extra = { id: '1' };
|
|
260
|
+
<Card children="fallback text" {...extra} />
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const { body } = await render(App);
|
|
264
|
+
const { document } = parseHtml(body);
|
|
265
|
+
expect(document.querySelector('.card').textContent).toBe('fallback text');
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('renders spread before explicit children', async () => {
|
|
269
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
270
|
+
<div class="card">{props.children}</div>
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
component App() {
|
|
274
|
+
const extra = { id: '1' };
|
|
275
|
+
<Card {...extra} children="fallback text" />
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const { body } = await render(App);
|
|
279
|
+
const { document } = parseHtml(body);
|
|
280
|
+
expect(document.querySelector('.card').textContent).toBe('fallback text');
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('template children override explicit children before spread', async () => {
|
|
284
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
285
|
+
<div class="card">{props.children}</div>
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
component App() {
|
|
289
|
+
const extra = { id: '1' };
|
|
290
|
+
<Card children="fallback text" {...extra}>
|
|
291
|
+
<span>{'template content'}</span>
|
|
292
|
+
</Card>
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const { body } = await render(App);
|
|
296
|
+
const { document } = parseHtml(body);
|
|
297
|
+
expect(document.querySelector('.card span').textContent).toBe('template content');
|
|
298
|
+
expect(document.querySelector('.card').textContent).toBe('template content');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('template children override explicit children after spread', async () => {
|
|
302
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
303
|
+
<div class="card">{props.children}</div>
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
component App() {
|
|
307
|
+
const extra = { id: '1' };
|
|
308
|
+
<Card {...extra} children="fallback text">
|
|
309
|
+
<span>{'template content'}</span>
|
|
310
|
+
</Card>
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { body } = await render(App);
|
|
314
|
+
const { document } = parseHtml(body);
|
|
315
|
+
expect(document.querySelector('.card span').textContent).toBe('template content');
|
|
316
|
+
expect(document.querySelector('.card').textContent).toBe('template content');
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('spread can override explicit children when no template children', async () => {
|
|
320
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
321
|
+
<div class="card">{props.children}</div>
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
component App() {
|
|
325
|
+
const extra = { id: '1', children: 'from spread' };
|
|
326
|
+
<Card
|
|
327
|
+
// @ts-ignore
|
|
328
|
+
children="explicit"
|
|
329
|
+
{...extra}
|
|
330
|
+
/>
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const { body } = await render(App);
|
|
334
|
+
const { document } = parseHtml(body);
|
|
335
|
+
expect(document.querySelector('.card').textContent).toBe('from spread');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('explicit children overrides spread children when it comes after', async () => {
|
|
339
|
+
component Card(props: PropsWithChildren<{ id: string }>) {
|
|
340
|
+
<div class="card">{props.children}</div>
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
component App() {
|
|
344
|
+
const extra = { id: '1', children: 'from spread' };
|
|
345
|
+
<Card {...extra} children="explicit" />
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const { body } = await render(App);
|
|
349
|
+
const { document } = parseHtml(body);
|
|
350
|
+
expect(document.querySelector('.card').textContent).toBe('explicit');
|
|
351
|
+
});
|
|
238
352
|
});
|
|
@@ -112,8 +112,9 @@ export component App() {
|
|
|
112
112
|
|
|
113
113
|
const result = compile(source, 'test.ripple', { mode: 'server' }).js.code;
|
|
114
114
|
|
|
115
|
+
// Template children should take precedence - explicit children prop should be removed
|
|
115
116
|
expect((result.match(/children:/g) || []).length).toBe(1);
|
|
116
|
-
expect(result).toContain('children: _$_.
|
|
117
|
+
expect(result).toContain('children: _$_.ripple_element(');
|
|
117
118
|
});
|
|
118
119
|
});
|
|
119
120
|
|
|
@@ -199,4 +200,40 @@ describe('compiler server block tests', () => {
|
|
|
199
200
|
|
|
200
201
|
expect(() => compile(source, 'test.ripple', { mode: 'server' })).toThrowError();
|
|
201
202
|
});
|
|
203
|
+
|
|
204
|
+
it('wraps children in normalize_children for explicit children prop passed to component', () => {
|
|
205
|
+
const source = `
|
|
206
|
+
component Card(props) {
|
|
207
|
+
<div>{props.children}</div>
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export component App() {
|
|
211
|
+
const content = 'hello';
|
|
212
|
+
|
|
213
|
+
<Card children={content} />
|
|
214
|
+
}
|
|
215
|
+
`;
|
|
216
|
+
|
|
217
|
+
const result = compile(source, 'test.ripple', { mode: 'server' }).js.code;
|
|
218
|
+
|
|
219
|
+
expect(result).toContain('_$_.normalize_children(');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('passes spread through to component when spread may contain children', () => {
|
|
223
|
+
const source = `
|
|
224
|
+
component Card(props) {
|
|
225
|
+
<div>{props.children}</div>
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export component App() {
|
|
229
|
+
const props = { children: 'hello' };
|
|
230
|
+
|
|
231
|
+
<Card {...props} />
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
const result = compile(source, 'test.ripple', { mode: 'server' }).js.code;
|
|
236
|
+
|
|
237
|
+
expect(result).toContain('...props');
|
|
238
|
+
});
|
|
202
239
|
});
|
package/types/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type RippleElement = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
/** Type for implicit children fragments rendered with `{children}`. */
|
|
11
|
-
export type Children = RippleElement;
|
|
11
|
+
export type Children = RippleElement | Component | string | number | boolean | null | undefined;
|
|
12
12
|
|
|
13
13
|
export function mount(
|
|
14
14
|
component: Component,
|