ripple 0.2.208 → 0.2.210

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 (108) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +2 -1
  3. package/package.json +2 -6
  4. package/shims/rollup-estree-types.d.ts +1 -1
  5. package/src/compiler/index.d.ts +1 -0
  6. package/src/compiler/index.js +7 -1
  7. package/src/compiler/phases/1-parse/index.js +15 -6
  8. package/src/compiler/phases/2-analyze/css-analyze.js +100 -104
  9. package/src/compiler/phases/2-analyze/index.js +215 -2
  10. package/src/compiler/phases/3-transform/client/index.js +388 -50
  11. package/src/compiler/phases/3-transform/segments.js +123 -39
  12. package/src/compiler/phases/3-transform/server/index.js +266 -13
  13. package/src/compiler/types/index.d.ts +16 -3
  14. package/src/compiler/utils.js +1 -15
  15. package/src/constants.js +0 -2
  16. package/src/helpers.d.ts +4 -0
  17. package/src/html-tree-validation.js +211 -0
  18. package/src/jsx-runtime.d.ts +260 -259
  19. package/src/jsx-runtime.js +12 -12
  20. package/src/runtime/array.js +17 -17
  21. package/src/runtime/create-subscriber.js +1 -1
  22. package/src/runtime/index-client.js +1 -5
  23. package/src/runtime/index-server.js +15 -0
  24. package/src/runtime/internal/client/compat.js +3 -3
  25. package/src/runtime/internal/client/composite.js +6 -1
  26. package/src/runtime/internal/client/head.js +50 -4
  27. package/src/runtime/internal/client/html.js +73 -12
  28. package/src/runtime/internal/client/hydration.js +12 -0
  29. package/src/runtime/internal/client/index.js +1 -1
  30. package/src/runtime/internal/client/portal.js +54 -29
  31. package/src/runtime/internal/client/rpc.js +3 -1
  32. package/src/runtime/internal/client/switch.js +5 -0
  33. package/src/runtime/internal/client/template.js +117 -11
  34. package/src/runtime/internal/client/try.js +1 -0
  35. package/src/runtime/internal/server/index.js +113 -1
  36. package/src/runtime/internal/server/rpc.js +4 -4
  37. package/src/runtime/map.js +2 -2
  38. package/src/runtime/object.js +6 -6
  39. package/src/runtime/proxy.js +12 -11
  40. package/src/runtime/reactive-value.js +9 -1
  41. package/src/runtime/set.js +12 -7
  42. package/src/runtime/url-search-params.js +0 -1
  43. package/src/server/index.js +4 -0
  44. package/src/utils/hashing.js +15 -0
  45. package/src/utils/normalize_css_property_name.js +1 -1
  46. package/tests/client/array/array.mutations.test.ripple +8 -8
  47. package/tests/client/basic/basic.errors.test.ripple +28 -0
  48. package/tests/client/basic/basic.events.test.ripple +6 -3
  49. package/tests/client/basic/basic.utilities.test.ripple +1 -1
  50. package/tests/client/compiler/compiler.regex.test.ripple +10 -8
  51. package/tests/client/composite/composite.generics.test.ripple +5 -2
  52. package/tests/client/dynamic-elements.test.ripple +30 -1
  53. package/tests/client/function-overload-import.ripple +6 -7
  54. package/tests/client/html.test.ripple +0 -1
  55. package/tests/client/object.test.ripple +2 -2
  56. package/tests/client/portal.test.ripple +3 -3
  57. package/tests/client/return.test.ripple +2500 -0
  58. package/tests/client/try.test.ripple +69 -0
  59. package/tests/client/typescript-generics.test.ripple +1 -1
  60. package/tests/client/url/url.derived.test.ripple +1 -1
  61. package/tests/client/url/url.parsing.test.ripple +3 -3
  62. package/tests/client/url/url.partial-removal.test.ripple +7 -7
  63. package/tests/client/url/url.reactivity.test.ripple +15 -15
  64. package/tests/client/url/url.serialization.test.ripple +2 -2
  65. package/tests/hydration/basic.test.js +23 -0
  66. package/tests/hydration/build-components.js +10 -4
  67. package/tests/hydration/compiled/client/basic.js +165 -3
  68. package/tests/hydration/compiled/client/for.js +1140 -23
  69. package/tests/hydration/compiled/client/head.js +234 -0
  70. package/tests/hydration/compiled/client/html.js +135 -0
  71. package/tests/hydration/compiled/client/portal.js +172 -0
  72. package/tests/hydration/compiled/client/reactivity.js +3 -1
  73. package/tests/hydration/compiled/client/return.js +1976 -0
  74. package/tests/hydration/compiled/client/switch.js +162 -0
  75. package/tests/hydration/compiled/server/basic.js +249 -0
  76. package/tests/hydration/compiled/server/events.js +1 -1
  77. package/tests/hydration/compiled/server/for.js +891 -1
  78. package/tests/hydration/compiled/server/head.js +291 -0
  79. package/tests/hydration/compiled/server/html.js +133 -0
  80. package/tests/hydration/compiled/server/if.js +1 -1
  81. package/tests/hydration/compiled/server/portal.js +250 -0
  82. package/tests/hydration/compiled/server/reactivity.js +1 -1
  83. package/tests/hydration/compiled/server/return.js +1969 -0
  84. package/tests/hydration/compiled/server/switch.js +130 -0
  85. package/tests/hydration/components/basic.ripple +55 -0
  86. package/tests/hydration/components/for.ripple +403 -0
  87. package/tests/hydration/components/head.ripple +111 -0
  88. package/tests/hydration/components/html.ripple +38 -0
  89. package/tests/hydration/components/portal.ripple +49 -0
  90. package/tests/hydration/components/return.ripple +564 -0
  91. package/tests/hydration/components/switch.ripple +51 -0
  92. package/tests/hydration/for.test.js +363 -0
  93. package/tests/hydration/head.test.js +105 -0
  94. package/tests/hydration/html.test.js +46 -0
  95. package/tests/hydration/portal.test.js +71 -0
  96. package/tests/hydration/return.test.js +544 -0
  97. package/tests/hydration/switch.test.js +42 -0
  98. package/tests/server/basic.attributes.test.ripple +1 -1
  99. package/tests/server/compiler.test.ripple +22 -0
  100. package/tests/server/composite.test.ripple +5 -2
  101. package/tests/server/html-nesting-validation.test.ripple +237 -0
  102. package/tests/server/return.test.ripple +1379 -0
  103. package/tests/setup-hydration.js +6 -1
  104. package/tests/utils/escaping.test.js +3 -1
  105. package/tests/utils/normalize_css_property_name.test.js +0 -1
  106. package/tests/utils/patterns.test.js +6 -2
  107. package/tests/utils/sanitize_template_string.test.js +3 -2
  108. package/types/server.d.ts +16 -0
