Skip to content

Commit d52c2ca

Browse files
committed
feat: add reactive Date object to svelte/reactivity
1 parent b4a70ea commit d52c2ca

File tree

5 files changed

+164
-0
lines changed

5 files changed

+164
-0
lines changed

.changeset/new-rabbits-flow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
feat: add reactive Date object to svelte/reactivity

packages/svelte/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@
6262
"types": "./types/index.d.ts",
6363
"default": "./src/motion/index.js"
6464
},
65+
"./reactivity": {
66+
"types": "./types/index.d.ts",
67+
"default": "./src/reactivity/index.js"
68+
},
6569
"./server": {
6670
"types": "./types/index.d.ts",
6771
"default": "./src/server/index.js"
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { source } from '../internal/client/reactivity/sources';
2+
import { get, set } from '../internal/client/runtime';
3+
4+
const read = [
5+
'getDate',
6+
'getDay',
7+
'getFullYear',
8+
'getHours',
9+
'getMilliseconds',
10+
'getMinutes',
11+
'getMonth',
12+
'getSeconds',
13+
'getTime',
14+
'getTimezoneOffset',
15+
'getUTCDate',
16+
'getUTCDay',
17+
'getUTCFullYear',
18+
'getUTCHours',
19+
'getUTCMilliseconds',
20+
'getUTCMinutes',
21+
'getUTCMonth',
22+
'getUTCSeconds',
23+
'getYear',
24+
'toDateString',
25+
'toISOString',
26+
'toJSON',
27+
'toLocaleDateString',
28+
'toLocalString',
29+
'toLocalTimeString',
30+
'toString',
31+
'toTimeString',
32+
'toUTCString'
33+
];
34+
35+
const write = [
36+
'setDate',
37+
'setFullYear',
38+
'setHours',
39+
'setMilliseconds',
40+
'setMinutes',
41+
'setMonth',
42+
'setSeconds',
43+
'setTime',
44+
'setUTCDate',
45+
'setUTCFullYear',
46+
'setUTCHours',
47+
'setUTCMilliseconds',
48+
'setUTCMinutes',
49+
'setUTCMonth',
50+
'setUTCSeconds',
51+
'setYear'
52+
];
53+
54+
class ReactiveDate extends Date {
55+
#raw_time = source(super.getTime());
56+
static #inited = false;
57+
58+
// We init as part of the first instance so that we can treeshake this class
59+
#init() {
60+
if (!ReactiveDate.#inited) {
61+
ReactiveDate.#inited = true;
62+
const proto = ReactiveDate.prototype;
63+
const date_proto = Date.prototype;
64+
for (const method of read) {
65+
// @ts-ignore
66+
proto[method] = function () {
67+
get(this.#raw_time);
68+
// @ts-ignore
69+
return date_proto[method].call(this);
70+
};
71+
}
72+
for (const method of write) {
73+
// @ts-ignore
74+
proto[method] = function (/** @type {any} */ ...args) {
75+
// @ts-ignore
76+
const v = date_proto[method].apply(this, args);
77+
const time = date_proto.getTime.call(this);
78+
if (time !== this.#raw_time.v) {
79+
set(this.#raw_time, time);
80+
}
81+
return v;
82+
};
83+
}
84+
}
85+
}
86+
87+
/**
88+
* @param {any[]} values
89+
*/
90+
constructor(...values) {
91+
// @ts-ignore
92+
super(...values);
93+
this.#init();
94+
}
95+
}
96+
97+
export { ReactiveDate as Date };
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { flushSync } from '../../../../src/main/main-client';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: `<div>getSeconds: 0</div><div>getMinutes: 0</div><div>getHours: 15</div><div>getTime: 1708700400000</div><div>toDateString: Fri Feb 23 2024</div><button>1 second</button><button>1 minute</button><button>1 hour</button>`,
6+
7+
test({ assert, target }) {
8+
const [btn, btn2, btn3] = target.querySelectorAll('button');
9+
10+
flushSync(() => {
11+
btn?.click();
12+
});
13+
14+
assert.htmlEqual(
15+
target.innerHTML,
16+
`<div>getSeconds: 1</div><div>getMinutes: 0</div><div>getHours: 15</div><div>getTime: 1708700401000</div><div>toDateString: Fri Feb 23 2024</div><button>1 second</button><button>1 minute</button><button>1 hour</button>`
17+
);
18+
19+
flushSync(() => {
20+
btn2?.click();
21+
});
22+
23+
assert.htmlEqual(
24+
target.innerHTML,
25+
`<div>getSeconds: 1</div><div>getMinutes: 1</div><div>getHours: 15</div><div>getTime: 1708700461000</div><div>toDateString: Fri Feb 23 2024</div><button>1 second</button><button>1 minute</button><button>1 hour</button>`
26+
);
27+
28+
flushSync(() => {
29+
btn3?.click();
30+
});
31+
32+
assert.htmlEqual(
33+
target.innerHTML,
34+
`<div>getSeconds: 1</div><div>getMinutes: 1</div><div>getHours: 16</div><div>getTime: 1708704061000</div><div>toDateString: Fri Feb 23 2024</div><button>1 second</button><button>1 minute</button><button>1 hour</button>`
35+
);
36+
}
37+
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script>
2+
import { Date } from 'svelte/reactivity';
3+
4+
let date = new Date('2024/02/23 15:00:00');
5+
</script>
6+
7+
<div>getSeconds: {date.getSeconds()}</div>
8+
<div>getMinutes: {date.getMinutes()}</div>
9+
<div>getHours: {date.getHours()}</div>
10+
<div>getTime: {date.getTime()}</div>
11+
<div>toDateString: {date.toDateString()}</div>
12+
13+
<button onclick={() => {
14+
date.setSeconds(date.getSeconds() + 1);
15+
}}>1 second</button>
16+
<button onclick={() => {
17+
date.setMinutes(date.getMinutes() + 1);
18+
}}>1 minute</button>
19+
<button onclick={() => {
20+
date.setHours(date.getHours() + 1);
21+
}}>1 hour</button>

0 commit comments

Comments
 (0)