ripple 0.2.28 → 0.2.31

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.
@@ -0,0 +1,108 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mount, flushSync, effect } from 'ripple';
3
+
4
+ describe('passing reactivity between boundaries tests', () => {
5
+ let container;
6
+
7
+ function render(component) {
8
+ mount(component, {
9
+ target: container
10
+ });
11
+ }
12
+
13
+ beforeEach(() => {
14
+ container = document.createElement('div');
15
+ document.body.appendChild(container);
16
+ });
17
+
18
+ afterEach(() => {
19
+ document.body.removeChild(container);
20
+ container = null;
21
+ });
22
+
23
+ it('can pass reactivity between functions with simple arrays and destructuring', () => {
24
+ let log: string[] = [];
25
+
26
+ function createDouble([ $count ]) {
27
+ const $double = $count * 2;
28
+
29
+ effect(() => {
30
+ log.push('Count:' + $count);
31
+ });
32
+
33
+ return [ $double ];
34
+ }
35
+
36
+ component App() {
37
+ let $count = 0;
38
+
39
+ const [ $double ] = createDouble([ $count ]);
40
+
41
+ <div>{'Double: ' + $double}</div>
42
+ <button onClick={() => { $count++; }}>{'Increment'}</button>
43
+ }
44
+
45
+ render(App);
46
+ flushSync();
47
+
48
+ expect(container.querySelector('div').textContent).toBe('Double: 0');
49
+ expect(log).toEqual(['Count:0']);
50
+
51
+ const button = container.querySelector('button');
52
+
53
+ button.click();
54
+ flushSync();
55
+
56
+ expect(container.querySelector('div').textContent).toBe('Double: 2');
57
+ expect(log).toEqual(['Count:0', 'Count:1']);
58
+
59
+ button.click();
60
+ flushSync();
61
+
62
+ expect(container.querySelector('div').textContent).toBe('Double: 4');
63
+ expect(log).toEqual(['Count:0', 'Count:1', 'Count:2']);
64
+ });
65
+
66
+ it('can pass reactivity between functions with simple objects and destructuring', () => {
67
+ let log: string[] = [];
68
+
69
+ function createDouble({ $count }) {
70
+ const $double = $count * 2;
71
+
72
+ effect(() => {
73
+ log.push('Count:' + $count);
74
+ });
75
+
76
+ return { $double };
77
+ }
78
+
79
+ component App() {
80
+ let $count = 0;
81
+
82
+ const { $double } = createDouble({ $count });
83
+
84
+ <div>{'Double: ' + $double}</div>
85
+ <button onClick={() => { $count++; }}>{'Increment'}</button>
86
+ }
87
+
88
+ render(App);
89
+ flushSync();
90
+
91
+ expect(container.querySelector('div').textContent).toBe('Double: 0');
92
+ expect(log).toEqual(['Count:0']);
93
+
94
+ const button = container.querySelector('button');
95
+
96
+ button.click();
97
+ flushSync();
98
+
99
+ expect(container.querySelector('div').textContent).toBe('Double: 2');
100
+ expect(log).toEqual(['Count:0', 'Count:1']);
101
+
102
+ button.click();
103
+ flushSync();
104
+
105
+ expect(container.querySelector('div').textContent).toBe('Double: 4');
106
+ expect(log).toEqual(['Count:0', 'Count:1', 'Count:2']);
107
+ });
108
+ });
@@ -1,6 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
-
3
- import { mount } from 'ripple';
2
+ import { mount, RippleArray } from 'ripple';
4
3
 
