breaking: rename svelte/reactivity helpers to include Svelte prefix (#12248)

* breaking: rename svelte/reactivity helpers to include Svelte prefix

* keep old exports

* add runtime errors

* add runtime errors

* feedback

* feedback

* feedback

* Update .changeset/nice-jobs-breathe.md

Co-authored-by: Conduitry <git@chor.date>

---------

Co-authored-by: Conduitry <git@chor.date>
pull/12246/head
Dominic Gannaway 6 months ago committed by GitHub
parent 9a293ea8c4
commit cae5f1ed26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
breaking: rename `svelte/reactivity` helpers to include `Svelte` prefix

@ -57,14 +57,14 @@ const write = [
var inited = false; var inited = false;
export class ReactiveDate extends Date { export class SvelteDate extends Date {
#raw_time = source(super.getTime()); #raw_time = source(super.getTime());
// We init as part of the first instance so that we can treeshake this class // We init as part of the first instance so that we can treeshake this class
#init() { #init() {
if (!inited) { if (!inited) {
inited = true; inited = true;
const proto = ReactiveDate.prototype; const proto = SvelteDate.prototype;
const date_proto = Date.prototype; const date_proto = Date.prototype;
for (const method of read) { for (const method of read) {

@ -1,4 +1,29 @@
export { ReactiveDate as Date } from './date.js'; export { SvelteDate } from './date.js';
export { ReactiveSet as Set } from './set.js'; export { SvelteSet } from './set.js';
export { ReactiveMap as Map } from './map.js'; export { SvelteMap } from './map.js';
export { ReactiveURL as URL, ReactiveURLSearchParams as URLSearchParams } from './url.js'; export { SvelteURL, SvelteURLSearchParams } from './url.js';
/** @deprecated Use `SvelteDate` instead */
export function Date() {
throw new Error('Date has been removed, use SvelteDate instead.');
}
/** @deprecated Use `SvelteSet` instead */
export function Set() {
throw new Error('Set has been removed, use SvelteSet instead.');
}
/** @deprecated Use `SvelteMap` instead */
export function Map() {
throw new Error('Map has been removed, use SvelteMap instead.');
}
/** @deprecated Use `SvelteURL` instead */
export function URL() {
throw new Error('URL has been removed, use SvelteURL instead.');
}
/** @deprecated Use `SvelteURLSearchParams` instead */
export function URLSearchParams() {
throw new Error('URLSearchParams has been removed, use SvelteURLSearchParams instead.');
}

@ -1,5 +1,30 @@
export const Date = globalThis.Date; export const SvelteDate = globalThis.Date;
export const Set = globalThis.Set; export const SvelteSet = globalThis.Set;
export const Map = globalThis.Map; export const SvelteMap = globalThis.Map;
export const URL = globalThis.URL; export const SvelteURL = globalThis.URL;
export const URLSearchParams = globalThis.URLSearchParams; export const SvelteURLSearchParams = globalThis.URLSearchParams;
/** @deprecated Use `SvelteDate` instead */
export function Date() {
throw new Error('Date has been removed, use SvelteDate instead.');
}
/** @deprecated Use `SvelteSet` instead */
export function Set() {
throw new Error('Set has been removed, use SvelteSet instead.');
}
/** @deprecated Use `SvelteMap` instead */
export function Map() {
throw new Error('Map has been removed, use SvelteMap instead.');
}
/** @deprecated Use `SvelteURL` instead */
export function URL() {
throw new Error('URL has been removed, use SvelteURL instead.');
}
/** @deprecated Use `SvelteURLSearchParams` instead */
export function URLSearchParams() {
throw new Error('URLSearchParams has been removed, use SvelteURLSearchParams instead.');
}

@ -8,7 +8,7 @@ import { increment } from './utils.js';
* @template V * @template V
* @extends {Map<K, V>} * @extends {Map<K, V>}
*/ */
export class ReactiveMap extends Map { export class SvelteMap extends Map {
/** @type {Map<K, import('#client').Source<number>>} */ /** @type {Map<K, import('#client').Source<number>>} */
#sources = new Map(); #sources = new Map();
#version = source(0); #version = source(0);

@ -1,10 +1,10 @@
import { render_effect, effect_root } from '../internal/client/reactivity/effects.js'; import { render_effect, effect_root } from '../internal/client/reactivity/effects.js';
import { flushSync } from '../index-client.js'; import { flushSync } from '../index-client.js';
import { ReactiveMap } from './map.js'; import { SvelteMap } from './map.js';
import { assert, test } from 'vitest'; import { assert, test } from 'vitest';
test('map.values()', () => { test('map.values()', () => {
const map = new ReactiveMap([ const map = new SvelteMap([
[1, 1], [1, 1],
[2, 2], [2, 2],
[3, 3], [3, 3],
@ -65,7 +65,7 @@ test('map.values()', () => {
}); });
test('map.get(...)', () => { test('map.get(...)', () => {
const map = new ReactiveMap([ const map = new SvelteMap([
[1, 1], [1, 1],
[2, 2], [2, 2],
[3, 3] [3, 3]
@ -101,7 +101,7 @@ test('map.get(...)', () => {
}); });
test('map.has(...)', () => { test('map.has(...)', () => {
const map = new ReactiveMap([ const map = new SvelteMap([
[1, 1], [1, 1],
[2, 2], [2, 2],
[3, 3] [3, 3]
@ -148,7 +148,7 @@ test('map.has(...)', () => {
}); });
test('map.forEach(...)', () => { test('map.forEach(...)', () => {
const map = new ReactiveMap([ const map = new SvelteMap([
[1, 1], [1, 1],
[2, 2], [2, 2],
[3, 3] [3, 3]
@ -169,7 +169,7 @@ test('map.forEach(...)', () => {
}); });
test('map.delete(...)', () => { test('map.delete(...)', () => {
const map = new ReactiveMap([ const map = new SvelteMap([
[1, 1], [1, 1],
[2, 2], [2, 2],
[3, 3] [3, 3]
@ -182,7 +182,7 @@ test('map.delete(...)', () => {
}); });
test('map handling of undefined values', () => { test('map handling of undefined values', () => {
const map = new ReactiveMap(); const map = new SvelteMap();
const log: any = []; const log: any = [];
@ -208,7 +208,7 @@ test('map handling of undefined values', () => {
}); });
test('not invoking reactivity when value is not in the map after changes', () => { test('not invoking reactivity when value is not in the map after changes', () => {
const map = new ReactiveMap([[1, 1]]); const map = new SvelteMap([[1, 1]]);
const log: any = []; const log: any = [];
@ -236,5 +236,5 @@ test('not invoking reactivity when value is not in the map after changes', () =>
}); });
test('Map.instanceOf', () => { test('Map.instanceOf', () => {
assert.equal(new ReactiveMap() instanceof Map, true); assert.equal(new SvelteMap() instanceof Map, true);
}); });

@ -12,7 +12,7 @@ var inited = false;
* @template T * @template T
* @extends {Set<T>} * @extends {Set<T>}
*/ */
export class ReactiveSet extends Set { export class SvelteSet extends Set {
/** @type {Map<T, import('#client').Source<boolean>>} */ /** @type {Map<T, import('#client').Source<boolean>>} */
#sources = new Map(); #sources = new Map();
#version = source(0); #version = source(0);
@ -41,7 +41,7 @@ export class ReactiveSet extends Set {
#init() { #init() {
inited = true; inited = true;
var proto = ReactiveSet.prototype; var proto = SvelteSet.prototype;
var set_proto = Set.prototype; var set_proto = Set.prototype;
for (const method of read_methods) { for (const method of read_methods) {
@ -59,7 +59,7 @@ export class ReactiveSet extends Set {
get(this.#version); get(this.#version);
// @ts-ignore // @ts-ignore
var set = /** @type {Set<T>} */ (set_proto[method].apply(this, v)); var set = /** @type {Set<T>} */ (set_proto[method].apply(this, v));
return new ReactiveSet(set); return new SvelteSet(set);
}; };
} }
} }

@ -1,10 +1,10 @@
import { render_effect, effect_root } from '../internal/client/reactivity/effects.js'; import { render_effect, effect_root } from '../internal/client/reactivity/effects.js';
import { flushSync } from '../index-client.js'; import { flushSync } from '../index-client.js';
import { ReactiveSet } from './set.js'; import { SvelteSet } from './set.js';
import { assert, test } from 'vitest'; import { assert, test } from 'vitest';
test('set.values()', () => { test('set.values()', () => {
const set = new ReactiveSet([1, 2, 3, 4, 5]); const set = new SvelteSet([1, 2, 3, 4, 5]);
const log: any = []; const log: any = [];
@ -36,7 +36,7 @@ test('set.values()', () => {
}); });
test('set.has(...)', () => { test('set.has(...)', () => {
const set = new ReactiveSet([1, 2, 3]); const set = new SvelteSet([1, 2, 3]);
const log: any = []; const log: any = [];
@ -79,7 +79,7 @@ test('set.has(...)', () => {
}); });
test('set.delete(...)', () => { test('set.delete(...)', () => {
const set = new ReactiveSet([1, 2, 3]); const set = new SvelteSet([1, 2, 3]);
assert.equal(set.delete(3), true); assert.equal(set.delete(3), true);
assert.equal(set.delete(3), false); assert.equal(set.delete(3), false);
@ -88,7 +88,7 @@ test('set.delete(...)', () => {
}); });
test('set.forEach()', () => { test('set.forEach()', () => {
const set = new ReactiveSet([1, 2, 3, 4, 5]); const set = new SvelteSet([1, 2, 3, 4, 5]);
const log: any = []; const log: any = [];
@ -108,7 +108,7 @@ test('set.forEach()', () => {
}); });
test('not invoking reactivity when value is not in the set after changes', () => { test('not invoking reactivity when value is not in the set after changes', () => {
const set = new ReactiveSet([1, 2]); const set = new SvelteSet([1, 2]);
const log: any = []; const log: any = [];
@ -155,5 +155,5 @@ test('not invoking reactivity when value is not in the set after changes', () =>
}); });
test('Set.instanceOf', () => { test('Set.instanceOf', () => {
assert.equal(new ReactiveSet() instanceof Set, true); assert.equal(new SvelteSet() instanceof Set, true);
}); });

@ -4,7 +4,7 @@ import { increment } from './utils.js';
const REPLACE = Symbol(); const REPLACE = Symbol();
export class ReactiveURL extends URL { export class SvelteURL extends URL {
#protocol = source(super.protocol); #protocol = source(super.protocol);
#username = source(super.username); #username = source(super.username);
#password = source(super.password); #password = source(super.password);
@ -12,7 +12,7 @@ export class ReactiveURL extends URL {
#port = source(super.port); #port = source(super.port);
#pathname = source(super.pathname); #pathname = source(super.pathname);
#hash = source(super.hash); #hash = source(super.hash);
#searchParams = new ReactiveURLSearchParams(); #searchParams = new SvelteURLSearchParams();
/** /**
* @param {string | URL} url * @param {string | URL} url
@ -153,7 +153,7 @@ export class ReactiveURL extends URL {
} }
} }
export class ReactiveURLSearchParams extends URLSearchParams { export class SvelteURLSearchParams extends URLSearchParams {
#version = source(0); #version = source(0);
/** /**

@ -1,10 +1,10 @@
import { render_effect, effect_root } from '../internal/client/reactivity/effects.js'; import { render_effect, effect_root } from '../internal/client/reactivity/effects.js';
import { flushSync } from '../index-client.js'; import { flushSync } from '../index-client.js';
import { ReactiveURL, ReactiveURLSearchParams } from './url.js'; import { SvelteURL, SvelteURLSearchParams } from './url.js';
import { assert, test } from 'vitest'; import { assert, test } from 'vitest';
test('url.hash', () => { test('url.hash', () => {
const url = new ReactiveURL('http://google.com'); const url = new SvelteURL('http://google.com');
const log: any = []; const log: any = [];
const cleanup = effect_root(() => { const cleanup = effect_root(() => {
@ -32,7 +32,7 @@ test('url.hash', () => {
}); });
test('url.searchParams', () => { test('url.searchParams', () => {
const url = new ReactiveURL('https://svelte.dev?foo=bar&t=123'); const url = new SvelteURL('https://svelte.dev?foo=bar&t=123');
const log: any = []; const log: any = [];
const cleanup = effect_root(() => { const cleanup = effect_root(() => {
@ -78,7 +78,7 @@ test('url.searchParams', () => {
}); });
test('URLSearchParams', () => { test('URLSearchParams', () => {
const params = new ReactiveURLSearchParams(); const params = new SvelteURLSearchParams();
const log: any = []; const log: any = [];
const cleanup = effect_root(() => { const cleanup = effect_root(() => {

@ -1,7 +1,7 @@
<script> <script>
import { Date } from 'svelte/reactivity'; import { SvelteDate } from 'svelte/reactivity';
let date = new Date('2024-02-23T15:00:00Z'); let date = new SvelteDate('2024-02-23T15:00:00Z');
</script> </script>
<div>getSeconds: {date.getUTCSeconds()}</div> <div>getSeconds: {date.getUTCSeconds()}</div>

@ -1,7 +1,7 @@
<script> <script>
import { Map } from 'svelte/reactivity'; import { SvelteMap } from 'svelte/reactivity';
let state = new Map([[0, 0]]); let state = new SvelteMap([[0, 0]]);
</script> </script>
<button <button

@ -1,7 +1,7 @@
<script> <script>
import { Set } from 'svelte/reactivity'; import { SvelteSet } from 'svelte/reactivity';
let state = new Set([0]); let state = new SvelteSet([0]);
</script> </script>
<button onclick={() => state.delete(0)}>delete initial</button> <button onclick={() => state.delete(0)}>delete initial</button>

@ -1,10 +1,10 @@
<script> <script>
import { Set as ReactiveSet, Map as ReactiveMap } from 'svelte/reactivity'; import { SvelteSet, SvelteMap } from 'svelte/reactivity';
let map = new Map(); let map = new Map();
let set = new Set(); let set = new Set();
let rmap = new ReactiveMap(); let rmap = new SvelteMap();
let rset = new ReactiveSet(); let rset = new SvelteSet();
</script> </script>
<div>{rset.entries()} {rset.keys()} {rset.values()}</div> <div>{rset.entries()} {rset.keys()} {rset.values()}</div>

@ -1,7 +1,7 @@
<script> <script>
import { URL } from 'svelte/reactivity'; import { SvelteURL } from 'svelte/reactivity';
let url = new URL('https://svelte.dev/repl/hello-world?version=5.0'); let url = new SvelteURL('https://svelte.dev/repl/hello-world?version=5.0');
</script> </script>
<div>href: {url.href}</div> <div>href: {url.href}</div>

@ -1,6 +1,6 @@
<script> <script>
import { Set } from 'svelte/reactivity'; import { SvelteSet } from 'svelte/reactivity';
const set = new Set(); const set = new SvelteSet();
</script> </script>
<form onsubmit={e => { <form onsubmit={e => {

@ -2131,37 +2131,47 @@ declare module 'svelte/motion' {
} }
declare module 'svelte/reactivity' { declare module 'svelte/reactivity' {
class ReactiveDate extends Date { /** @deprecated Use `SvelteDate` instead */
function Date_1(): void;
/** @deprecated Use `SvelteSet` instead */
function Set_1(): void;
/** @deprecated Use `SvelteMap` instead */
function Map_1(): void;
/** @deprecated Use `SvelteURL` instead */
function URL_1(): void;
/** @deprecated Use `SvelteURLSearchParams` instead */
function URLSearchParams_1(): void;
class SvelteDate extends Date {
constructor(...values: any[]); constructor(...values: any[]);
#private; #private;
} }
class ReactiveSet<T> extends Set<T> { class SvelteSet<T> extends Set<T> {
constructor(value?: Iterable<T> | null | undefined); constructor(value?: Iterable<T> | null | undefined);
add(value: T): this; add(value: T): this;
#private; #private;
} }
class ReactiveMap<K, V> extends Map<K, V> { class SvelteMap<K, V> extends Map<K, V> {
constructor(value?: Iterable<readonly [K, V]> | null | undefined); constructor(value?: Iterable<readonly [K, V]> | null | undefined);
set(key: K, value: V): this; set(key: K, value: V): this;
#private; #private;
} }
class ReactiveURL extends URL { class SvelteURL extends URL {
get searchParams(): ReactiveURLSearchParams; get searchParams(): SvelteURLSearchParams;
#private; #private;
} }
class ReactiveURLSearchParams extends URLSearchParams { class SvelteURLSearchParams extends URLSearchParams {
[REPLACE](params: URLSearchParams): void; [REPLACE](params: URLSearchParams): void;
#private; #private;
} }
const REPLACE: unique symbol; const REPLACE: unique symbol;
export { ReactiveDate as Date, ReactiveSet as Set, ReactiveMap as Map, ReactiveURL as URL, ReactiveURLSearchParams as URLSearchParams }; export { Date_1 as Date, Set_1 as Set, Map_1 as Map, URL_1 as URL, URLSearchParams_1 as URLSearchParams, SvelteDate, SvelteSet, SvelteMap, SvelteURL, SvelteURLSearchParams };
} }
declare module 'svelte/server' { declare module 'svelte/server' {

@ -95,13 +95,13 @@ To prevent something from being treated as an `$effect`/`$derived` dependency, u
## `svelte/reactivity` ## `svelte/reactivity`
Svelte provides reactive `Map`, `Set`, `Date` and `URL` classes. These can be imported from `svelte/reactivity` and used just like their native counterparts. [Demo:](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAE32QzWrDMBCEX2Wri1uo7bvrBHrvqdBTUogqryuBfhZp5SQYv3slSsmpOc7uN8zsrmI2FpMYDqvw0qEYxCuReBZ8pSrSgpax6BRyVHUyJhUN8f7oj2wchciwwsf7G2wwx-Cg-bX0EaVisxi-Ni-FLbQKPjHkaGEHHs_V9NhoZkpD3-NFOrLYqeB6kqybp-Ia-1uYHx_aFpSW_hsTcADWmLDrOmjbsh-Np8zwZfw0LNJm3K0lqaMYOKhgt_8RHRLX0-8gtdAfUiAdb4XOxlrINElGOOmI8wmkn2AxCmHBmOTdetWw7ct7XZjMbHASA8eM2-f2A-JarmyZAQAA) Svelte provides reactive `SvelteMap`, `SvelteSet`, `SvelteDate` and `SvelteURL` classes. These can be imported from `svelte/reactivity` and used just like their native counterparts. [Demo:](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAE32QwUrEMBBAf2XMpQrb9t7tFrx7UjxZYWM6NYFkEpJJ16X03yWK9OQeZ3iPecwqZmMxie5tFSQdik48hiAOgq-hDGlByygOIvkcVdn0SUUTeBhpZOOCjwwrvPxgr89PsMEcvYPqV2wjSsVmMXytjiMVR3lKDDlaOAHhZVfvK80cUte2-CVdsNgo79ogWVcPx5H6dj9M_V1dg9KSPjEBe2CNCZumgboeRuoNhczwYWjqFmkzntYcbROiZ6-83f5HtE9c3nADKUF_yEi9jnvQxVgLOUySEc464nwGSRMsRiEsGJO8mVeEbRAH4fxkZoOT6Dhm3N63b9_bGfOlAQAA)
```svelte ```svelte
<script> <script>
import { URL } from 'svelte/reactivity'; import { SvelteURL } from 'svelte/reactivity';
const url = new URL('https://example.com/path'); const url = new SvelteURL('https://example.com/path');
</script> </script>
<!-- changes to these... --> <!-- changes to these... -->

Loading…
Cancel
Save