ripple 0.2.152 → 0.2.154

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.
Files changed (67) hide show
  1. package/README.md +3 -3
  2. package/package.json +5 -5
  3. package/src/compiler/phases/1-parse/index.js +1 -1
  4. package/src/compiler/phases/3-transform/client/index.js +37 -16
  5. package/src/compiler/phases/3-transform/server/index.js +43 -25
  6. package/src/runtime/internal/client/events.js +5 -1
  7. package/src/runtime/internal/client/index.js +2 -1
  8. package/src/runtime/internal/client/render.js +18 -15
  9. package/src/runtime/internal/client/runtime.js +75 -10
  10. package/src/runtime/internal/server/index.js +51 -11
  11. package/src/server/index.js +1 -1
  12. package/tests/client/array/array.derived.test.ripple +61 -33
  13. package/tests/client/array/array.iteration.test.ripple +3 -1
  14. package/tests/client/array/array.mutations.test.ripple +19 -15
  15. package/tests/client/array/array.static.test.ripple +115 -104
  16. package/tests/client/array/array.to-methods.test.ripple +3 -3
  17. package/tests/client/basic/basic.attributes.test.ripple +110 -57
  18. package/tests/client/basic/basic.collections.test.ripple +41 -22
  19. package/tests/client/basic/basic.errors.test.ripple +12 -6
  20. package/tests/client/basic/basic.events.test.ripple +51 -33
  21. package/tests/client/basic/basic.reactivity.test.ripple +120 -56
  22. package/tests/client/basic/basic.rendering.test.ripple +49 -19
  23. package/tests/client/basic/basic.styling.test.ripple +2 -2
  24. package/tests/client/basic/basic.utilities.test.ripple +1 -1
  25. package/tests/client/boundaries.test.ripple +70 -58
  26. package/tests/client/compiler/compiler.assignments.test.ripple +32 -4
  27. package/tests/client/compiler/compiler.attributes.test.ripple +46 -46
  28. package/tests/client/compiler/compiler.basic.test.ripple +18 -15
  29. package/tests/client/compiler/compiler.tracked-access.test.ripple +53 -42
  30. package/tests/client/compiler/compiler.typescript.test.ripple +1 -2
  31. package/tests/client/composite/composite.dynamic-components.test.ripple +6 -6
  32. package/tests/client/composite/composite.generics.test.ripple +39 -36
  33. package/tests/client/composite/composite.props.test.ripple +4 -3
  34. package/tests/client/composite/composite.reactivity.test.ripple +112 -27
  35. package/tests/client/composite/composite.render.test.ripple +9 -8
  36. package/tests/client/computed-properties.test.ripple +24 -24
  37. package/tests/client/context.test.ripple +11 -9
  38. package/tests/client/date.test.ripple +3 -1
  39. package/tests/client/dynamic-elements.test.ripple +103 -78
  40. package/tests/client/for.test.ripple +27 -17
  41. package/tests/client/head.test.ripple +42 -6
  42. package/tests/client/html.test.ripple +42 -32
  43. package/tests/client/input-value.test.ripple +4 -4
  44. package/tests/client/map.test.ripple +140 -141
  45. package/tests/client/media-query.test.ripple +31 -31
  46. package/tests/client/object.test.ripple +148 -112
  47. package/tests/client/portal.test.ripple +29 -15
  48. package/tests/client/ref.test.ripple +9 -3
  49. package/tests/client/set.test.ripple +111 -111
  50. package/tests/client/tracked-expression.test.ripple +16 -17
  51. package/tests/client/url/url.derived.test.ripple +19 -9
  52. package/tests/client/url/url.parsing.test.ripple +24 -8
  53. package/tests/client/url/url.partial-removal.test.ripple +12 -4
  54. package/tests/client/url/url.reactivity.test.ripple +63 -25
  55. package/tests/client/url/url.serialization.test.ripple +18 -6
  56. package/tests/client/url-search-params/url-search-params.derived.test.ripple +10 -6
  57. package/tests/client/url-search-params/url-search-params.iteration.test.ripple +3 -1
  58. package/tests/client/url-search-params/url-search-params.mutation.test.ripple +26 -14
  59. package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +3 -1
  60. package/tests/server/await.test.ripple +23 -22
  61. package/tests/server/basic.test.ripple +1 -1
  62. package/tests/server/compiler.test.ripple +3 -7
  63. package/tests/server/composite.test.ripple +38 -36
  64. package/tests/server/for.test.ripple +9 -5
  65. package/tests/server/if.test.ripple +1 -1
  66. package/tests/server/streaming-ssr.test.ripple +67 -0
  67. package/types/server.d.ts +5 -4
