ripple 0.3.3 → 0.3.5
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 +90 -0
- package/package.json +2 -2
- package/src/compiler/identifier-utils.js +1 -8
- package/src/compiler/phases/1-parse/index.js +101 -195
- package/src/compiler/phases/2-analyze/index.js +115 -174
- package/src/compiler/phases/2-analyze/prune.js +2 -2
- package/src/compiler/phases/3-transform/client/index.js +177 -261
- package/src/compiler/phases/3-transform/server/index.js +185 -42
- package/src/compiler/types/index.d.ts +15 -34
- package/src/compiler/utils.js +32 -20
- package/src/runtime/index-client.js +0 -17
- package/src/runtime/internal/client/bindings.js +118 -7
- package/src/runtime/internal/client/render.js +5 -1
- package/src/runtime/internal/client/runtime.js +1 -1
- package/src/runtime/internal/client/types.d.ts +4 -0
- package/src/runtime/internal/server/index.js +11 -0
- package/tests/client/array/array.copy-within.test.ripple +7 -7
- package/tests/client/array/array.derived.test.ripple +24 -24
- package/tests/client/array/array.iteration.test.ripple +7 -7
- package/tests/client/array/array.mutations.test.ripple +17 -17
- package/tests/client/array/array.to-methods.test.ripple +4 -4
- package/tests/client/async-suspend.test.ripple +3 -3
- package/tests/client/basic/basic.attributes.test.ripple +31 -31
- package/tests/client/basic/basic.collections.test.ripple +6 -6
- package/tests/client/basic/basic.components.test.ripple +8 -8
- package/tests/client/basic/basic.errors.test.ripple +31 -34
- package/tests/client/basic/basic.events.test.ripple +11 -11
- package/tests/client/basic/basic.get-set.test.ripple +18 -18
- package/tests/client/basic/basic.reactivity.test.ripple +36 -36
- package/tests/client/basic/basic.rendering.test.ripple +7 -7
- package/tests/client/basic/basic.utilities.test.ripple +4 -4
- package/tests/client/boundaries.test.ripple +7 -7
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +24 -0
- package/tests/client/compiler/compiler.assignments.test.ripple +12 -10
- package/tests/client/compiler/compiler.basic.test.ripple +57 -58
- package/tests/client/compiler/compiler.tracked-access.test.ripple +14 -8
- package/tests/client/compiler/compiler.typescript.test.ripple +31 -0
- package/tests/client/composite/composite.dynamic-components.test.ripple +6 -6
- package/tests/client/composite/composite.props.test.ripple +9 -9
- package/tests/client/composite/composite.reactivity.test.ripple +23 -23
- package/tests/client/composite/composite.render.test.ripple +52 -4
- package/tests/client/computed-properties.test.ripple +3 -3
- package/tests/client/context.test.ripple +3 -3
- package/tests/client/css/global-additional-cases.test.ripple +5 -2
- package/tests/client/css/style-identifier.test.ripple +40 -49
- package/tests/client/date.test.ripple +39 -39
- package/tests/client/dynamic-elements.test.ripple +37 -37
- package/tests/client/events.test.ripple +25 -25
- package/tests/client/for.test.ripple +8 -8
- package/tests/client/head.test.ripple +7 -7
- package/tests/client/html.test.ripple +2 -2
- package/tests/client/input-value.test.ripple +376 -177
- package/tests/client/lazy-destructuring.test.ripple +209 -0
- package/tests/client/map.test.ripple +20 -20
- package/tests/client/media-query.test.ripple +4 -4
- package/tests/client/object.test.ripple +5 -5
- package/tests/client/portal.test.ripple +4 -4
- package/tests/client/ref.test.ripple +3 -3
- package/tests/client/return.test.ripple +17 -17
- package/tests/client/set.test.ripple +10 -10
- package/tests/client/svg.test.ripple +6 -5
- package/tests/client/switch.test.ripple +10 -10
- package/tests/client/tracked-expression.test.ripple +3 -1
- package/tests/client/try.test.ripple +4 -4
- package/tests/client/url/url.derived.test.ripple +6 -7
- package/tests/client/url/url.parsing.test.ripple +9 -9
- package/tests/client/url/url.partial-removal.test.ripple +9 -9
- package/tests/client/url/url.reactivity.test.ripple +16 -16
- package/tests/client/url/url.serialization.test.ripple +3 -3
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +7 -8
- package/tests/client/url-search-params/url-search-params.initialization.test.ripple +6 -4
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +12 -12
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +18 -18
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +16 -16
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +4 -4
- package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +3 -3
- package/tests/hydration/build-components.js +4 -10
- package/tests/hydration/compiled/client/basic.js +4 -4
- package/tests/hydration/compiled/client/events.js +2 -0
- package/tests/hydration/compiled/client/for.js +2 -0
- package/tests/hydration/compiled/client/head.js +13 -11
- package/tests/hydration/compiled/client/hmr.js +4 -2
- package/tests/hydration/compiled/client/html.js +82 -95
- package/tests/hydration/compiled/client/if-children.js +8 -9
- package/tests/hydration/compiled/client/if.js +2 -0
- package/tests/hydration/compiled/client/mixed-control-flow.js +4 -2
- package/tests/hydration/compiled/client/portal.js +1 -1
- package/tests/hydration/compiled/client/reactivity.js +2 -0
- package/tests/hydration/compiled/client/return.js +2 -0
- package/tests/hydration/compiled/client/switch.js +2 -0
- package/tests/hydration/compiled/server/composite.js +2 -2
- package/tests/hydration/compiled/server/events.js +2 -0
- package/tests/hydration/compiled/server/for.js +2 -0
- package/tests/hydration/compiled/server/head.js +13 -11
- package/tests/hydration/compiled/server/hmr.js +2 -0
- package/tests/hydration/compiled/server/html.js +2 -0
- package/tests/hydration/compiled/server/if-children.js +2 -0
- package/tests/hydration/compiled/server/if.js +2 -0
- package/tests/hydration/compiled/server/mixed-control-flow.js +2 -0
- package/tests/hydration/compiled/server/portal.js +1 -1
- package/tests/hydration/compiled/server/reactivity.js +2 -0
- package/tests/hydration/compiled/server/return.js +2 -0
- package/tests/hydration/compiled/server/switch.js +2 -0
- package/tests/hydration/components/composite.ripple +1 -1
- package/tests/hydration/components/events.ripple +10 -8
- package/tests/hydration/components/for.ripple +22 -20
- package/tests/hydration/components/head.ripple +8 -6
- package/tests/hydration/components/hmr.ripple +3 -1
- package/tests/hydration/components/html.ripple +3 -1
- package/tests/hydration/components/if-children.ripple +9 -7
- package/tests/hydration/components/if.ripple +7 -5
- package/tests/hydration/components/mixed-control-flow.ripple +5 -3
- package/tests/hydration/components/portal.ripple +2 -2
- package/tests/hydration/components/reactivity.ripple +11 -9
- package/tests/hydration/components/return.ripple +13 -11
- package/tests/hydration/components/switch.ripple +6 -4
- package/tests/server/__snapshots__/compiler.test.ripple.snap +22 -0
- package/tests/server/await.test.ripple +2 -2
- package/tests/server/basic.attributes.test.ripple +21 -19
- package/tests/server/basic.components.test.ripple +5 -4
- package/tests/server/basic.test.ripple +21 -20
- package/tests/server/compiler.test.ripple +36 -5
- package/tests/server/composite.props.test.ripple +7 -6
- package/tests/server/context.test.ripple +3 -1
- package/tests/server/dynamic-elements.test.ripple +24 -24
- package/tests/server/head.test.ripple +7 -5
- package/tests/server/lazy-destructuring.test.ripple +103 -0
- package/tests/server/style-identifier.test.ripple +95 -16
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { PropsWithExtras } from 'ripple';
|
|
2
|
-
import { createRefKey } from 'ripple';
|
|
2
|
+
import { createRefKey, track, trackSplit } from 'ripple';
|
|
3
3
|
|
|
4
4
|
describe('server dynamic DOM elements', () => {
|
|
5
5
|
it('renders static dynamic element', async () => {
|
|
6
6
|
component App() {
|
|
7
|
-
let tag =
|
|
7
|
+
let tag = track('div');
|
|
8
8
|
|
|
9
9
|
<@tag>{'Hello World'}</@tag>
|
|
10
10
|
}
|
|
@@ -18,7 +18,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
18
18
|
// They can be ignored for now. But we'll fix them via jsx() vs <jsx>
|
|
19
19
|
it('renders static dynamic element from a plain object with a tracked property', async () => {
|
|
20
20
|
component App() {
|
|
21
|
-
let obj = { tag:
|
|
21
|
+
let obj = { tag: track('div') };
|
|
22
22
|
|
|
23
23
|
<obj.@tag>{'Hello World'}</obj.@tag>
|
|
24
24
|
}
|
|
@@ -30,7 +30,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
30
30
|
|
|
31
31
|
it('renders static dynamic element from a tracked object with a tracked property', async () => {
|
|
32
32
|
component App() {
|
|
33
|
-
let obj =
|
|
33
|
+
let obj = track({ tag: track('div') });
|
|
34
34
|
|
|
35
35
|
<@obj.@tag>{'Hello World'}</@obj.@tag>
|
|
36
36
|
}
|
|
@@ -44,7 +44,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
44
44
|
'renders static dynamic element from a tracked object with a computed tracked property',
|
|
45
45
|
async () => {
|
|
46
46
|
component App() {
|
|
47
|
-
let obj =
|
|
47
|
+
let obj = track({ tag: track('div') });
|
|
48
48
|
|
|
49
49
|
<@obj.@['tag']>{'Hello World'}</@obj.@['tag']>
|
|
50
50
|
}
|
|
@@ -57,7 +57,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
57
57
|
|
|
58
58
|
it('renders self-closing dynamic element', async () => {
|
|
59
59
|
component App() {
|
|
60
|
-
let tag =
|
|
60
|
+
let tag = track('input');
|
|
61
61
|
|
|
62
62
|
<@tag type="text" value="test" />
|
|
63
63
|
}
|
|
@@ -69,8 +69,8 @@ describe('server dynamic DOM elements', () => {
|
|
|
69
69
|
|
|
70
70
|
it('handles dynamic element with attributes', async () => {
|
|
71
71
|
component App() {
|
|
72
|
-
let tag =
|
|
73
|
-
let className =
|
|
72
|
+
let tag = track('div');
|
|
73
|
+
let className = track('test-class');
|
|
74
74
|
|
|
75
75
|
<@tag class={@className} id="test" data-testid="dynamic-element">{'Content'}</@tag>
|
|
76
76
|
}
|
|
@@ -87,8 +87,8 @@ describe('server dynamic DOM elements', () => {
|
|
|
87
87
|
|
|
88
88
|
it('handles nested dynamic elements', async () => {
|
|
89
89
|
component App() {
|
|
90
|
-
let outerTag =
|
|
91
|
-
let innerTag =
|
|
90
|
+
let outerTag = track('div');
|
|
91
|
+
let innerTag = track('span');
|
|
92
92
|
|
|
93
93
|
<@outerTag class="outer">
|
|
94
94
|
<@innerTag class="inner">{'Nested content'}</@innerTag>
|
|
@@ -108,8 +108,8 @@ describe('server dynamic DOM elements', () => {
|
|
|
108
108
|
|
|
109
109
|
it('handles dynamic element with class object', async () => {
|
|
110
110
|
component App() {
|
|
111
|
-
let tag =
|
|
112
|
-
let active =
|
|
111
|
+
let tag = track('div');
|
|
112
|
+
let active = track(true);
|
|
113
113
|
|
|
114
114
|
<@tag class={{ active: @active, 'dynamic-element': true }}>
|
|
115
115
|
{'Element with class object'}
|
|
@@ -127,7 +127,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
127
127
|
|
|
128
128
|
it('handles dynamic element with style object', async () => {
|
|
129
129
|
component App() {
|
|
130
|
-
let tag =
|
|
130
|
+
let tag = track('span');
|
|
131
131
|
|
|
132
132
|
<@tag
|
|
133
133
|
style={{
|
|
@@ -152,7 +152,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
152
152
|
|
|
153
153
|
it('handles dynamic element with spread attributes', async () => {
|
|
154
154
|
component App() {
|
|
155
|
-
let tag =
|
|
155
|
+
let tag = track('section');
|
|
156
156
|
const attrs = {
|
|
157
157
|
id: 'spread-section',
|
|
158
158
|
'data-testid': 'spread-test',
|
|
@@ -176,7 +176,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
176
176
|
let capturedElement: HTMLElement | null = null;
|
|
177
177
|
|
|
178
178
|
component App() {
|
|
179
|
-
let tag =
|
|
179
|
+
let tag = track('article');
|
|
180
180
|
|
|
181
181
|
<@tag
|
|
182
182
|
{ref (node: HTMLElement) => {
|
|
@@ -202,7 +202,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
202
202
|
|
|
203
203
|
it('handles dynamic element with createRefKey in spread', async () => {
|
|
204
204
|
component App() {
|
|
205
|
-
let tag =
|
|
205
|
+
let tag = track('header');
|
|
206
206
|
|
|
207
207
|
function elementRef(node: HTMLElement) {
|
|
208
208
|
// Set an attribute on the element to prove ref was called
|
|
@@ -233,7 +233,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
233
233
|
|
|
234
234
|
it('applies scoped CSS to dynamic elements', async () => {
|
|
235
235
|
component App() {
|
|
236
|
-
let tag =
|
|
236
|
+
let tag = track('div');
|
|
237
237
|
|
|
238
238
|
<@tag class="test-class">{'Dynamic element'}</@tag>
|
|
239
239
|
|
|
@@ -261,8 +261,8 @@ describe('server dynamic DOM elements', () => {
|
|
|
261
261
|
class: string;
|
|
262
262
|
id: string;
|
|
263
263
|
}>) {
|
|
264
|
-
const tag =
|
|
265
|
-
const [rest] =
|
|
264
|
+
const tag = track('button');
|
|
265
|
+
const [rest] = trackSplit(props, []);
|
|
266
266
|
<@tag {...@rest}>{@rest.class}</@tag>
|
|
267
267
|
|
|
268
268
|
<style>
|
|
@@ -276,7 +276,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
component App() {
|
|
279
|
-
const count =
|
|
279
|
+
const count = track(0);
|
|
280
280
|
<DynamicButton class={@count % 2 ? 'even' : 'odd'} id={@count % 2 ? 'even' : 'odd'} />
|
|
281
281
|
}
|
|
282
282
|
|
|
@@ -298,7 +298,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
298
298
|
|
|
299
299
|
it('adds scoping class to dynamic elements', async () => {
|
|
300
300
|
component App() {
|
|
301
|
-
let tag =
|
|
301
|
+
let tag = track('div');
|
|
302
302
|
|
|
303
303
|
<@tag class="scoped">
|
|
304
304
|
<p>{'Scoped dynamic element'}</p>
|
|
@@ -327,7 +327,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
327
327
|
// NOTE: We always add the class scoping hash if there is css
|
|
328
328
|
// but the tag selector will be marked as unused if it's not explicitly seen in the template.
|
|
329
329
|
component App() {
|
|
330
|
-
let tag =
|
|
330
|
+
let tag = track('div');
|
|
331
331
|
|
|
332
332
|
<@tag class="scoped">
|
|
333
333
|
<p>{'Scoped dynamic element'}</p>
|
|
@@ -365,7 +365,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
component App() {
|
|
368
|
-
let tag =
|
|
368
|
+
let tag = track('div');
|
|
369
369
|
|
|
370
370
|
<@tag class="scoped">
|
|
371
371
|
<p>{'Scoped dynamic element'}</p>
|
|
@@ -412,7 +412,7 @@ describe('server dynamic DOM elements', () => {
|
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
component App() {
|
|
415
|
-
let tag =
|
|
415
|
+
let tag = track(() => Child);
|
|
416
416
|
|
|
417
417
|
<@tag />
|
|
418
418
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
2
|
+
|
|
1
3
|
describe('head elements', () => {
|
|
2
4
|
it('renders static title element', async () => {
|
|
3
5
|
component App() {
|
|
@@ -17,7 +19,7 @@ describe('head elements', () => {
|
|
|
17
19
|
|
|
18
20
|
it('renders reactive title element', async () => {
|
|
19
21
|
component App() {
|
|
20
|
-
let title =
|
|
22
|
+
let title = track('Initial Title');
|
|
21
23
|
|
|
22
24
|
<head>
|
|
23
25
|
<title>{@title}</title>
|
|
@@ -36,7 +38,7 @@ describe('head elements', () => {
|
|
|
36
38
|
|
|
37
39
|
it('renders title with template literal', async () => {
|
|
38
40
|
component App() {
|
|
39
|
-
let name =
|
|
41
|
+
let name = track('World');
|
|
40
42
|
|
|
41
43
|
<head>
|
|
42
44
|
<title>{`Hello ${@name}!`}</title>
|
|
@@ -51,7 +53,7 @@ describe('head elements', () => {
|
|
|
51
53
|
|
|
52
54
|
it('renders title with computed value', async () => {
|
|
53
55
|
component App() {
|
|
54
|
-
let count =
|
|
56
|
+
let count = track(0);
|
|
55
57
|
let prefix = 'Count: ';
|
|
56
58
|
|
|
57
59
|
<head>
|
|
@@ -84,8 +86,8 @@ describe('head elements', () => {
|
|
|
84
86
|
|
|
85
87
|
it('renders title with conditional content', async () => {
|
|
86
88
|
component App() {
|
|
87
|
-
let showPrefix =
|
|
88
|
-
let title =
|
|
89
|
+
let showPrefix = track(true);
|
|
90
|
+
let title = track('Main Page');
|
|
89
91
|
|
|
90
92
|
<head>
|
|
91
93
|
<title>{@showPrefix ? 'App - ' + @title : @title}</title>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
describe('lazy destructuring', () => {
|
|
2
|
+
it('lazily accesses object properties', async () => {
|
|
3
|
+
component Inner(&{ a, b }: { a: number; b: string }) {
|
|
4
|
+
<pre>{`${a}-${b}`}</pre>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
component Test() {
|
|
8
|
+
<Inner a={1} b="hello" />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { body } = await render(Test);
|
|
12
|
+
expect(body).toBeHtml('<pre>1-hello</pre>');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('supports default values in lazy object destructuring', async () => {
|
|
16
|
+
component Test() {
|
|
17
|
+
const obj = { a: 5 };
|
|
18
|
+
const &{ a, b = 99 } = obj;
|
|
19
|
+
<pre>{`${a}-${b}`}</pre>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { body } = await render(Test);
|
|
23
|
+
expect(body).toBeHtml('<pre>5-99</pre>');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('supports let lazy destructuring with assignment writeback', async () => {
|
|
27
|
+
component Test() {
|
|
28
|
+
const obj = { a: 1, b: 2 };
|
|
29
|
+
let &{ a, b } = obj;
|
|
30
|
+
a = 10;
|
|
31
|
+
b = 20;
|
|
32
|
+
<pre>{`${obj.a}-${obj.b}`}</pre>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { body } = await render(Test);
|
|
36
|
+
expect(body).toBeHtml('<pre>10-20</pre>');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('supports compound assignment operators on lazy bindings', async () => {
|
|
40
|
+
component Test() {
|
|
41
|
+
const obj = { a: 5, b: 10 };
|
|
42
|
+
let &{ a, b } = obj;
|
|
43
|
+
a += 3;
|
|
44
|
+
b *= 2;
|
|
45
|
+
<pre>{`${obj.a}-${obj.b}`}</pre>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const { body } = await render(Test);
|
|
49
|
+
expect(body).toBeHtml('<pre>8-20</pre>');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('supports update expressions on lazy bindings', async () => {
|
|
53
|
+
component Test() {
|
|
54
|
+
const obj = { count: 0 };
|
|
55
|
+
let &{ count } = obj;
|
|
56
|
+
count++;
|
|
57
|
+
count++;
|
|
58
|
+
count--;
|
|
59
|
+
<pre>{obj.count}</pre>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const { body } = await render(Test);
|
|
63
|
+
expect(body).toBeHtml('<pre>1</pre>');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('supports update expressions on lazy bindings with default values', async () => {
|
|
67
|
+
component Test() {
|
|
68
|
+
const obj: { count?: number } = {};
|
|
69
|
+
let &{ count = 0 } = obj;
|
|
70
|
+
count++;
|
|
71
|
+
count++;
|
|
72
|
+
<pre>{obj.count}</pre>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const { body } = await render(Test);
|
|
76
|
+
expect(body).toBeHtml('<pre>2</pre>');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('supports function params with lazy destructuring and default values', async () => {
|
|
80
|
+
component Test() {
|
|
81
|
+
function calc(&{ x, y = 100 }: { x: number; y?: number }) {
|
|
82
|
+
return x + y;
|
|
83
|
+
}
|
|
84
|
+
const a = calc({ x: 5, y: 10 });
|
|
85
|
+
const b = calc({ x: 5 });
|
|
86
|
+
<pre>{`${a}-${b}`}</pre>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { body } = await render(Test);
|
|
90
|
+
expect(body).toBeHtml('<pre>15-105</pre>');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('supports member access on lazy destructured objects', async () => {
|
|
94
|
+
component Test() {
|
|
95
|
+
const obj = { user: { name: 'Alice', age: 30 } };
|
|
96
|
+
const &{ user } = obj;
|
|
97
|
+
<pre>{`${user.name}-${user.age}`}</pre>
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const { body } = await render(Test);
|
|
101
|
+
expect(body).toBeHtml('<pre>Alice-30</pre>');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { track } from 'ripple';
|
|
1
2
|
import { compile } from 'ripple/compiler';
|
|
2
3
|
|
|
3
|
-
describe('#
|
|
4
|
+
describe('#style identifier (server)', () => {
|
|
4
5
|
describe('basic usage with components', () => {
|
|
5
|
-
it('passes scoped class to a child component via #
|
|
6
|
+
it('passes scoped class to a child component via #style', async () => {
|
|
6
7
|
component Child({ className }: { className: string }) {
|
|
7
8
|
<div class={className}>{'styled child'}</div>
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
component Parent() {
|
|
11
|
-
<Child className={#
|
|
12
|
+
<Child className={#style.highlight} />
|
|
12
13
|
|
|
13
14
|
<style>
|
|
14
15
|
.highlight {
|
|
@@ -28,14 +29,14 @@ describe('#ripple.style identifier (server)', () => {
|
|
|
28
29
|
expect(classes.some((cls: string) => cls === 'highlight')).toBe(true);
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
it('passes multiple #
|
|
32
|
+
it('passes multiple #style classes to a child component', async () => {
|
|
32
33
|
component Child({ primary, secondary }: { primary: string; secondary: string }) {
|
|
33
34
|
<div class={primary}>{'primary'}</div>
|
|
34
35
|
<span class={secondary}>{'secondary'}</span>
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
component Parent() {
|
|
38
|
-
<Child primary={#
|
|
39
|
+
<Child primary={#style.primary} secondary={#style.secondary} />
|
|
39
40
|
|
|
40
41
|
<style>
|
|
41
42
|
.primary {
|
|
@@ -67,13 +68,13 @@ describe('#ripple.style identifier (server)', () => {
|
|
|
67
68
|
});
|
|
68
69
|
|
|
69
70
|
describe('parent styling applied to child', () => {
|
|
70
|
-
it('allows parent to style child elements via #
|
|
71
|
+
it('allows parent to style child elements via #style prop', async () => {
|
|
71
72
|
component Button({ extraClass }: { extraClass?: string }) {
|
|
72
73
|
<button class={extraClass ?? ''}>{'Click me'}</button>
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
component App() {
|
|
76
|
-
<Button extraClass={#
|
|
77
|
+
<Button extraClass={#style.fancy} />
|
|
77
78
|
|
|
78
79
|
<style>
|
|
79
80
|
.fancy {
|
|
@@ -92,7 +93,7 @@ describe('#ripple.style identifier (server)', () => {
|
|
|
92
93
|
expect(classes.some((cls: string) => cls === 'fancy')).toBe(true);
|
|
93
94
|
});
|
|
94
95
|
|
|
95
|
-
it('child can combine its own classes with parent #
|
|
96
|
+
it('child can combine its own classes with parent #style class', async () => {
|
|
96
97
|
component Card({ className }: { className?: string }) {
|
|
97
98
|
<div class={['card-base', className ?? '']}>{'card content'}</div>
|
|
98
99
|
|
|
@@ -104,7 +105,7 @@ describe('#ripple.style identifier (server)', () => {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
component App() {
|
|
107
|
-
<Card className={#
|
|
108
|
+
<Card className={#style.themed} />
|
|
108
109
|
|
|
109
110
|
<style>
|
|
110
111
|
.themed {
|
|
@@ -132,7 +133,7 @@ describe('#ripple.style identifier (server)', () => {
|
|
|
132
133
|
|
|
133
134
|
component App() {
|
|
134
135
|
<div class="parent">
|
|
135
|
-
<Child cls={#
|
|
136
|
+
<Child cls={#style.dual} />
|
|
136
137
|
</div>
|
|
137
138
|
|
|
138
139
|
<style>
|
|
@@ -157,15 +158,15 @@ describe('#ripple.style identifier (server)', () => {
|
|
|
157
158
|
);
|
|
158
159
|
});
|
|
159
160
|
|
|
160
|
-
it('passes scoped class to a dynamic child component via #
|
|
161
|
+
it('passes scoped class to a dynamic child component via #style', async () => {
|
|
161
162
|
component Child({ cls }: { cls: string }) {
|
|
162
163
|
<span class={cls}>{'text'}</span>
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
component Parent() {
|
|
166
|
-
let dynamic =
|
|
167
|
+
let dynamic = track(() => Child);
|
|
167
168
|
<div class="wrapper">
|
|
168
|
-
<@dynamic cls={#
|
|
169
|
+
<@dynamic cls={#style.text} />
|
|
169
170
|
</div>
|
|
170
171
|
|
|
171
172
|
<style>
|
|
@@ -185,14 +186,92 @@ describe('#ripple.style identifier (server)', () => {
|
|
|
185
186
|
expect(classes.some((cls: string) => cls === 'text')).toBe(true);
|
|
186
187
|
});
|
|
187
188
|
|
|
189
|
+
it('preserves caller scoped hash through wrapper children', async () => {
|
|
190
|
+
component Wrapper({ children }) {
|
|
191
|
+
<div class="green">
|
|
192
|
+
{'Wrapper'}
|
|
193
|
+
<children />
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<style>
|
|
197
|
+
.green {
|
|
198
|
+
color: green;
|
|
199
|
+
}
|
|
200
|
+
</style>
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
component Child() {
|
|
204
|
+
<div class="red">{'Child'}</div>
|
|
205
|
+
|
|
206
|
+
<style>
|
|
207
|
+
.red {
|
|
208
|
+
color: red;
|
|
209
|
+
}
|
|
210
|
+
</style>
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
component App() {
|
|
214
|
+
<Wrapper>
|
|
215
|
+
<Child />
|
|
216
|
+
</Wrapper>
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const { body } = await render(App);
|
|
220
|
+
const { document } = parseHtml(body);
|
|
221
|
+
const wrapper = document.querySelector('.green');
|
|
222
|
+
const child = document.querySelector('.red');
|
|
223
|
+
const wrapper_scopes = Array.from(wrapper.classList).filter(
|
|
224
|
+
(name) => name.startsWith('ripple-'),
|
|
225
|
+
);
|
|
226
|
+
const child_scopes = Array.from(child.classList).filter((name) => name.startsWith('ripple-'));
|
|
227
|
+
|
|
228
|
+
expect(wrapper_scopes).toHaveLength(1);
|
|
229
|
+
expect(child_scopes).toHaveLength(1);
|
|
230
|
+
|
|
231
|
+
const wrapper_scope = wrapper_scopes[0];
|
|
232
|
+
const child_scope = child_scopes.find((name) => name !== wrapper_scope) || child_scopes[0];
|
|
233
|
+
expect(wrapper_scope).not.toBe(child_scope);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('applies caller scoped hash to slotted children through dynamic components', async () => {
|
|
237
|
+
component Wrapper({ children }) {
|
|
238
|
+
<section>
|
|
239
|
+
<children />
|
|
240
|
+
</section>
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
component App() {
|
|
244
|
+
const DynamicWrapper = track(() => Wrapper);
|
|
245
|
+
|
|
246
|
+
<@DynamicWrapper>
|
|
247
|
+
<div class="green">{'Slotted child'}</div>
|
|
248
|
+
</@DynamicWrapper>
|
|
249
|
+
|
|
250
|
+
<style>
|
|
251
|
+
.green {
|
|
252
|
+
color: green;
|
|
253
|
+
}
|
|
254
|
+
</style>
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const { body } = await render(App);
|
|
258
|
+
const { document } = parseHtml(body);
|
|
259
|
+
const slotted_child = document.querySelector('section > div.green');
|
|
260
|
+
const slotted_scopes = Array.from(slotted_child.classList).filter(
|
|
261
|
+
(name) => name.startsWith('ripple-'),
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
expect(slotted_scopes).toHaveLength(1);
|
|
265
|
+
});
|
|
266
|
+
|
|
188
267
|
describe('server compiler output', () => {
|
|
189
|
-
it('generates #
|
|
268
|
+
it('generates #style object with standalone classes', () => {
|
|
190
269
|
const source = `
|
|
191
270
|
component Child({ cls }: { cls: string }) {
|
|
192
271
|
<div class={cls}>{'text'}</div>
|
|
193
272
|
}
|
|
194
273
|
export component App() {
|
|
195
|
-
<Child cls={#
|
|
274
|
+
<Child cls={#style.highlight} />
|
|
196
275
|
|
|
197
276
|
<style>
|
|
198
277
|
.highlight {
|
|
@@ -213,7 +292,7 @@ export component App() {
|
|
|
213
292
|
}
|
|
214
293
|
|
|
215
294
|
component App() {
|
|
216
|
-
<Child cls={#
|
|
295
|
+
<Child cls={#style.styled} />
|
|
217
296
|
|
|
218
297
|
<style>
|
|
219
298
|
.styled {
|