ripple 0.2.48 → 0.2.50
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/README.md +2 -4
- package/package.json +2 -2
- package/src/compiler/phases/1-parse/index.js +908 -885
- package/src/compiler/phases/3-transform/index.js +10 -41
- package/src/runtime/internal/client/index.js +0 -18
- package/src/runtime/internal/client/runtime.js +1 -1
- package/tests/accessors-props.test.ripple +19 -23
- package/tests/array.test.ripple +103 -103
- package/tests/basic.test.ripple +184 -152
- package/tests/composite.test.ripple +12 -1
- package/tests/map.test.ripple +13 -13
- package/tests/set.test.ripple +3 -3
- package/types/index.d.ts +1 -1
- package/src/runtime/internal/client/array.js +0 -352
package/tests/basic.test.ripple
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mount, flushSync, effect } from 'ripple';
|
|
2
|
+
import { mount, flushSync, effect, track } from 'ripple';
|
|
3
3
|
import { compile } from 'ripple/compiler';
|
|
4
4
|
|
|
5
5
|
describe('basic', () => {
|
|
@@ -54,10 +54,10 @@ describe('basic', () => {
|
|
|
54
54
|
|
|
55
55
|
it('render dynamic text', () => {
|
|
56
56
|
component Basic() {
|
|
57
|
-
let
|
|
57
|
+
let text = track('Hello World');
|
|
58
58
|
|
|
59
|
-
<button onClick={() =>
|
|
60
|
-
<div>{
|
|
59
|
+
<button onClick={() => { @text = 'Hello Ripple' }}>{'Change Text'}</button>
|
|
60
|
+
<div>{@text}</div>
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
render(Basic);
|
|
@@ -89,20 +89,20 @@ describe('basic', () => {
|
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
it('render tick template literal for nested children', () => {
|
|
92
|
-
component Child({
|
|
93
|
-
if(
|
|
92
|
+
component Child({ level, children }) {
|
|
93
|
+
if(level == 1) {
|
|
94
94
|
<h1><children /></h1>
|
|
95
95
|
}
|
|
96
|
-
if(
|
|
96
|
+
if(level == 2) {
|
|
97
97
|
<h2><children /></h2>
|
|
98
98
|
}
|
|
99
|
-
if(
|
|
99
|
+
if(level == 3) {
|
|
100
100
|
<h3><children /></h3>
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
component App() {
|
|
105
|
-
<Child
|
|
105
|
+
<Child level={1}>{`Heading 1`}</Child>
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
render(App);
|
|
@@ -111,10 +111,10 @@ describe('basic', () => {
|
|
|
111
111
|
|
|
112
112
|
it('render dynamic class attribute', () => {
|
|
113
113
|
component Basic() {
|
|
114
|
-
let
|
|
114
|
+
let active = track(false);
|
|
115
115
|
|
|
116
|
-
<button onClick={() =>
|
|
117
|
-
<div
|
|
116
|
+
<button onClick={() => { @active = !@active }}>{'Toggle'}</button>
|
|
117
|
+
<div class={@active ? 'active' : 'inactive'}>{'Dynamic Class'}</div>
|
|
118
118
|
|
|
119
119
|
<style>
|
|
120
120
|
.active {
|
|
@@ -143,10 +143,10 @@ describe('basic', () => {
|
|
|
143
143
|
|
|
144
144
|
it('render dynamic id attribute', () => {
|
|
145
145
|
component Basic() {
|
|
146
|
-
let
|
|
146
|
+
let count = track(0);
|
|
147
147
|
|
|
148
|
-
<button onClick={() =>
|
|
149
|
-
<div
|
|
148
|
+
<button onClick={() => { @count++ }}>{'Increment'}</button>
|
|
149
|
+
<div id={`item-${@count}`}>{'Dynamic ID'}</div>
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
render(Basic);
|
|
@@ -169,10 +169,10 @@ describe('basic', () => {
|
|
|
169
169
|
|
|
170
170
|
it('render dynamic style attribute', () => {
|
|
171
171
|
component Basic() {
|
|
172
|
-
let
|
|
172
|
+
let color = track('red');
|
|
173
173
|
|
|
174
|
-
<button onClick={() =>
|
|
175
|
-
<div
|
|
174
|
+
<button onClick={() => { @color = @color === 'red' ? 'blue' : 'red' }}>{'Change Color'}</button>
|
|
175
|
+
<div style={`color: ${@color}; font-weight: bold;`}>{'Dynamic Style'}</div>
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
render(Basic);
|
|
@@ -217,14 +217,14 @@ describe('basic', () => {
|
|
|
217
217
|
|
|
218
218
|
it('render dynamic boolean attributes', () => {
|
|
219
219
|
component Basic() {
|
|
220
|
-
let
|
|
221
|
-
let
|
|
220
|
+
let disabled = track(false);
|
|
221
|
+
let checked = track(false);
|
|
222
222
|
|
|
223
223
|
<button onClick={() => {
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
@disabled = !@disabled;
|
|
225
|
+
@checked = !@checked;
|
|
226
226
|
}}>{'Toggle'}</button>
|
|
227
|
-
<input type='checkbox'
|
|
227
|
+
<input type='checkbox' disabled={@disabled} checked={@checked} />
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
render(Basic);
|
|
@@ -244,16 +244,16 @@ describe('basic', () => {
|
|
|
244
244
|
|
|
245
245
|
it('render multiple dynamic attributes', () => {
|
|
246
246
|
component Basic() {
|
|
247
|
-
let
|
|
248
|
-
let
|
|
247
|
+
let theme = track('light');
|
|
248
|
+
let size = track('medium');
|
|
249
249
|
|
|
250
250
|
<button
|
|
251
251
|
onClick={() => {
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
@theme = @theme === 'light' ? 'dark' : 'light';
|
|
253
|
+
@size = @size === 'medium' ? 'large' : 'medium';
|
|
254
254
|
}}
|
|
255
255
|
>{'Toggle Theme & Size'}</button>
|
|
256
|
-
<div
|
|
256
|
+
<div class={`theme-${@theme} size-${@size}`} data-theme={@theme} data-size={@size}>{'Multiple Dynamic Attributes'}</div>
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
render(Basic);
|
|
@@ -275,16 +275,16 @@ describe('basic', () => {
|
|
|
275
275
|
|
|
276
276
|
it('render conditional attributes', () => {
|
|
277
277
|
component Basic() {
|
|
278
|
-
let
|
|
279
|
-
let
|
|
278
|
+
let showTitle = track(false);
|
|
279
|
+
let showAria = track(false);
|
|
280
280
|
|
|
281
281
|
<button onClick={() => {
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
@showTitle = !@showTitle;
|
|
283
|
+
@showAria = !@showAria;
|
|
284
284
|
}}>{'Toggle Attributes'}</button>
|
|
285
285
|
<div
|
|
286
|
-
|
|
287
|
-
|
|
286
|
+
title={@showTitle ? 'This is a title' : null}
|
|
287
|
+
aria-label={@showAria ? 'Accessible label' : null}
|
|
288
288
|
>{'Conditional Attributes'}</div>
|
|
289
289
|
}
|
|
290
290
|
|
|
@@ -311,21 +311,21 @@ describe('basic', () => {
|
|
|
311
311
|
|
|
312
312
|
it('render spread attributes', () => {
|
|
313
313
|
component Basic() {
|
|
314
|
-
let
|
|
314
|
+
let attrs = track({
|
|
315
315
|
class: 'initial',
|
|
316
316
|
id: 'test-1'
|
|
317
|
-
};
|
|
317
|
+
});
|
|
318
318
|
|
|
319
319
|
<button
|
|
320
320
|
onClick={() => {
|
|
321
|
-
|
|
321
|
+
@attrs = {
|
|
322
322
|
class: 'updated',
|
|
323
323
|
id: 'test-2',
|
|
324
324
|
'data-extra': 'value'
|
|
325
325
|
};
|
|
326
326
|
}}
|
|
327
327
|
>{'Update Attributes'}</button>
|
|
328
|
-
<div {
|
|
328
|
+
<div {...@attrs}>{'Spread Attributes'}</div>
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
render(Basic);
|
|
@@ -349,19 +349,19 @@ describe('basic', () => {
|
|
|
349
349
|
component Basic() {
|
|
350
350
|
<div>
|
|
351
351
|
let obj = {
|
|
352
|
-
|
|
352
|
+
count: track(0)
|
|
353
353
|
};
|
|
354
354
|
|
|
355
|
-
<span>{obj
|
|
355
|
+
<span>{obj.@count}</span>
|
|
356
356
|
</div>
|
|
357
357
|
<div>
|
|
358
358
|
let b = {
|
|
359
|
-
|
|
359
|
+
count: track(0)
|
|
360
360
|
};
|
|
361
361
|
|
|
362
|
-
<button onClick={() => b
|
|
363
|
-
<span class='count'>{b
|
|
364
|
-
<button onClick={() => b
|
|
362
|
+
<button onClick={() => { b.@count-- }}>{'-'}</button>
|
|
363
|
+
<span class='count'>{b.@count}</span>
|
|
364
|
+
<button onClick={() => { b.@count++ }}>{'+'}</button>
|
|
365
365
|
</div>
|
|
366
366
|
}
|
|
367
367
|
render(Basic);
|
|
@@ -379,25 +379,27 @@ describe('basic', () => {
|
|
|
379
379
|
expect(container.querySelector('.count').textContent).toBe('0');
|
|
380
380
|
});
|
|
381
381
|
|
|
382
|
-
|
|
382
|
+
// TODO
|
|
383
|
+
it.skip('renders multiple reactive lexical blocks with complexity', () => {
|
|
384
|
+
|
|
383
385
|
component Basic() {
|
|
384
|
-
const count = '
|
|
386
|
+
const count = 'count';
|
|
385
387
|
|
|
386
388
|
<div>
|
|
387
389
|
let obj = {
|
|
388
|
-
|
|
390
|
+
count: track(0)
|
|
389
391
|
};
|
|
390
392
|
|
|
391
393
|
<span>{obj[count]}</span>
|
|
392
394
|
</div>
|
|
393
395
|
<div>
|
|
394
396
|
let b = {
|
|
395
|
-
|
|
397
|
+
count: track(0)
|
|
396
398
|
};
|
|
397
399
|
|
|
398
|
-
<button onClick={() => b[count]--}>{'-'}</button>
|
|
400
|
+
<button onClick={() => { b[count]-- }}>{'-'}</button>
|
|
399
401
|
<span class='count'>{b[count]}</span>
|
|
400
|
-
<button onClick={() => b[count]++}>{'+'}</button>
|
|
402
|
+
<button onClick={() => { b[count]++ }}>{'+'}</button>
|
|
401
403
|
</div>
|
|
402
404
|
}
|
|
403
405
|
render(Basic);
|
|
@@ -417,15 +419,15 @@ describe('basic', () => {
|
|
|
417
419
|
|
|
418
420
|
it('renders with different event types', () => {
|
|
419
421
|
component Basic() {
|
|
420
|
-
let
|
|
421
|
-
let
|
|
422
|
+
let focusCount = track(0);
|
|
423
|
+
let clickCount = track(0);
|
|
422
424
|
|
|
423
425
|
<button
|
|
424
|
-
onFocus={() =>
|
|
425
|
-
onClick={() =>
|
|
426
|
+
onFocus={() => { @focusCount++ }}
|
|
427
|
+
onClick={() => { @clickCount++ }}
|
|
426
428
|
>{'Test Button'}</button>
|
|
427
|
-
<div class='focus-count'>{
|
|
428
|
-
<div class='click-count'>{
|
|
429
|
+
<div class='focus-count'>{@focusCount}</div>
|
|
430
|
+
<div class='click-count'>{@clickCount}</div>
|
|
429
431
|
}
|
|
430
432
|
|
|
431
433
|
render(Basic);
|
|
@@ -445,13 +447,13 @@ describe('basic', () => {
|
|
|
445
447
|
|
|
446
448
|
it('renders with capture events', () => {
|
|
447
449
|
component Basic() {
|
|
448
|
-
let
|
|
449
|
-
let
|
|
450
|
+
let captureClicks = track(0);
|
|
451
|
+
let bubbleClicks = track(0);
|
|
450
452
|
|
|
451
|
-
<div onClickCapture={() =>
|
|
452
|
-
<button onClick={() =>
|
|
453
|
-
<div class='capture-count'>{
|
|
454
|
-
<div class='bubble-count'>{
|
|
453
|
+
<div onClickCapture={() => { @captureClicks++ }}>
|
|
454
|
+
<button onClick={() => { @bubbleClicks++ }}>{'Click me'}</button>
|
|
455
|
+
<div class='capture-count'>{@captureClicks}</div>
|
|
456
|
+
<div class='bubble-count'>{@bubbleClicks}</div>
|
|
455
457
|
</div>
|
|
456
458
|
}
|
|
457
459
|
|
|
@@ -471,13 +473,13 @@ describe('basic', () => {
|
|
|
471
473
|
it('renders with component composition and children', () => {
|
|
472
474
|
component Card(props) {
|
|
473
475
|
<div class='card'>
|
|
474
|
-
<props
|
|
476
|
+
<props.children />
|
|
475
477
|
</div>
|
|
476
478
|
}
|
|
477
479
|
|
|
478
480
|
component Basic() {
|
|
479
481
|
<Card>
|
|
480
|
-
component
|
|
482
|
+
component children() {
|
|
481
483
|
<p>{'Card content here'}</p>
|
|
482
484
|
}
|
|
483
485
|
</Card>
|
|
@@ -494,22 +496,22 @@ describe('basic', () => {
|
|
|
494
496
|
|
|
495
497
|
it('renders with error handling simulation', () => {
|
|
496
498
|
component Basic() {
|
|
497
|
-
let
|
|
498
|
-
let
|
|
499
|
+
let hasError = track(false);
|
|
500
|
+
let errorMessage = track('');
|
|
499
501
|
|
|
500
502
|
const triggerError = () => {
|
|
501
503
|
try {
|
|
502
504
|
throw new Error('Test error');
|
|
503
505
|
} catch (e) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
+
@hasError = true;
|
|
507
|
+
@errorMessage = e.message;
|
|
506
508
|
}
|
|
507
509
|
};
|
|
508
510
|
|
|
509
511
|
<div>
|
|
510
512
|
<button onClick={triggerError}>{'Trigger Error'}</button>
|
|
511
|
-
if (
|
|
512
|
-
<div class='error'>{'Error caught: ' +
|
|
513
|
+
if (@hasError) {
|
|
514
|
+
<div class='error'>{'Error caught: ' + @errorMessage}</div>
|
|
513
515
|
} else {
|
|
514
516
|
<div class='success'>{'No error'}</div>
|
|
515
517
|
}
|
|
@@ -534,12 +536,12 @@ describe('basic', () => {
|
|
|
534
536
|
|
|
535
537
|
it('renders with computed reactive state', () => {
|
|
536
538
|
component Basic() {
|
|
537
|
-
let
|
|
539
|
+
let count = track(5);
|
|
538
540
|
|
|
539
|
-
<div class='count'>{
|
|
540
|
-
<div class='doubled'>{
|
|
541
|
-
<div class='is-even'>{
|
|
542
|
-
<button onClick={() =>
|
|
541
|
+
<div class='count'>{@count}</div>
|
|
542
|
+
<div class='doubled'>{@count * 2}</div>
|
|
543
|
+
<div class='is-even'>{@count % 2 === 0 ? 'Even' : 'Odd'}</div>
|
|
544
|
+
<button onClick={() => { @count++ }}>{'Increment'}</button>
|
|
543
545
|
}
|
|
544
546
|
|
|
545
547
|
render(Basic);
|
|
@@ -577,16 +579,46 @@ describe('basic', () => {
|
|
|
577
579
|
|
|
578
580
|
it('renders with simple reactive objects', () => {
|
|
579
581
|
component Basic() {
|
|
580
|
-
let
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
};
|
|
582
|
+
let user = track({
|
|
583
|
+
name: 'John',
|
|
584
|
+
age: 25
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
<div class='name'>{@user.name}</div>
|
|
588
|
+
<div class='age'>{@user.age}</div>
|
|
589
|
+
<button onClick={() => {
|
|
590
|
+
@user = {...@user, name: 'Jane', age: 30}
|
|
591
|
+
}}>{'Update User'}</button>
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
render(Basic);
|
|
595
|
+
|
|
596
|
+
const nameDiv = container.querySelector('.name');
|
|
597
|
+
const ageDiv = container.querySelector('.age');
|
|
598
|
+
const button = container.querySelector('button');
|
|
599
|
+
|
|
600
|
+
expect(nameDiv.textContent).toBe('John');
|
|
601
|
+
expect(ageDiv.textContent).toBe('25');
|
|
602
|
+
|
|
603
|
+
button.click();
|
|
604
|
+
flushSync();
|
|
605
|
+
|
|
606
|
+
expect(nameDiv.textContent).toBe('Jane');
|
|
607
|
+
expect(ageDiv.textContent).toBe('30');
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it('renders with nested reactive objects', () => {
|
|
611
|
+
component Basic() {
|
|
612
|
+
let user = track({
|
|
613
|
+
name: track('John'),
|
|
614
|
+
age: track(25)
|
|
615
|
+
});
|
|
584
616
|
|
|
585
|
-
<div class='name'>{
|
|
586
|
-
<div class='age'>{
|
|
617
|
+
<div class='name'>{@user.@name}</div>
|
|
618
|
+
<div class='age'>{@user.@age}</div>
|
|
587
619
|
<button onClick={() => {
|
|
588
|
-
|
|
589
|
-
|
|
620
|
+
@user.@name = 'Jane';
|
|
621
|
+
@user.@age = 30;
|
|
590
622
|
}}>{'Update User'}</button>
|
|
591
623
|
}
|
|
592
624
|
|
|
@@ -608,15 +640,15 @@ describe('basic', () => {
|
|
|
608
640
|
|
|
609
641
|
it('renders with conditional rendering using if statements', () => {
|
|
610
642
|
component Basic() {
|
|
611
|
-
let
|
|
612
|
-
let
|
|
643
|
+
let showContent = track(false);
|
|
644
|
+
let userRole = track('guest');
|
|
613
645
|
|
|
614
|
-
<button onClick={() =>
|
|
615
|
-
<button onClick={() =>
|
|
646
|
+
<button onClick={() => { @showContent = !@showContent }}>{'Toggle Content'}</button>
|
|
647
|
+
<button onClick={() => { @userRole = @userRole === 'guest' ? 'admin' : 'guest' }}>{'Toggle Role'}</button>
|
|
616
648
|
|
|
617
649
|
<div class='content'>
|
|
618
|
-
if (
|
|
619
|
-
if (
|
|
650
|
+
if (@showContent) {
|
|
651
|
+
if (@userRole === 'admin') {
|
|
620
652
|
<div class='admin-content'>{'Admin content'}</div>
|
|
621
653
|
} else {
|
|
622
654
|
<div class='user-content'>{'User content'}</div>
|
|
@@ -667,15 +699,15 @@ describe('basic', () => {
|
|
|
667
699
|
}
|
|
668
700
|
|
|
669
701
|
component Basic() {
|
|
670
|
-
let
|
|
702
|
+
let clicked = track(false);
|
|
671
703
|
|
|
672
704
|
<Card
|
|
673
705
|
title='Test Card'
|
|
674
706
|
content='This is a test card'
|
|
675
707
|
buttonText='Click me'
|
|
676
|
-
onAction={() =>
|
|
708
|
+
onAction={() => @clicked = true}
|
|
677
709
|
/>
|
|
678
|
-
<div class='status'>{
|
|
710
|
+
<div class='status'>{@clicked ? 'Clicked' : 'Not clicked'}</div>
|
|
679
711
|
}
|
|
680
712
|
|
|
681
713
|
render(Basic);
|
|
@@ -700,31 +732,31 @@ describe('basic', () => {
|
|
|
700
732
|
|
|
701
733
|
it('renders with complex event handling and state updates', () => {
|
|
702
734
|
component Basic() {
|
|
703
|
-
let
|
|
704
|
-
let
|
|
705
|
-
let
|
|
735
|
+
let counter = track(0);
|
|
736
|
+
let history = track([]);
|
|
737
|
+
let isEven = track(true);
|
|
706
738
|
|
|
707
739
|
const handleIncrement = () => {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
740
|
+
@counter++;
|
|
741
|
+
@history = [...@history, `Inc to ${@counter}`];
|
|
742
|
+
@isEven = @counter % 2 === 0;
|
|
711
743
|
};
|
|
712
744
|
|
|
713
745
|
const handleDecrement = () => {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
746
|
+
@counter--;
|
|
747
|
+
@history = [...@history, `Dec to ${@counter}`];
|
|
748
|
+
@isEven = @counter % 2 === 0;
|
|
717
749
|
};
|
|
718
750
|
|
|
719
751
|
const handleReset = () => {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
752
|
+
@counter = 0;
|
|
753
|
+
@history = [...@history, 'Reset'];
|
|
754
|
+
@isEven = true;
|
|
723
755
|
};
|
|
724
756
|
|
|
725
|
-
<div class='counter'>{
|
|
726
|
-
<div class='parity'>{
|
|
727
|
-
<div class='history-count'>{
|
|
757
|
+
<div class='counter'>{@counter}</div>
|
|
758
|
+
<div class='parity'>{@isEven ? 'Even' : 'Odd'}</div>
|
|
759
|
+
<div class='history-count'>{@history.length}</div>
|
|
728
760
|
|
|
729
761
|
<button class='inc-btn' onClick={handleIncrement}>{'+'}</button>
|
|
730
762
|
<button class='dec-btn' onClick={handleDecrement}>{'-'}</button>
|
|
@@ -775,18 +807,18 @@ describe('basic', () => {
|
|
|
775
807
|
|
|
776
808
|
it('renders with reactive component props', () => {
|
|
777
809
|
component ChildComponent(props) {
|
|
778
|
-
<div class='child-content'>{props
|
|
779
|
-
<div class='child-count'>{props
|
|
810
|
+
<div class='child-content'>{props.@text}</div>
|
|
811
|
+
<div class='child-count'>{props.@count}</div>
|
|
780
812
|
}
|
|
781
813
|
|
|
782
814
|
component Basic() {
|
|
783
|
-
let
|
|
784
|
-
let
|
|
815
|
+
let message = track('Hello');
|
|
816
|
+
let number = track(1);
|
|
785
817
|
|
|
786
|
-
<ChildComponent
|
|
818
|
+
<ChildComponent text={message} count={number} />
|
|
787
819
|
<button onClick={() => {
|
|
788
|
-
|
|
789
|
-
|
|
820
|
+
@message = @message === 'Hello' ? 'Goodbye' : 'Hello';
|
|
821
|
+
@number++;
|
|
790
822
|
}}>{'Update Props'}</button>
|
|
791
823
|
}
|
|
792
824
|
|
|
@@ -850,16 +882,16 @@ describe('basic', () => {
|
|
|
850
882
|
|
|
851
883
|
it('renders with mixed static and dynamic content', () => {
|
|
852
884
|
component Basic() {
|
|
853
|
-
let
|
|
854
|
-
let
|
|
885
|
+
let name = track('World');
|
|
886
|
+
let count = track(0);
|
|
855
887
|
const staticMessage = 'Welcome to Ripple!';
|
|
856
888
|
|
|
857
889
|
<div class='mixed-content'>
|
|
858
890
|
<h1>{staticMessage}</h1>
|
|
859
|
-
<p class='greeting'>{'Hello, ' +
|
|
860
|
-
<p class='notifications'>{'You have ' +
|
|
861
|
-
<button onClick={() =>
|
|
862
|
-
<button onClick={() =>
|
|
891
|
+
<p class='greeting'>{'Hello, ' + @name + '!'}</p>
|
|
892
|
+
<p class='notifications'>{'You have ' + @count + ' notifications'}</p>
|
|
893
|
+
<button onClick={() => { @count++ }}>{'Add Notification'}</button>
|
|
894
|
+
<button onClick={() => { @name = @name === 'World' ? 'User' : 'World' }}>{'Toggle Name'}</button>
|
|
863
895
|
</div>
|
|
864
896
|
}
|
|
865
897
|
|
|
@@ -885,14 +917,14 @@ describe('basic', () => {
|
|
|
885
917
|
|
|
886
918
|
it('renders with reactive attributes with nested reactive attributes', () => {
|
|
887
919
|
component App() {
|
|
888
|
-
let
|
|
920
|
+
let value = track('parent-class');
|
|
889
921
|
|
|
890
|
-
<p
|
|
922
|
+
<p class={@value}>{'Colored parent value'}</p>
|
|
891
923
|
|
|
892
924
|
<div>
|
|
893
|
-
let
|
|
925
|
+
let nested = track('nested-class');
|
|
894
926
|
|
|
895
|
-
<p
|
|
927
|
+
<p class={@nested}>{'Colored nested value'}</p>
|
|
896
928
|
</div>
|
|
897
929
|
}
|
|
898
930
|
|
|
@@ -927,35 +959,35 @@ describe('basic', () => {
|
|
|
927
959
|
let logs = [];
|
|
928
960
|
|
|
929
961
|
component App() {
|
|
930
|
-
let
|
|
931
|
-
let
|
|
932
|
-
const arr = [
|
|
962
|
+
let first = track(0);
|
|
963
|
+
let second = track(0);
|
|
964
|
+
const arr = [first, second];
|
|
933
965
|
|
|
934
|
-
const
|
|
966
|
+
const total = track(() => arr.reduce((a, b) => a + @b, 0));
|
|
935
967
|
|
|
936
|
-
<button onClick={() => {
|
|
937
|
-
<button onClick={() => {
|
|
968
|
+
<button onClick={() => { @first++; }}>{'first:' + @first}</button>
|
|
969
|
+
<button onClick={() => { @second++; }}>{'second: ' + @second}</button>
|
|
938
970
|
|
|
939
971
|
effect(() => {
|
|
940
972
|
let _arr = [];
|
|
941
973
|
|
|
942
974
|
arr.forEach((item) => {
|
|
943
|
-
_arr.push(item);
|
|
975
|
+
_arr.push(@item);
|
|
944
976
|
});
|
|
945
977
|
|
|
946
978
|
logs.push(_arr.join(', '));
|
|
947
979
|
});
|
|
948
980
|
|
|
949
981
|
effect(() => {
|
|
950
|
-
if (arr.includes(1)) {
|
|
982
|
+
if (arr.map(a => @a).includes(1)) {
|
|
951
983
|
logs.push('arr includes 1');
|
|
952
984
|
}
|
|
953
985
|
});
|
|
954
986
|
|
|
955
|
-
<div>{'Sum: ' +
|
|
956
|
-
<div>{'Comma Separated: ' + arr.join(', ')}</div>
|
|
957
|
-
<div>{'Number to string: ' + arr.map(a => String(a))}</div>
|
|
958
|
-
<div>{'Even numbers: ' + arr.filter(a => a % 2 === 0)}</div>
|
|
987
|
+
<div>{'Sum: ' + @total}</div>
|
|
988
|
+
<div>{'Comma Separated: ' + arr.map(a => @a).join(', ')}</div>
|
|
989
|
+
<div>{'Number to string: ' + arr.map(a => String(@a))}</div>
|
|
990
|
+
<div>{'Even numbers: ' + arr.map(a => @a).filter(a => a % 2 === 0)}</div>
|
|
959
991
|
}
|
|
960
992
|
|
|
961
993
|
render(App);
|
|
@@ -986,22 +1018,22 @@ describe('basic', () => {
|
|
|
986
1018
|
expect(divs[1].textContent).toBe('Comma Separated: 1, 1');
|
|
987
1019
|
expect(divs[2].textContent).toBe('Number to string: 1,1');
|
|
988
1020
|
expect(divs[3].textContent).toBe('Even numbers: ');
|
|
989
|
-
expect(logs).toEqual(['0, 0', '1, 0', 'arr includes 1', '1, 1']);
|
|
1021
|
+
expect(logs).toEqual(['0, 0', '1, 0', 'arr includes 1', '1, 1', 'arr includes 1']);
|
|
990
1022
|
});
|
|
991
1023
|
|
|
992
1024
|
it('it retains this context with bracketed prop functions and keeps original chaining', () => {
|
|
993
1025
|
component App() {
|
|
994
1026
|
const SYMBOL_PROP = Symbol();
|
|
995
|
-
let
|
|
1027
|
+
let hasError = track(false);
|
|
996
1028
|
const obj = {
|
|
997
|
-
|
|
1029
|
+
count: track(0),
|
|
998
1030
|
increment() {
|
|
999
|
-
this
|
|
1031
|
+
this.@count++;
|
|
1000
1032
|
},
|
|
1001
1033
|
[SYMBOL_PROP]() {
|
|
1002
|
-
this
|
|
1034
|
+
this.@count++;
|
|
1003
1035
|
},
|
|
1004
|
-
arr: [() => obj
|
|
1036
|
+
arr: [() => obj.@count++, () => obj.@count--],
|
|
1005
1037
|
};
|
|
1006
1038
|
|
|
1007
1039
|
const obj2 = null;
|
|
@@ -1010,48 +1042,48 @@ describe('basic', () => {
|
|
|
1010
1042
|
<button onClick={() => obj[SYMBOL_PROP]()}>{'Increment'}</button>
|
|
1011
1043
|
<button
|
|
1012
1044
|
onClick={() => {
|
|
1013
|
-
|
|
1045
|
+
@hasError = false;
|
|
1014
1046
|
try {
|
|
1015
1047
|
obj['nonexistent']();
|
|
1016
1048
|
} catch {
|
|
1017
|
-
|
|
1049
|
+
@hasError = true;
|
|
1018
1050
|
}
|
|
1019
1051
|
}}
|
|
1020
1052
|
>{'Nonexistent'}</button>
|
|
1021
1053
|
<button
|
|
1022
1054
|
onClick={() => {
|
|
1023
|
-
|
|
1055
|
+
@hasError = false;
|
|
1024
1056
|
try {
|
|
1025
1057
|
obj['nonexistent']?.();
|
|
1026
1058
|
} catch {
|
|
1027
|
-
|
|
1059
|
+
@hasError = true;
|
|
1028
1060
|
}
|
|
1029
1061
|
}}
|
|
1030
1062
|
>{'Nonexistent chaining'}</button>
|
|
1031
1063
|
<button
|
|
1032
1064
|
onClick={() => {
|
|
1033
|
-
|
|
1065
|
+
@hasError = false;
|
|
1034
1066
|
try {
|
|
1035
1067
|
obj2['nonexistent']();
|
|
1036
1068
|
} catch {
|
|
1037
|
-
|
|
1069
|
+
@hasError = true;
|
|
1038
1070
|
}
|
|
1039
1071
|
}}
|
|
1040
1072
|
>{'Object null'}</button>
|
|
1041
1073
|
<button
|
|
1042
1074
|
onClick={() => {
|
|
1043
|
-
|
|
1075
|
+
@hasError = false;
|
|
1044
1076
|
try {
|
|
1045
1077
|
obj2?.['nonexistent']?.();
|
|
1046
1078
|
} catch {
|
|
1047
|
-
|
|
1079
|
+
@hasError = true;
|
|
1048
1080
|
}
|
|
1049
1081
|
}}
|
|
1050
1082
|
>{'Object null chained'}</button>
|
|
1051
1083
|
<button onClick={() => obj.arr[obj.arr.length - 1]()}>{'BinaryExpression prop'}</button>
|
|
1052
1084
|
|
|
1053
|
-
<span>{obj
|
|
1054
|
-
<span>{
|
|
1085
|
+
<span>{obj.@count}</span>
|
|
1086
|
+
<span>{@hasError}</span>
|
|
1055
1087
|
}
|
|
1056
1088
|
|
|
1057
1089
|
render(App);
|