@@ -2,163 +2,199 @@ import { flushSync, TrackedObject } from 'ripple';
2
2
  import { TRACKED_OBJECT } from '../../src/runtime/internal/client/constants.js';
3
3
 
4
4
  describe('TrackedObject', () => {
5
- it('makes new properties reactive', () => {
6
- component ObjectTest() {
7
- const obj = new TrackedObject<{ a: number; }>({});
5
+ it('makes new properties reactive', () => {
6
+ component ObjectTest() {
7
+ const obj = new TrackedObject<{ a: number }>({});
8
8
 
9
- obj.a = 0;
9
+ obj.a = 0;
10
10
 
11
- <pre>{obj.a}</pre>
12
- <button onClick={() => { obj.a++; }}>{'Increment A'}</button>
13
- }
11
+ <pre>{obj.a}</pre>
12
+ <button
13
+ onClick={() => {
14
+ obj.a++;
15
+ }}
16
+ >
17
+ {'Increment A'}
18
+ </button>
19
+ }
14
20
 
15
- render(ObjectTest);
21
+ render(ObjectTest);
16
22
 
17
- const pre1 = container.querySelectorAll('pre')[0];
18
- const button = container.querySelectorAll('button')[0 ];
23
+ const pre1 = container.querySelectorAll('pre')[0];
24
+ const button = container.querySelectorAll('button')[0];
19
25
 
20
- expect(pre1.textContent).toBe('0');
26
+ expect(pre1.textContent).toBe('0');
21
27
 
22
- button.click();
23
- flushSync();
28
+ button.click();
29
+ flushSync();
24
30
 
25
- expect(pre1.textContent).toBe('1');
26
- });
31
+ expect(pre1.textContent).toBe('1');
32
+ });
27
33
 
28
- it('makes existing object properties reactive', () => {
29
- component ObjectTest() {
30
- const obj = new TrackedObject({ a: 0 });
34
+ it('makes existing object properties reactive', () => {
35
+ component ObjectTest() {
36
+ const obj = new TrackedObject({ a: 0 });
31
37
 
32
- <pre>{obj.a}</pre>
33
- <button onClick={() => { obj.a++; }}>{'Increment A'}</button>
34
- }
38
+ <pre>{obj.a}</pre>
39
+ <button
40
+ onClick={() => {
41
+ obj.a++;
42
+ }}
43
+ >
44
+ {'Increment A'}
45
+ </button>
46
+ }
35
47
 
36
- render(ObjectTest);
48
+ render(ObjectTest);
37
49
 
38
- const pre1 = container.querySelectorAll('pre')[0];
39
- const button = container.querySelectorAll('button')[0 ];
50
+ const pre1 = container.querySelectorAll('pre')[0];
51
+ const button = container.querySelectorAll('button')[0];
40
52
 
41
- expect(pre1.textContent).toBe('0');
53
+ expect(pre1.textContent).toBe('0');
42
54
 
43
- button.click();
44
- flushSync();
55
+ button.click();
56
+ flushSync();
45
57
 
46
- expect(pre1.textContent).toBe('1');
47
- });
58
+ expect(pre1.textContent).toBe('1');
59
+ });
48
60
 
49
- it('checks if property exists via the has trap', () => {
50
- component ObjectTest() {
51
- const obj = new TrackedObject<{ a: number; b: number; }>({b: 1});
61
+ it('checks if property exists via the has trap', () => {
62
+ component ObjectTest() {
63
+ const obj = new TrackedObject<{ a: number; b: number }>({ b: 1 });
52
64
 
53
- obj.a = 0;
65
+ obj.a = 0;
54
66
 
55
- <pre>{'a' in obj && 'b' in obj}</pre>
56
- }
67
+ <pre>{'a' in obj && 'b' in obj}</pre>
68
+ }
57
69
 
58
- render(ObjectTest);
70
+ render(ObjectTest);
59
71
 
60
- const pre1 = container.querySelectorAll('pre')[0];
72
+ const pre1 = container.querySelectorAll('pre')[0];
61
73
 
62
- expect(pre1.textContent).toBe('true');
63
- });
74
+ expect(pre1.textContent).toBe('true');
75
+ });
64
76
 
65
- it('deletes properties via the delete trap', () => {
66
- component ObjectTest() {
67
- const obj = new TrackedObject<{ a?: number; b: number; }>({a: 0, b: 1});
77
+ it('deletes properties via the delete trap', () => {
78
+ component ObjectTest() {
79
+ const obj = new TrackedObject<{ a?: number; b: number }>({ a: 0, b: 1 });
68
80
 
69
- <pre>{String(obj.a)}</pre>
70
- <button onClick={() => { delete obj.a; }}>{'Delete A'}</button>
71
- }
81
+ <pre>{String(obj.a)}</pre>
82
+ <button
83
+ onClick={() => {
84
+ delete obj.a;
85
+ }}
86
+ >
87
+ {'Delete A'}
88
+ </button>
89
+ }
72
90
 
73
- render(ObjectTest);
91
+ render(ObjectTest);
74
92
 
75
- const pre1 = container.querySelectorAll('pre')[0];
76
- const button = container.querySelectorAll('button')[0 ];
93
+ const pre1 = container.querySelectorAll('pre')[0];
94
+ const button = container.querySelectorAll('button')[0];
77
95
 
78
- expect(pre1.textContent).toBe('0');
96
+ expect(pre1.textContent).toBe('0');
79
97
 
80
- button.click();
81
- flushSync();
98
+ button.click();
99
+ flushSync();
82
100
 
83
- expect(pre1.textContent).toBe('undefined');
84
- });
101
+ expect(pre1.textContent).toBe('undefined');
102
+ });
85
103
 
86
- it('checks if non-existent property is reactive when added later', () => {
87
- component ObjectTest() {
88
- const obj = new TrackedObject<{ a?: number; }>({});
104
+ it('checks if non-existent property is reactive when added later', () => {
105
+ component ObjectTest() {
106
+ const obj = new TrackedObject<{ a?: number }>({});
89
107
 
90
- <pre>{String(obj.a)} </pre>
91
- <button onClick={() => { obj.a = 1; }}>{'Add A'}</button>
92
- }
108
+ <pre>{String(obj.a)}</pre>
109
+ <button
110
+ onClick={() => {
111
+ obj.a = 1;
112
+ }}
113
+ >
114
+ {'Add A'}
115
+ </button>
116
+ }
93
117
 
94
- render(ObjectTest);
118
+ render(ObjectTest);
95
119
 
96
- const pre1 = container.querySelectorAll('pre')[0];
97
- const button = container.querySelectorAll('button')[0 ];
120
+ const pre1 = container.querySelectorAll('pre')[0];
121
+ const button = container.querySelectorAll('button')[0];
98
122
 
99
- expect(pre1.textContent).toBe('undefined');
123
+ expect(pre1.textContent).toBe('undefined');
100
124
 
101
- button.click();
102
- flushSync();
125
+ button.click();
126
+ flushSync();
103
127
 
104
- expect(pre1.textContent).toBe('1');
105
- });
128
+ expect(pre1.textContent).toBe('1');
129
+ });
106
130
 
107
- it('checks that deeply nested objects are not proxied or reactive', () => {
108
- component ObjectTest() {
109
- const obj = new TrackedObject({ a: { b: 1 } });
131
+ it('checks that deeply nested objects are not proxied or reactive', () => {
132
+ component ObjectTest() {
133
+ const obj = new TrackedObject({ a: { b: 1 } });
110
134
 
111
- <pre>{String(obj.a.b)}</pre>
112
- <button onClick={() => { obj.a.b++; }}>{'Increment B'}</button>
113
- }
135
+ <pre>{String(obj.a.b)}</pre>
136
+ <button
137
+ onClick={() => {
138
+ obj.a.b++;
139
+ }}
140
+ >
141
+ {'Increment B'}
142
+ </button>
143
+ }
114
144
 
115
- render(ObjectTest);
145
+ render(ObjectTest);
116
146
 
117
- const pre1 = container.querySelectorAll('pre')[0];
118
- const button = container.querySelectorAll('button')[0 ];
147
+ const pre1 = container.querySelectorAll('pre')[0];
148
+ const button = container.querySelectorAll('button')[0];
119
149
 
120
- expect(pre1.textContent).toBe('1');
150
+ expect(pre1.textContent).toBe('1');
121
151
 
122
- button.click();
123
- flushSync();
152
+ button.click();
153
+ flushSync();
124
154
 
125
- // remains unchanged
126
- expect(pre1.textContent).toBe('1');
127
- });
155
+ // remains unchanged
156
+ expect(pre1.textContent).toBe('1');
157
+ });
128
158
 
129
- it('checks if TRACKED_OBJECT symbol is present on TrackedObject instances', () => {
130
- component ObjectTest() {
131
- const obj = new TrackedObject({ a: 0 });
159
+ it('checks if TRACKED_OBJECT symbol is present on TrackedObject instances', () => {
160
+ component ObjectTest() {
161
+ const obj = new TrackedObject({ a: 0 });
132
162
 
133
- expect(obj[TRACKED_OBJECT]).toBe(true);
134
- }
135
- });
163
+ expect(obj[TRACKED_OBJECT]).toBe(true);
164
+ }
165
+ });
136
166
 
137
- it('uses the hash syntax for creating TrackedObject', () => {
138
- component ObjectTest() {
139
- const obj = #{ a: 0, b: 1, c: { d: {e: 8} } };
167
+ it('uses the hash syntax for creating TrackedObject', () => {
168
+ component ObjectTest() {
169
+ const obj = #{ a: 0, b: 1, c: { d: { e: 8 } } };
140
170
 
141
- <pre>{obj.a}</pre>
142
- <pre>{TRACKED_OBJECT in obj}</pre>
143
- <pre>{JSON.stringify(obj)}</pre>
144
- <button onClick={() => { obj.a++; }}>{'Increment A'}</button>
145
- }
171
+ <pre>{obj.a}</pre>
172
+ <pre>{TRACKED_OBJECT in obj}</pre>
173
+ <pre>{JSON.stringify(obj)}</pre>
174
+ <button
175
+ onClick={() => {
176
+ obj.a++;
177
+ }}
178
+ >
179
+ {'Increment A'}
180
+ </button>
181
+ }
182
+
183
+ render(ObjectTest);
184
+
185
+ const pre1 = container.querySelectorAll('pre')[0];
186
+ const pre2 = container.querySelectorAll('pre')[1];
187
+ const pre3 = container.querySelectorAll('pre')[2];
188
+ const button = container.querySelectorAll('button')[0];
146
189
 
147
- render(ObjectTest);
190
+ expect(pre1.textContent).toBe('0');
191
+ expect(pre2.textContent).toBe('true');
192
+ expect(pre3.textContent).toBe('{"a":0,"b":1,"c":{"d":{"e":8}}}');
148
193
 
149
- const pre1 = container.querySelectorAll('pre')[0];
150
- const pre2 = container.querySelectorAll('pre')[1];
151
- const pre3 = container.querySelectorAll('pre')[2];
152
- const button = container.querySelectorAll('button')[0 ];
153
-
154
- expect(pre1.textContent).toBe('0');
155
- expect(pre2.textContent).toBe('true');
156
- expect(pre3.textContent).toBe('{"a":0,"b":1,"c":{"d":{"e":8}}}');
157
-
158
- button.click();
159
- flushSync();
160
-
161
- expect(pre1.textContent).toBe('1');
162
- expect(pre3.textContent).toBe('{"a":1,"b":1,"c":{"d":{"e":8}}}');
163
- })
194
+ button.click();
195
+ flushSync();
196
+
197
+ expect(pre1.textContent).toBe('1');
198
+ expect(pre3.textContent).toBe('{"a":1,"b":1,"c":{"d":{"e":8}}}');
199
+ });
164
200
  });
