@cloudcome/utils-core 1.1.0 → 1.1.1
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 +52 -0
- package/LICENSE +21 -0
- package/package.json +279 -1
- package/src/array.ts +312 -0
- package/src/async.ts +379 -0
- package/src/base64.ts +20 -0
- package/src/cache.ts +146 -0
- package/{dist/color/contrast.d.ts → src/color/contrast.ts} +12 -2
- package/src/color/distance.ts +28 -0
- package/src/color/helpers.ts +23 -0
- package/src/color/hex-hsl.ts +11 -0
- package/{dist/color/hex-hsv.d.ts → src/color/hex-hsv.ts} +11 -3
- package/{dist/color/hex-hwb.d.ts → src/color/hex-hwb.ts} +11 -3
- package/src/color/hex-rgb.ts +39 -0
- package/{dist/color/hsl-lighten.d.ts → src/color/hsl-lighten.ts} +7 -2
- package/{dist/color/hsv-brighten.d.ts → src/color/hsv-brighten.ts} +7 -2
- package/{dist/color/luminance.d.ts → src/color/luminance.ts} +9 -2
- package/{dist/color/mix.d.ts → src/color/mix.ts} +10 -2
- package/src/color/rgb-hsl.ts +53 -0
- package/{dist/color/rgb-hsv.d.ts → src/color/rgb-hsv.ts} +30 -3
- package/src/color/rgb-hwb.ts +56 -0
- package/{dist/color/rgb-lab.d.ts → src/color/rgb-lab.ts} +11 -3
- package/src/color/rgb-whiter.ts +22 -0
- package/src/color/rgb-xyz.ts +62 -0
- package/{dist/color/types.d.ts → src/color/types.ts} +12 -30
- package/{dist/color/xyz-lab.d.ts → src/color/xyz-lab.ts} +32 -3
- package/src/crypto/md5.mjs +357 -0
- package/src/crypto/sha1.mjs +300 -0
- package/src/crypto/sha256.mjs +310 -0
- package/src/crypto/sha512.mjs +459 -0
- package/{dist/crypto.d.ts → src/crypto.ts} +20 -4
- package/src/date/const.ts +6 -0
- package/src/date/core.ts +162 -0
- package/src/date/days.ts +51 -0
- package/{dist/date/is.d.ts → src/date/is.ts} +102 -8
- package/src/date/relative.ts +92 -0
- package/src/date/start-end.ts +246 -0
- package/src/date/timezone.ts +220 -0
- package/src/date/weeks.ts +100 -0
- package/src/dts/global.d.ts +27 -0
- package/src/easing.ts +166 -0
- package/src/emitter.ts +117 -0
- package/src/enum.ts +171 -0
- package/{dist/env.d.ts → src/env.ts} +30 -6
- package/{dist/error.d.ts → src/error.ts} +12 -3
- package/src/exception.ts +68 -0
- package/src/fn.ts +197 -0
- package/src/index.ts +1 -0
- package/src/number.ts +236 -0
- package/{dist/object/each.d.ts → src/object/each.ts} +23 -3
- package/src/object/get-set.ts +273 -0
- package/src/object/is.ts +128 -0
- package/src/object/merge.ts +180 -0
- package/{dist/object/process.d.ts → src/object/process.ts} +38 -4
- package/src/path.ts +188 -0
- package/{dist/promise.d.ts → src/promise.ts} +67 -6
- package/{dist/qs.d.ts → src/qs.ts} +60 -3
- package/src/regexp.ts +156 -0
- package/src/string.ts +146 -0
- package/src/time/from.ts +57 -0
- package/src/time/to.ts +106 -0
- package/{dist/timer.mjs → src/timer.ts} +124 -17
- package/{dist/tree.d.ts → src/tree.ts} +225 -41
- package/{dist/type.d.ts → src/type.ts} +96 -20
- package/{dist/types.d.ts → src/types.ts} +33 -12
- package/src/unique.ts +77 -0
- package/src/url.ts +93 -0
- package/src/version.ts +71 -0
- package/test/array.test.ts +332 -0
- package/test/async-real.test.ts +39 -0
- package/test/async.test.ts +375 -0
- package/test/base64.test.ts +32 -0
- package/test/cache.test.ts +83 -0
- package/test/color.test.ts +163 -0
- package/test/crypto.test.ts +34 -0
- package/test/date-tz.test.ts +206 -0
- package/test/date.test.ts +353 -0
- package/test/easing.test.ts +33 -0
- package/test/emitter.test.ts +71 -0
- package/test/enum.test.ts +113 -0
- package/test/env.test.ts +69 -0
- package/test/error.test.ts +58 -0
- package/test/exception.test.ts +43 -0
- package/test/fn.test.ts +263 -0
- package/test/helpers.ts +23 -0
- package/test/index.test.ts +6 -0
- package/test/number.test.ts +213 -0
- package/test/object.test.ts +309 -0
- package/test/path.test.ts +156 -0
- package/test/promise.test.ts +199 -0
- package/test/qs.test.ts +79 -0
- package/test/regexp.test.ts +97 -0
- package/test/string.test.ts +150 -0
- package/test/time.test.ts +214 -0
- package/test/timer.test.ts +114 -0
- package/test/tree.test.ts +348 -0
- package/test/type.test.ts +226 -0
- package/test/unique.test.ts +71 -0
- package/test/url.test.ts +136 -0
- package/test/version.test.ts +52 -0
- package/tsconfig.json +31 -0
- package/vite.config.mts +114 -0
- package/dist/array.cjs +0 -129
- package/dist/array.cjs.map +0 -1
- package/dist/array.d.ts +0 -171
- package/dist/array.mjs +0 -129
- package/dist/array.mjs.map +0 -1
- package/dist/async.cjs +0 -219
- package/dist/async.cjs.map +0 -1
- package/dist/async.d.ts +0 -137
- package/dist/async.mjs +0 -219
- package/dist/async.mjs.map +0 -1
- package/dist/base64.cjs +0 -16
- package/dist/base64.cjs.map +0 -1
- package/dist/base64.d.ts +0 -7
- package/dist/base64.mjs +0 -16
- package/dist/base64.mjs.map +0 -1
- package/dist/cache.cjs +0 -79
- package/dist/cache.cjs.map +0 -1
- package/dist/cache.d.ts +0 -90
- package/dist/cache.mjs +0 -79
- package/dist/cache.mjs.map +0 -1
- package/dist/color/distance.d.ts +0 -8
- package/dist/color/helpers.d.ts +0 -2
- package/dist/color/hex-hsl.d.ts +0 -3
- package/dist/color/hex-rgb.d.ts +0 -18
- package/dist/color/rgb-hsl.d.ts +0 -23
- package/dist/color/rgb-hwb.d.ts +0 -29
- package/dist/color/rgb-whiter.d.ts +0 -12
- package/dist/color/rgb-xyz.d.ts +0 -22
- package/dist/color.cjs +0 -250
- package/dist/color.cjs.map +0 -1
- package/dist/color.mjs +0 -250
- package/dist/color.mjs.map +0 -1
- package/dist/const.cjs +0 -14
- package/dist/const.cjs.map +0 -1
- package/dist/const.mjs +0 -15
- package/dist/const.mjs.map +0 -1
- package/dist/core.cjs +0 -250
- package/dist/core.cjs.map +0 -1
- package/dist/core.mjs +0 -251
- package/dist/core.mjs.map +0 -1
- package/dist/crypto/md5.d.mts +0 -1
- package/dist/crypto/sha1.d.mts +0 -1
- package/dist/crypto/sha256.d.mts +0 -1
- package/dist/crypto/sha512.d.mts +0 -1
- package/dist/crypto.cjs +0 -812
- package/dist/crypto.cjs.map +0 -1
- package/dist/crypto.mjs +0 -812
- package/dist/crypto.mjs.map +0 -1
- package/dist/date/const.d.ts +0 -6
- package/dist/date/core.d.ts +0 -52
- package/dist/date/days.d.ts +0 -23
- package/dist/date/relative.d.ts +0 -44
- package/dist/date/start-end.d.ts +0 -73
- package/dist/date/timezone.d.ts +0 -67
- package/dist/date/weeks.d.ts +0 -72
- package/dist/date.cjs +0 -239
- package/dist/date.cjs.map +0 -1
- package/dist/date.mjs +0 -241
- package/dist/date.mjs.map +0 -1
- package/dist/dict.cjs +0 -2
- package/dist/dict.cjs.map +0 -1
- package/dist/dict.mjs +0 -2
- package/dist/dict.mjs.map +0 -1
- package/dist/each.cjs +0 -18
- package/dist/each.cjs.map +0 -1
- package/dist/each.mjs +0 -19
- package/dist/each.mjs.map +0 -1
- package/dist/easing.cjs +0 -151
- package/dist/easing.cjs.map +0 -1
- package/dist/easing.d.ts +0 -46
- package/dist/easing.mjs +0 -151
- package/dist/easing.mjs.map +0 -1
- package/dist/emitter.cjs +0 -94
- package/dist/emitter.cjs.map +0 -1
- package/dist/emitter.d.ts +0 -68
- package/dist/emitter.mjs +0 -94
- package/dist/emitter.mjs.map +0 -1
- package/dist/enum.cjs +0 -58
- package/dist/enum.cjs.map +0 -1
- package/dist/enum.d.ts +0 -68
- package/dist/enum.mjs +0 -58
- package/dist/enum.mjs.map +0 -1
- package/dist/env.cjs +0 -28
- package/dist/env.cjs.map +0 -1
- package/dist/env.mjs +0 -28
- package/dist/env.mjs.map +0 -1
- package/dist/error.cjs +0 -12
- package/dist/error.cjs.map +0 -1
- package/dist/error.mjs +0 -12
- package/dist/error.mjs.map +0 -1
- package/dist/exception.cjs +0 -22
- package/dist/exception.cjs.map +0 -1
- package/dist/exception.d.ts +0 -31
- package/dist/exception.mjs +0 -22
- package/dist/exception.mjs.map +0 -1
- package/dist/fn.cjs +0 -76
- package/dist/fn.cjs.map +0 -1
- package/dist/fn.d.ts +0 -102
- package/dist/fn.mjs +0 -76
- package/dist/fn.mjs.map +0 -1
- package/dist/index.cjs +0 -5
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.mjs +0 -5
- package/dist/index.mjs.map +0 -1
- package/dist/merge.cjs +0 -87
- package/dist/merge.cjs.map +0 -1
- package/dist/merge.mjs +0 -88
- package/dist/merge.mjs.map +0 -1
- package/dist/number.cjs +0 -11
- package/dist/number.cjs.map +0 -1
- package/dist/number.d.ts +0 -137
- package/dist/number.mjs +0 -11
- package/dist/number.mjs.map +0 -1
- package/dist/object/get-set.d.ts +0 -111
- package/dist/object/is.d.ts +0 -32
- package/dist/object/merge.d.ts +0 -72
- package/dist/object.cjs +0 -130
- package/dist/object.cjs.map +0 -1
- package/dist/object.mjs +0 -130
- package/dist/object.mjs.map +0 -1
- package/dist/path.cjs +0 -77
- package/dist/path.cjs.map +0 -1
- package/dist/path.d.ts +0 -82
- package/dist/path.mjs +0 -77
- package/dist/path.mjs.map +0 -1
- package/dist/promise.cjs +0 -62
- package/dist/promise.cjs.map +0 -1
- package/dist/promise.mjs +0 -62
- package/dist/promise.mjs.map +0 -1
- package/dist/qs.cjs +0 -47
- package/dist/qs.cjs.map +0 -1
- package/dist/qs.mjs +0 -47
- package/dist/qs.mjs.map +0 -1
- package/dist/regexp.cjs +0 -66
- package/dist/regexp.cjs.map +0 -1
- package/dist/regexp.d.ts +0 -65
- package/dist/regexp.mjs +0 -66
- package/dist/regexp.mjs.map +0 -1
- package/dist/string.cjs +0 -16
- package/dist/string.cjs.map +0 -1
- package/dist/string.d.ts +0 -80
- package/dist/string.mjs +0 -16
- package/dist/string.mjs.map +0 -1
- package/dist/string2.cjs +0 -147
- package/dist/string2.cjs.map +0 -1
- package/dist/string2.mjs +0 -148
- package/dist/string2.mjs.map +0 -1
- package/dist/time/from.d.ts +0 -14
- package/dist/time/to.d.ts +0 -38
- package/dist/time.cjs +0 -82
- package/dist/time.cjs.map +0 -1
- package/dist/time.mjs +0 -82
- package/dist/time.mjs.map +0 -1
- package/dist/timer.cjs +0 -119
- package/dist/timer.cjs.map +0 -1
- package/dist/timer.d.ts +0 -96
- package/dist/timer.mjs.map +0 -1
- package/dist/tree.cjs +0 -125
- package/dist/tree.cjs.map +0 -1
- package/dist/tree.mjs +0 -125
- package/dist/tree.mjs.map +0 -1
- package/dist/type.cjs +0 -78
- package/dist/type.cjs.map +0 -1
- package/dist/type.mjs +0 -78
- package/dist/type.mjs.map +0 -1
- package/dist/types.cjs +0 -2
- package/dist/types.cjs.map +0 -1
- package/dist/types.mjs +0 -2
- package/dist/types.mjs.map +0 -1
- package/dist/unique.cjs +0 -46
- package/dist/unique.cjs.map +0 -1
- package/dist/unique.d.ts +0 -22
- package/dist/unique.mjs +0 -46
- package/dist/unique.mjs.map +0 -1
- package/dist/url.cjs +0 -37
- package/dist/url.cjs.map +0 -1
- package/dist/url.d.ts +0 -53
- package/dist/url.mjs +0 -37
- package/dist/url.mjs.map +0 -1
- package/dist/version.cjs +0 -33
- package/dist/version.cjs.map +0 -1
- package/dist/version.d.ts +0 -32
- package/dist/version.mjs +0 -33
- package/dist/version.mjs.map +0 -1
- /package/{dist/color.d.ts → src/color.ts} +0 -0
- /package/{dist/date.d.ts → src/date.ts} +0 -0
- /package/{dist/dict.d.ts → src/dict.ts} +0 -0
- /package/{dist/object.d.ts → src/object.ts} +0 -0
- /package/{dist/time.d.ts → src/time.ts} +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { isNumber } from '../type';
|
|
2
|
+
import { dateFormat } from './core';
|
|
3
|
+
|
|
4
|
+
export type TTzDateOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* 时间戳
|
|
7
|
+
* @default Date.now()
|
|
8
|
+
*/
|
|
9
|
+
timestamp?: number;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 日期值
|
|
13
|
+
*/
|
|
14
|
+
value?: readonly [
|
|
15
|
+
year?: number,
|
|
16
|
+
month?: number,
|
|
17
|
+
day?: number,
|
|
18
|
+
hours?: number,
|
|
19
|
+
minutes?: number,
|
|
20
|
+
seconds?: number,
|
|
21
|
+
milliseconds?: number,
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 时区偏移量,单位为分钟,默认为当前时区
|
|
26
|
+
*/
|
|
27
|
+
offset?: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const TZ_OFFSET_MS = 60 * 1000;
|
|
31
|
+
|
|
32
|
+
export class TzDate {
|
|
33
|
+
#timestamp: number;
|
|
34
|
+
#targetDate: Date;
|
|
35
|
+
#utcDate: Date;
|
|
36
|
+
|
|
37
|
+
#localTZOffset = TzDate.getOffset();
|
|
38
|
+
#localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;
|
|
39
|
+
|
|
40
|
+
#targetTzOffset = 0;
|
|
41
|
+
#targetTzOffsetMS = 0;
|
|
42
|
+
|
|
43
|
+
#options: TTzDateOptions;
|
|
44
|
+
|
|
45
|
+
constructor(options?: TTzDateOptions | TzDate) {
|
|
46
|
+
this.#options = (options instanceof TzDate ? options.#options : options) || {};
|
|
47
|
+
const { offset, timestamp, value } = this.#options;
|
|
48
|
+
this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;
|
|
49
|
+
this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;
|
|
50
|
+
|
|
51
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
52
|
+
const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;
|
|
53
|
+
const timestamp = Date.UTC(
|
|
54
|
+
fullYear ?? 0,
|
|
55
|
+
month ?? 0,
|
|
56
|
+
day ?? 1,
|
|
57
|
+
hours ?? 0,
|
|
58
|
+
minutes ?? 0,
|
|
59
|
+
seconds ?? 0,
|
|
60
|
+
milliseconds ?? 0,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
this.#timestamp = timestamp + this.#targetTzOffsetMS;
|
|
64
|
+
} else {
|
|
65
|
+
this.#timestamp = timestamp || Date.now();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);
|
|
69
|
+
this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#updateTimestamp() {
|
|
73
|
+
this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;
|
|
74
|
+
this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getTimezoneOffset() {
|
|
78
|
+
return this.#targetTzOffset;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getTimezoneOrder() {
|
|
82
|
+
return TzDate.getOrder(this.#targetTzOffset);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getFullYear() {
|
|
86
|
+
return this.#targetDate.getFullYear();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getMonth() {
|
|
90
|
+
return this.#targetDate.getMonth();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getDate() {
|
|
94
|
+
return this.#targetDate.getDate();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getHours() {
|
|
98
|
+
return this.#targetDate.getHours();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getMinutes() {
|
|
102
|
+
return this.#targetDate.getMinutes();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getSeconds() {
|
|
106
|
+
return this.#targetDate.getSeconds();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
getMilliseconds() {
|
|
110
|
+
return this.#targetDate.getMilliseconds();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
setFullYear(year: number, month?: number, date?: number) {
|
|
114
|
+
this.#targetDate.setFullYear(year);
|
|
115
|
+
this.#updateTimestamp();
|
|
116
|
+
|
|
117
|
+
if (isNumber(month)) this.setMonth(month);
|
|
118
|
+
if (isNumber(date)) this.setDate(date);
|
|
119
|
+
|
|
120
|
+
return this.getTime();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
setMonth(month: number, date?: number) {
|
|
124
|
+
this.#targetDate.setMonth(month);
|
|
125
|
+
this.#updateTimestamp();
|
|
126
|
+
|
|
127
|
+
if (isNumber(date)) this.setDate(date);
|
|
128
|
+
|
|
129
|
+
return this.getTime();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
setDate(date: number) {
|
|
133
|
+
this.#targetDate.setDate(date);
|
|
134
|
+
this.#updateTimestamp();
|
|
135
|
+
|
|
136
|
+
return this.getTime();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {
|
|
140
|
+
this.#targetDate.setHours(hours);
|
|
141
|
+
this.#updateTimestamp();
|
|
142
|
+
|
|
143
|
+
if (isNumber(minutes)) this.setMinutes(minutes);
|
|
144
|
+
if (isNumber(seconds)) this.setSeconds(seconds);
|
|
145
|
+
if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);
|
|
146
|
+
|
|
147
|
+
return this.getTime();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
setMinutes(minutes: number, seconds?: number, milliseconds?: number) {
|
|
151
|
+
this.#targetDate.setMinutes(minutes);
|
|
152
|
+
this.#updateTimestamp();
|
|
153
|
+
|
|
154
|
+
if (isNumber(seconds)) this.setSeconds(seconds);
|
|
155
|
+
if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);
|
|
156
|
+
|
|
157
|
+
return this.getTime();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
setSeconds(seconds: number, milliseconds?: number) {
|
|
161
|
+
this.#targetDate.setSeconds(seconds);
|
|
162
|
+
this.#updateTimestamp();
|
|
163
|
+
|
|
164
|
+
if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);
|
|
165
|
+
|
|
166
|
+
return this.getTime();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setMilliseconds(milliseconds: number) {
|
|
170
|
+
this.#targetDate.setMilliseconds(milliseconds);
|
|
171
|
+
this.#updateTimestamp();
|
|
172
|
+
|
|
173
|
+
return this.getTime();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getTime() {
|
|
177
|
+
return this.#timestamp;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
getDay() {
|
|
181
|
+
return this.#targetDate.getDay();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
toISOString() {
|
|
185
|
+
return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* 创建一个 TzDate 对象
|
|
190
|
+
* @param td - 需要转换的日期对象
|
|
191
|
+
* @param offset - 目标时区分钟偏移量,默认为当前时区
|
|
192
|
+
* @returns 返回一个 TzDate 对象
|
|
193
|
+
* @example
|
|
194
|
+
* ```js
|
|
195
|
+
* const tzDate = TzDate.from(new TzDate());
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
static from(td: TzDate, offset = TzDate.getOffset()) {
|
|
199
|
+
return new TzDate({
|
|
200
|
+
offset: offset,
|
|
201
|
+
timestamp: td.getTime(),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 获取时区序号
|
|
207
|
+
* @param offset - 默认使用当前时区分钟偏移量
|
|
208
|
+
*/
|
|
209
|
+
static getOrder(offset = TzDate.getOffset()) {
|
|
210
|
+
return offset / -60;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 获取时区分钟偏移量
|
|
215
|
+
* @param gmtOrder - 默认使用当前时区序号
|
|
216
|
+
*/
|
|
217
|
+
static getOffset(gmtOrder?: number) {
|
|
218
|
+
return isNumber(gmtOrder) ? gmtOrder * -60 : new Date().getTimezoneOffset();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { DATE_DAY_MS } from './const';
|
|
2
|
+
import { type TDateValue, dateParse } from './core';
|
|
3
|
+
|
|
4
|
+
export enum EWeekStart {
|
|
5
|
+
/**
|
|
6
|
+
* 周日作为一周的起始日
|
|
7
|
+
*/
|
|
8
|
+
sunday = 0,
|
|
9
|
+
/**
|
|
10
|
+
* 周一作为一周的起始日
|
|
11
|
+
*/
|
|
12
|
+
monday = 1,
|
|
13
|
+
/**
|
|
14
|
+
* 周二作为一周的起始日
|
|
15
|
+
*/
|
|
16
|
+
tuesday = 2,
|
|
17
|
+
/**
|
|
18
|
+
* 周三作为一周的起始日
|
|
19
|
+
*/
|
|
20
|
+
wednesday = 3,
|
|
21
|
+
/**
|
|
22
|
+
* 周四作为一周的起始日
|
|
23
|
+
*/
|
|
24
|
+
thursday = 4,
|
|
25
|
+
/**
|
|
26
|
+
* 周五作为一周的起始日
|
|
27
|
+
*/
|
|
28
|
+
friday = 5,
|
|
29
|
+
/**
|
|
30
|
+
* 周六作为一周的起始日
|
|
31
|
+
*/
|
|
32
|
+
saturday = 6,
|
|
33
|
+
// /**
|
|
34
|
+
// * 1号所在的周为第一周
|
|
35
|
+
// */
|
|
36
|
+
// firstDate = 7,
|
|
37
|
+
// /**
|
|
38
|
+
// * 完整7天表示第一周
|
|
39
|
+
// */
|
|
40
|
+
// firstFullWeek = 8,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 计算指定日期所在年份或月份的周数
|
|
45
|
+
* @param dateValue - 可以是数值、字符串或 Date 对象
|
|
46
|
+
* @param type - 计算范围,'Y' 表示年份,'M' 表示月份
|
|
47
|
+
* @param weekStart - 一周的起始日,默认为 0(周日)
|
|
48
|
+
* @returns 返回指定日期所在年份或月份的周数
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const date = new Date(2023, 0, 1); // 2023-01-01
|
|
52
|
+
* _dateWeeks(date, 'Y'); // 1 (计算年份的周数)
|
|
53
|
+
* _dateWeeks(date, 'M'); // 1 (计算月份的周数)
|
|
54
|
+
* _dateWeeks(date, 'Y', 1); // 1 (周一作为一周的起始日,计算年份的周数)
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function _dateWeeks(dateValue: TDateValue, type: 'Y' | 'M', weekStart: EWeekStart = 0) {
|
|
58
|
+
const date = dateParse(dateValue);
|
|
59
|
+
|
|
60
|
+
const year = date.getFullYear();
|
|
61
|
+
const month = date.getMonth();
|
|
62
|
+
|
|
63
|
+
const firstDate = type === 'Y' ? new Date(year, 0, 1) : new Date(year, month, 1);
|
|
64
|
+
const firstWeek = firstDate.getDay();
|
|
65
|
+
const days = Math.ceil((date.getTime() - firstDate.getTime()) / DATE_DAY_MS);
|
|
66
|
+
|
|
67
|
+
return Math.ceil((firstWeek + days - weekStart) / 7);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 计算指定日期所在年份的周数
|
|
72
|
+
* @param dateValue - 可以是数值、字符串或 Date 对象
|
|
73
|
+
* @param weekStart - 一周的起始日,默认为 0(周日)
|
|
74
|
+
* @returns 返回指定日期所在年份的周数
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const date = new Date(2023, 0, 1); // 2023-01-01
|
|
78
|
+
* weeksOfYear(date); // 1
|
|
79
|
+
* weeksOfYear(date, 1); // 1 (周一作为一周的起始日)
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function weeksOfYear(dateValue: TDateValue, weekStart: EWeekStart = 0) {
|
|
83
|
+
return _dateWeeks(dateValue, 'Y', weekStart);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 计算指定日期所在月份的周数
|
|
88
|
+
* @param dateValue - 可以是数值、字符串或 Date 对象
|
|
89
|
+
* @param weekStart - 一周的起始日,默认为 0(周日)
|
|
90
|
+
* @returns 返回指定日期所在月份的周数
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const date = new Date(2023, 0, 1); // 2023-01-01
|
|
94
|
+
* weeksOfMonth(date); // 1
|
|
95
|
+
* weeksOfMonth(date, 1); // 1 (周一作为一周的起始日)
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export function weeksOfMonth(dateValue: TDateValue, weekStart: EWeekStart = 0) {
|
|
99
|
+
return _dateWeeks(dateValue, 'M', weekStart);
|
|
100
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file global.d.ts
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* package.json name
|
|
7
|
+
*/
|
|
8
|
+
declare const PKG_NAME: string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* package.json version
|
|
12
|
+
*/
|
|
13
|
+
declare const PKG_VERSION: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* package.json description
|
|
17
|
+
*/
|
|
18
|
+
declare const PKG_DESCRIPTION: string;
|
|
19
|
+
|
|
20
|
+
declare const IS_TEST: string;
|
|
21
|
+
|
|
22
|
+
interface TEST_MOCK {
|
|
23
|
+
IS_BROWSER: boolean;
|
|
24
|
+
IS_NODE: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare const TEST_MOCK: TEST_MOCK;
|
package/src/easing.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* https://github.com/gre/bezier-easing
|
|
3
|
+
* BezierEasing - use bezier curve for transition easing function
|
|
4
|
+
* by Gaëtan Renaudeau 2014 - 2015 – MIT License
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// These values are established by empiricism with tests (tradeoff: performance VS precision)
|
|
8
|
+
const NEWTON_ITERATIONS = 4;
|
|
9
|
+
const NEWTON_MIN_SLOPE = 0.001;
|
|
10
|
+
const SUBDIVISION_PRECISION = 0.0000001;
|
|
11
|
+
const SUBDIVISION_MAX_ITERATIONS = 10;
|
|
12
|
+
|
|
13
|
+
const kSplineTableSize = 11;
|
|
14
|
+
const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
|
|
15
|
+
|
|
16
|
+
const float32ArraySupported = typeof Float32Array === 'function';
|
|
17
|
+
|
|
18
|
+
function A(aA1: number, aA2: number) {
|
|
19
|
+
return 1.0 - 3.0 * aA2 + 3.0 * aA1;
|
|
20
|
+
}
|
|
21
|
+
function B(aA1: number, aA2: number) {
|
|
22
|
+
return 3.0 * aA2 - 6.0 * aA1;
|
|
23
|
+
}
|
|
24
|
+
function C(aA1: number) {
|
|
25
|
+
return 3.0 * aA1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
29
|
+
function calcBezier(aT: number, aA1: number, aA2: number) {
|
|
30
|
+
return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
|
|
34
|
+
function getSlope(aT: number, aA1: number, aA2: number) {
|
|
35
|
+
return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function binarySubdivide(aX: number, aA: number, aB: number, mX1: number, mX2: number) {
|
|
39
|
+
let currentX: number;
|
|
40
|
+
let currentT: number;
|
|
41
|
+
let i = 0;
|
|
42
|
+
let aBFinal = aB;
|
|
43
|
+
let aAFinal = aA;
|
|
44
|
+
|
|
45
|
+
do {
|
|
46
|
+
currentT = aAFinal + (aBFinal - aAFinal) / 2.0;
|
|
47
|
+
currentX = calcBezier(currentT, mX1, mX2) - aX;
|
|
48
|
+
if (currentX > 0.0) {
|
|
49
|
+
aBFinal = currentT;
|
|
50
|
+
} else {
|
|
51
|
+
aAFinal = currentT;
|
|
52
|
+
}
|
|
53
|
+
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
|
|
54
|
+
return currentT;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function newtonRaphsonIterate(aX: number, aGuessT: number, mX1: number, mX2: number) {
|
|
58
|
+
let aGuessTFinal = aGuessT;
|
|
59
|
+
for (let i = 0; i < NEWTON_ITERATIONS; ++i) {
|
|
60
|
+
const currentSlope = getSlope(aGuessTFinal, mX1, mX2);
|
|
61
|
+
if (currentSlope === 0.0) {
|
|
62
|
+
return aGuessTFinal;
|
|
63
|
+
}
|
|
64
|
+
const currentX = calcBezier(aGuessTFinal, mX1, mX2) - aX;
|
|
65
|
+
aGuessTFinal -= currentX / currentSlope;
|
|
66
|
+
}
|
|
67
|
+
return aGuessTFinal;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function LinearEasing(x: number) {
|
|
71
|
+
return x;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 创建一个基于贝塞尔曲线的缓动函数。
|
|
76
|
+
*
|
|
77
|
+
* @param x1 - 贝塞尔曲线的第一个控制点的 X 坐标,必须在 [0, 1] 范围内。
|
|
78
|
+
* @param y1 - 贝塞尔曲线的第一个控制点的 Y 坐标,必须在 [0, 1] 范围内。
|
|
79
|
+
* @param x2 - 贝塞尔曲线的第二个控制点的 X 坐标,必须在 [0, 1] 范围内。
|
|
80
|
+
* @param y2 - 贝塞尔曲线的第二个控制点的 Y 坐标,必须在 [0, 1] 范围内。
|
|
81
|
+
* @returns 返回一个缓动函数,该函数接受一个参数 x(范围在 0 到 1 之间),并返回相应的缓动值。
|
|
82
|
+
* @throws 如果 mX1 或 mX2 不在 [0, 1] 范围内,则抛出错误。
|
|
83
|
+
*/
|
|
84
|
+
export function createEasingFn(x1: number, y1: number, x2: number, y2: number) {
|
|
85
|
+
if (!(0 <= x1 && x1 <= 1 && 0 <= x2 && x2 <= 1)) {
|
|
86
|
+
throw new Error('bezier x values must be in [0, 1] range');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (x1 === y1 && x2 === y2) {
|
|
90
|
+
return LinearEasing;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Precompute samples table
|
|
94
|
+
const sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
|
|
95
|
+
for (let i = 0; i < kSplineTableSize; ++i) {
|
|
96
|
+
sampleValues[i] = calcBezier(i * kSampleStepSize, x1, x2);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getTForX(aX: number) {
|
|
100
|
+
let intervalStart = 0.0;
|
|
101
|
+
let currentSample = 1;
|
|
102
|
+
const lastSample = kSplineTableSize - 1;
|
|
103
|
+
|
|
104
|
+
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
|
|
105
|
+
intervalStart += kSampleStepSize;
|
|
106
|
+
}
|
|
107
|
+
--currentSample;
|
|
108
|
+
|
|
109
|
+
// Interpolate to provide an initial guess for t
|
|
110
|
+
const dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
|
|
111
|
+
const guessForT = intervalStart + dist * kSampleStepSize;
|
|
112
|
+
const initialSlope = getSlope(guessForT, x1, x2);
|
|
113
|
+
|
|
114
|
+
if (initialSlope >= NEWTON_MIN_SLOPE) {
|
|
115
|
+
return newtonRaphsonIterate(aX, guessForT, x1, x2);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (initialSlope === 0.0) {
|
|
119
|
+
return guessForT;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, x1, x2);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 贝塞尔曲线方程
|
|
127
|
+
* @param x {number} 0~1
|
|
128
|
+
*/
|
|
129
|
+
return function easingFunc(x: number) {
|
|
130
|
+
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
|
|
131
|
+
if (x === 0 || x === 1) {
|
|
132
|
+
return x;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return calcBezier(getTForX(x), y1, y2);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const easingEase = createEasingFn(0.25, 0.1, 0.25, 1);
|
|
140
|
+
export const easingLinear = createEasingFn(0, 0, 1, 1);
|
|
141
|
+
export const easingSnap = createEasingFn(0, 1, 0.5, 1);
|
|
142
|
+
export const easingIn = createEasingFn(0.42, 0, 1, 1);
|
|
143
|
+
export const easingOut = createEasingFn(0, 0, 0.58, 1);
|
|
144
|
+
export const easingInOut = createEasingFn(0.42, 0, 0.58, 1);
|
|
145
|
+
export const easingInQuad = createEasingFn(0.55, 0.085, 0.68, 0.53);
|
|
146
|
+
export const easingInCubic = createEasingFn(0.55, 0.055, 0.675, 0.19);
|
|
147
|
+
export const easingInQuart = createEasingFn(0.895, 0.03, 0.685, 0.22);
|
|
148
|
+
export const easingInQuint = createEasingFn(0.755, 0.05, 0.855, 0.06);
|
|
149
|
+
export const easingInSine = createEasingFn(0.47, 0, 0.745, 0.715);
|
|
150
|
+
export const easingInExpo = createEasingFn(0.95, 0.05, 0.795, 0.035);
|
|
151
|
+
export const easingInCirc = createEasingFn(0.6, 0.04, 0.98, 0.335);
|
|
152
|
+
export const easingInBack = createEasingFn(0.6, -0.28, 0.735, 0.045);
|
|
153
|
+
export const easingOutQuad = createEasingFn(0.25, 0.46, 0.45, 0.94);
|
|
154
|
+
export const easingOutCubic = createEasingFn(0.215, 0.61, 0.355, 1);
|
|
155
|
+
export const easingOutQuart = createEasingFn(0.165, 0.84, 0.44, 1);
|
|
156
|
+
export const easingOutQuint = createEasingFn(0.23, 1, 0.32, 1);
|
|
157
|
+
export const easingOutSine = createEasingFn(0.39, 0.575, 0.565, 1);
|
|
158
|
+
export const easingOutExpo = createEasingFn(0.19, 1, 0.22, 1);
|
|
159
|
+
export const easingOutCirc = createEasingFn(0.075, 0.82, 0.165, 1);
|
|
160
|
+
export const easingOutBack = createEasingFn(0.175, 0.885, 0.32, 1.275);
|
|
161
|
+
export const easingInOutQuart = createEasingFn(0.77, 0, 0.175, 1);
|
|
162
|
+
export const easingInOutQuint = createEasingFn(0.86, 0, 0.07, 1);
|
|
163
|
+
export const easingInOutSine = createEasingFn(0.445, 0.05, 0.55, 0.95);
|
|
164
|
+
export const easingInOutExpo = createEasingFn(1, 0, 0, 1);
|
|
165
|
+
export const easingInOutCirc = createEasingFn(0.785, 0.135, 0.15, 0.86);
|
|
166
|
+
export const easingInOutBack = createEasingFn(0.68, -0.55, 0.265, 1.55);
|
package/src/emitter.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { AnyFunction, AnyObject } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 事件类型映射,key 为事件名称,value 为事件参数类型数组
|
|
5
|
+
*/
|
|
6
|
+
export type EmitterMap = Record<string, unknown[]>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 事件监听器函数类型
|
|
10
|
+
* @template E - EmitterMap 类型
|
|
11
|
+
* @template K - 事件名称类型
|
|
12
|
+
*/
|
|
13
|
+
export type EmitterListener<E extends EmitterMap, K extends keyof E> = (...payloads: E[K]) => false | unknown;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 事件发射器类,用于管理事件监听和触发
|
|
17
|
+
* @template E - 事件类型映射
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* type MyEvents = {
|
|
21
|
+
* 'click': [x: number, y: number];
|
|
22
|
+
* 'change': [value: string];
|
|
23
|
+
* };
|
|
24
|
+
*
|
|
25
|
+
* const emitter = new Emitter<MyEvents>();
|
|
26
|
+
* emitter.on('click', (x, y) => {
|
|
27
|
+
* console.log(`Clicked at (${x}, ${y})`);
|
|
28
|
+
* });
|
|
29
|
+
* emitter.emit('click', 10, 20);
|
|
30
|
+
*/
|
|
31
|
+
export class Emitter<E extends EmitterMap> {
|
|
32
|
+
#events: Map<keyof E, Set<AnyFunction>> = new Map();
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 注册事件监听器
|
|
36
|
+
* @param event - 要监听的事件名称
|
|
37
|
+
* @param listener - 事件监听器函数
|
|
38
|
+
* @example
|
|
39
|
+
* emitter.on('click', (x, y) => {
|
|
40
|
+
* console.log(`Clicked at (${x}, ${y})`);
|
|
41
|
+
* });
|
|
42
|
+
*/
|
|
43
|
+
on<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {
|
|
44
|
+
const listeners = this.#events.get(event);
|
|
45
|
+
if (listeners) {
|
|
46
|
+
listeners.add(listener);
|
|
47
|
+
} else {
|
|
48
|
+
this.#events.set(event, new Set([listener]));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 移除事件监听器,有三种使用方式:
|
|
54
|
+
* 1. 移除特定事件的特定监听器
|
|
55
|
+
* 2. 移除特定事件的所有监听器
|
|
56
|
+
* 3. 移除所有事件的所有监听器
|
|
57
|
+
* @param event - 要移除的事件名称(可选)
|
|
58
|
+
* @param listener - 要移除的监听器函数(可选)
|
|
59
|
+
* @example
|
|
60
|
+
* // 移除特定事件的特定监听器
|
|
61
|
+
* emitter.off('click', clickHandler);
|
|
62
|
+
*
|
|
63
|
+
* // 移除特定事件的所有监听器
|
|
64
|
+
* emitter.off('click');
|
|
65
|
+
*
|
|
66
|
+
* // 移除所有事件的所有监听器
|
|
67
|
+
* emitter.off();
|
|
68
|
+
*/
|
|
69
|
+
off<K extends keyof E>(event?: K, listener?: EmitterListener<E, K>) {
|
|
70
|
+
if (event && listener) {
|
|
71
|
+
this.#offListener(event, listener);
|
|
72
|
+
} else if (event) {
|
|
73
|
+
this.#offEvent(event);
|
|
74
|
+
} else {
|
|
75
|
+
this.#offAll();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#offAll() {
|
|
80
|
+
this.#events.clear();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#offEvent<K extends keyof E>(event: K) {
|
|
84
|
+
this.#events.delete(event);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#offListener<K extends keyof E>(event: K, listener: EmitterListener<E, K>) {
|
|
88
|
+
const listeners = this.#events.get(event);
|
|
89
|
+
|
|
90
|
+
if (listeners) {
|
|
91
|
+
listeners.delete(listener);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 触发指定事件,调用所有注册的监听器
|
|
97
|
+
* @param event - 要触发的事件名称
|
|
98
|
+
* @param payloads - 传递给监听器的参数
|
|
99
|
+
* @remarks
|
|
100
|
+
* 监听器会按照注册的顺序依次执行,如果某个监听器返回 false,
|
|
101
|
+
* 则后续监听器将不会被执行
|
|
102
|
+
* @example
|
|
103
|
+
* emitter.emit('click', 10, 20);
|
|
104
|
+
*/
|
|
105
|
+
emit<K extends keyof E>(event: K, ...payloads: Parameters<EmitterListener<E, K>>) {
|
|
106
|
+
const listeners = this.#events.get(event) as Set<EmitterListener<E, K>> | undefined;
|
|
107
|
+
|
|
108
|
+
if (!listeners) return;
|
|
109
|
+
|
|
110
|
+
// 避免在 emit、on 的过程中改变 listeners 从而影响本次 emit
|
|
111
|
+
for (const listener of [...listeners]) {
|
|
112
|
+
if (listener(...payloads) === false) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|