ripple 0.3.49 → 0.3.52

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 CHANGED
@@ -1,5 +1,41 @@
1
1
  # ripple
2
2
 
3
+ ## 0.3.52
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ [[`2010290`](https://github.com/Ripple-TS/ripple/commit/20102904d68951b47dce3958f88ddd1fc150e7a1)]:
9
+ - @tsrx/core@0.1.2
10
+ - ripple@0.3.52
11
+ - @tsrx/ripple@0.1.2
12
+
13
+ ## 0.3.51
14
+
15
+ ### Patch Changes
16
+
17
+ - [`f1b1f94`](https://github.com/Ripple-TS/ripple/commit/f1b1f9475553cbe3632a5cc9794a8f54615c29f2)
18
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Patch packages currently
19
+ versioned at 0.3.50 to fix the bump that caused major 1.0.0 release with a minor
20
+ changeset.
21
+
22
+ - Updated dependencies
23
+ [[`0fdf340`](https://github.com/Ripple-TS/ripple/commit/0fdf3408417a7565a00304b766e958b438b3c834),
24
+ [`f1b1f94`](https://github.com/Ripple-TS/ripple/commit/f1b1f9475553cbe3632a5cc9794a8f54615c29f2)]:
25
+ - @tsrx/core@0.1.1
26
+ - ripple@0.3.51
27
+ - @tsrx/ripple@0.1.1
28
+
29
+ ## 0.3.50
30
+
31
+ ### Patch Changes
32
+
33
+ - Updated dependencies
34
+ [[`2a85e9b`](https://github.com/Ripple-TS/ripple/commit/2a85e9bb73f4d82f2bd2273c33735b4dc7b82d5f)]:
35
+ - @tsrx/core@0.1.0
36
+ - @tsrx/ripple@0.1.0
37
+ - ripple@0.3.50
38
+
3
39
  ## 0.3.49
4
40
 
5
41
  ### 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.49",
6
+ "version": "0.3.52",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -76,8 +76,8 @@
76
76
  "esm-env": "^1.2.2",
77
77
  "@types/estree": "^1.0.8",
78
78
  "@types/estree-jsx": "^1.0.5",
79
- "@tsrx/core": "0.0.28",
80
- "@tsrx/ripple": "0.0.30"
79
+ "@tsrx/core": "0.1.2",
80
+ "@tsrx/ripple": "0.1.2"
81
81
  },
82
82
  "devDependencies": {
83
83
  "@types/node": "^24.3.0",
@@ -87,6 +87,6 @@
87
87
  "vscode-languageserver-types": "^3.17.5"
88
88
  },
89
89
  "peerDependencies": {
90
- "ripple": "0.3.49"
90
+ "ripple": "0.3.52"
91
91
  }
92
92
  }
@@ -108,7 +108,10 @@ describe('tsx expression', () => {
108
108
 
109
109
  it('renders a tsx element with multiple children', () => {
110
110
  component App() {
111
- const el = <tsx><div>first</div><div>second</div></tsx>;
111
+ const el = <tsx>
112
+ <div>first</div>
113
+ <div>second</div>
114
+ </tsx>;
112
115
  {el}
113
116
  }
114
117
  render(App);
@@ -209,6 +212,7 @@ describe('tsx expression', () => {
209
212
  const el = <tsx>just text</tsx>;
210
213
  {el}
211
214
  }
215
+
212
216
  render(App);
213
217
  expect(container.textContent).toBe('just text');
214
218
  });
@@ -220,6 +224,7 @@ describe('tsx expression', () => {
220
224
  </tsx>;
221
225
  {el}
222
226
  }
227
+
223
228
  render(App);
224
229
  const div = container.querySelector('div');
225
230
  expect(div.id).toBe('my-id');
@@ -231,10 +236,12 @@ describe('tsx expression', () => {
231
236
  it('renders tsx element with dynamic attribute values', () => {
232
237
  component App() {
233
238
  let &[name] = track('initial');
239
+
234
240
  const el = <tsx><div id={name} class={'cls-' + name}>content</div></tsx>;
235
241
  {el}
236
242
  <button onClick={() => (name = 'updated')}>{'update'}</button>
237
243
  }
244
+
238
245
  render(App);
239
246
  const div = container.querySelector('div');
240
247
  expect(div.id).toBe('initial');
@@ -249,6 +256,7 @@ describe('tsx expression', () => {
249
256
  it('renders tsx element with event handlers', () => {
250
257
  component App() {
251
258
  let &[clicked] = track(false);
259
+
252
260
  const el = <tsx>
253
261
  <button onClick={() => (clicked = true)}>
254
262
  {'click me'}
@@ -257,6 +265,7 @@ describe('tsx expression', () => {
257
265
  {el}
258
266
  <div class="status">{clicked ? 'clicked' : 'not clicked'}</div>
259
267
  }
268
+
260
269
  render(App);
261
270
  expect(container.querySelector('.status').textContent).toBe('not clicked');
262
271
 
@@ -268,6 +277,7 @@ describe('tsx expression', () => {
268
277
  it('renders tsx element with boolean attributes', () => {
269
278
  component App() {
270
279
  let &[isDisabled] = track(true);
280
+
271
281
  const el = <tsx>
272
282
  <button disabled={isDisabled}>
273
283
  {'btn'}
@@ -276,6 +286,7 @@ describe('tsx expression', () => {
276
286
  {el}
277
287
  <button class="toggle" onClick={() => (isDisabled = !isDisabled)}>{'toggle'}</button>
278
288
  }
289
+
279
290
  render(App);
280
291
  expect(container.querySelector('button:not(.toggle)').disabled).toBe(true);
281
292
 
@@ -287,10 +298,12 @@ describe('tsx expression', () => {
287
298
  it('renders tsx element with style attribute', () => {
288
299
  component App() {
289
300
  let &[color] = track('red');
301
+
290
302
  const el = <tsx><div style={'color: ' + color}>styled</div></tsx>;
291
303
  {el}
292
304
  <button onClick={() => (color = 'blue')}>{'change color'}</button>
293
305
  }
306
+
294
307
  render(App);
295
308
  expect(container.querySelector('div').style.color).toBe('red');
296
309
 
@@ -302,6 +315,7 @@ describe('tsx expression', () => {
302
315
  it('renders tsx element with multiple dynamic attributes', () => {
303
316
  component App() {
304
317
  let &[index] = track(0);
318
+
305
319
  const el = <tsx>
306
320
  <div id={'item-' + index} class={'item pos-' + index} data-index={index} title={'Item ' +
307
321
  index}>
@@ -311,6 +325,7 @@ describe('tsx expression', () => {
311
325
  {el}
312
326
  <button onClick={() => index++}>{'next'}</button>
313
327
  }
328
+
314
329
  render(App);
315
330
  const div = container.querySelector('div');
316
331
  expect(div.id).toBe('item-0');
@@ -334,6 +349,7 @@ describe('tsx expression', () => {
334
349
  component App() {
335
350
  <Wrapper content={<tsx><span class="inner">direct prop</span></tsx>} />
336
351
  }
352
+
337
353
  render(App);
338
354
  const wrapper = container.querySelector('.wrapper');
339
355
  expect(wrapper).toBeTruthy();
@@ -355,6 +371,7 @@ describe('tsx expression', () => {
355
371
  children={<tsx><p>Card content here</p></tsx>}
356
372
  />
357
373
  }
374
+
358
375
  render(App);
359
376
  const card = container.querySelector('.card');
360
377
  expect(card.querySelector('.card-title .bold').textContent).toBe('Title');
@@ -363,17 +380,14 @@ describe('tsx expression', () => {
363
380
 
364
381
  it('renders tsx from function defined outside component', () => {
365
382
  function createBadge(label: string) {
366
- return <tsx>
367
- <span class="badge">
368
- {label}
369
- </span>
370
- </tsx>;
383
+ return <tsx><span class="badge">{label}</span></tsx>;
371
384
  }
372
385
 
373
386
  component App() {
374
387
  const badge = createBadge('New');
375
388
  {badge}
376
389
  }
390
+
377
391
  render(App);
378
392
  expect(container.querySelector('.badge')).toBeTruthy();
379
393
  expect(container.querySelector('.badge').textContent).toBe('New');
@@ -381,11 +395,7 @@ describe('tsx expression', () => {
381
395
 
382
396
  it('renders tsx from function with multiple elements', () => {
383
397
  function createListItem(item: string) {
384
- return <tsx>
385
- <li class="list-item">
386
- {item}
387
- </li>
388
- </tsx>;
398
+ return <tsx><li class="list-item">{item}</li></tsx>;
389
399
  }
390
400
 
391
401
  component App() {
@@ -396,6 +406,7 @@ describe('tsx expression', () => {
396
406
  }
397
407
  </ul>
398
408
  }
409
+
399
410
  render(App);
400
411
  const listItems = container.querySelectorAll('.list-item');
401
412
  expect(listItems.length).toBe(3);
@@ -416,9 +427,7 @@ describe('tsx expression', () => {
416
427
  function itemRenderer(item: string) {
417
428
  return <tsx>
418
429
  <li>
419
- <span class="item-content">
420
- {item}
421
- </span>
430
+ <span class="item-content">{item}</span>
422
431
  </li>
423
432
  </tsx>;
424
433
  }
@@ -426,6 +435,7 @@ describe('tsx expression', () => {
426
435
  component App() {
427
436
  <List items={['One', 'Two', 'Three']} renderItem={itemRenderer} />
428
437
  }
438
+
429
439
  render(App);
430
440
  const items = container.querySelectorAll('.item-content');
431
441
  expect(items.length).toBe(3);
@@ -438,9 +448,7 @@ describe('tsx expression', () => {
438
448
  function createCounter(label: string, getCount: () => number) {
439
449
  return <tsx>
440
450
  <div class="counter-display">
441
- <span class="label">
442
- {label}
443
- </span>
451
+ <span class="label">{label}</span>
444
452
  <span class="count">
445
453
  {getCount()}
446
454
  </span>
@@ -450,10 +458,12 @@ describe('tsx expression', () => {
450
458
 
451
459
  component App() {
452
460
  let &[count] = track(0);
461
+
453
462
  const counterElement = createCounter('Count:', () => count);
454
463
  {counterElement}
455
464
  <button onClick={() => count++}>{'increment'}</button>
456
465
  }
466
+
457
467
  render(App);
458
468
  expect(container.querySelector('.label').textContent).toBe('Count:');
459
469
  expect(container.querySelector('.count').textContent).toBe('0');
@@ -472,9 +482,7 @@ describe('tsx expression', () => {
472
482
  return <tsx>
473
483
  <button class="icon-button">
474
484
  {createIcon(icon)}
475
- <span class="btn-label">
476
- {label}
477
- </span>
485
+ <span class="btn-label">{label}</span>
478
486
  </button>
479
487
  </tsx>;
480
488
  }
@@ -483,6 +491,7 @@ describe('tsx expression', () => {
483
491
  const btn = createButton('save', 'Save');
484
492
  {btn}
485
493
  }
494
+
486
495
  render(App);
487
496
  const button = container.querySelector('.icon-button');
488
497
  expect(button).toBeTruthy();
@@ -502,6 +511,7 @@ describe('tsx expression', () => {
502
511
  <Alert message="No icon" />
503
512
  <Alert icon={<tsx><span class="custom-icon">✓</span></tsx>} message="Custom icon" />
504
513
  }
514
+
505
515
  render(App);
506
516
  const alerts = container.querySelectorAll('.alert');
507
517
  expect(alerts[0].querySelector('.message').textContent).toBe('No icon');
@@ -511,11 +521,7 @@ describe('tsx expression', () => {
511
521
 
512
522
  it('renders tsx stored in array via function', () => {
513
523
  function createItem(className: string, content: string) {
514
- return <tsx>
515
- <div class={className}>
516
- {content}
517
- </div>
518
- </tsx>;
524
+ return <tsx><div class={className}>{content}</div></tsx>;
519
525
  }
520
526
 
521
527
  component App() {
@@ -531,6 +537,7 @@ describe('tsx expression', () => {
531
537
  }
532
538
  </div>
533
539
  }
540
+
534
541
  render(App);
535
542
  const container_el = container.querySelector('.container');
536
543
  expect(container_el.querySelector('.item-a').textContent).toBe('A');
@@ -554,6 +561,7 @@ describe('tsx expression', () => {
554
561
  <button class="set-success" onClick={() => (status = 'success')}>{'Success'}</button>
555
562
  <button class="set-error" onClick={() => (status = 'error')}>{'Error'}</button>
556
563
  }
564
+
557
565
  render(App);
558
566
  expect(container.querySelector('.default')).toBeTruthy();
559
567
 
@@ -568,3 +576,84 @@ describe('tsx expression', () => {
568
576
  expect(container.querySelector('.success')).toBeFalsy();
569
577
  });
570
578
  });
579
+
580
+ describe('tsrx expression', () => {
581
+ it('renders native double-quoted text in an assigned fragment', () => {
582
+ component App() {
583
+ const el = <tsrx>
584
+ <div>"Hello world"</div>
585
+ </tsrx>;
586
+ {el}
587
+ }
588
+
589
+ render(App);
590
+
591
+ const div = container.querySelector('div');
592
+ expect(div).toBeTruthy();
593
+ expect(div.textContent).toBe('Hello world');
594
+ });
595
+
596
+ it('runs setup statements before native template output', () => {
597
+ component App() {
598
+ const el = <tsrx>
599
+ const label = 'from setup';
600
+ <div>{label}</div>
601
+ </tsrx>;
602
+ {el}
603
+ }
604
+
605
+ render(App);
606
+
607
+ expect(container.querySelector('div').textContent).toBe('from setup');
608
+ });
609
+
610
+ it('updates reactive expressions inside native fragments', () => {
611
+ component App() {
612
+ let &[count] = track(0);
613
+
614
+ const el = <tsrx>
615
+ <div>{'count: ' + count}</div>
616
+ </tsrx>;
617
+ {el}
618
+ <button onClick={() => count++}>{'increment'}</button>
619
+ }
620
+
621
+ render(App);
622
+
623
+ expect(container.querySelector('div').textContent).toBe('count: 0');
624
+ container.querySelector('button').click();
625
+ flushSync();
626
+ expect(container.querySelector('div').textContent).toBe('count: 1');
627
+ });
628
+
629
+ it('renders native control flow inside an assigned fragment', () => {
630
+ component App() {
631
+ const el = <tsrx>
632
+ if (true) {
633
+ <span>"visible"</span>
634
+ }
635
+ </tsrx>;
636
+ {el}
637
+ }
638
+
639
+ render(App);
640
+
641
+ expect(container.querySelector('span').textContent).toBe('visible');
642
+ });
643
+
644
+ it('renders fragments returned from helpers outside components', () => {
645
+ function makeFragment(label: string) {
646
+ return <tsrx>
647
+ <span>{label}</span>
648
+ </tsrx>;
649
+ }
650
+
651
+ component App() {
652
+ {makeFragment('from helper')}
653
+ }
654
+
655
+ render(App);
656
+
657
+ expect(container.querySelector('span').textContent).toBe('from helper');
658
+ });
659
+ });
@@ -40,6 +40,21 @@ second"</pre>
40
40
  );
41
41
  });
42
42
 
43
+ it('renders inline tsrx fragments', async () => {
44
+ component Basic() {
45
+ const content = <tsrx>
46
+ const label = 'Server';
47
+ <span>{label}</span>
48
+ </tsrx>;
49
+
50
+ <div>{content}</div>
51
+ }
52
+
53
+ const { body } = await render(Basic);
54
+
55
+ expect(body).toBeHtml('<div><span>Server</span></div>');
56
+ });
57
+
43
58
  it('renders tracked state updates', async () => {
44
59
  component Counter() {
45
60
  let &[count] = track(0);