ripple 0.3.67 → 0.3.69
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 +57 -0
- package/package.json +3 -3
- package/src/jsx-runtime.d.ts +2 -2
- package/src/runtime/element.js +1 -1
- package/src/runtime/index-client.js +11 -11
- package/src/runtime/index-server.js +7 -4
- package/src/runtime/internal/client/bindings.js +1 -1
- package/src/runtime/internal/client/blocks.js +13 -4
- package/src/runtime/internal/client/component.js +55 -0
- package/src/runtime/internal/client/composite.js +4 -2
- package/src/runtime/internal/client/expression.js +65 -7
- package/src/runtime/internal/client/hmr.js +54 -43
- package/src/runtime/internal/client/index.js +5 -1
- package/src/runtime/internal/client/portal.js +70 -69
- package/src/runtime/internal/client/render.js +3 -0
- package/src/runtime/internal/server/index.js +92 -8
- package/tests/client/__snapshots__/html.test.tsrx.snap +3 -3
- package/tests/client/array/array.copy-within.test.tsrx +33 -31
- package/tests/client/array/array.derived.test.tsrx +186 -169
- package/tests/client/array/array.iteration.test.tsrx +40 -37
- package/tests/client/array/array.mutations.test.tsrx +113 -101
- package/tests/client/array/array.static.test.tsrx +119 -101
- package/tests/client/array/array.to-methods.test.tsrx +24 -21
- package/tests/client/async-suspend.test.tsrx +247 -246
- package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +0 -1
- package/tests/client/basic/basic.attributes.test.tsrx +428 -423
- package/tests/client/basic/basic.collections.test.tsrx +109 -102
- package/tests/client/basic/basic.components.test.tsrx +323 -205
- package/tests/client/basic/basic.errors.test.tsrx +91 -91
- package/tests/client/basic/basic.events.test.tsrx +114 -115
- package/tests/client/basic/basic.get-set.test.tsrx +97 -87
- package/tests/client/basic/basic.hmr.test.tsrx +19 -16
- package/tests/client/basic/basic.reactivity.test.tsrx +199 -191
- package/tests/client/basic/basic.rendering.test.tsrx +272 -182
- package/tests/client/basic/basic.styling.test.tsrx +23 -22
- package/tests/client/basic/basic.utilities.test.tsrx +10 -8
- package/tests/client/boundaries.test.tsrx +26 -26
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +5 -5
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +5 -5
- package/tests/client/compiler/compiler.assignments.test.tsrx +77 -81
- package/tests/client/compiler/compiler.attributes.test.tsrx +15 -15
- package/tests/client/compiler/compiler.basic.test.tsrx +322 -314
- package/tests/client/compiler/compiler.regex.test.tsrx +44 -47
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +38 -38
- package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
- package/tests/client/compiler/compiler.typescript.test.tsrx +2 -2
- package/tests/client/composite/composite.dynamic-components.test.tsrx +47 -48
- package/tests/client/composite/composite.generics.test.tsrx +168 -192
- package/tests/client/composite/composite.props.test.tsrx +97 -81
- package/tests/client/composite/composite.reactivity.test.tsrx +177 -147
- package/tests/client/composite/composite.render.test.tsrx +122 -105
- package/tests/client/computed-properties.test.tsrx +28 -28
- package/tests/client/context.test.tsrx +21 -21
- package/tests/client/css/global-additional-cases.test.tsrx +58 -58
- package/tests/client/css/global-advanced-selectors.test.tsrx +16 -16
- package/tests/client/css/global-at-rules.test.tsrx +10 -10
- package/tests/client/css/global-basic.test.tsrx +14 -14
- package/tests/client/css/global-classes-ids.test.tsrx +14 -14
- package/tests/client/css/global-combinators.test.tsrx +10 -10
- package/tests/client/css/global-complex-nesting.test.tsrx +14 -14
- package/tests/client/css/global-edge-cases.test.tsrx +18 -18
- package/tests/client/css/global-keyframes.test.tsrx +12 -12
- package/tests/client/css/global-nested.test.tsrx +10 -10
- package/tests/client/css/global-pseudo.test.tsrx +12 -12
- package/tests/client/css/global-scoping.test.tsrx +20 -20
- package/tests/client/css/style-identifier.test.tsrx +143 -291
- package/tests/client/date.test.tsrx +146 -133
- package/tests/client/dynamic-elements.test.tsrx +398 -365
- package/tests/client/events.test.tsrx +292 -290
- package/tests/client/for.test.tsrx +156 -153
- package/tests/client/head.test.tsrx +105 -96
- package/tests/client/html.test.tsrx +122 -26
- package/tests/client/input-value.test.tsrx +1361 -1314
- package/tests/client/lazy-array.test.tsrx +16 -13
- package/tests/client/lazy-destructuring.test.tsrx +257 -213
- package/tests/client/map.test.tsrx +65 -60
- package/tests/client/media-query.test.tsrx +22 -20
- package/tests/client/object.test.tsrx +87 -81
- package/tests/client/portal.test.tsrx +57 -51
- package/tests/client/ref.test.tsrx +233 -202
- package/tests/client/return.test.tsrx +71 -2560
- package/tests/client/set.test.tsrx +54 -45
- package/tests/client/svg.test.tsrx +216 -186
- package/tests/client/switch.test.tsrx +194 -193
- package/tests/client/track-async-hydration.test.tsrx +18 -14
- package/tests/client/tracked-index-access.test.tsrx +28 -18
- package/tests/client/try.test.tsrx +675 -548
- package/tests/client/tsx.test.tsrx +373 -311
- package/tests/client/typescript-generics.test.tsrx +145 -145
- package/tests/client/url/url.derived.test.tsrx +33 -28
- package/tests/client/url/url.parsing.test.tsrx +61 -51
- package/tests/client/url/url.partial-removal.test.tsrx +56 -48
- package/tests/client/url/url.reactivity.test.tsrx +142 -125
- package/tests/client/url/url.serialization.test.tsrx +13 -11
- package/tests/client/url-search-params/url-search-params.derived.test.tsrx +34 -29
- package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +25 -21
- package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +50 -45
- package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +111 -99
- package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +49 -43
- package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +14 -12
- package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +16 -14
- package/tests/hydration/basic.test.js +3 -3
- package/tests/hydration/compiled/client/basic.js +586 -651
- package/tests/hydration/compiled/client/composite.js +79 -104
- package/tests/hydration/compiled/client/events.js +140 -148
- package/tests/hydration/compiled/client/for.js +1005 -1018
- package/tests/hydration/compiled/client/head.js +124 -134
- package/tests/hydration/compiled/client/hmr.js +41 -48
- package/tests/hydration/compiled/client/html-in-template.js +38 -41
- package/tests/hydration/compiled/client/html.js +970 -1314
- package/tests/hydration/compiled/client/if-children.js +234 -249
- package/tests/hydration/compiled/client/if.js +182 -189
- package/tests/hydration/compiled/client/mixed-control-flow.js +347 -303
- package/tests/hydration/compiled/client/nested-control-flow.js +1084 -832
- package/tests/hydration/compiled/client/portal.js +65 -85
- package/tests/hydration/compiled/client/reactivity.js +84 -90
- package/tests/hydration/compiled/client/return.js +38 -1939
- package/tests/hydration/compiled/client/switch.js +218 -224
- package/tests/hydration/compiled/client/track-async-serialization.js +250 -259
- package/tests/hydration/compiled/client/try.js +123 -132
- package/tests/hydration/compiled/server/basic.js +773 -831
- package/tests/hydration/compiled/server/composite.js +166 -191
- package/tests/hydration/compiled/server/events.js +170 -184
- package/tests/hydration/compiled/server/for.js +851 -909
- package/tests/hydration/compiled/server/head.js +206 -216
- package/tests/hydration/compiled/server/hmr.js +64 -72
- package/tests/hydration/compiled/server/html-in-template.js +42 -76
- package/tests/hydration/compiled/server/html.js +1362 -1667
- package/tests/hydration/compiled/server/if-children.js +419 -445
- package/tests/hydration/compiled/server/if.js +194 -208
- package/tests/hydration/compiled/server/mixed-control-flow.js +249 -257
- package/tests/hydration/compiled/server/nested-control-flow.js +491 -515
- package/tests/hydration/compiled/server/portal.js +152 -160
- package/tests/hydration/compiled/server/reactivity.js +94 -106
- package/tests/hydration/compiled/server/return.js +28 -2172
- package/tests/hydration/compiled/server/switch.js +274 -286
- package/tests/hydration/compiled/server/track-async-serialization.js +340 -358
- package/tests/hydration/compiled/server/try.js +167 -185
- package/tests/hydration/components/basic.tsrx +320 -272
- package/tests/hydration/components/composite.tsrx +44 -32
- package/tests/hydration/components/events.tsrx +101 -91
- package/tests/hydration/components/for.tsrx +510 -452
- package/tests/hydration/components/head.tsrx +87 -80
- package/tests/hydration/components/hmr.tsrx +22 -17
- package/tests/hydration/components/html-in-template.tsrx +22 -17
- package/tests/hydration/components/html.tsrx +525 -443
- package/tests/hydration/components/if-children.tsrx +158 -148
- package/tests/hydration/components/if.tsrx +109 -95
- package/tests/hydration/components/mixed-control-flow.tsrx +100 -96
- package/tests/hydration/components/nested-control-flow.tsrx +215 -203
- package/tests/hydration/components/portal.tsrx +41 -34
- package/tests/hydration/components/reactivity.tsrx +37 -27
- package/tests/hydration/components/return.tsrx +12 -556
- package/tests/hydration/components/switch.tsrx +120 -114
- package/tests/hydration/components/track-async-serialization.tsrx +107 -91
- package/tests/hydration/components/try.tsrx +55 -40
- package/tests/hydration/html.test.js +4 -4
- package/tests/hydration/return.test.js +13 -532
- package/tests/server/await.test.tsrx +3 -3
- package/tests/server/basic.attributes.test.tsrx +264 -195
- package/tests/server/basic.components.test.tsrx +296 -169
- package/tests/server/basic.test.tsrx +300 -198
- package/tests/server/compiler.test.tsrx +62 -60
- package/tests/server/composite.props.test.tsrx +77 -63
- package/tests/server/composite.test.tsrx +168 -192
- package/tests/server/context.test.tsrx +18 -12
- package/tests/server/dynamic-elements.test.tsrx +197 -180
- package/tests/server/for.test.tsrx +85 -78
- package/tests/server/head.test.tsrx +50 -43
- package/tests/server/html-nesting-validation.test.tsrx +8 -8
- package/tests/server/if.test.tsrx +57 -51
- package/tests/server/lazy-destructuring.test.tsrx +366 -294
- package/tests/server/return.test.tsrx +76 -1355
- package/tests/server/streaming-ssr.test.tsrx +4 -75
- package/tests/server/style-identifier.test.tsrx +169 -148
- package/tests/server/switch.test.tsrx +91 -85
- package/tests/server/track-async-serialization.test.tsrx +105 -85
- package/tests/server/try.test.tsrx +374 -280
- package/tests/utils/compiler-compat-config.test.js +2 -2
- package/tests/utils/runtime-imports.test.js +10 -0
- package/types/index.d.ts +8 -0
- package/tests/client/__snapshots__/html.test.rsrx.snap +0 -40
|
@@ -10,16 +10,17 @@ import { did_error } from '../capture-error.js';
|
|
|
10
10
|
|
|
11
11
|
describe('basic client > components & composition', () => {
|
|
12
12
|
it('renders with component composition and children', () => {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
function Card(props: PropsWithChildren<{}>) {
|
|
14
|
+
return <><div class="card">{props.children}</div></>;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
function Basic() {
|
|
18
|
+
return <>
|
|
19
|
+
function children() {
|
|
20
|
+
return <><p>{'Card content here'}</p></>;
|
|
21
|
+
}
|
|
22
|
+
<Card {children} />
|
|
23
|
+
</>;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
render(Basic);
|
|
@@ -32,20 +33,23 @@ describe('basic client > components & composition', () => {
|
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
it('does not render a falsy component call', () => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
function Card(props: PropsWithChildrenOptional<{ test?: Component }>) {
|
|
37
|
+
return <>
|
|
38
|
+
<div class="card">
|
|
39
|
+
if (props.children) {
|
|
40
|
+
{props.children}
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
43
|
+
</>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function Basic() {
|
|
47
|
+
return <>
|
|
48
|
+
function test() {
|
|
49
|
+
return <><p>{'Card content here'}</p></>;
|
|
39
50
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
component Basic() {
|
|
44
|
-
component test() {
|
|
45
|
-
<p>{'Card content here'}</p>
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
<Card {test} />
|
|
51
|
+
<Card {test} />
|
|
52
|
+
</>;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
render(Basic);
|
|
@@ -58,23 +62,25 @@ describe('basic client > components & composition', () => {
|
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
it('allows tracked variables alongside explicit component props', () => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
function Card(props: PropsWithChildrenOptional<{ test?: Component }>) {
|
|
66
|
+
return <>
|
|
67
|
+
<div class="card">
|
|
68
|
+
if (props.children) {
|
|
69
|
+
{props.children}
|
|
70
|
+
}
|
|
71
|
+
</div>
|
|
72
|
+
</>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function Basic() {
|
|
76
|
+
return <>
|
|
77
|
+
let &[test] = track(false);
|
|
78
|
+
function TestSlot() {
|
|
79
|
+
return <><p>{'Card content here'}</p></>;
|
|
65
80
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
component Basic() {
|
|
70
|
-
let &[test] = track(false);
|
|
71
|
-
|
|
72
|
-
component TestSlot() {
|
|
73
|
-
<p>{'Card content here'}</p>
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
<Card test={TestSlot} />
|
|
77
|
-
<div>{test ? 'yes' : 'no'}</div>
|
|
81
|
+
<Card test={TestSlot} />
|
|
82
|
+
<div>{test ? 'yes' : 'no'}</div>
|
|
83
|
+
</>;
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
render(Basic);
|
|
@@ -88,15 +94,17 @@ describe('basic client > components & composition', () => {
|
|
|
88
94
|
});
|
|
89
95
|
|
|
90
96
|
it('renders a component when children is set a component prop', () => {
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
function Card(props: PropsWithChildren<{}>) {
|
|
98
|
+
return <><div class="card">{props.children}</div></>;
|
|
93
99
|
}
|
|
94
100
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
function Basic() {
|
|
102
|
+
return <>
|
|
103
|
+
function children() {
|
|
104
|
+
return <><p>{'Card content here'}</p></>;
|
|
105
|
+
}
|
|
106
|
+
<Card {children} />
|
|
107
|
+
</>;
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
render(Basic);
|
|
@@ -108,38 +116,115 @@ describe('basic client > components & composition', () => {
|
|
|
108
116
|
expect(paragraph.textContent).toBe('Card content here');
|
|
109
117
|
});
|
|
110
118
|
|
|
119
|
+
it('renders direct component function calls as values', () => {
|
|
120
|
+
function Test({ label }: { label: string }) {
|
|
121
|
+
return <><span>{label}</span></>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function App() {
|
|
125
|
+
return <>{Test({ label: 'direct call' })}</>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
render(App);
|
|
129
|
+
|
|
130
|
+
expect(container.querySelector('span')?.textContent).toBe('direct call');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('renders arrays and primitives returned from component calls', () => {
|
|
134
|
+
function Test() {
|
|
135
|
+
const item = <span>{'A'}</span>;
|
|
136
|
+
return [item, 'B', null, undefined];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function App() {
|
|
140
|
+
return <><Test /></>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
render(App);
|
|
144
|
+
|
|
145
|
+
expect(container.textContent).toBe('AB');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('throws when a TSRXElement value is used as a component type', () => {
|
|
149
|
+
function Test() {
|
|
150
|
+
return <><span>{'value'}</span></>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function App() {
|
|
154
|
+
const El = Test({});
|
|
155
|
+
return <><El /></>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
expect(() => render(App)).toThrow('Invalid component type');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('allows a plain function as a component type', () => {
|
|
162
|
+
function Func() {
|
|
163
|
+
return 'plain';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function App() {
|
|
167
|
+
return <><Func /></>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
render(App);
|
|
171
|
+
|
|
172
|
+
expect(container.textContent).toBe('plain');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('allows a compat-only function as a component type', () => {
|
|
176
|
+
function CompatOnly() {
|
|
177
|
+
return <tsx>
|
|
178
|
+
<div>
|
|
179
|
+
{'compat'}
|
|
180
|
+
</div>
|
|
181
|
+
</tsx>;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function App() {
|
|
185
|
+
return <><CompatOnly /></>;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
render(App);
|
|
189
|
+
|
|
190
|
+
expect(container.textContent).toBe('compat');
|
|
191
|
+
});
|
|
192
|
+
|
|
111
193
|
it('renders with nested components and prop passing', () => {
|
|
112
|
-
|
|
194
|
+
function Button(props: PropsWithExtras<{
|
|
113
195
|
variant: string;
|
|
114
196
|
label: string;
|
|
115
197
|
onClick: EventListener;
|
|
116
198
|
}>) {
|
|
117
|
-
|
|
199
|
+
return <><button class={props.variant} onClick={props.onClick}>{props.label}</button></>;
|
|
118
200
|
}
|
|
119
201
|
|
|
120
|
-
|
|
202
|
+
function Card(props: PropsWithExtras<{
|
|
121
203
|
title: string;
|
|
122
204
|
content: string;
|
|
123
205
|
buttonText: string;
|
|
124
206
|
onAction: EventListener;
|
|
125
207
|
}>) {
|
|
126
|
-
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
208
|
+
return <>
|
|
209
|
+
<div class="card">
|
|
210
|
+
<h3>{props.title}</h3>
|
|
211
|
+
<p>{props.content}</p>
|
|
212
|
+
<Button variant="primary" label={props.buttonText} onClick={props.onAction} />
|
|
213
|
+
</div>
|
|
214
|
+
</>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function Basic() {
|
|
218
|
+
return <>
|
|
219
|
+
let &[clicked] = track(false);
|
|
220
|
+
<Card
|
|
221
|
+
title="Test Card"
|
|
222
|
+
content="This is a test card"
|
|
223
|
+
buttonText="Click me"
|
|
224
|
+
onAction={() => (clicked = true)}
|
|
225
|
+
/>
|
|
226
|
+
<div class="status">{clicked ? 'Clicked' : 'Not clicked'}</div>
|
|
227
|
+
</>;
|
|
143
228
|
}
|
|
144
229
|
|
|
145
230
|
render(Basic);
|
|
@@ -163,27 +248,30 @@ describe('basic client > components & composition', () => {
|
|
|
163
248
|
});
|
|
164
249
|
|
|
165
250
|
it('renders with reactive component props', () => {
|
|
166
|
-
|
|
251
|
+
function ChildComponent(props: PropsWithExtras<{
|
|
167
252
|
text: Tracked<string>;
|
|
168
253
|
count: Tracked<number>;
|
|
169
254
|
}>) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
255
|
+
return <>
|
|
256
|
+
<div class="child-content">{props.text.value}</div>
|
|
257
|
+
<div class="child-count">{props.count.value}</div>
|
|
258
|
+
</>;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function Basic() {
|
|
262
|
+
return <>
|
|
263
|
+
let &[message, messageTracked] = track('Hello');
|
|
264
|
+
let &[number, numberTracked] = track(1);
|
|
265
|
+
<ChildComponent text={messageTracked} count={numberTracked} />
|
|
266
|
+
<button
|
|
267
|
+
onClick={() => {
|
|
268
|
+
message = message === 'Hello' ? 'Goodbye' : 'Hello';
|
|
269
|
+
number++;
|
|
270
|
+
}}
|
|
271
|
+
>
|
|
272
|
+
{'Update Props'}
|
|
273
|
+
</button>
|
|
274
|
+
</>;
|
|
187
275
|
}
|
|
188
276
|
|
|
189
277
|
render(Basic);
|
|
@@ -209,15 +297,16 @@ describe('basic client > components & composition', () => {
|
|
|
209
297
|
});
|
|
210
298
|
|
|
211
299
|
it('updates explicit text children props reactively', () => {
|
|
212
|
-
|
|
213
|
-
|
|
300
|
+
function TextProp(&{ children }: PropsWithChildren<{}>) {
|
|
301
|
+
return <><div class="text-prop">{children}</div></>;
|
|
214
302
|
}
|
|
215
303
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
304
|
+
function Basic() {
|
|
305
|
+
return <>
|
|
306
|
+
let &[show] = track(false);
|
|
307
|
+
<TextProp children={show ? 'hello' : ''} />
|
|
308
|
+
<button class="show-text" onClick={() => (show = true)}>{'Show'}</button>
|
|
309
|
+
</>;
|
|
221
310
|
}
|
|
222
311
|
|
|
223
312
|
render(Basic);
|
|
@@ -231,7 +320,7 @@ describe('basic client > components & composition', () => {
|
|
|
231
320
|
});
|
|
232
321
|
|
|
233
322
|
it('it retains this context with bracketed prop functions and keeps original chaining', () => {
|
|
234
|
-
|
|
323
|
+
function App() {
|
|
235
324
|
const SYMBOL_PROP = Symbol();
|
|
236
325
|
let &[hasError] = track(false);
|
|
237
326
|
const obj: {
|
|
@@ -280,16 +369,17 @@ describe('basic client > components & composition', () => {
|
|
|
280
369
|
});
|
|
281
370
|
}
|
|
282
371
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
372
|
+
return <>
|
|
373
|
+
<button onClick={() => obj['increment']()}>{'Increment'}</button>
|
|
374
|
+
<button onClick={() => obj[SYMBOL_PROP]()}>{'Increment'}</button>
|
|
375
|
+
<button onClick={trigger_nonexistent}>{'Nonexistent'}</button>
|
|
376
|
+
<button onClick={trigger_nonexistent_chaining}>{'Nonexistent chaining'}</button>
|
|
377
|
+
<button onClick={trigger_object_null}>{'Object null'}</button>
|
|
378
|
+
<button onClick={trigger_object_null_chained}>{'Object null chained'}</button>
|
|
379
|
+
<button onClick={() => obj.arr[obj.arr.length - 1]()}>{'BinaryExpression prop'}</button>
|
|
380
|
+
<span>{obj.count.value}</span>
|
|
381
|
+
<span>{hasError}</span>
|
|
382
|
+
</>;
|
|
293
383
|
}
|
|
294
384
|
|
|
295
385
|
render(App);
|
|
@@ -340,29 +430,36 @@ describe('basic client > components & composition', () => {
|
|
|
340
430
|
});
|
|
341
431
|
|
|
342
432
|
it('renders components as named and anonymous properties', () => {
|
|
433
|
+
function Span() {
|
|
434
|
+
return <><span>{'Hello from Span'}</span></>;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function Button({ children }: PropsWithChildren<{}>) {
|
|
438
|
+
return <><button>{children}</button></>;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function ArrowButton({ children }: PropsWithChildren<{}>) {
|
|
442
|
+
return <><button class="arrow-button">{children}</button></>;
|
|
443
|
+
}
|
|
444
|
+
|
|
343
445
|
const UI = {
|
|
344
|
-
span:
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
button: component({ children }: PropsWithChildren<{}>) {
|
|
348
|
-
<button>{children}</button>
|
|
349
|
-
},
|
|
350
|
-
arrowButton: component({ children }: PropsWithChildren<{}>) => {
|
|
351
|
-
<button class="arrow-button">{children}</button>
|
|
352
|
-
},
|
|
446
|
+
span: Span,
|
|
447
|
+
button: Button,
|
|
448
|
+
arrowButton: ArrowButton,
|
|
353
449
|
};
|
|
354
450
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
451
|
+
function App() {
|
|
452
|
+
return <>
|
|
453
|
+
function children() {
|
|
454
|
+
return <><span>{'Click me!'}</span></>;
|
|
455
|
+
}
|
|
456
|
+
<div>
|
|
457
|
+
<h1>{'Component as Property Test'}</h1>
|
|
458
|
+
<UI.span />
|
|
459
|
+
<UI.button {children} />
|
|
460
|
+
<UI.arrowButton {children} />
|
|
461
|
+
</div>
|
|
462
|
+
</>;
|
|
366
463
|
}
|
|
367
464
|
|
|
368
465
|
render(App);
|
|
@@ -381,14 +478,16 @@ describe('basic client > components & composition', () => {
|
|
|
381
478
|
});
|
|
382
479
|
|
|
383
480
|
it('handles empty string children', () => {
|
|
384
|
-
|
|
385
|
-
{children}
|
|
481
|
+
function Button({ children }: PropsWithChildren<{}>) {
|
|
482
|
+
return <>{children}</>;
|
|
386
483
|
}
|
|
387
484
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
485
|
+
function App() {
|
|
486
|
+
return <>
|
|
487
|
+
let content = '';
|
|
488
|
+
<Button>{''}</Button>
|
|
489
|
+
<Button>{content}</Button>
|
|
490
|
+
</>;
|
|
392
491
|
}
|
|
393
492
|
|
|
394
493
|
expect(() => {
|
|
@@ -397,19 +496,20 @@ describe('basic client > components & composition', () => {
|
|
|
397
496
|
});
|
|
398
497
|
|
|
399
498
|
it('handles component without any output', () => {
|
|
400
|
-
|
|
401
|
-
|
|
499
|
+
function Noop() {
|
|
500
|
+
return <></>;
|
|
402
501
|
}
|
|
403
502
|
|
|
404
|
-
|
|
405
|
-
|
|
503
|
+
function Op() {
|
|
504
|
+
return <><div>{'Some HTML content'}</div></>;
|
|
406
505
|
}
|
|
407
506
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
507
|
+
function App() {
|
|
508
|
+
return <>
|
|
509
|
+
let &[Content] = track(() => Noop);
|
|
510
|
+
<@Content />
|
|
511
|
+
<button onClick={() => (Content = Op)}>{'Show Op'}</button>
|
|
512
|
+
</>;
|
|
413
513
|
}
|
|
414
514
|
|
|
415
515
|
render(App);
|
|
@@ -422,12 +522,12 @@ describe('basic client > components & composition', () => {
|
|
|
422
522
|
});
|
|
423
523
|
|
|
424
524
|
it('renders explicit children prop without spread', () => {
|
|
425
|
-
|
|
426
|
-
|
|
525
|
+
function Card(props: PropsWithChildren<{}>) {
|
|
526
|
+
return <><div class="card">{props.children}</div></>;
|
|
427
527
|
}
|
|
428
528
|
|
|
429
|
-
|
|
430
|
-
|
|
529
|
+
function App() {
|
|
530
|
+
return <><Card children="fallback text" /></>;
|
|
431
531
|
}
|
|
432
532
|
|
|
433
533
|
render(App);
|
|
@@ -435,13 +535,15 @@ describe('basic client > components & composition', () => {
|
|
|
435
535
|
});
|
|
436
536
|
|
|
437
537
|
it('renders explicit children before spread', () => {
|
|
438
|
-
|
|
439
|
-
|
|
538
|
+
function Card(props: PropsWithChildren<{ id: string }>) {
|
|
539
|
+
return <><div class="card">{props.children}</div></>;
|
|
440
540
|
}
|
|
441
541
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
542
|
+
function App() {
|
|
543
|
+
return <>
|
|
544
|
+
const extra = { id: '1' };
|
|
545
|
+
<Card children="fallback text" {...extra} />
|
|
546
|
+
</>;
|
|
445
547
|
}
|
|
446
548
|
|
|
447
549
|
render(App);
|
|
@@ -449,13 +551,15 @@ describe('basic client > components & composition', () => {
|
|
|
449
551
|
});
|
|
450
552
|
|
|
451
553
|
it('renders spread before explicit children', () => {
|
|
452
|
-
|
|
453
|
-
|
|
554
|
+
function Card(props: PropsWithChildren<{ id: string }>) {
|
|
555
|
+
return <><div class="card">{props.children}</div></>;
|
|
454
556
|
}
|
|
455
557
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
558
|
+
function App() {
|
|
559
|
+
return <>
|
|
560
|
+
const extra = { id: '1' };
|
|
561
|
+
<Card {...extra} children="fallback text" />
|
|
562
|
+
</>;
|
|
459
563
|
}
|
|
460
564
|
|
|
461
565
|
render(App);
|
|
@@ -463,15 +567,17 @@ describe('basic client > components & composition', () => {
|
|
|
463
567
|
});
|
|
464
568
|
|
|
465
569
|
it('template children override explicit children before spread', () => {
|
|
466
|
-
|
|
467
|
-
|
|
570
|
+
function Card(props: PropsWithChildren<{ id: string }>) {
|
|
571
|
+
return <><div class="card">{props.children}</div></>;
|
|
468
572
|
}
|
|
469
573
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
<
|
|
474
|
-
|
|
574
|
+
function App() {
|
|
575
|
+
return <>
|
|
576
|
+
const extra = { id: '1' };
|
|
577
|
+
<Card children="fallback text" {...extra}>
|
|
578
|
+
<span>{'template content'}</span>
|
|
579
|
+
</Card>
|
|
580
|
+
</>;
|
|
475
581
|
}
|
|
476
582
|
|
|
477
583
|
render(App);
|
|
@@ -480,15 +586,17 @@ describe('basic client > components & composition', () => {
|
|
|
480
586
|
});
|
|
481
587
|
|
|
482
588
|
it('template children override explicit children after spread', () => {
|
|
483
|
-
|
|
484
|
-
|
|
589
|
+
function Card(props: PropsWithChildren<{ id: string }>) {
|
|
590
|
+
return <><div class="card">{props.children}</div></>;
|
|
485
591
|
}
|
|
486
592
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
<
|
|
491
|
-
|
|
593
|
+
function App() {
|
|
594
|
+
return <>
|
|
595
|
+
const extra = { id: '1' };
|
|
596
|
+
<Card {...extra} children="fallback text">
|
|
597
|
+
<span>{'template content'}</span>
|
|
598
|
+
</Card>
|
|
599
|
+
</>;
|
|
492
600
|
}
|
|
493
601
|
|
|
494
602
|
render(App);
|
|
@@ -497,17 +605,19 @@ describe('basic client > components & composition', () => {
|
|
|
497
605
|
});
|
|
498
606
|
|
|
499
607
|
it('spread can override explicit children when no template children', () => {
|
|
500
|
-
|
|
501
|
-
|
|
608
|
+
function Card(props: PropsWithChildren<{ id: string }>) {
|
|
609
|
+
return <><div class="card">{props.children}</div></>;
|
|
502
610
|
}
|
|
503
611
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
612
|
+
function App() {
|
|
613
|
+
return <>
|
|
614
|
+
const extra = { id: '1', children: 'from spread' };
|
|
615
|
+
<Card
|
|
616
|
+
// @ts-expect-error children specified more than once
|
|
617
|
+
children="explicit"
|
|
618
|
+
{...extra}
|
|
619
|
+
/>
|
|
620
|
+
</>;
|
|
511
621
|
}
|
|
512
622
|
|
|
513
623
|
render(App);
|
|
@@ -515,13 +625,15 @@ describe('basic client > components & composition', () => {
|
|
|
515
625
|
});
|
|
516
626
|
|
|
517
627
|
it('explicit children overrides spread children when it comes after', () => {
|
|
518
|
-
|
|
519
|
-
|
|
628
|
+
function Card(props: PropsWithChildren<{ id: string }>) {
|
|
629
|
+
return <><div class="card">{props.children}</div></>;
|
|
520
630
|
}
|
|
521
631
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
632
|
+
function App() {
|
|
633
|
+
return <>
|
|
634
|
+
const extra = { id: '1', children: 'from spread' };
|
|
635
|
+
<Card {...extra} children="explicit" />
|
|
636
|
+
</>;
|
|
525
637
|
}
|
|
526
638
|
|
|
527
639
|
render(App);
|
|
@@ -529,18 +641,20 @@ describe('basic client > components & composition', () => {
|
|
|
529
641
|
});
|
|
530
642
|
|
|
531
643
|
it('renders components declared inside composite element children', () => {
|
|
532
|
-
|
|
533
|
-
|
|
644
|
+
function Wrapper(props: PropsWithChildren<{}>) {
|
|
645
|
+
return <><div class="wrapper">{props.children}</div></>;
|
|
534
646
|
}
|
|
535
647
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
648
|
+
function App() {
|
|
649
|
+
return <>
|
|
650
|
+
<Wrapper>
|
|
651
|
+
function Inner() {
|
|
652
|
+
return <><span class="inner">{'inner content'}</span></>;
|
|
653
|
+
}
|
|
541
654
|
|
|
542
|
-
|
|
543
|
-
|
|
655
|
+
<Inner />
|
|
656
|
+
</Wrapper>
|
|
657
|
+
</>;
|
|
544
658
|
}
|
|
545
659
|
|
|
546
660
|
render(App);
|
|
@@ -548,25 +662,29 @@ describe('basic client > components & composition', () => {
|
|
|
548
662
|
});
|
|
549
663
|
|
|
550
664
|
it('renders nested components declared inside composite children with prop passing', () => {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
665
|
+
function Wrapper(props: PropsWithChildren<{}>) {
|
|
666
|
+
return <><div class="wrapper">{props.children}</div></>;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function App() {
|
|
670
|
+
return <>
|
|
671
|
+
<Wrapper>
|
|
672
|
+
function Z() {
|
|
673
|
+
return <><div class="z">{'I am Z'}</div></>;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function Child(&{ Z }: { Z: Component }) {
|
|
677
|
+
return <>
|
|
678
|
+
<div class="child">
|
|
679
|
+
{'Child Component: '}
|
|
680
|
+
<Z />
|
|
681
|
+
</div>
|
|
682
|
+
</>;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
<Child {Z} />
|
|
686
|
+
</Wrapper>
|
|
687
|
+
</>;
|
|
570
688
|
}
|
|
571
689
|
|
|
572
690
|
render(App);
|