5
4
  describe('compiler success tests', () => {
6
5
  let container;
@@ -58,4 +57,100 @@ describe('compiler success tests', () => {
58
57
  render(App);
59
58
  });
60
59
 
60
+ it('render lexical blocks without crashing', () => {
61
+ component App() {
62
+ <div>
63
+ const a = 1;
64
+ <div>
65
+ const b = 1;
66
+ </div>
67
+ <div>
68
+ const b = 1;
69
+ </div>
70
+ </div>
71
+ <div>
72
+ const a = 2;
73
+ <div>
74
+ const b = 1;
75
+ </div>
76
+ </div>
77
+ }
78
+
79
+ render(App);
80
+ });
81
+
82
+ it('properly handles JS assignments, reads and updates to array indices', () => {
83
+ const logs = [];
84
+
85
+ component App() {
86
+ let items = [];
87
+ let $items = [];
88
+ let items2 = new Array();
89
+ let items3 = new RippleArray();
90
+ let i = 0;
91
+
92
+ logs.push(items[0]);
93
+ logs.push(items[i]);
94
+ logs.push($items[0]);
95
+ logs.push($items[i]);
96
+ logs.push(items2[0]);
97
+ logs.push(items2[i]);
98
+ logs.push(items3[0]);
99
+ logs.push(items3[i]);
100
+
101
+ items[0] = 123;
102
+ items[i] = 123;
103
+ $items[0] = 123;
104
+ $items[i] = 123;
105
+ items2[0] = 123;
106
+ items2[i] = 123;
107
+ items3[0] = 123;
108
+ items3[i] = 123;
109
+
110
+ logs.push(items[0]);
111
+ logs.push(items[i]);
112
+ logs.push($items[0]);
113
+ logs.push($items[i]);
114
+ logs.push(items2[0]);
115
+ logs.push(items2[i]);
116
+ logs.push(items3[0]);
117
+ logs.push(items3[i]);
118
+
119
+ items[0]++;
120
+ items[i]++;
121
+ $items[0]++;
122
+ $items[i]++;
123
+ items2[0]++;
124
+ items2[i]++;
125
+ items3[0]++;
126
+ items3[i]++;
127
+
128
+ logs.push(items[0]);
129
+ logs.push(items[i]);
130
+ logs.push($items[0]);
131
+ logs.push($items[i]);
132
+ logs.push(items2[0]);
133
+ logs.push(items2[i]);
134
+ logs.push(items3[0]);
135
+ logs.push(items3[i]);
136
+
137
+ logs.push(--items[0]);
138
+ logs.push(--items[i]);
139
+ logs.push(--$items[0]);
140
+ logs.push(--$items[i]);
141
+ logs.push(--items2[0]);
142
+ logs.push(--items2[i]);
143
+ logs.push(--items3[0]);
144
+ logs.push(--items3[i]);
145
+ }
146
+
147
+ render(App);
148
+
149
+ expect(logs).toEqual([
150
+ undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined,
151
+ 123, 123, 123, 123, 123, 123, 123, 123,
152
+ 125, 125, 125, 125, 125, 125, 125, 125,
153
+ 124, 123, 124, 123, 124, 123, 124, 123
154
+ ]);
155
+ });
61
156
  });
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
-
3
2
  import { mount, flushSync } from 'ripple';
4
3
 
