ripple 0.3.3 → 0.3.4
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 +72 -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 +82 -174
- package/src/compiler/phases/2-analyze/prune.js +2 -2
- package/src/compiler/phases/3-transform/client/index.js +169 -261
- package/src/compiler/phases/3-transform/server/index.js +185 -42
- package/src/compiler/types/index.d.ts +14 -33
- 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/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 +185 -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/style-identifier.test.ripple +95 -16
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { flushSync, track } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('switch statements', () => {
|
|
4
4
|
it('renders simple switch with literal cases', () => {
|
|
5
5
|
component App() {
|
|
6
|
-
let value =
|
|
6
|
+
let value = track('b');
|
|
7
7
|
|
|
8
8
|
<button onClick={() => (@value = 'c')}>{'Change to C'}</button>
|
|
9
9
|
<button onClick={() => (@value = 'a')}>{'Change to A'}</button>
|
|
@@ -38,7 +38,7 @@ describe('switch statements', () => {
|
|
|
38
38
|
|
|
39
39
|
it('renders switch with reactive discriminant', () => {
|
|
40
40
|
component App() {
|
|
41
|
-
let count =
|
|
41
|
+
let count = track(1);
|
|
42
42
|
|
|
43
43
|
<button onClick={() => @count++}>{'Increment'}</button>
|
|
44
44
|
|
|
@@ -70,7 +70,7 @@ describe('switch statements', () => {
|
|
|
70
70
|
|
|
71
71
|
it('renders switch with default clause only', () => {
|
|
72
72
|
component App() {
|
|
73
|
-
let value =
|
|
73
|
+
let value = track('x');
|
|
74
74
|
|
|
75
75
|
<button onClick={() => (@value = 'y')}>{'Change Value'}</button>
|
|
76
76
|
|
|
@@ -91,7 +91,7 @@ describe('switch statements', () => {
|
|
|
91
91
|
|
|
92
92
|
it('renders switch using empty case fall-through', () => {
|
|
93
93
|
component App() {
|
|
94
|
-
let value =
|
|
94
|
+
let value = track('a');
|
|
95
95
|
|
|
96
96
|
<button onClick={() => (@value = 'b')}>{'Change to B'}</button>
|
|
97
97
|
<button onClick={() => (@value = 'c')}>{'Change to C'}</button>
|
|
@@ -133,8 +133,8 @@ describe('switch statements', () => {
|
|
|
133
133
|
|
|
134
134
|
it('renders switch with template content and reacts to tracked changes', () => {
|
|
135
135
|
component App() {
|
|
136
|
-
let status =
|
|
137
|
-
let message =
|
|
136
|
+
let status = track('active');
|
|
137
|
+
let message = track('');
|
|
138
138
|
|
|
139
139
|
<button onClick={() => (@status = 'pending')}>{'Pending'}</button>
|
|
140
140
|
<button onClick={() => (@status = 'completed')}>{'Completed'}</button>
|
|
@@ -185,7 +185,7 @@ describe('switch statements', () => {
|
|
|
185
185
|
'renders switch with multiple non-empty fall-through cases and reacts to tracked changes without recreating DOM unnecessarily',
|
|
186
186
|
() => {
|
|
187
187
|
component App() {
|
|
188
|
-
let status =
|
|
188
|
+
let status = track(0);
|
|
189
189
|
<div>
|
|
190
190
|
switch (@status) {
|
|
191
191
|
case -1:
|
|
@@ -253,7 +253,7 @@ describe('switch statements', () => {
|
|
|
253
253
|
'renders a fall-through default in the middle of switch cases and reacts to changes without recreating DOM unnecessarily',
|
|
254
254
|
() => {
|
|
255
255
|
component App() {
|
|
256
|
-
let value =
|
|
256
|
+
let value = track('x');
|
|
257
257
|
|
|
258
258
|
<button onClick={() => (@value = 'a')}>{'Set A'}</button>
|
|
259
259
|
<button onClick={() => (@value = 'b')}>{'Set B'}</button>
|
|
@@ -359,7 +359,7 @@ describe('switch statements', () => {
|
|
|
359
359
|
|
|
360
360
|
it('renders switch with block-scoped cases and break inside blocks', () => {
|
|
361
361
|
component App() {
|
|
362
|
-
let level =
|
|
362
|
+
let level = track(1);
|
|
363
363
|
|
|
364
364
|
<button
|
|
365
365
|
onClick={() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bindValue, flushSync,
|
|
1
|
+
import { RippleArray, bindValue, flushSync, track } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('try block with catch and pending', () => {
|
|
4
4
|
it('catch block works when component throws before await with pending block', async () => {
|
|
@@ -88,7 +88,7 @@ describe('try block', () => {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
component Child() {
|
|
91
|
-
let value =
|
|
91
|
+
let value = track(1);
|
|
92
92
|
await Promise.resolve(@value + 1);
|
|
93
93
|
|
|
94
94
|
<input type="number" {ref bindValue(value)} />
|
|
@@ -140,7 +140,7 @@ describe('try block', () => {
|
|
|
140
140
|
'does not crash when async component with tracked state is used inside try/pending',
|
|
141
141
|
async () => {
|
|
142
142
|
component App() {
|
|
143
|
-
let query =
|
|
143
|
+
let query = track('');
|
|
144
144
|
|
|
145
145
|
try {
|
|
146
146
|
<FilteredList {query} />
|
|
@@ -152,7 +152,7 @@ describe('try block', () => {
|
|
|
152
152
|
component FilteredList({ query }: { query: any }) {
|
|
153
153
|
let items = await Promise.resolve(['apple', 'banana', 'cherry']);
|
|
154
154
|
let list = RippleArray.from(items);
|
|
155
|
-
let filtered =
|
|
155
|
+
let filtered = track(() => list.filter((item: string) => item.includes(@query)));
|
|
156
156
|
|
|
157
157
|
<ul>
|
|
158
158
|
for (let item of @filtered) {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { RippleURL, flushSync, track } from 'ripple';
|
|
3
2
|
|
|
4
3
|
describe('RippleURL > derived', () => {
|
|
5
4
|
it('handles reactive computed properties based on URL', () => {
|
|
6
5
|
component URLTest() {
|
|
7
|
-
const url =
|
|
8
|
-
let userId =
|
|
9
|
-
let activeTab =
|
|
6
|
+
const url = RippleURL('https://example.com/users/123?tab=profile');
|
|
7
|
+
let userId = track(() => url.pathname.split('/').pop());
|
|
8
|
+
let activeTab = track(() => url.searchParams.get('tab'));
|
|
10
9
|
|
|
11
10
|
<button onClick={() => (url.pathname = '/users/456')}>{'Change User'}</button>
|
|
12
11
|
<button onClick={() => url.searchParams.set('tab', 'settings')}>{'Change Tab'}</button>
|
|
@@ -40,7 +39,7 @@ describe('RippleURL > derived', () => {
|
|
|
40
39
|
|
|
41
40
|
it('maintains reactivity across multiple components', () => {
|
|
42
41
|
component ParentTest() {
|
|
43
|
-
const url =
|
|
42
|
+
const url = RippleURL('https://example.com/path?count=0');
|
|
44
43
|
|
|
45
44
|
<ChildA {url} />
|
|
46
45
|
<ChildB {url} />
|
|
@@ -58,7 +57,7 @@ describe('RippleURL > derived', () => {
|
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
component ChildB({ url }: { url: RippleURL }) {
|
|
61
|
-
let count =
|
|
60
|
+
let count = track(() => url.searchParams.get('count'));
|
|
62
61
|
|
|
63
62
|
<pre>{url.href}</pre>
|
|
64
63
|
<pre>{@count}</pre>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { RippleURL, flushSync } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('RippleURL > parsing', () => {
|
|
4
4
|
it('creates URL from string with reactivity', () => {
|
|
5
5
|
component URLTest() {
|
|
6
|
-
const url =
|
|
6
|
+
const url = RippleURL('https://example.com:8080/path?foo=bar#section');
|
|
7
7
|
|
|
8
8
|
<pre>{url.href}</pre>
|
|
9
9
|
<pre>{url.protocol}</pre>
|
|
@@ -29,7 +29,7 @@ describe('RippleURL > parsing', () => {
|
|
|
29
29
|
|
|
30
30
|
it('creates URL from string with base URL', () => {
|
|
31
31
|
component URLTest() {
|
|
32
|
-
const url =
|
|
32
|
+
const url = RippleURL('/path?query=value', 'https://example.com');
|
|
33
33
|
|
|
34
34
|
<pre>{url.href}</pre>
|
|
35
35
|
<pre>{url.origin}</pre>
|
|
@@ -45,7 +45,7 @@ describe('RippleURL > parsing', () => {
|
|
|
45
45
|
|
|
46
46
|
it('handles URL encoding correctly', () => {
|
|
47
47
|
component URLTest() {
|
|
48
|
-
const url =
|
|
48
|
+
const url = RippleURL('https://example.com/path with spaces?key=value with spaces');
|
|
49
49
|
|
|
50
50
|
<pre>{url.pathname}</pre>
|
|
51
51
|
<pre>{url.search}</pre>
|
|
@@ -63,7 +63,7 @@ describe('RippleURL > parsing', () => {
|
|
|
63
63
|
|
|
64
64
|
it('handles URL with file protocol', () => {
|
|
65
65
|
component URLTest() {
|
|
66
|
-
const url =
|
|
66
|
+
const url = RippleURL('file:///Users/username/documents/file.txt');
|
|
67
67
|
|
|
68
68
|
<pre>{url.protocol}</pre>
|
|
69
69
|
<pre>{url.pathname}</pre>
|
|
@@ -83,7 +83,7 @@ describe('RippleURL > parsing', () => {
|
|
|
83
83
|
|
|
84
84
|
it('handles URL with IPv4 address', () => {
|
|
85
85
|
component URLTest() {
|
|
86
|
-
const url =
|
|
86
|
+
const url = RippleURL('https://192.168.1.1:8080/path');
|
|
87
87
|
|
|
88
88
|
<button onClick={() => (url.hostname = '10.0.0.1')}>{'Change IP'}</button>
|
|
89
89
|
<pre>{url.href}</pre>
|
|
@@ -108,7 +108,7 @@ describe('RippleURL > parsing', () => {
|
|
|
108
108
|
|
|
109
109
|
it('handles URL with localhost', () => {
|
|
110
110
|
component URLTest() {
|
|
111
|
-
const url =
|
|
111
|
+
const url = RippleURL('http://localhost:3000/api/data');
|
|
112
112
|
|
|
113
113
|
<button onClick={() => (url.port = '8080')}>{'Change Port'}</button>
|
|
114
114
|
<pre>{url.href}</pre>
|
|
@@ -136,7 +136,7 @@ describe('RippleURL > parsing', () => {
|
|
|
136
136
|
|
|
137
137
|
it('handles URL with multiple path segments', () => {
|
|
138
138
|
component URLTest() {
|
|
139
|
-
const url =
|
|
139
|
+
const url = RippleURL('https://example.com/api/v1/users/123/profile');
|
|
140
140
|
|
|
141
141
|
<button onClick={() => (url.pathname = '/api/v2/users/456/settings')}>{'Change Path'}</button>
|
|
142
142
|
<pre>{url.pathname}</pre>
|
|
@@ -165,7 +165,7 @@ describe('RippleURL > parsing', () => {
|
|
|
165
165
|
|
|
166
166
|
it('handles relative URL paths correctly', () => {
|
|
167
167
|
component URLTest() {
|
|
168
|
-
const url =
|
|
168
|
+
const url = RippleURL('../sibling/path', 'https://example.com/parent/current');
|
|
169
169
|
|
|
170
170
|
<pre>{url.href}</pre>
|
|
171
171
|
<pre>{url.pathname}</pre>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { RippleURL, flushSync } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('RippleURL > partials/removal', () => {
|
|
4
4
|
it('handles URL with no port specified', () => {
|
|
5
5
|
component URLTest() {
|
|
6
|
-
const url =
|
|
6
|
+
const url = RippleURL('https://example.com/path');
|
|
7
7
|
|
|
8
8
|
<pre>{url.port}</pre>
|
|
9
9
|
<pre>{url.host}</pre>
|
|
@@ -28,7 +28,7 @@ describe('RippleURL > partials/removal', () => {
|
|
|
28
28
|
|
|
29
29
|
it('handles URL with no search params', () => {
|
|
30
30
|
component URLTest() {
|
|
31
|
-
const url =
|
|
31
|
+
const url = RippleURL('https://example.com/path');
|
|
32
32
|
|
|
33
33
|
<pre>{url.search}</pre>
|
|
34
34
|
<pre>{url.searchParams.size}</pre>
|
|
@@ -53,7 +53,7 @@ describe('RippleURL > partials/removal', () => {
|
|
|
53
53
|
|
|
54
54
|
it('handles URL with no hash', () => {
|
|
55
55
|
component URLTest() {
|
|
56
|
-
const url =
|
|
56
|
+
const url = RippleURL('https://example.com/path');
|
|
57
57
|
|
|
58
58
|
<pre>{url.hash}</pre>
|
|
59
59
|
<button onClick={() => (url.hash = '#section')}>{'Add Hash'}</button>
|
|
@@ -75,7 +75,7 @@ describe('RippleURL > partials/removal', () => {
|
|
|
75
75
|
|
|
76
76
|
it('handles removing port by setting empty string', () => {
|
|
77
77
|
component URLTest() {
|
|
78
|
-
const url =
|
|
78
|
+
const url = RippleURL('https://example.com:8080/path');
|
|
79
79
|
|
|
80
80
|
<button onClick={() => (url.port = '')}>{'Remove Port'}</button>
|
|
81
81
|
<pre>{url.href}</pre>
|
|
@@ -100,7 +100,7 @@ describe('RippleURL > partials/removal', () => {
|
|
|
100
100
|
|
|
101
101
|
it('handles removing hash by setting empty string', () => {
|
|
102
102
|
component URLTest() {
|
|
103
|
-
const url =
|
|
103
|
+
const url = RippleURL('https://example.com/path#section');
|
|
104
104
|
|
|
105
105
|
<button onClick={() => (url.hash = '')}>{'Remove Hash'}</button>
|
|
106
106
|
<pre>{url.href}</pre>
|
|
@@ -127,7 +127,7 @@ describe('RippleURL > partials/removal', () => {
|
|
|
127
127
|
|
|
128
128
|
it('handles removing search by setting empty string', () => {
|
|
129
129
|
component URLTest() {
|
|
130
|
-
const url =
|
|
130
|
+
const url = RippleURL('https://example.com/path?foo=bar');
|
|
131
131
|
|
|
132
132
|
<button onClick={() => (url.search = '')}>{'Remove Search'}</button>
|
|
133
133
|
<pre>{url.href}</pre>
|
|
@@ -157,7 +157,7 @@ describe('RippleURL > partials/removal', () => {
|
|
|
157
157
|
|
|
158
158
|
it('handles hash without leading # character', () => {
|
|
159
159
|
component URLTest() {
|
|
160
|
-
const url =
|
|
160
|
+
const url = RippleURL('https://example.com/path');
|
|
161
161
|
|
|
162
162
|
<button onClick={() => (url.hash = 'section')}>{'Set Hash'}</button>
|
|
163
163
|
<pre>{url.hash}</pre>
|
|
@@ -183,7 +183,7 @@ describe('RippleURL > partials/removal', () => {
|
|
|
183
183
|
|
|
184
184
|
it('handles search without leading ? character', () => {
|
|
185
185
|
component URLTest() {
|
|
186
|
-
const url =
|
|
186
|
+
const url = RippleURL('https://example.com/path');
|
|
187
187
|
|
|
188
188
|
<button onClick={() => (url.search = 'foo=bar')}>{'Set Search'}</button>
|
|
189
189
|
<pre>{url.search}</pre>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { RippleURL, flushSync } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('RippleURL > reactivity', () => {
|
|
4
4
|
it('handles protocol changes with reactivity', () => {
|
|
5
5
|
component URLTest() {
|
|
6
|
-
const url =
|
|
6
|
+
const url = RippleURL('https://example.com/path');
|
|
7
7
|
|
|
8
8
|
<button onClick={() => (url.protocol = 'http:')}>{'Change Protocol'}</button>
|
|
9
9
|
<pre>{url.href}</pre>
|
|
@@ -31,7 +31,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
31
31
|
|
|
32
32
|
it('handles hostname changes with reactivity', () => {
|
|
33
33
|
component URLTest() {
|
|
34
|
-
const url =
|
|
34
|
+
const url = RippleURL('https://example.com/path');
|
|
35
35
|
|
|
36
36
|
<button onClick={() => (url.hostname = 'newdomain.com')}>{'Change Hostname'}</button>
|
|
37
37
|
<pre>{url.href}</pre>
|
|
@@ -59,7 +59,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
59
59
|
|
|
60
60
|
it('handles port changes with reactivity', () => {
|
|
61
61
|
component URLTest() {
|
|
62
|
-
const url =
|
|
62
|
+
const url = RippleURL('https://example.com:8080/path');
|
|
63
63
|
|
|
64
64
|
<button onClick={() => (url.port = '9090')}>{'Change Port'}</button>
|
|
65
65
|
<pre>{url.href}</pre>
|
|
@@ -87,7 +87,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
87
87
|
|
|
88
88
|
it('handles host changes with reactivity', () => {
|
|
89
89
|
component URLTest() {
|
|
90
|
-
const url =
|
|
90
|
+
const url = RippleURL('https://example.com:8080/path');
|
|
91
91
|
|
|
92
92
|
<button onClick={() => (url.host = 'newdomain.com:9090')}>{'Change Host'}</button>
|
|
93
93
|
<pre>{url.href}</pre>
|
|
@@ -120,7 +120,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
120
120
|
|
|
121
121
|
it('handles pathname changes with reactivity', () => {
|
|
122
122
|
component URLTest() {
|
|
123
|
-
const url =
|
|
123
|
+
const url = RippleURL('https://example.com/old-path');
|
|
124
124
|
|
|
125
125
|
<button onClick={() => (url.pathname = '/new-path')}>{'Change Pathname'}</button>
|
|
126
126
|
<pre>{url.href}</pre>
|
|
@@ -145,7 +145,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
145
145
|
|
|
146
146
|
it('handles search changes with reactivity', () => {
|
|
147
147
|
component URLTest() {
|
|
148
|
-
const url =
|
|
148
|
+
const url = RippleURL('https://example.com/path?foo=bar');
|
|
149
149
|
|
|
150
150
|
<button onClick={() => (url.search = '?baz=qux')}>{'Change Search'}</button>
|
|
151
151
|
<pre>{url.href}</pre>
|
|
@@ -174,7 +174,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
174
174
|
|
|
175
175
|
it('handles hash changes with reactivity', () => {
|
|
176
176
|
component URLTest() {
|
|
177
|
-
const url =
|
|
177
|
+
const url = RippleURL('https://example.com/path#section1');
|
|
178
178
|
|
|
179
179
|
<button onClick={() => (url.hash = '#section2')}>{'Change Hash'}</button>
|
|
180
180
|
<pre>{url.href}</pre>
|
|
@@ -203,7 +203,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
203
203
|
|
|
204
204
|
it('handles username changes with reactivity', () => {
|
|
205
205
|
component URLTest() {
|
|
206
|
-
const url =
|
|
206
|
+
const url = RippleURL('https://user:pass@example.com/path');
|
|
207
207
|
|
|
208
208
|
<button onClick={() => (url.username = 'newuser')}>{'Change Username'}</button>
|
|
209
209
|
<pre>{url.href}</pre>
|
|
@@ -232,7 +232,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
232
232
|
|
|
233
233
|
it('handles password changes with reactivity', () => {
|
|
234
234
|
component URLTest() {
|
|
235
|
-
const url =
|
|
235
|
+
const url = RippleURL('https://user:pass@example.com/path');
|
|
236
236
|
|
|
237
237
|
<button onClick={() => (url.password = 'newpass')}>{'Change Password'}</button>
|
|
238
238
|
<pre>{url.href}</pre>
|
|
@@ -261,7 +261,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
261
261
|
|
|
262
262
|
it('handles href changes with reactivity', () => {
|
|
263
263
|
component URLTest() {
|
|
264
|
-
const url =
|
|
264
|
+
const url = RippleURL('https://example.com/path?foo=bar#section');
|
|
265
265
|
|
|
266
266
|
<button onClick={() => (url.href = 'https://newdomain.com:9090/newpath?baz=qux#newsection')}>
|
|
267
267
|
{'Change Href'}
|
|
@@ -307,7 +307,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
307
307
|
|
|
308
308
|
it('handles origin property reactivity', () => {
|
|
309
309
|
component URLTest() {
|
|
310
|
-
const url =
|
|
310
|
+
const url = RippleURL('https://example.com:8080/path');
|
|
311
311
|
|
|
312
312
|
<button onClick={() => (url.protocol = 'http:')}>{'Change Protocol'}</button>
|
|
313
313
|
<button onClick={() => (url.hostname = 'newdomain.com')}>{'Change Hostname'}</button>
|
|
@@ -339,7 +339,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
339
339
|
});
|
|
340
340
|
it('handles searchParams changes with reactivity', () => {
|
|
341
341
|
component URLTest() {
|
|
342
|
-
const url =
|
|
342
|
+
const url = RippleURL('https://example.com/path?foo=bar');
|
|
343
343
|
const params = url.searchParams;
|
|
344
344
|
|
|
345
345
|
<button onClick={() => params.set('foo', 'updated')}>{'Update Foo'}</button>
|
|
@@ -383,7 +383,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
383
383
|
|
|
384
384
|
it('handles search property updates reflected in searchParams', () => {
|
|
385
385
|
component URLTest() {
|
|
386
|
-
const url =
|
|
386
|
+
const url = RippleURL('https://example.com/path?foo=bar');
|
|
387
387
|
const params = url.searchParams;
|
|
388
388
|
|
|
389
389
|
<button onClick={() => (url.search = '?baz=qux&test=value')}>{'Change Search'}</button>
|
|
@@ -418,7 +418,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
418
418
|
|
|
419
419
|
it('handles multiple URL property changes in sequence', () => {
|
|
420
420
|
component URLTest() {
|
|
421
|
-
const url =
|
|
421
|
+
const url = RippleURL('https://example.com/path');
|
|
422
422
|
|
|
423
423
|
<button
|
|
424
424
|
onClick={() => {
|
|
@@ -453,7 +453,7 @@ describe('RippleURL > reactivity', () => {
|
|
|
453
453
|
|
|
454
454
|
it('handles href change updates all properties and searchParams', () => {
|
|
455
455
|
component URLTest() {
|
|
456
|
-
const url =
|
|
456
|
+
const url = RippleURL('https://old.com/old?foo=bar#old');
|
|
457
457
|
const params = url.searchParams;
|
|
458
458
|
|
|
459
459
|
<button onClick={() => (url.href = 'https://new.com:9090/new?baz=qux#new')}>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { RippleURL, flushSync } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('RippleURL > serialization', () => {
|
|
4
4
|
it('handles toString method', () => {
|
|
5
5
|
component URLTest() {
|
|
6
|
-
const url =
|
|
6
|
+
const url = RippleURL('https://example.com/path?foo=bar#section');
|
|
7
7
|
|
|
8
8
|
<button onClick={() => (url.pathname = '/newpath')}>{'Change Pathname'}</button>
|
|
9
9
|
<pre>{url.toString()}</pre>
|
|
@@ -29,7 +29,7 @@ describe('RippleURL > serialization', () => {
|
|
|
29
29
|
|
|
30
30
|
it('handles toJSON method', () => {
|
|
31
31
|
component URLTest() {
|
|
32
|
-
const url =
|
|
32
|
+
const url = RippleURL('https://example.com/path?foo=bar');
|
|
33
33
|
|
|
34
34
|
<button onClick={() => (url.pathname = '/api')}>{'Change Pathname'}</button>
|
|
35
35
|
<pre>{url.toJSON()}</pre>
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { RippleURL, RippleURLSearchParams, flushSync, track } from 'ripple';
|
|
3
2
|
|
|
4
3
|
describe('RippleURLSearchParams > derived', () => {
|
|
5
4
|
it('handles reactive computed properties based on search params', () => {
|
|
6
5
|
component URLTest() {
|
|
7
|
-
const params =
|
|
8
|
-
let page =
|
|
9
|
-
let limit =
|
|
10
|
-
let offset =
|
|
6
|
+
const params = RippleURLSearchParams('page=1&limit=10');
|
|
7
|
+
let page = track(() => parseInt(params.get('page') || '1', 10));
|
|
8
|
+
let limit = track(() => parseInt(params.get('limit') || '10', 10));
|
|
9
|
+
let offset = track(() => (@page - 1) * @limit);
|
|
11
10
|
|
|
12
11
|
<button onClick={() => params.set('page', '2')}>{'next page'}</button>
|
|
13
12
|
<button onClick={() => params.set('page', '1')}>{'first page'}</button>
|
|
@@ -45,7 +44,7 @@ describe('RippleURLSearchParams > derived', () => {
|
|
|
45
44
|
|
|
46
45
|
it('maintains reactivity across multiple components', () => {
|
|
47
46
|
component ParentTest() {
|
|
48
|
-
const params =
|
|
47
|
+
const params = RippleURLSearchParams('count=0');
|
|
49
48
|
|
|
50
49
|
<ChildA {params} />
|
|
51
50
|
<ChildB {params} />
|
|
@@ -63,7 +62,7 @@ describe('RippleURLSearchParams > derived', () => {
|
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
component ChildB({ params }: { params: RippleURLSearchParams }) {
|
|
66
|
-
let count =
|
|
65
|
+
let count = track(() => params.get('count'));
|
|
67
66
|
|
|
68
67
|
<pre>{@count}</pre>
|
|
69
68
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { RippleURL, RippleURLSearchParams } from 'ripple';
|
|
2
|
+
|
|
1
3
|
describe('RippleURLSearchParams > initialization', () => {
|
|
2
4
|
it('creates empty URLSearchParams with reactivity', () => {
|
|
3
5
|
component URLTest() {
|
|
4
|
-
const params =
|
|
6
|
+
const params = RippleURLSearchParams();
|
|
5
7
|
|
|
6
8
|
<pre>{params.toString()}</pre>
|
|
7
9
|
<pre>{params.size}</pre>
|
|
@@ -15,7 +17,7 @@ describe('RippleURLSearchParams > initialization', () => {
|
|
|
15
17
|
|
|
16
18
|
it('creates URLSearchParams from string with reactivity', () => {
|
|
17
19
|
component URLTest() {
|
|
18
|
-
const params =
|
|
20
|
+
const params = RippleURLSearchParams('foo=bar&baz=qux');
|
|
19
21
|
|
|
20
22
|
<pre>{params.toString()}</pre>
|
|
21
23
|
<pre>{params.size}</pre>
|
|
@@ -31,7 +33,7 @@ describe('RippleURLSearchParams > initialization', () => {
|
|
|
31
33
|
|
|
32
34
|
it('creates URLSearchParams from object with reactivity', () => {
|
|
33
35
|
component URLTest() {
|
|
34
|
-
const params =
|
|
36
|
+
const params = RippleURLSearchParams({ foo: 'bar', baz: 'qux' });
|
|
35
37
|
|
|
36
38
|
<pre>{params.toString()}</pre>
|
|
37
39
|
<pre>{params.size}</pre>
|
|
@@ -45,7 +47,7 @@ describe('RippleURLSearchParams > initialization', () => {
|
|
|
45
47
|
|
|
46
48
|
it('handles URL-encoded characters correctly', () => {
|
|
47
49
|
component URLTest() {
|
|
48
|
-
const params =
|
|
50
|
+
const params = RippleURLSearchParams('name=John+Doe&email=john%40example.com');
|
|
49
51
|
|
|
50
52
|
<pre>{params.get('name')}</pre>
|
|
51
53
|
<pre>{params.get('email')}</pre>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { flushSync } from 'ripple';
|
|
1
|
+
import { RippleURL, RippleURLSearchParams, flushSync, track } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('RippleURLSearchParams > iteration', () => {
|
|
4
4
|
it('handles keys method with reactivity', () => {
|
|
5
5
|
component URLTest() {
|
|
6
|
-
const params =
|
|
7
|
-
let keys =
|
|
6
|
+
const params = RippleURLSearchParams('foo=bar&baz=qux');
|
|
7
|
+
let keys = track(() => Array.from(params.keys()));
|
|
8
8
|
|
|
9
9
|
<button onClick={() => params.append('new', 'value')}>{'add param'}</button>
|
|
10
10
|
<pre>{JSON.stringify(@keys)}</pre>
|
|
@@ -26,8 +26,8 @@ describe('RippleURLSearchParams > iteration', () => {
|
|
|
26
26
|
|
|
27
27
|
it('handles values method with reactivity', () => {
|
|
28
28
|
component URLTest() {
|
|
29
|
-
const params =
|
|
30
|
-
let values =
|
|
29
|
+
const params = RippleURLSearchParams('foo=bar&baz=qux');
|
|
30
|
+
let values = track(() => Array.from(params.values()));
|
|
31
31
|
|
|
32
32
|
<button onClick={() => params.set('foo', 'updated')}>{'update foo'}</button>
|
|
33
33
|
<pre>{JSON.stringify(@values)}</pre>
|
|
@@ -49,8 +49,8 @@ describe('RippleURLSearchParams > iteration', () => {
|
|
|
49
49
|
|
|
50
50
|
it('handles entries method with reactivity', () => {
|
|
51
51
|
component URLTest() {
|
|
52
|
-
const params =
|
|
53
|
-
let entries =
|
|
52
|
+
const params = RippleURLSearchParams('foo=bar&baz=qux');
|
|
53
|
+
let entries = track(() => Array.from(params.entries()));
|
|
54
54
|
|
|
55
55
|
<button onClick={() => params.append('new', 'value')}>{'add param'}</button>
|
|
56
56
|
<pre>{JSON.stringify(@entries)}</pre>
|
|
@@ -74,8 +74,8 @@ describe('RippleURLSearchParams > iteration', () => {
|
|
|
74
74
|
|
|
75
75
|
it('handles Symbol.iterator with reactivity', () => {
|
|
76
76
|
component URLTest() {
|
|
77
|
-
const params =
|
|
78
|
-
let entries =
|
|
77
|
+
const params = RippleURLSearchParams('foo=bar&baz=qux');
|
|
78
|
+
let entries = track(() => Array.from(params));
|
|
79
79
|
|
|
80
80
|
<button onClick={() => params.delete('foo')}>{'delete foo'}</button>
|
|
81
81
|
<pre>{JSON.stringify(@entries)}</pre>
|
|
@@ -97,7 +97,7 @@ describe('RippleURLSearchParams > iteration', () => {
|
|
|
97
97
|
|
|
98
98
|
it('handles iteration with for...of', () => {
|
|
99
99
|
component URLTest() {
|
|
100
|
-
const params =
|
|
100
|
+
const params = RippleURLSearchParams('foo=bar&baz=qux');
|
|
101
101
|
|
|
102
102
|
<button onClick={() => params.append('new', 'value')}>{'add param'}</button>
|
|
103
103
|
|
|
@@ -125,8 +125,8 @@ describe('RippleURLSearchParams > iteration', () => {
|
|
|
125
125
|
|
|
126
126
|
it('handles forEach iteration', () => {
|
|
127
127
|
component URLTest() {
|
|
128
|
-
const params =
|
|
129
|
-
let sum =
|
|
128
|
+
const params = RippleURLSearchParams('a=1&b=2&c=3');
|
|
129
|
+
let sum = track(() => {
|
|
130
130
|
let total = 0;
|
|
131
131
|
// Access the params reactively through entries
|
|
132
132
|
for (const [key, value] of params.entries()) {
|