-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
445 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"svelte": patch | ||
--- | ||
|
||
feat: reactive url |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { ReactiveDate as Date } from './date.js'; | ||
export { ReactiveSet as Set } from './set.js'; | ||
export { ReactiveMap as Map } from './map.js'; | ||
export { ReactiveURL as URL, ReactiveURLSearchParams as URLSearchParams } from './url.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
export const Date = globalThis.Date; | ||
export const Set = globalThis.Set; | ||
export const Map = globalThis.Map; | ||
export const URL = globalThis.URL; | ||
export const URLSearchParams = globalThis.URLSearchParams; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,287 @@ | ||
import { source, set } from '../internal/client/reactivity/sources.js'; | ||
import { get } from '../internal/client/runtime.js'; | ||
import { map } from './utils.js'; | ||
|
||
const UPDATE = Symbol.for('UPDATE'); | ||
|
||
export class ReactiveURL extends URL { | ||
#url = { | ||
protocol: source(super.protocol), | ||
username: source(super.username), | ||
password: source(super.password), | ||
hostname: source(super.hostname), | ||
port: source(super.port), | ||
pathname: source(super.pathname), | ||
search: source(super.search), | ||
hash: source(super.hash) | ||
}; | ||
#searchParams = new ReactiveURLSearchParams(super.searchParams, this.#url.search); | ||
|
||
get hash() { | ||
get(this.#url.hash); | ||
return super.hash; | ||
} | ||
|
||
set hash(value) { | ||
super.hash = value; | ||
set(this.#url.hash, super.hash); | ||
} | ||
|
||
get host() { | ||
get(this.#url.hostname); | ||
get(this.#url.port); | ||
return super.host; | ||
} | ||
|
||
set host(value) { | ||
super.host = value; | ||
set(this.#url.hostname, super.hostname); | ||
set(this.#url.port, super.port); | ||
} | ||
|
||
get hostname() { | ||
get(this.#url.hostname); | ||
return super.hostname; | ||
} | ||
|
||
set hostname(value) { | ||
super.hostname = value; | ||
set(this.#url.hostname, super.hostname); | ||
} | ||
|
||
get href() { | ||
get(this.#url.protocol); | ||
get(this.#url.username); | ||
get(this.#url.password); | ||
get(this.#url.hostname); | ||
get(this.#url.port); | ||
get(this.#url.pathname); | ||
get(this.#url.search); | ||
get(this.#url.hash); | ||
return super.href; | ||
} | ||
|
||
set href(value) { | ||
super.href = value; | ||
set(this.#url.protocol, super.protocol); | ||
set(this.#url.username, super.username); | ||
set(this.#url.password, super.password); | ||
set(this.#url.hostname, super.hostname); | ||
set(this.#url.port, super.port); | ||
set(this.#url.pathname, super.pathname); | ||
set(this.#url.search, super.search); | ||
set(this.#url.hash, super.hash); | ||
this.#searchParams[UPDATE](super.searchParams); | ||
} | ||
|
||
get password() { | ||
get(this.#url.password); | ||
return super.password; | ||
} | ||
|
||
set password(value) { | ||
super.password = value; | ||
set(this.#url.password, super.password); | ||
} | ||
|
||
get pathname() { | ||
get(this.#url.pathname); | ||
return super.pathname; | ||
} | ||
|
||
set pathname(value) { | ||
super.pathname = value; | ||
set(this.#url.pathname, super.pathname); | ||
} | ||
|
||
get port() { | ||
get(this.#url.port); | ||
return super.port; | ||
} | ||
|
||
set port(value) { | ||
super.port = value; | ||
set(this.#url.port, super.port); | ||
} | ||
|
||
get protocol() { | ||
get(this.#url.protocol); | ||
return super.protocol; | ||
} | ||
|
||
set protocol(value) { | ||
super.protocol = value; | ||
set(this.#url.protocol, super.protocol); | ||
} | ||
|
||
get search() { | ||
get(this.#url.search); | ||
return super.search; | ||
} | ||
|
||
set search(value) { | ||
super.search = value; | ||
set(this.#url.search, super.search); | ||
this.#searchParams[UPDATE](super.searchParams); | ||
} | ||
|
||
get username() { | ||
get(this.#url.username); | ||
return super.username; | ||
} | ||
|
||
set username(value) { | ||
super.username = value; | ||
set(this.#url.username, super.username); | ||
} | ||
|
||
get origin() { | ||
get(this.#url.protocol); | ||
get(this.#url.hostname); | ||
get(this.#url.port); | ||
return super.origin; | ||
} | ||
|
||
get searchParams() { | ||
return this.#searchParams; | ||
} | ||
|
||
toString() { | ||
this.href; | ||
return super.toString(); | ||
} | ||
|
||
toJSON() { | ||
this.href; | ||
return super.toJSON(); | ||
} | ||
|
||
/** | ||
* @param {string} input | ||
* @param {string=} base | ||
*/ | ||
constructor(input, base) { | ||
super(input, base); | ||
} | ||
} | ||
|
||
export class ReactiveURLSearchParams extends URLSearchParams { | ||
#url_search_params; | ||
#search; | ||
#version = source(0); | ||
|
||
#increment_version() { | ||
set(this.#version, this.#version.v + 1); | ||
} | ||
#update_search() { | ||
set(this.#search, '?' + this.#url_search_params.toString()); | ||
} | ||
|
||
/** | ||
* | ||
* @param {URLSearchParams} value | ||
*/ | ||
[UPDATE](value) { | ||
this.#url_search_params = value; | ||
this.#increment_version(); | ||
} | ||
/** | ||
* | ||
* @param {URLSearchParams} url_search_params | ||
* @param {import('../internal/client/reactivity/types.js').Source<string>} search | ||
*/ | ||
constructor(url_search_params, search) { | ||
super(); | ||
this.#url_search_params = url_search_params; | ||
this.#search = search; | ||
} | ||
|
||
/** | ||
* | ||
* @param {string} name | ||
* @param {string} value | ||
* @returns {void} | ||
*/ | ||
append(name, value) { | ||
this.#increment_version(); | ||
this.#update_search(); | ||
return this.#url_search_params.append(name, value); | ||
} | ||
/** | ||
* | ||
* @param {string} name | ||
* @param {string=} value | ||
* @returns {void} | ||
*/ | ||
delete(name, value) { | ||
this.#increment_version(); | ||
this.#update_search(); | ||
return this.#url_search_params.delete(name, value); | ||
} | ||
/** | ||
* | ||
* @param {string} name | ||
* @returns {string|null} | ||
*/ | ||
get(name) { | ||
get(this.#version); | ||
return this.#url_search_params.get(name); | ||
} | ||
/** | ||
* | ||
* @param {string} name | ||
* @returns {string[]} | ||
*/ | ||
getAll(name) { | ||
get(this.#version); | ||
return this.#url_search_params.getAll(name); | ||
} | ||
/** | ||
* | ||
* @param {string} name | ||
* @param {string=} value | ||
* @returns {boolean} | ||
*/ | ||
has(name, value) { | ||
get(this.#version); | ||
return this.#url_search_params.has(name, value); | ||
} | ||
keys() { | ||
get(this.#version); | ||
return this.#url_search_params.keys(); | ||
} | ||
/** | ||
* | ||
* @param {string} name | ||
* @param {string} value | ||
* @returns {void} | ||
*/ | ||
set(name, value) { | ||
this.#increment_version(); | ||
this.#update_search(); | ||
return this.#url_search_params.set(name, value); | ||
} | ||
sort() { | ||
this.#increment_version(); | ||
this.#update_search(); | ||
return this.#url_search_params.sort(); | ||
} | ||
toString() { | ||
get(this.#version); | ||
return this.#url_search_params.toString(); | ||
} | ||
values() { | ||
get(this.#version); | ||
return this.#url_search_params.values(); | ||
} | ||
entries() { | ||
get(this.#version); | ||
return this.#url_search_params.entries(); | ||
} | ||
[Symbol.iterator]() { | ||
return this.entries(); | ||
} | ||
get size() { | ||
return this.#url_search_params.size; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { render_effect, effect_root } from '../internal/client/reactivity/effects.js'; | ||
import { flushSync } from '../index-client.js'; | ||
import { ReactiveURL } from './url.js'; | ||
import { assert, test } from 'vitest'; | ||
|
||
test('url.hash', () => { | ||
const url = new ReactiveURL('http://google.com'); | ||
const log: any = []; | ||
|
||
const cleanup = effect_root(() => { | ||
render_effect(() => { | ||
log.push(url.hash); | ||
}); | ||
}); | ||
|
||
flushSync(() => { | ||
url.hash = 'abc'; | ||
}); | ||
|
||
flushSync(() => { | ||
url.href = 'http://google.com/a/b/c#def'; | ||
}); | ||
|
||
flushSync(() => { | ||
// does not affect hash | ||
url.pathname = 'e/f'; | ||
}); | ||
|
||
assert.deepEqual(log, ['', '#abc', '#def']); | ||
|
||
cleanup(); | ||
}); | ||
|
||
test('url.searchParams', () => { | ||
const url = new ReactiveURL('https://svelte.dev?foo=bar&t=123'); | ||
const log: any = []; | ||
|
||
const cleanup = effect_root(() => { | ||
render_effect(() => { | ||
log.push('search: ' + url.search); | ||
}); | ||
render_effect(() => { | ||
log.push('foo: ' + url.searchParams.get('foo')); | ||
}); | ||
render_effect(() => { | ||
log.push('q: ' + url.searchParams.has('q')); | ||
}); | ||
}); | ||
|
||
flushSync(() => { | ||
url.search = '?q=kit&foo=baz'; | ||
}); | ||
|
||
flushSync(() => { | ||
url.searchParams.append('foo', 'qux'); | ||
}); | ||
|
||
flushSync(() => { | ||
url.searchParams.delete('foo'); | ||
}); | ||
|
||
assert.deepEqual(log, [ | ||
'search: ?foo=bar&t=123', | ||
'foo: bar', | ||
'q: false', | ||
'search: ?q=kit&foo=baz', | ||
'foo: baz', | ||
'q: true', | ||
'search: ?q=kit&foo=baz&foo=qux', | ||
'foo: baz', | ||
'q: true', | ||
'search: ?q=kit', | ||
'foo: null', | ||
'q: true' | ||
]); | ||
|
||
cleanup(); | ||
}); |
2 changes: 1 addition & 1 deletion
2
packages/svelte/tests/runtime-runes/samples/reactive-date/main.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.