5
4
  describe('composite components', () => {
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
-
3
2
  import { mount, createContext } from 'ripple';
4
3
 
5
4
  describe('context', () => {
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
-
3
2
  import { mount, flushSync, RippleArray } from 'ripple';
4
3
 
5
4
  describe('@use element decorators', () => {
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mount, flushSync, RippleMap } from 'ripple';
3
+
4
+ describe('RippleMap', () => {
5
+ let container;
6
+
7
+ function render(component) {
8
+ mount(component, {
9
+ target: container
10
+ });
11
+ }
12
+
13
+ beforeEach(() => {
14
+ container = document.createElement('div');
15
+ document.body.appendChild(container);
16
+ });
17
+
18
+ afterEach(() => {
19
+ document.body.removeChild(container);
20
+ container = null;
21
+ });
22
+
23
+ it('handles set with update and delete operations with a reactive $size var', () => {
24
+ component MapTest() {
25
+ let map = new RippleMap([['a', 1], ['b', 2], ['c', 3]]);
26
+ let $value = map.get('a');
27
+ let $size = map.$size;
28
+
29
+ <button onClick={() => map.set('d', 4)}>{'set'}</button>
30
+ <button onClick={() => map.delete('b')}>{'delete'}</button>
31
+ <button onClick={() => map.set('a', 5)}>{'update'}</button>
32
+
33
+ <pre>{map.get('d')}</pre>
34
+ <pre>{$size}</pre>
35
+ <pre>{$value}</pre>
36
+ }
37
+
38
+ render(MapTest);
39
+
40
+ const setButton = container.querySelectorAll('button')[0];
41
+ const deleteButton = container.querySelectorAll('button')[1];
42
+ const updateButton = container.querySelectorAll('button')[2];
43
+
44
+ setButton.click();
45
+ flushSync();
46
+
47
+ expect(container.querySelectorAll('pre')[0].textContent).toBe('4');
48
+ expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
49
+ expect(container.querySelectorAll('pre')[2].textContent).toBe('1');
50
+
51
+ deleteButton.click();
52
+ flushSync();
53
+
54
+ expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
55
+
56
+ updateButton.click();
57
+ flushSync();
58
+
59
+ expect(container.querySelectorAll('pre')[2].textContent).toBe('5');
60
+ });
61
+
62
+ it('handles clear operation', () => {
63
+ component MapTest() {
64
+ let map = new RippleMap([['a', 1], ['b', 2], ['c', 3]]);
65
+
66
+ <button onClick={() => map.clear()}>{'clear'}</button>
67
+ <pre>{map.$size}</pre>
68
+ }
69
+
70
+ render(MapTest);
71
+
72
+ const clearButton = container.querySelector('button');
73
+
74
+ clearButton.click();
75
+ flushSync();
76
+
77
+ expect(container.querySelector('pre').textContent).toBe('0');
78
+ });
79
+
80
+ it('handles has operation and tracks reactive $has', () => {
81
+ component MapTest() {
82
+ let map = new RippleMap([['a', 1], ['b', 2], ['c', 3]]);
83
+ let $has = map.has('b');
84
+
85
+ <button onClick={() => map.delete('b')}>{'delete'}</button>
86
+ <pre>{$has}</pre>
87
+ }
88
+
89
+ render(MapTest);
90
+
91
+ const deleteButton = container.querySelector('button');
92
+ expect(container.querySelector('pre').textContent).toBe('true');
93
+
94
+ deleteButton.click();
95
+ flushSync();
96
+
97
+ expect(container.querySelector('pre').textContent).toBe('false');
98
+ });
99
+
100
+ it('handles reactivity of keys, values, and entries', () => {
101
+ component MapTest() {
102
+ let map = new RippleMap([['x', 10], ['y', 20]]);
103
+ let $keys = Array.from(map.keys());
104
+ let $values = Array.from(map.values());
105
+ let $entries = Array.from(map.entries());
106
+
107
+ <button onClick={() => map.delete('x')}>{'delete'}</button>
108
+
109
+ <pre>{JSON.stringify($keys)}</pre>
110
+ <pre>{JSON.stringify($values)}</pre>
111
+ <pre>{JSON.stringify($entries)}</pre>
112
+ }
113
+
114
+ render(MapTest);
115
+
116
+ const deleteButton = container.querySelector('button');
117
+
118
+ expect(container.querySelectorAll('pre')[0].textContent).toBe('["x","y"]');
119
+ expect(container.querySelectorAll('pre')[1].textContent).toBe('[10,20]');
120
+ expect(container.querySelectorAll('pre')[2].textContent).toBe('[["x",10],["y",20]]');
121
+
122
+ deleteButton.click();
123
+ flushSync();
124
+
125
+ expect(container.querySelectorAll('pre')[0].textContent).toBe('["y"]');
126
+ expect(container.querySelectorAll('pre')[1].textContent).toBe('[20]');
127
+ expect(container.querySelectorAll('pre')[2].textContent).toBe('[["y",20]]');
128
+ });
129
+
130
+ it('toJSON returns correct object', () => {
131
+ component MapTest() {
132
+ let map = new RippleMap([['foo', 1], ['bar', 2]]);
133
+
134
+ <pre>{JSON.stringify(map)}</pre>
135
+ }
136
+
137
+ render(MapTest);
138
+
139
+ expect(container.querySelectorAll('pre')[0].textContent).toBe('[["foo",1],["bar",2]]');
140
+ });
141
+ });
@@ -82,7 +82,7 @@ describe('RippleSet', () => {
82
82
  let $hasValue = items.has(2);
83
83
 
84
84
  <button onClick={() => items.delete(2)}>{'delete'}</button>
85
- <pre>{JSON.stringify($hasValue)}</pre>
85
+ <pre>{$hasValue}</pre>
86
86
  }
87
87
 
88
88
  render(SetTest);
package/types/index.d.ts CHANGED
@@ -50,3 +50,8 @@ export class RippleSet<T> extends Set<T> {
50
50
  union(other: RippleSet<T> | Set<T>): RippleSet<T>;
51
51
  toJSON(): T[];
52
52
  }
53
+
54
+ export class RippleMap<K, V> extends Map<K, V> {
55
+ get $size(): number;
56
+ toJSON(): [K, V][];
57
+ }