@@ -0,0 +1,69 @@
1
+ import { flushSync, track, TrackedArray } from 'ripple';
2
+
3
+ describe('try block', () => {
4
+ it('does not crash when async component is used inside try/pending', async () => {
5
+ component App() {
6
+ try {
7
+ <AsyncChild />
8
+ } pending {
9
+ <p>{'loading...'}</p>
10
+ }
11
+ }
12
+
13
+ component AsyncChild() {
14
+ let data = await Promise.resolve(['a', 'b', 'c']);
15
+
16
+ <ul>
17
+ for (let item of data) {
18
+ <li>{item}</li>
19
+ }
20
+ </ul>
21
+ }
22
+
23
+ render(App);
24
+
25
+ await new Promise((resolve) => setTimeout(resolve, 0));
26
+ flushSync();
27
+
28
+ const items = container.querySelectorAll('li');
29
+ expect(items.length).toBe(3);
30
+ expect(items[0].textContent).toBe('a');
31
+ expect(items[1].textContent).toBe('b');
32
+ expect(items[2].textContent).toBe('c');
33
+ });
34
+
35
+ it(
36
+ 'does not crash when async component with tracked state is used inside try/pending',
37
+ async () => {
38
+ component App() {
39
+ let query = track('');
40
+
41
+ try {
42
+ <FilteredList {query} />
43
+ } pending {
44
+ <p>{'loading...'}</p>
45
+ }
46
+ }
47
+
48
+ component FilteredList({ query }: { query: any }) {
49
+ let items = await Promise.resolve(['apple', 'banana', 'cherry']);
50
+ let list = TrackedArray.from(items);
51
+ let filtered = track(() => list.filter((item: string) => item.includes(@query)));
52
+
53
+ <ul>
54
+ for (let item of @filtered) {
55
+ <li>{item}</li>
56
+ }
57
+ </ul>
58
+ }
59
+
60
+ render(App);
61
+
62
+ await new Promise((resolve) => setTimeout(resolve, 0));
63
+ flushSync();
64
+
65
+ const listItems = container.querySelectorAll('li');
66
+ expect(listItems.length).toBe(3);
67
+ },
68
+ );
69
+ });
@@ -120,7 +120,7 @@ describe('generic patterns', () => {
120
120
  component App() {
121
121
  function getBuilder() {
122
122
  return <T,>() => ({
123
- build<V,T,U>(): { build: () => V; data: T; key: U } {
123
+ build<V, T, U>(): { build: () => V; data: T; key: U } {
124
124
  return {
125
125
  build(): V {
126
126
  return 'test' as V;
@@ -7,7 +7,7 @@ describe('TrackedURL > derived', () => {
7
7
  let userId = track(() => url.pathname.split('/').pop());
8
8
  let activeTab = track(() => url.searchParams.get('tab'));
9
9
 
10
- <button onClick={() => url.pathname = '/users/456'}>{'Change User'}</button>
10
+ <button onClick={() => (url.pathname = '/users/456')}>{'Change User'}</button>
11
11
  <button onClick={() => url.searchParams.set('tab', 'settings')}>{'Change Tab'}</button>
12
12
  <pre>{`User ID: ${@userId}`}</pre>
13
13
  <pre>{`Active Tab: ${@activeTab}`}</pre>
@@ -85,7 +85,7 @@ describe('TrackedURL > parsing', () => {
85
85
  component URLTest() {
86
86
  const url = new TrackedURL('https://192.168.1.1:8080/path');
87
87
 
88
- <button onClick={() => url.hostname = '10.0.0.1'}>{'Change IP'}</button>
88
+ <button onClick={() => (url.hostname = '10.0.0.1')}>{'Change IP'}</button>
89
89
  <pre>{url.href}</pre>
90
90
  <pre>{url.hostname}</pre>
91
91
  }
@@ -110,7 +110,7 @@ describe('TrackedURL > parsing', () => {
110
110
  component URLTest() {
111
111
  const url = new TrackedURL('http://localhost:3000/api/data');
112
112
 
113
- <button onClick={() => url.port = '8080'}>{'Change Port'}</button>
113
+ <button onClick={() => (url.port = '8080')}>{'Change Port'}</button>
114
114
  <pre>{url.href}</pre>
115
115
  <pre>{url.hostname}</pre>
116
116
  <pre>{url.port}</pre>
@@ -138,7 +138,7 @@ describe('TrackedURL > parsing', () => {
138
138
  component URLTest() {
139
139
  const url = new TrackedURL('https://example.com/api/v1/users/123/profile');
140
140
 
141
- <button onClick={() => url.pathname = '/api/v2/users/456/settings'}>{'Change Path'}</button>
141
+ <button onClick={() => (url.pathname = '/api/v2/users/456/settings')}>{'Change Path'}</button>
142
142
  <pre>{url.pathname}</pre>
143
143
  <pre>{url.href}</pre>
144
144
  }
@@ -7,7 +7,7 @@ describe('TrackedURL > partials/removal', () => {
7
7
 
8
8
  <pre>{url.port}</pre>
9
9
  <pre>{url.host}</pre>
10
- <button onClick={() => url.port = '8080'}>{'Add Port'}</button>
10
+ <button onClick={() => (url.port = '8080')}>{'Add Port'}</button>
11
11
  }
12
12
 
13
13
  render(URLTest);
@@ -56,7 +56,7 @@ describe('TrackedURL > partials/removal', () => {
56
56
  const url = new TrackedURL('https://example.com/path');
57
57
 
58
58
  <pre>{url.hash}</pre>
59
- <button onClick={() => url.hash = '#section'}>{'Add Hash'}</button>
59
+ <button onClick={() => (url.hash = '#section')}>{'Add Hash'}</button>
60
60
  }
61
61
 
62
62
  render(URLTest);
@@ -77,7 +77,7 @@ describe('TrackedURL > partials/removal', () => {
77
77
  component URLTest() {
78
78
  const url = new TrackedURL('https://example.com:8080/path');
79
79
 
80
- <button onClick={() => url.port = ''}>{'Remove Port'}</button>
80
+ <button onClick={() => (url.port = '')}>{'Remove Port'}</button>
81
81
  <pre>{url.href}</pre>
82
82
  <pre>{url.port}</pre>
83
83
  }
@@ -102,7 +102,7 @@ describe('TrackedURL > partials/removal', () => {
102
102
  component URLTest() {
103
103
  const url = new TrackedURL('https://example.com/path#section');
104
104
 
105
- <button onClick={() => url.hash = ''}>{'Remove Hash'}</button>
105
+ <button onClick={() => (url.hash = '')}>{'Remove Hash'}</button>
106
106
  <pre>{url.href}</pre>
107
107
  <pre>{url.hash}</pre>
108
108
  }
@@ -129,7 +129,7 @@ describe('TrackedURL > partials/removal', () => {
129
129
  component URLTest() {
130
130
  const url = new TrackedURL('https://example.com/path?foo=bar');
131
131
 
132
- <button onClick={() => url.search = ''}>{'Remove Search'}</button>
132
+ <button onClick={() => (url.search = '')}>{'Remove Search'}</button>
133
133
  <pre>{url.href}</pre>
134
134
  <pre>{url.search}</pre>
135
135
  <pre>{url.searchParams.size}</pre>
@@ -159,7 +159,7 @@ describe('TrackedURL > partials/removal', () => {
159
159
  component URLTest() {
160
160
  const url = new TrackedURL('https://example.com/path');
161
161
 
162
- <button onClick={() => url.hash = 'section'}>{'Set Hash'}</button>
162
+ <button onClick={() => (url.hash = 'section')}>{'Set Hash'}</button>
163
163
  <pre>{url.hash}</pre>
164
164
  <pre>{url.href}</pre>
165
165
  }
@@ -185,7 +185,7 @@ describe('TrackedURL > partials/removal', () => {
185
185
  component URLTest() {
186
186
  const url = new TrackedURL('https://example.com/path');
187
187
 
188
- <button onClick={() => url.search = 'foo=bar'}>{'Set Search'}</button>
188
+ <button onClick={() => (url.search = 'foo=bar')}>{'Set Search'}</button>
189
189
  <pre>{url.search}</pre>
190
190
  <pre>{url.href}</pre>
191
191
  }
@@ -5,7 +5,7 @@ describe('TrackedURL > reactivity', () => {
5
5
  component URLTest() {
6
6
  const url = new TrackedURL('https://example.com/path');
7
7
 
8
- <button onClick={() => url.protocol = 'http:'}>{'Change Protocol'}</button>
8
+ <button onClick={() => (url.protocol = 'http:')}>{'Change Protocol'}</button>
9
9
  <pre>{url.href}</pre>
10
10
  <pre>{url.protocol}</pre>
11
11
  <pre>{url.origin}</pre>
@@ -33,7 +33,7 @@ describe('TrackedURL > reactivity', () => {
33
33
  component URLTest() {
34
34
  const url = new TrackedURL('https://example.com/path');
35
35
 
36
- <button onClick={() => url.hostname = 'newdomain.com'}>{'Change Hostname'}</button>
36
+ <button onClick={() => (url.hostname = 'newdomain.com')}>{'Change Hostname'}</button>
37
37
  <pre>{url.href}</pre>
38
38
  <pre>{url.hostname}</pre>
39
39
  <pre>{url.host}</pre>
@@ -61,7 +61,7 @@ describe('TrackedURL > reactivity', () => {
61
61
  component URLTest() {
62
62
  const url = new TrackedURL('https://example.com:8080/path');
63
63
 
64
- <button onClick={() => url.port = '9090'}>{'Change Port'}</button>
64
+ <button onClick={() => (url.port = '9090')}>{'Change Port'}</button>
65
65
  <pre>{url.href}</pre>
66
66
  <pre>{url.port}</pre>
67
67
  <pre>{url.host}</pre>
@@ -89,7 +89,7 @@ describe('TrackedURL > reactivity', () => {
89
89
  component URLTest() {
90
90
  const url = new TrackedURL('https://example.com:8080/path');
91
91
 
92
- <button onClick={() => url.host = 'newdomain.com:9090'}>{'Change Host'}</button>
92
+ <button onClick={() => (url.host = 'newdomain.com:9090')}>{'Change Host'}</button>
93
93
  <pre>{url.href}</pre>
94
94
  <pre>{url.host}</pre>
95
95
  <pre>{url.hostname}</pre>
@@ -122,7 +122,7 @@ describe('TrackedURL > reactivity', () => {
122
122
  component URLTest() {
123
123
  const url = new TrackedURL('https://example.com/old-path');
124
124
 
125
- <button onClick={() => url.pathname = '/new-path'}>{'Change Pathname'}</button>
125
+ <button onClick={() => (url.pathname = '/new-path')}>{'Change Pathname'}</button>
126
126
  <pre>{url.href}</pre>
127
127
  <pre>{url.pathname}</pre>
128
128
  }
@@ -147,7 +147,7 @@ describe('TrackedURL > reactivity', () => {
147
147
  component URLTest() {
148
148
  const url = new TrackedURL('https://example.com/path?foo=bar');
149
149
 
150
- <button onClick={() => url.search = '?baz=qux'}>{'Change Search'}</button>
150
+ <button onClick={() => (url.search = '?baz=qux')}>{'Change Search'}</button>
151
151
  <pre>{url.href}</pre>
152
152
  <pre>{url.search}</pre>
153
153
  }
@@ -176,7 +176,7 @@ describe('TrackedURL > reactivity', () => {
176
176
  component URLTest() {
177
177
  const url = new TrackedURL('https://example.com/path#section1');
178
178
 
179
- <button onClick={() => url.hash = '#section2'}>{'Change Hash'}</button>
179
+ <button onClick={() => (url.hash = '#section2')}>{'Change Hash'}</button>
180
180
  <pre>{url.href}</pre>
181
181
  <pre>{url.hash}</pre>
182
182
  }
@@ -205,7 +205,7 @@ describe('TrackedURL > reactivity', () => {
205
205
  component URLTest() {
206
206
  const url = new TrackedURL('https://user:pass@example.com/path');
207
207
 
208
- <button onClick={() => url.username = 'newuser'}>{'Change Username'}</button>
208
+ <button onClick={() => (url.username = 'newuser')}>{'Change Username'}</button>
209
209
  <pre>{url.href}</pre>
210
210
  <pre>{url.username}</pre>
211
211
  }
@@ -234,7 +234,7 @@ describe('TrackedURL > reactivity', () => {
234
234
  component URLTest() {
235
235
  const url = new TrackedURL('https://user:pass@example.com/path');
236
236
 
237
- <button onClick={() => url.password = 'newpass'}>{'Change Password'}</button>
237
+ <button onClick={() => (url.password = 'newpass')}>{'Change Password'}</button>
238
238
  <pre>{url.href}</pre>
239
239
  <pre>{url.password}</pre>
240
240
  }
@@ -263,7 +263,7 @@ describe('TrackedURL > reactivity', () => {
263
263
  component URLTest() {
264
264
  const url = new TrackedURL('https://example.com/path?foo=bar#section');
265
265
 
266
- <button onClick={() => url.href = 'https://newdomain.com:9090/newpath?baz=qux#newsection'}>
266
+ <button onClick={() => (url.href = 'https://newdomain.com:9090/newpath?baz=qux#newsection')}>
267
267
  {'Change Href'}
268
268
  </button>
269
269
  <pre>{url.href}</pre>
@@ -309,9 +309,9 @@ describe('TrackedURL > reactivity', () => {
309
309
  component URLTest() {
310
310
  const url = new TrackedURL('https://example.com:8080/path');
311
311
 
312
- <button onClick={() => url.protocol = 'http:'}>{'Change Protocol'}</button>
313
- <button onClick={() => url.hostname = 'newdomain.com'}>{'Change Hostname'}</button>
314
- <button onClick={() => url.port = '9090'}>{'Change Port'}</button>
312
+ <button onClick={() => (url.protocol = 'http:')}>{'Change Protocol'}</button>
313
+ <button onClick={() => (url.hostname = 'newdomain.com')}>{'Change Hostname'}</button>
314
+ <button onClick={() => (url.port = '9090')}>{'Change Port'}</button>
315
315
  <pre>{url.origin}</pre>
316
316
  }
317
317
 
@@ -386,7 +386,7 @@ describe('TrackedURL > reactivity', () => {
386
386
  const url = new TrackedURL('https://example.com/path?foo=bar');
387
387
  const params = url.searchParams;
388
388
 
389
- <button onClick={() => url.search = '?baz=qux&test=value'}>{'Change Search'}</button>
389
+ <button onClick={() => (url.search = '?baz=qux&test=value')}>{'Change Search'}</button>
390
390
  <pre>{url.search}</pre>
391
391
  <pre>{params.get('foo')}</pre>
392
392
  <pre>{params.get('baz')}</pre>
@@ -456,7 +456,7 @@ describe('TrackedURL > reactivity', () => {
456
456
  const url = new TrackedURL('https://old.com/old?foo=bar#old');
457
457
  const params = url.searchParams;
458
458
 
459
- <button onClick={() => url.href = 'https://new.com:9090/new?baz=qux#new'}>
459
+ <button onClick={() => (url.href = 'https://new.com:9090/new?baz=qux#new')}>
460
460
  {'Change Href'}
461
461
  </button>
462
462
  <pre>{params.get('foo')}</pre>
@@ -5,7 +5,7 @@ describe('TrackedURL > serialization', () => {
5
5
  component URLTest() {
6
6
  const url = new TrackedURL('https://example.com/path?foo=bar#section');
7
7
 
8
- <button onClick={() => url.pathname = '/newpath'}>{'Change Pathname'}</button>
8
+ <button onClick={() => (url.pathname = '/newpath')}>{'Change Pathname'}</button>
9
9
  <pre>{url.toString()}</pre>
10
10
  }
11
11
 
@@ -31,7 +31,7 @@ describe('TrackedURL > serialization', () => {
31
31
  component URLTest() {
32
32
  const url = new TrackedURL('https://example.com/path?foo=bar');
33
33
 
34
- <button onClick={() => url.pathname = '/api'}>{'Change Pathname'}</button>
34
+ <button onClick={() => (url.pathname = '/api')}>{'Change Pathname'}</button>
35
35
  <pre>{url.toJSON()}</pre>
36
36
  <pre>{JSON.stringify({ url: url.toJSON() })}</pre>
37
37
  }
@@ -58,4 +58,27 @@ describe('hydration > basic', () => {
58
58
  await hydrateComponent(ServerComponents.ExpressionContent, ClientComponents.ExpressionContent);
59
59
  expect(container.innerHTML).toBeHtml('<div>42</div><span>COMPUTED</span>');
60
60
  });
61
+
62
+ it('hydrates static child component followed by sibling content', async () => {
63
+ await hydrateComponent(
64
+ ServerComponents.StaticChildWithSiblings,
65
+ ClientComponents.StaticChildWithSiblings,
66
+ );
67
+ expect(container.querySelector('.sr-only')?.textContent).toBe('heading');
68
+ expect(container.querySelectorAll('.subtitle').length).toBe(2);
69
+ expect(container.querySelector('.sibling1')?.textContent).toBe('bar');
70
+ expect(container.querySelector('.sibling2')?.textContent).toBe('bar');
71
+ });
72
+
73
+ it('hydrates website-like component structure', async () => {
74
+ await hydrateComponent(ServerComponents.WebsiteIndex, ClientComponents.WebsiteIndex);
75
+ expect(container.querySelector('.sr-only')?.textContent).toBe('Ripple');
76
+ expect(container.querySelector('.logo')).toBeTruthy();
77
+ expect(container.querySelector('.subtitle')?.textContent).toBe(
78
+ 'the elegant TypeScript UI framework',
79
+ );
80
+ expect(container.querySelectorAll('.social-links').length).toBe(2);
81
+ expect(container.querySelector('.playground-link')?.textContent).toBe('Playground');
82
+ expect(container.querySelector('.content')).toBeTruthy();
83
+ });
61
84
  });
@@ -20,18 +20,24 @@ const serverOutDir = join(__dirname, 'compiled', 'server');
20
20
  /**
21
21
  * Transform server-compiled code to use server runtime imports.
22
22
  * This is necessary because vitest runs with browser conditions, but
23
- * server-compiled code needs server's track() which has different internals.
23
+ * server-compiled code needs server's track() and Portal which have different internals.
24
24
  * @param {string} code - The compiled server code
25
25
  * @returns {string} - Transformed code with server-compatible imports
26
26
  */
27
27
  function transformServerImports(code) {
28
28
  // Replace `import { track } from 'ripple'` with server version
29
- // Use 'ripple/ssr' which always points to the server runtime,
29
+ // Replace `import { Portal } from 'ripple'` with server version
30
+ // Use 'ripple/server' which always points to the server runtime,
30
31
  // bypassing the browser/default condition resolution
31
- return code.replace(
32
+ let transformed = code.replace(
32
33
  /import\s*\{\s*track\s*\}\s*from\s*['"]ripple['"]/g,
33
- "import { track } from 'ripple/ssr'",
34
+ "import { track } from 'ripple/server'",
34
35
  );
36
+ transformed = transformed.replace(
37
+ /import\s*\{\s*Portal\s*\}\s*from\s*['"]ripple['"]/g,
38
+ "import { Portal } from 'ripple/server'",
39
+ );
40
+ return transformed;
35
41
  }
36
42
 
37
43
  function buildComponents() {
@@ -12,6 +12,15 @@ var root_8 = _$_.template(`<!><!>`, 1);
12
12
  var root_9 = _$_.template(`<div> </div>`, 0);
13
13
  var root_10 = _$_.template(`<!>`, 1);
14
14
  var root_11 = _$_.template(`<div> </div><span> </span>`, 1);
15
+ var root_12 = _$_.template(`<h1 class="sr-only">heading</h1><p class="subtitle">first paragraph</p><p class="subtitle">second paragraph</p>`, 1);
16
+ var root_13 = _$_.template(`<!><span class="sibling1"> </span><span class="sibling2"> </span>`, 1);
17
+ var root_14 = _$_.template(`<h1 class="sr-only">Ripple</h1><img src="/images/logo.png" alt="Logo" class="logo"><p class="subtitle">the elegant TypeScript UI framework</p>`, 1);
18
+ var root_16 = _$_.template(`<a href="/playground" class="playground-link">Playground</a>`, 0);
19
+ var root_15 = _$_.template(`<div class="social-links"><a href="https://github.com" class="github-link">GitHub</a><a href="https://discord.com" class="discord-link">Discord</a><!></div>`, 0);
20
+ var root_17 = _$_.template(`<main><div class="container"><!></div></main>`, 0);
21
+ var root_18 = _$_.template(`<div class="content"><p>Some content here</p></div>`, 0);
22
+ var root_20 = _$_.template(`<!><!><!><!>`, 1);
23
+ var root_19 = _$_.template(`<!>`, 1);
15
24
 
16
25
  export function StaticText(__anchor, _, __block) {
17
26
  _$_.push_component();
@@ -27,7 +36,8 @@ export function MultipleElements(__anchor, _, __block) {
27
36
 
28
37
  var fragment = root_1();
29
38
 
30
- _$_.append(__anchor, fragment);
39
+ _$_.next(2);
40
+ _$_.append(__anchor, fragment, true);
31
41
  _$_.pop_component();
32
42
  }
33
43
 
@@ -45,7 +55,8 @@ export function WithAttributes(__anchor, _, __block) {
45
55
 
46
56
  var fragment_1 = root_3();
47
57
 
48
- _$_.append(__anchor, fragment_1);
58
+ _$_.next();
59
+ _$_.append(__anchor, fragment_1, true);
49
60
  _$_.pop_component();
50
61
  }
51
62
 
@@ -160,10 +171,161 @@ export function ExpressionContent(__anchor, _, __block) {
160
171
  _$_.pop(span_2);
161
172
  }
162
173
 
174
+ _$_.next();
175
+
163
176
  _$_.render(() => {
164
177
  _$_.set_text(text_3, _$_.with_scope(__block, () => text.toUpperCase()));
165
178
  });
166
179
 
167
- _$_.append(__anchor, fragment_4);
180
+ _$_.append(__anchor, fragment_4, true);
181
+ _$_.pop_component();
182
+ }
183
+
184
+ function StaticHeader(__anchor, _, __block) {
185
+ _$_.push_component();
186
+
187
+ var fragment_5 = root_12();
188
+
189
+ _$_.next(2);
190
+ _$_.append(__anchor, fragment_5, true);
191
+ _$_.pop_component();
192
+ }
193
+
194
+ export function StaticChildWithSiblings(__anchor, _, __block) {
195
+ _$_.push_component();
196
+
197
+ const foo = 'bar';
198
+ var fragment_6 = root_13();
199
+ var node_4 = _$_.first_child_frag(fragment_6);
200
+
201
+ StaticHeader(node_4, {}, _$_.active_block);
202
+
203
+ var span_3 = _$_.sibling(node_4);
204
+
205
+ {
206
+ var text_4 = _$_.child(span_3, true);
207
+
208
+ text_4.nodeValue = foo;
209
+ _$_.pop(span_3);
210
+ }
211
+
212
+ var span_4 = _$_.sibling(span_3);
213
+
214
+ {
215
+ var text_5 = _$_.child(span_4, true);
216
+
217
+ text_5.nodeValue = foo;
218
+ _$_.pop(span_4);
219
+ }
220
+
221
+ _$_.next();
222
+ _$_.append(__anchor, fragment_6, true);
223
+ _$_.pop_component();
224
+ }
225
+
226
+ function Header(__anchor, _, __block) {
227
+ _$_.push_component();
228
+
229
+ var fragment_7 = root_14();
230
+
231
+ _$_.next(2);
232
+ _$_.append(__anchor, fragment_7, true);
233
+ _$_.pop_component();
234
+ }
235
+
236
+ function Actions(__anchor, __props, __block) {
237
+ _$_.push_component();
238
+
239
+ var div_8 = root_15();
240
+
241
+ {
242
+ var a_2 = _$_.child(div_8);
243
+ var a_1 = _$_.sibling(a_2);
244
+ var node_5 = _$_.sibling(a_1);
245
+
246
+ {
247
+ var consequent = (__anchor) => {
248
+ var a_3 = root_16();
249
+
250
+ _$_.append(__anchor, a_3);
251
+ };
252
+
253
+ _$_.if(node_5, (__render) => {
254
+ if (_$_.get(_$_.fallback(__props.playgroundVisible, false))) __render(consequent);
255
+ });
256
+ }
257
+
258
+ _$_.pop(div_8);
259
+ }
260
+
261
+ _$_.append(__anchor, div_8);
262
+ _$_.pop_component();
263
+ }
264
+
265
+ function Layout(__anchor, __props, __block) {
266
+ _$_.push_component();
267
+
268
+ var main_1 = root_17();
269
+
270
+ {
271
+ var div_9 = _$_.child(main_1);
272
+
273
+ {
274
+ var node_6 = _$_.child(div_9);
275
+
276
+ _$_.composite(() => __props.children, node_6, {});
277
+ _$_.pop(div_9);
278
+ }
279
+ }
280
+
281
+ _$_.append(__anchor, main_1);
282
+ _$_.pop_component();
283
+ }
284
+
285
+ function Content(__anchor, _, __block) {
286
+ _$_.push_component();
287
+
288
+ var div_10 = root_18();
289
+
290
+ _$_.append(__anchor, div_10);
291
+ _$_.pop_component();
292
+ }
293
+
294
+ export function WebsiteIndex(__anchor, _, __block) {
295
+ _$_.push_component();
296
+
297
+ var fragment_8 = root_19();
298
+ var node_7 = _$_.first_child_frag(fragment_8);
299
+
300
+ Layout(
301
+ node_7,
302
+ {
303
+ children(__anchor, _, __block) {
304
+ _$_.push_component();
305
+
306
+ var fragment_9 = root_20();
307
+ var node_8 = _$_.first_child_frag(fragment_9);
308
+
309
+ Header(node_8, {}, _$_.active_block);
310
+
311
+ var node_9 = _$_.sibling(node_8);
312
+
313
+ Actions(node_9, { playgroundVisible: true }, _$_.active_block);
314
+
315
+ var node_10 = _$_.sibling(node_9);
316
+
317
+ Content(node_10, {}, _$_.active_block);
318
+
319
+ var node_11 = _$_.sibling(node_10);
320
+
321
+ Actions(node_11, { playgroundVisible: false }, _$_.active_block);
322
+ _$_.append(__anchor, fragment_9);
323
+ _$_.pop_component();
324
+ }
325
+ },
326
+ _$_.active_block
327
+ );
328
+
329
+ _$_.append(__anchor, fragment_8);
168
330
  _$_.pop_component();
169
331
  }