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
|
@@ -2,17 +2,20 @@ import { RippleSet, flushSync, track } from 'ripple';
|
|
|
2
2
|
|
|
3
3
|
describe('RippleSet', () => {
|
|
4
4
|
it('handles add and delete operations', () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
function SetTest() {
|
|
6
|
+
return <>
|
|
7
|
+
let items = new RippleSet([1, 2, 3]);
|
|
8
|
+
<button onClick={() => items.add(4)}>{'add'}</button>
|
|
9
|
+
<button onClick={() => items.delete(2)}>{'delete'}</button>
|
|
10
|
+
<Child {items} />
|
|
11
|
+
</>;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
function Child({ items }: { items: RippleSet<number> }) {
|
|
15
|
+
return <>
|
|
16
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
17
|
+
<pre>{items.size}</pre>
|
|
18
|
+
</>;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
render(SetTest);
|
|
@@ -34,16 +37,19 @@ describe('RippleSet', () => {
|
|
|
34
37
|
});
|
|
35
38
|
|
|
36
39
|
it('handles clear operation', () => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
function SetTest() {
|
|
41
|
+
return <>
|
|
42
|
+
let items = new RippleSet([1, 2, 3]);
|
|
43
|
+
<button onClick={() => items.clear()}>{'clear'}</button>
|
|
44
|
+
<Child {items} />
|
|
45
|
+
</>;
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
function Child({ items }: { items: RippleSet<number> }) {
|
|
49
|
+
return <>
|
|
50
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
51
|
+
<pre>{items.size}</pre>
|
|
52
|
+
</>;
|
|
47
53
|
}
|
|
48
54
|
|
|
49
55
|
render(SetTest);
|
|
@@ -58,12 +64,13 @@ describe('RippleSet', () => {
|
|
|
58
64
|
});
|
|
59
65
|
|
|
60
66
|
it('handles has operation', () => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
function SetTest() {
|
|
68
|
+
return <>
|
|
69
|
+
let items = new RippleSet([1, 2, 3]);
|
|
70
|
+
let &[hasValue] = track(() => items.has(2));
|
|
71
|
+
<button onClick={() => items.delete(2)}>{'delete'}</button>
|
|
72
|
+
<pre>{hasValue}</pre>
|
|
73
|
+
</>;
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
render(SetTest);
|
|
@@ -79,11 +86,12 @@ describe('RippleSet', () => {
|
|
|
79
86
|
});
|
|
80
87
|
|
|
81
88
|
it('creates empty RippleSet using RippleSet() shorthand syntax', () => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
function SetTest() {
|
|
90
|
+
return <>
|
|
91
|
+
let items = RippleSet();
|
|
92
|
+
<button onClick={() => items.add(1)}>{'add'}</button>
|
|
93
|
+
<pre>{items.size}</pre>
|
|
94
|
+
</>;
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
render(SetTest);
|
|
@@ -98,13 +106,14 @@ describe('RippleSet', () => {
|
|
|
98
106
|
});
|
|
99
107
|
|
|
100
108
|
it('creates RippleSet with initial values using RippleSet() shorthand syntax', () => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
function SetTest() {
|
|
110
|
+
return <>
|
|
111
|
+
let items = RippleSet([1, 2, 3, 4]);
|
|
112
|
+
let &[hasValue] = track(() => items.has(3));
|
|
113
|
+
<button onClick={() => items.delete(3)}>{'delete'}</button>
|
|
114
|
+
<pre>{items.size}</pre>
|
|
115
|
+
<pre>{hasValue}</pre>
|
|
116
|
+
</>;
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
render(SetTest);
|
|
@@ -121,16 +130,16 @@ describe('RippleSet', () => {
|
|
|
121
130
|
});
|
|
122
131
|
|
|
123
132
|
it('handles all operations with RippleSet() shorthand syntax', () => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
function SetTest() {
|
|
134
|
+
return <>
|
|
135
|
+
let items = RippleSet([10, 20, 30]);
|
|
136
|
+
let &[values] = track(() => Array.from(items.values()));
|
|
137
|
+
<button onClick={() => items.add(40)}>{'add'}</button>
|
|
138
|
+
<button onClick={() => items.delete(20)}>{'delete'}</button>
|
|
139
|
+
<button onClick={() => items.clear()}>{'clear'}</button>
|
|
140
|
+
<pre>{JSON.stringify(values)}</pre>
|
|
141
|
+
<pre>{items.size}</pre>
|
|
142
|
+
</>;
|
|
134
143
|
}
|
|
135
144
|
|
|
136
145
|
render(SetTest);
|
|
@@ -3,18 +3,20 @@ import type { Component, PropsWithChildren, PropsWithExtras } from 'ripple';
|
|
|
3
3
|
|
|
4
4
|
describe('SVG namespace handling', () => {
|
|
5
5
|
it('should render static SVG elements with correct namespace', () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
function App() {
|
|
7
|
+
return <>
|
|
8
|
+
<svg
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
+
width="24"
|
|
11
|
+
height="24"
|
|
12
|
+
fill="none"
|
|
13
|
+
stroke="currentColor"
|
|
14
|
+
>
|
|
15
|
+
<path d="m14 12 4 4 4-4" />
|
|
16
|
+
<circle cx="12" cy="12" r="4" />
|
|
17
|
+
<rect x="4" y="4" width="16" height="16" />
|
|
18
|
+
</svg>
|
|
19
|
+
</>;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
render(App);
|
|
@@ -40,25 +42,26 @@ describe('SVG namespace handling', () => {
|
|
|
40
42
|
});
|
|
41
43
|
|
|
42
44
|
it('should render dynamic SVG paths with for loop (original issue)', () => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
function App() {
|
|
46
|
+
return <>
|
|
47
|
+
const d = [
|
|
48
|
+
'm14 12 4 4 4-4',
|
|
49
|
+
'M18 16V7',
|
|
50
|
+
'm2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16',
|
|
51
|
+
'M3.304 13h6.392',
|
|
52
|
+
];
|
|
53
|
+
<svg
|
|
54
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
55
|
+
width="24"
|
|
56
|
+
height="24"
|
|
57
|
+
fill="none"
|
|
58
|
+
stroke="currentColor"
|
|
59
|
+
>
|
|
60
|
+
for (const pathData of d) {
|
|
61
|
+
<path d={pathData} />
|
|
62
|
+
}
|
|
63
|
+
</svg>
|
|
64
|
+
</>;
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
render(App);
|
|
@@ -92,22 +95,23 @@ describe('SVG namespace handling', () => {
|
|
|
92
95
|
});
|
|
93
96
|
|
|
94
97
|
it('should handle mixed static and dynamic SVG elements', () => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
function App() {
|
|
99
|
+
return <>
|
|
100
|
+
const dynamicPaths = ['M12 2L2 7v10c0 5.55 3.84 10 9 11 5.16-1 9-5.45 9-11V7l-10-5z'];
|
|
101
|
+
<svg
|
|
102
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
103
|
+
width="24"
|
|
104
|
+
height="24"
|
|
105
|
+
fill="none"
|
|
106
|
+
stroke="currentColor"
|
|
107
|
+
>
|
|
108
|
+
<circle cx="12" cy="12" r="10" />
|
|
109
|
+
for (const pathData of dynamicPaths) {
|
|
110
|
+
<path d={pathData} />
|
|
111
|
+
}
|
|
112
|
+
<rect x="4" y="4" width="16" height="16" />
|
|
113
|
+
</svg>
|
|
114
|
+
</>;
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
render(App);
|
|
@@ -130,19 +134,20 @@ describe('SVG namespace handling', () => {
|
|
|
130
134
|
});
|
|
131
135
|
|
|
132
136
|
it('should handle nested SVG groups with for loops', () => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
137
|
+
function App() {
|
|
138
|
+
return <>
|
|
139
|
+
const items = [
|
|
140
|
+
{ x: '10', y: '10', width: '20', height: '20' },
|
|
141
|
+
{ x: '40', y: '40', width: '20', height: '20' },
|
|
142
|
+
];
|
|
143
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
|
144
|
+
<g fill="blue">
|
|
145
|
+
for (const item of items) {
|
|
146
|
+
<rect x={item.x} y={item.y} width={item.width} height={item.height} />
|
|
147
|
+
}
|
|
148
|
+
</g>
|
|
149
|
+
</svg>
|
|
150
|
+
</>;
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
render(App);
|
|
@@ -168,16 +173,17 @@ describe('SVG namespace handling', () => {
|
|
|
168
173
|
});
|
|
169
174
|
|
|
170
175
|
it('should handle SVG class attributes correctly', () => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
176
|
+
function App() {
|
|
177
|
+
return <>
|
|
178
|
+
let className = 'svg-element';
|
|
179
|
+
const paths = ['M10 10 L20 20'];
|
|
180
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" class={className}>
|
|
181
|
+
for (const pathData of paths) {
|
|
182
|
+
<path d={pathData} class="dynamic-path" />
|
|
183
|
+
}
|
|
184
|
+
<circle cx="50" cy="50" r="10" class={className} />
|
|
185
|
+
</svg>
|
|
186
|
+
</>;
|
|
181
187
|
}
|
|
182
188
|
|
|
183
189
|
render(App);
|
|
@@ -202,14 +208,16 @@ describe('SVG namespace handling', () => {
|
|
|
202
208
|
});
|
|
203
209
|
|
|
204
210
|
it('should handle namespace transitions with foreignObject', () => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
function App() {
|
|
212
|
+
return <>
|
|
213
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
|
|
214
|
+
<rect x="10" y="10" width="50" height="50" fill="red" />
|
|
215
|
+
<foreignObject x="100" y="100" width="80" height="80">
|
|
216
|
+
<div class="html-content">{'HTML inside SVG'}</div>
|
|
217
|
+
</foreignObject>
|
|
218
|
+
<circle cx="50" cy="150" r="20" fill="blue" />
|
|
219
|
+
</svg>
|
|
220
|
+
</>;
|
|
213
221
|
}
|
|
214
222
|
|
|
215
223
|
render(App);
|
|
@@ -232,21 +240,25 @@ describe('SVG namespace handling', () => {
|
|
|
232
240
|
});
|
|
233
241
|
|
|
234
242
|
it('should render SVG with children as svg elements', () => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
{
|
|
238
|
-
|
|
243
|
+
function SVG({ children }: PropsWithChildren<{}>) {
|
|
244
|
+
return <>
|
|
245
|
+
<svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
246
|
+
{children}
|
|
247
|
+
</svg>
|
|
248
|
+
</>;
|
|
239
249
|
}
|
|
240
250
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
function App() {
|
|
252
|
+
return <>
|
|
253
|
+
let isDiamond = true;
|
|
254
|
+
<SVG>
|
|
255
|
+
if (isDiamond) {
|
|
256
|
+
<polygon points="0,0 30,0 15,10" />
|
|
257
|
+
} else {
|
|
258
|
+
<polygon points="0,0 30,0 15,10" />
|
|
259
|
+
}
|
|
260
|
+
</SVG>
|
|
261
|
+
</>;
|
|
250
262
|
}
|
|
251
263
|
|
|
252
264
|
render(App);
|
|
@@ -259,18 +271,20 @@ describe('SVG namespace handling', () => {
|
|
|
259
271
|
});
|
|
260
272
|
|
|
261
273
|
it('should render SVG with props as svg elements', () => {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
<
|
|
265
|
-
|
|
274
|
+
function SVG({ Polygon }: PropsWithExtras<{ Polygon: Component }>) {
|
|
275
|
+
return <>
|
|
276
|
+
<svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
277
|
+
<Polygon />
|
|
278
|
+
</svg>
|
|
279
|
+
</>;
|
|
266
280
|
}
|
|
267
281
|
|
|
268
|
-
|
|
269
|
-
|
|
282
|
+
function App() {
|
|
283
|
+
return <><SVG {Polygon} /></>;
|
|
270
284
|
}
|
|
271
285
|
|
|
272
|
-
|
|
273
|
-
|
|
286
|
+
function Polygon() {
|
|
287
|
+
return <><polygon points="0,0 30,0 15,10" /></>;
|
|
274
288
|
}
|
|
275
289
|
|
|
276
290
|
render(App);
|
|
@@ -283,17 +297,21 @@ describe('SVG namespace handling', () => {
|
|
|
283
297
|
});
|
|
284
298
|
|
|
285
299
|
it('should render SVG with children as dynamic elements', () => {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
{
|
|
289
|
-
|
|
300
|
+
function SVG({ children }: PropsWithChildren<{}>) {
|
|
301
|
+
return <>
|
|
302
|
+
<svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
303
|
+
{children}
|
|
304
|
+
</svg>
|
|
305
|
+
</>;
|
|
290
306
|
}
|
|
291
307
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
308
|
+
function App() {
|
|
309
|
+
return <>
|
|
310
|
+
let &[dynTag] = track('polygon');
|
|
311
|
+
<SVG>
|
|
312
|
+
<@dynTag points="0,0 30,0 15,10" />
|
|
313
|
+
</SVG>
|
|
314
|
+
</>;
|
|
297
315
|
}
|
|
298
316
|
|
|
299
317
|
render(App);
|
|
@@ -306,21 +324,25 @@ describe('SVG namespace handling', () => {
|
|
|
306
324
|
});
|
|
307
325
|
|
|
308
326
|
it('should render SVG with children as dynamic components', () => {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
{
|
|
312
|
-
|
|
327
|
+
function SVG({ children }: PropsWithChildren<{}>) {
|
|
328
|
+
return <>
|
|
329
|
+
<svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
330
|
+
{children}
|
|
331
|
+
</svg>
|
|
332
|
+
</>;
|
|
313
333
|
}
|
|
314
334
|
|
|
315
|
-
|
|
316
|
-
|
|
335
|
+
function Polygon({ points }: PropsWithExtras<{ points: string }>) {
|
|
336
|
+
return <><polygon {points} /></>;
|
|
317
337
|
}
|
|
318
338
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
339
|
+
function App() {
|
|
340
|
+
return <>
|
|
341
|
+
let &[Component] = track(() => Polygon);
|
|
342
|
+
<SVG>
|
|
343
|
+
<@Component points="0,0 30,0 15,10" />
|
|
344
|
+
</SVG>
|
|
345
|
+
</>;
|
|
324
346
|
}
|
|
325
347
|
|
|
326
348
|
render(App);
|
|
@@ -333,23 +355,29 @@ describe('SVG namespace handling', () => {
|
|
|
333
355
|
});
|
|
334
356
|
|
|
335
357
|
it('should render SVG as a dynamic top element with any dynamic children elements', () => {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
{
|
|
340
|
-
|
|
358
|
+
function SVG({ children }: PropsWithChildren<{}>) {
|
|
359
|
+
return <>
|
|
360
|
+
let &[tag] = track('svg');
|
|
361
|
+
<@tag width={100} height={50} fill="red" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
362
|
+
{children}
|
|
363
|
+
</@tag>
|
|
364
|
+
</>;
|
|
341
365
|
}
|
|
342
366
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
367
|
+
function Polygon({ points }: PropsWithExtras<{ points: string }>) {
|
|
368
|
+
return <>
|
|
369
|
+
let &[dynTag] = track('polygon');
|
|
370
|
+
<@dynTag {points} />
|
|
371
|
+
</>;
|
|
346
372
|
}
|
|
347
373
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
374
|
+
function App() {
|
|
375
|
+
return <>
|
|
376
|
+
let &[Component] = track(() => Polygon);
|
|
377
|
+
<SVG>
|
|
378
|
+
<@Component points="0,0 30,0 15,10" />
|
|
379
|
+
</SVG>
|
|
380
|
+
</>;
|
|
353
381
|
}
|
|
354
382
|
|
|
355
383
|
render(App);
|
|
@@ -362,42 +390,43 @@ describe('SVG namespace handling', () => {
|
|
|
362
390
|
});
|
|
363
391
|
|
|
364
392
|
it('should compare static vs dynamic SVG rendering (original problem case)', () => {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
393
|
+
function App() {
|
|
394
|
+
return <>
|
|
395
|
+
const d = [
|
|
396
|
+
'm14 12 4 4 4-4',
|
|
397
|
+
'M18 16V7',
|
|
398
|
+
'm2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16',
|
|
399
|
+
'M3.304 13h6.392',
|
|
400
|
+
];
|
|
401
|
+
<div class="container">
|
|
402
|
+
<svg
|
|
403
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
404
|
+
width="24"
|
|
405
|
+
height="24"
|
|
406
|
+
fill="none"
|
|
407
|
+
stroke="currentColor"
|
|
408
|
+
class="dynamic-svg"
|
|
409
|
+
>
|
|
410
|
+
for (const path of d) {
|
|
411
|
+
<path d={path} />
|
|
412
|
+
}
|
|
413
|
+
</svg>
|
|
414
|
+
|
|
415
|
+
<svg
|
|
416
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
417
|
+
width="24"
|
|
418
|
+
height="24"
|
|
419
|
+
fill="none"
|
|
420
|
+
stroke="currentColor"
|
|
421
|
+
class="static-svg"
|
|
422
|
+
>
|
|
423
|
+
<path d="m14 12 4 4 4-4" />
|
|
424
|
+
<path d="M18 16V7" />
|
|
425
|
+
<path d="m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16" />
|
|
426
|
+
<path d="M3.304 13h6.392" />
|
|
427
|
+
</svg>
|
|
428
|
+
</div>
|
|
429
|
+
</>;
|
|
401
430
|
}
|
|
402
431
|
|
|
403
432
|
render(App);
|
|
@@ -440,25 +469,26 @@ describe('SVG namespace handling', () => {
|
|
|
440
469
|
});
|
|
441
470
|
|
|
442
471
|
it('should render dynamic SVG elements dispatched via a switch inside a for loop', () => {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
472
|
+
function App() {
|
|
473
|
+
return <>
|
|
474
|
+
const iconNodes: [string, Record<string, string>][] = [
|
|
475
|
+
['path', { d: 'm14 12 4 4 4-4' }],
|
|
476
|
+
['circle', { cx: '12', cy: '12', r: '4' }],
|
|
477
|
+
['path', { d: 'M18 16V7' }],
|
|
478
|
+
];
|
|
479
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
|
|
480
|
+
for (const [tag, attrs] of iconNodes) {
|
|
481
|
+
switch (tag) {
|
|
482
|
+
case 'path':
|
|
483
|
+
<path {...attrs} />
|
|
484
|
+
break;
|
|
485
|
+
case 'circle':
|
|
486
|
+
<circle {...attrs} />
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
459
489
|
}
|
|
460
|
-
|
|
461
|
-
|
|
490
|
+
</svg>
|
|
491
|
+
</>;
|
|
462
492
|
}
|
|
463
493
|
|
|
464
494
|
render(App);
|