ripple 0.3.68 → 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 +48 -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,17 +10,17 @@ describe('refs', () => {
|
|
|
10
10
|
expect(isRefProp({ value: null })).toBe(false);
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
it('captures a host element with
|
|
13
|
+
it('captures a host element with ref={...}', () => {
|
|
14
14
|
let captured: HTMLInputElement | null = null;
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
function App() {
|
|
17
|
+
return <>
|
|
18
|
+
let input: HTMLInputElement | undefined;
|
|
19
|
+
<input type="text" ref={input} />
|
|
20
|
+
effect(() => {
|
|
21
|
+
captured = input ?? null;
|
|
22
|
+
});
|
|
23
|
+
</>;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
render(App);
|
|
@@ -32,13 +32,12 @@ describe('refs', () => {
|
|
|
32
32
|
it('forwards a named ref prop explicitly through a component', () => {
|
|
33
33
|
let captured: HTMLInputElement | null = null;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<input type="text" ref={props.input_ref} />
|
|
35
|
+
function Child(props: PropsWithExtras<{}>) {
|
|
36
|
+
return <><input type="text" ref={props.input_ref} /></>;
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
function App() {
|
|
40
|
+
return <><Child input_ref={(node: HTMLInputElement | null) => (captured = node)} /></>;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
render(App);
|
|
@@ -47,16 +46,18 @@ describe('refs', () => {
|
|
|
47
46
|
expect(captured).toBeInstanceOf(HTMLInputElement);
|
|
48
47
|
});
|
|
49
48
|
|
|
50
|
-
it('
|
|
49
|
+
it('forwards an ordinary named prop explicitly from a host spread', () => {
|
|
51
50
|
let captured: HTMLInputElement | null = null;
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
function Child(props: PropsWithExtras<{}>) {
|
|
53
|
+
return <>
|
|
54
|
+
const { input_ref, ...rest } = props;
|
|
55
|
+
<input type="text" ref={input_ref} {...rest} />
|
|
56
|
+
</>;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
function App() {
|
|
60
|
+
return <><Child input_ref={(node: HTMLInputElement | null) => (captured = node)} /></>;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
render(App);
|
|
@@ -68,14 +69,16 @@ describe('refs', () => {
|
|
|
68
69
|
it('capture a <div>', () => {
|
|
69
70
|
let div: HTMLDivElement | undefined;
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
function Component() {
|
|
73
|
+
return <>
|
|
74
|
+
<div
|
|
75
|
+
ref={(node: HTMLDivElement) => {
|
|
76
|
+
div = node;
|
|
77
|
+
}}
|
|
78
|
+
>
|
|
79
|
+
{'Hello World'}
|
|
80
|
+
</div>
|
|
81
|
+
</>;
|
|
79
82
|
}
|
|
80
83
|
render(Component);
|
|
81
84
|
flushSync();
|
|
@@ -86,20 +89,22 @@ describe('refs', () => {
|
|
|
86
89
|
type Child = typeof Child;
|
|
87
90
|
let _node: Child | undefined;
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
function Component() {
|
|
93
|
+
return <>
|
|
94
|
+
let items = RippleArray.from([1, 2, 3]);
|
|
95
|
+
function componentRef(node: Child) {
|
|
96
|
+
_node = node;
|
|
97
|
+
}
|
|
98
|
+
<Child ref={componentRef} {items} />
|
|
99
|
+
</>;
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
function Child(props: { items: RippleArray<number> }) {
|
|
103
|
+
return <>
|
|
104
|
+
const { items, ...rest } = props;
|
|
105
|
+
<pre {...rest}>{JSON.stringify(items)}</pre>
|
|
106
|
+
<pre>{items.length}</pre>
|
|
107
|
+
</>;
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
render(Component);
|
|
@@ -111,26 +116,24 @@ describe('refs', () => {
|
|
|
111
116
|
it('should handle spreading into composite refs', () => {
|
|
112
117
|
let logs: string[] = [];
|
|
113
118
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
<Input {...props} />
|
|
119
|
+
function App() {
|
|
120
|
+
return <>
|
|
121
|
+
let &[value] = track('test');
|
|
122
|
+
function inputRef(node: HTMLInputElement) {
|
|
123
|
+
logs.push('ref called');
|
|
124
|
+
}
|
|
125
|
+
const props = {
|
|
126
|
+
id: 'example',
|
|
127
|
+
value,
|
|
128
|
+
[createRefKey()]: inputRef,
|
|
129
|
+
};
|
|
130
|
+
<input type="text" {...props} />
|
|
131
|
+
<Input {...props} />
|
|
132
|
+
</>;
|
|
130
133
|
}
|
|
131
134
|
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
function Input({ id, value, ...rest }: PropsWithExtras<{ id: string; value: string }>) {
|
|
136
|
+
return <><input type="text" {id} {value} {...rest} /></>;
|
|
134
137
|
}
|
|
135
138
|
|
|
136
139
|
render(App);
|
|
@@ -139,14 +142,15 @@ describe('refs', () => {
|
|
|
139
142
|
expect(logs).toEqual(['ref called', 'ref called']);
|
|
140
143
|
});
|
|
141
144
|
|
|
142
|
-
it('captures a host element into a Tracked via {
|
|
145
|
+
it('captures a host element into a Tracked via ref={tracker}', () => {
|
|
143
146
|
let captured: Tracked<HTMLDivElement | null> | undefined;
|
|
144
147
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
function Component() {
|
|
149
|
+
return <>
|
|
150
|
+
const tracker = track<HTMLDivElement | null>(null);
|
|
151
|
+
captured = tracker;
|
|
152
|
+
<div ref={tracker}>{'Hello World'}</div>
|
|
153
|
+
</>;
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
render(Component);
|
|
@@ -158,17 +162,16 @@ describe('refs', () => {
|
|
|
158
162
|
it('forwards a Tracked through a composite component via prop destructuring + spread', () => {
|
|
159
163
|
let captured: Tracked<HTMLInputElement | null> | undefined;
|
|
160
164
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// arrives on the DOM element via spread.
|
|
164
|
-
<input type="text" {id} {...rest} />
|
|
165
|
+
function Child({ id, ...rest }: PropsWithExtras<{ id: string }>) {
|
|
166
|
+
return <><input type="text" {id} {...rest} /></>;
|
|
165
167
|
}
|
|
166
168
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
function App() {
|
|
170
|
+
return <>
|
|
171
|
+
const tracker = track<HTMLInputElement | null>(null);
|
|
172
|
+
captured = tracker;
|
|
173
|
+
<Child id="example" ref={tracker} />
|
|
174
|
+
</>;
|
|
172
175
|
}
|
|
173
176
|
|
|
174
177
|
render(App);
|
|
@@ -177,20 +180,20 @@ describe('refs', () => {
|
|
|
177
180
|
expect(captured!.value!.id).toBe('example');
|
|
178
181
|
});
|
|
179
182
|
|
|
180
|
-
it('assigns a host element to a plain let variable via {
|
|
183
|
+
it('assigns a host element to a plain let variable via ref={var}', () => {
|
|
181
184
|
let captured: HTMLDivElement | null = null;
|
|
182
185
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
function App() {
|
|
187
|
+
return <>
|
|
188
|
+
let div: HTMLDivElement | undefined;
|
|
189
|
+
<div ref={div}>{'Hello World'}</div>
|
|
190
|
+
// Read the captured element through an effect so the assertion
|
|
191
|
+
// observes the post-mount value (component setup runs before the
|
|
192
|
+
// element is created).
|
|
193
|
+
effect(() => {
|
|
194
|
+
captured = div ?? null;
|
|
195
|
+
});
|
|
196
|
+
</>;
|
|
194
197
|
}
|
|
195
198
|
|
|
196
199
|
render(App);
|
|
@@ -202,14 +205,14 @@ describe('refs', () => {
|
|
|
202
205
|
it('assigns a host element to a plain let variable via ref={var}', () => {
|
|
203
206
|
let captured: HTMLDivElement | null = null;
|
|
204
207
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
208
|
+
function App() {
|
|
209
|
+
return <>
|
|
210
|
+
let div: HTMLDivElement | undefined;
|
|
211
|
+
<div ref={div}>{'Hello ref attr'}</div>
|
|
212
|
+
effect(() => {
|
|
213
|
+
captured = div ?? null;
|
|
214
|
+
});
|
|
215
|
+
</>;
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
render(App);
|
|
@@ -221,14 +224,14 @@ describe('refs', () => {
|
|
|
221
224
|
it('clears a plain let variable via ref={var} when the host element unmounts', () => {
|
|
222
225
|
let div: HTMLDivElement | null | undefined;
|
|
223
226
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
227
|
+
function App() {
|
|
228
|
+
return <>
|
|
229
|
+
let &[show] = track(true);
|
|
230
|
+
if (show) {
|
|
231
|
+
<div ref={div}>{'Hello cleanup'}</div>
|
|
232
|
+
}
|
|
233
|
+
<button class="toggle" onClick={() => (show = false)}>{'hide'}</button>
|
|
234
|
+
</>;
|
|
232
235
|
}
|
|
233
236
|
|
|
234
237
|
render(App);
|
|
@@ -243,14 +246,14 @@ describe('refs', () => {
|
|
|
243
246
|
it('assigns a host element to a member expression via ref={state.var}', () => {
|
|
244
247
|
let captured: HTMLInputElement | null = null;
|
|
245
248
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
function App() {
|
|
250
|
+
return <>
|
|
251
|
+
const state: { input?: HTMLInputElement } = {};
|
|
252
|
+
<input type="text" ref={state.input} />
|
|
253
|
+
effect(() => {
|
|
254
|
+
captured = state.input ?? null;
|
|
255
|
+
});
|
|
256
|
+
</>;
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
render(App);
|
|
@@ -262,18 +265,18 @@ describe('refs', () => {
|
|
|
262
265
|
let input: HTMLInputElement | null | undefined;
|
|
263
266
|
let previous: HTMLInputElement | undefined;
|
|
264
267
|
|
|
265
|
-
|
|
266
|
-
|
|
268
|
+
function Child(props: PropsWithExtras<{}>) {
|
|
269
|
+
return <><input type="text" value="keep" {...props} /></>;
|
|
267
270
|
}
|
|
268
271
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
272
|
+
function App() {
|
|
273
|
+
return <>
|
|
274
|
+
let &[show] = track(true);
|
|
275
|
+
if (show) {
|
|
276
|
+
<Child ref={input} />
|
|
277
|
+
}
|
|
278
|
+
<button class="toggle" onClick={() => (show = false)}>{'hide'}</button>
|
|
279
|
+
</>;
|
|
277
280
|
}
|
|
278
281
|
|
|
279
282
|
render(App);
|
|
@@ -293,12 +296,13 @@ describe('refs', () => {
|
|
|
293
296
|
() => {
|
|
294
297
|
let logs: string[] = [];
|
|
295
298
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
function App() {
|
|
300
|
+
return <>
|
|
301
|
+
let cb = (node: HTMLDivElement) => {
|
|
302
|
+
logs.push(`mount:${node.textContent}`);
|
|
303
|
+
};
|
|
304
|
+
<div ref={cb}>{'Hello'}</div>
|
|
305
|
+
</>;
|
|
302
306
|
}
|
|
303
307
|
|
|
304
308
|
render(App);
|
|
@@ -312,12 +316,13 @@ describe('refs', () => {
|
|
|
312
316
|
() => {
|
|
313
317
|
let captured: Tracked<HTMLDivElement | null> | undefined;
|
|
314
318
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
319
|
+
function App() {
|
|
320
|
+
return <>
|
|
321
|
+
const tracker = track<HTMLDivElement | null>(null);
|
|
322
|
+
let slot = tracker;
|
|
323
|
+
captured = tracker;
|
|
324
|
+
<div ref={slot}>{'Hello'}</div>
|
|
325
|
+
</>;
|
|
321
326
|
}
|
|
322
327
|
|
|
323
328
|
render(App);
|
|
@@ -329,18 +334,18 @@ describe('refs', () => {
|
|
|
329
334
|
it('propagates a plain let variable through a composite component via {...rest}', () => {
|
|
330
335
|
let captured: HTMLInputElement | null = null;
|
|
331
336
|
|
|
332
|
-
|
|
333
|
-
|
|
337
|
+
function Child({ id, ...rest }: PropsWithExtras<{ id: string }>) {
|
|
338
|
+
return <><input type="text" {id} {...rest} /></>;
|
|
334
339
|
}
|
|
335
340
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
341
|
+
function App() {
|
|
342
|
+
return <>
|
|
343
|
+
let input: HTMLInputElement | undefined;
|
|
344
|
+
<Child id="example" ref={input} />
|
|
345
|
+
effect(() => {
|
|
346
|
+
captured = input ?? null;
|
|
347
|
+
});
|
|
348
|
+
</>;
|
|
344
349
|
}
|
|
345
350
|
|
|
346
351
|
render(App);
|
|
@@ -351,23 +356,30 @@ describe('refs', () => {
|
|
|
351
356
|
});
|
|
352
357
|
|
|
353
358
|
it(
|
|
354
|
-
'clears a plain let variable forwarded through a
|
|
359
|
+
'clears a plain let variable forwarded through a component ref prop when the host element unmounts',
|
|
355
360
|
() => {
|
|
356
361
|
let input: HTMLInputElement | null | undefined;
|
|
357
362
|
let previous: HTMLInputElement | undefined;
|
|
358
363
|
|
|
359
|
-
|
|
360
|
-
|
|
364
|
+
function Child(props: PropsWithExtras<{}>) {
|
|
365
|
+
return <><input type="text" value="keep" {...props} /></>;
|
|
361
366
|
}
|
|
362
367
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
function App() {
|
|
369
|
+
return <>
|
|
370
|
+
let &[show] = track(true);
|
|
371
|
+
if (show) {
|
|
372
|
+
<Child
|
|
373
|
+
ref={(node: HTMLInputElement | null) => {
|
|
374
|
+
input = node;
|
|
375
|
+
return () => {
|
|
376
|
+
input = null;
|
|
377
|
+
};
|
|
378
|
+
}}
|
|
379
|
+
/>
|
|
380
|
+
}
|
|
381
|
+
<button class="toggle" onClick={() => (show = false)}>{'hide'}</button>
|
|
382
|
+
</>;
|
|
371
383
|
}
|
|
372
384
|
|
|
373
385
|
render(App);
|
|
@@ -383,23 +395,33 @@ describe('refs', () => {
|
|
|
383
395
|
},
|
|
384
396
|
);
|
|
385
397
|
|
|
386
|
-
it('clears a
|
|
398
|
+
it('clears a component ref prop when a host spread changes it to a regular prop', () => {
|
|
387
399
|
let input: HTMLInputElement | null | undefined;
|
|
388
400
|
let previous: HTMLInputElement | undefined;
|
|
389
401
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
402
|
+
function Child(props: PropsWithExtras<{}>) {
|
|
403
|
+
return <>
|
|
404
|
+
let &[as_ref] = track(true);
|
|
405
|
+
<input
|
|
406
|
+
type="text"
|
|
407
|
+
value="keep"
|
|
408
|
+
{...(as_ref ? { ref: props.ref } : { input_ref: 'regular prop' })}
|
|
409
|
+
/>
|
|
410
|
+
<button class="toggle" onClick={() => (as_ref = false)}>{'toggle'}</button>
|
|
411
|
+
</>;
|
|
399
412
|
}
|
|
400
413
|
|
|
401
|
-
|
|
402
|
-
|
|
414
|
+
function App() {
|
|
415
|
+
return <>
|
|
416
|
+
<Child
|
|
417
|
+
ref={(node: HTMLInputElement | null) => {
|
|
418
|
+
input = node;
|
|
419
|
+
return () => {
|
|
420
|
+
input = null;
|
|
421
|
+
};
|
|
422
|
+
}}
|
|
423
|
+
/>
|
|
424
|
+
</>;
|
|
403
425
|
}
|
|
404
426
|
|
|
405
427
|
render(App);
|
|
@@ -416,23 +438,33 @@ describe('refs', () => {
|
|
|
416
438
|
expect(previous.getAttribute('input_ref')).toBe('regular prop');
|
|
417
439
|
});
|
|
418
440
|
|
|
419
|
-
it('removes a regular spread attribute when the key changes to a
|
|
441
|
+
it('removes a regular spread attribute when the key changes to a component ref prop', () => {
|
|
420
442
|
let input: HTMLInputElement | null | undefined;
|
|
421
443
|
let previous: HTMLInputElement | undefined;
|
|
422
444
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
445
|
+
function Child(props: PropsWithExtras<{}>) {
|
|
446
|
+
return <>
|
|
447
|
+
let &[as_ref] = track(false);
|
|
448
|
+
<input
|
|
449
|
+
type="text"
|
|
450
|
+
value="keep"
|
|
451
|
+
{...(as_ref ? { ref: props.ref } : { input_ref: 'regular prop' })}
|
|
452
|
+
/>
|
|
453
|
+
<button class="toggle" onClick={() => (as_ref = true)}>{'toggle'}</button>
|
|
454
|
+
</>;
|
|
432
455
|
}
|
|
433
456
|
|
|
434
|
-
|
|
435
|
-
|
|
457
|
+
function App() {
|
|
458
|
+
return <>
|
|
459
|
+
<Child
|
|
460
|
+
ref={(node: HTMLInputElement | null) => {
|
|
461
|
+
input = node;
|
|
462
|
+
return () => {
|
|
463
|
+
input = null;
|
|
464
|
+
};
|
|
465
|
+
}}
|
|
466
|
+
/>
|
|
467
|
+
</>;
|
|
436
468
|
}
|
|
437
469
|
|
|
438
470
|
render(App);
|
|
@@ -453,15 +485,16 @@ describe('refs', () => {
|
|
|
453
485
|
let captured: Tracked<HTMLDivElement | null> | undefined;
|
|
454
486
|
let toggle: Tracked<boolean> | undefined;
|
|
455
487
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
488
|
+
function Component() {
|
|
489
|
+
return <>
|
|
490
|
+
const tracker = track<HTMLDivElement | null>(null);
|
|
491
|
+
const show = track(true);
|
|
492
|
+
captured = tracker;
|
|
493
|
+
toggle = show;
|
|
494
|
+
if (show.value) {
|
|
495
|
+
<div ref={tracker}>{'Hello World'}</div>
|
|
496
|
+
}
|
|
497
|
+
</>;
|
|
465
498
|
}
|
|
466
499
|
|
|
467
500
|
render(Component);
|
|
@@ -476,25 +509,23 @@ describe('refs', () => {
|
|
|
476
509
|
it('should handle spreading props with a static ref', () => {
|
|
477
510
|
let logs: string[] = [];
|
|
478
511
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
<Input {ref inputRef} {...props} />
|
|
512
|
+
function App() {
|
|
513
|
+
return <>
|
|
514
|
+
let &[value] = track('test');
|
|
515
|
+
function inputRef(node: HTMLInputElement) {
|
|
516
|
+
logs.push('ref called');
|
|
517
|
+
}
|
|
518
|
+
const props = {
|
|
519
|
+
id: 'example',
|
|
520
|
+
value,
|
|
521
|
+
};
|
|
522
|
+
<input type="text" ref={inputRef} {...props} />
|
|
523
|
+
<Input ref={inputRef} {...props} />
|
|
524
|
+
</>;
|
|
494
525
|
}
|
|
495
526
|
|
|
496
|
-
|
|
497
|
-
|
|
527
|
+
function Input({ id, value, ...rest }: PropsWithExtras<{ id: string; value: string }>) {
|
|
528
|
+
return <><input type="text" {id} {value} {...rest} /></>;
|
|
498
529
|
}
|
|
499
530
|
|
|
500
531
|
render(App);
|