@@ -4,7 +4,7 @@ describe('Portal', () => {
4
4
  afterEach(() => {
5
5
  // Clean up any leftover portal content from document.body
6
6
  const portals = document.body.querySelectorAll('.test-portal');
7
- portals.forEach(el => el.remove());
7
+ portals.forEach((el) => el.remove());
8
8
  });
9
9
 
10
10
  it('renders portal content to target element', () => {
@@ -12,7 +12,9 @@ describe('Portal', () => {
12
12
  document.body.appendChild(target);
13
13
 
14
14
  component TestPortal() {
15
- <Portal target={target}><div class='test-portal'>{'Portal works!'}</div></Portal>
15
+ <Portal {target}>
16
+ <div class="test-portal">{'Portal works!'}</div>
17
+ </Portal>
16
18
  }
17
19
 
18
20
  render(TestPortal);
@@ -27,7 +29,9 @@ describe('Portal', () => {
27
29
 
28
30
  it('renders portal content to document.body', () => {
29
31
  component TestPortal() {
30
- <Portal target={document.body}><div class='test-portal'>{'In document.body!'}</div></Portal>
32
+ <Portal target={document.body}>
33
+ <div class="test-portal">{'In document.body!'}</div>
34
+ </Portal>
31
35
  }
32
36
 
33
37
  render(TestPortal);
@@ -45,7 +49,9 @@ describe('Portal', () => {
45
49
  let open = track(true);
46
50
 
47
51
  if (@open) {
48
- <Portal target={document.body}><div class='test-portal'>{'Conditional content'}</div></Portal>
52
+ <Portal target={document.body}>
53
+ <div class="test-portal">{'Conditional content'}</div>
54
+ </Portal>
49
55
  }
50
56
 
51
57
  <button onClick={() => @open = false}>{'Close'}</button>
@@ -69,10 +75,12 @@ describe('Portal', () => {
69
75
  let open = track(false);
70
76
 
71
77
  if (@open) {
72
- <Portal target={document.body}><div class='test-portal'>
73
- {'Content'}
74
- <button onClick={() => @open = false}>{'Close'}</button>
75
- </div></Portal>
78
+ <Portal target={document.body}>
79
+ <div class="test-portal">
80
+ {'Content'}
81
+ <button onClick={() => @open = false}>{'Close'}</button>
82
+ </div>
83
+ </Portal>
76
84
  }
77
85
 
78
86
  if (!@open) {
@@ -106,9 +114,13 @@ describe('Portal', () => {
106
114
  document.body.appendChild(target2);
107
115
 
108
116
  component TestMultiPortal() {
109
- <Portal target={target1}><div class='test-portal'>{'Portal 1 content'}</div></Portal>
117
+ <Portal target={target1}>
118
+ <div class="test-portal">{'Portal 1 content'}</div>
119
+ </Portal>
110
120
 
111
- <Portal target={target2}><div class='test-portal'>{'Portal 2 content'}</div></Portal>
121
+ <Portal target={target2}>
122
+ <div class="test-portal">{'Portal 2 content'}</div>
123
+ </Portal>
112
124
  }
113
125
 
114
126
  render(TestMultiPortal);
@@ -128,11 +140,13 @@ describe('Portal', () => {
128
140
  component TestReactivePortal() {
129
141
  let count = track(0);
130
142
 
131
- <Portal target={document.body}><div class='test-portal'>
132
- {'Count: '}
133
- {String(@count)}
134
- <button onClick={() => @count++}>{'Increment'}</button>
135
- </div></Portal>
143
+ <Portal target={document.body}>
144
+ <div class="test-portal">
145
+ {'Count: '}
146
+ {String(@count)}
147
+ <button onClick={() => @count++}>{'Increment'}</button>
148
+ </div>
149
+ </Portal>
136
150
  }
137
151
 
138
152
  render(TestReactivePortal);
@@ -6,7 +6,13 @@ describe('refs', () => {
6
6
  let div: HTMLDivElement | undefined;
7
7
 
8
8
  component Component() {
9
- <div {ref (node: HTMLDivElement) => { div = node; }}>{'Hello World'}</div>
9
+ <div
10
+ {ref (node: HTMLDivElement) => {
11
+ div = node;
12
+ }}
13
+ >
14
+ {'Hello World'}
15
+ </div>
10
16
  }
11
17
  render(Component);
12
18
  flushSync();
@@ -49,9 +55,9 @@ describe('refs', () => {
49
55
  }
50
56
 
51
57
  const props = {
52
- id: "example",
58
+ id: 'example',
53
59
  @value,
54
- [createRefKey()]: inputRef
60
+ [createRefKey()]: inputRef,
55
61
  };
56
62
 
57
63
  <input type="text" {...props} />