mui-temporal-pickers 1.0.0

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.
Files changed (39) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +130 -0
  3. package/dist/adapters/adapter-formats.d.ts +2 -0
  4. package/dist/adapters/adapter-formats.js +25 -0
  5. package/dist/adapters/base.d.ts +97 -0
  6. package/dist/adapters/base.js +216 -0
  7. package/dist/adapters/operations.d.ts +70 -0
  8. package/dist/adapters/operations.js +120 -0
  9. package/dist/adapters/plain-date-time.d.ts +12 -0
  10. package/dist/adapters/plain-date-time.js +46 -0
  11. package/dist/adapters/plain-date.d.ts +6 -0
  12. package/dist/adapters/plain-date.js +46 -0
  13. package/dist/adapters/plain-time.d.ts +6 -0
  14. package/dist/adapters/plain-time.js +46 -0
  15. package/dist/adapters/zoned-date-time.d.ts +12 -0
  16. package/dist/adapters/zoned-date-time.js +55 -0
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +1 -0
  19. package/dist/locale/format/formatter.d.ts +12 -0
  20. package/dist/locale/format/formatter.js +377 -0
  21. package/dist/locale/format/tokenizer.d.ts +9 -0
  22. package/dist/locale/format/tokenizer.js +83 -0
  23. package/dist/locale/format/tokens.d.ts +8 -0
  24. package/dist/locale/format/tokens.js +70 -0
  25. package/dist/locale/specs.d.ts +9 -0
  26. package/dist/locale/specs.js +30 -0
  27. package/dist/providers/index.d.ts +5 -0
  28. package/dist/providers/index.js +5 -0
  29. package/dist/providers/plain-date-time.d.ts +5 -0
  30. package/dist/providers/plain-date-time.js +8 -0
  31. package/dist/providers/plain-date.d.ts +5 -0
  32. package/dist/providers/plain-date.js +8 -0
  33. package/dist/providers/plain-time.d.ts +5 -0
  34. package/dist/providers/plain-time.js +8 -0
  35. package/dist/providers/root.d.ts +13 -0
  36. package/dist/providers/root.js +7 -0
  37. package/dist/providers/zoned-date-time.d.ts +5 -0
  38. package/dist/providers/zoned-date-time.js +8 -0
  39. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2025, Ben Scholzen 'DASPRiD'
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # Temporal Pickers for MUI X
2
+
3
+ [![Release](https://github.com/dasprid/mui-temporal-pickers/actions/workflows/release.yml/badge.svg)](https://github.com/dasprid/mui-temporal-pickers/actions/workflows/release.yml)
4
+
5
+ A small utility library providing [Temporal](https://tc39.es/proposal-temporal/) support for
6
+ [MUI X Date and Time Pickers](https://mui.com/x/react-date-pickers/).
7
+
8
+ This package bridges the gap between MUI X and the TC39 Temporal API by introducing context-based providers that adapt
9
+ pickers to work seamlessly with `Temporal.PlainDate`, `Temporal.PlainTime`, `Temporal.PlainDateTime`, and
10
+ `Temporal.ZonedDateTime`.
11
+
12
+ ## Features
13
+
14
+ - Plug-and-play support for Temporal types in MUI X pickers
15
+ - Supports all major temporal types: `PlainDate`, `PlainTime`, `PlainDateTime`, `ZonedDateTime`
16
+ - Global locale, format, and text customization via root provider
17
+ - Fully tree-shakable and composable
18
+ - Built-in localization fallback to `en-US`
19
+
20
+ ## Getting Started
21
+
22
+ Install via your favorite package manager:
23
+
24
+ ```bash
25
+ npm install mui-temporal-pickers
26
+ # or
27
+ pnpm add mui-temporal-pickers
28
+ # or
29
+ yarn add mui-temporal-pickers
30
+ ```
31
+
32
+ ### Try the demo
33
+
34
+ This repository includes a working demo app. You can run it locally using:
35
+
36
+ ```bash
37
+ pnpm demo
38
+ ```
39
+
40
+ This will launch a Vite-powered playground with all picker types wired up.
41
+
42
+ ## Using the Temporal Polyfill
43
+
44
+ If you want to use the [Temporal API](https://tc39.es/proposal-temporal/) in environments where it is not yet natively
45
+ supported, you can include the [temporal-polyfill](https://www.npmjs.com/package/temporal-polyfill).
46
+
47
+ Once you have it installed, you can enable it:
48
+
49
+ ```ts
50
+ if (typeof Temporal === "undefined") {
51
+ await import("temporal-polyfill/global");
52
+ }
53
+ ```
54
+
55
+ This will globally patch the environment, adding the Temporal API on `globalThis.Temporal`.
56
+
57
+ ### TypeScript support for Temporal
58
+
59
+ To get proper TypeScript typings for the polyfill (and the Temporal API in general), you need to install the
60
+ [temporal-spec](https://www.npmjs.com/package/temporal-spec) types package.
61
+
62
+ Then create a `temporal.d.ts` file in your project (e.g., in your `src` folder or your `types` folder) with the
63
+ following content:
64
+
65
+ ```ts
66
+ import "temporal-spec/global";
67
+ ```
68
+
69
+ This will augment the TypeScript global scope with Temporal API types, so your editor and compiler understand `Temporal`
70
+ properly.
71
+
72
+ ## Usage
73
+
74
+ ### 1. (Optional) Wrap your app with TemporalRootProvider
75
+
76
+ This allows you to configure global `locale`, `dateFormats`, and `localeText`, similar to MUI's `LocalizationProvider`.
77
+ You can omit this if you don't need customization.
78
+
79
+ ```tsx
80
+ import { TemporalRootProvider } from 'mui-temporal-pickers';
81
+
82
+ <TemporalRootProvider locale="de-DE">
83
+ <App />
84
+ </TemporalRootProvider>
85
+ ```
86
+
87
+ ### 2. Wrap pickers with the appropriate Temporal provider
88
+
89
+ You must wrap each picker (or group of same-kind pickers) in a provider that matches the Temporal type being used.
90
+
91
+ ```tsx
92
+ import { TemporalPlainDateProvider } from 'mui-temporal-pickers';
93
+ import { DatePicker, TimePicker, DateTimePicker } from '@mui/x-date-pickers';
94
+
95
+ // Example: PlainDate
96
+ <TemporalPlainDateProvider>
97
+ <DatePicker
98
+ label="PlainDate"
99
+ value={Temporal.PlainDate.from('2025-06-19')}
100
+ onChange={(val) => console.log(val?.toString())}
101
+ />
102
+ </TemporalPlainDateProvider>
103
+ ```
104
+
105
+ Pickers **must be wrapped** in the matching provider to work correctly. Mixed types or mismatched types will result in
106
+ runtime errors.
107
+
108
+ ## Caveats
109
+
110
+ ### Limited formatting token support
111
+
112
+ Due to how `Intl.DateTimeFormat` works, text field formatting only supports numeric tokens (like `yyyy`, `MM`, `dd`,
113
+ `HH`, `mm`). Literal characters (like slashes or dashes) are fine.
114
+
115
+ The only non-numeric token allowed is **AM/PM**, which is not currently localized and always displays as `"AM"` /
116
+ `"PM"`.
117
+
118
+ ### No runtime validation of input types
119
+
120
+ For performance reasons, this library **does not validate** that the value passed to a picker matches the expected
121
+ Temporal type. Passing an incorrect type (e.g., `PlainDate` to a time picker) will lead to downstream errors from MUI
122
+ or the Temporal API.
123
+
124
+ Use with care and ensure values match the context's expectation.
125
+
126
+ ## Package Goals
127
+
128
+ - Stay minimal: no runtime conversions or unnecessary wrappers
129
+ - Keep compatibility with MUI X moving forward
130
+ - Encourage adoption of Temporal without losing MUI's power
@@ -0,0 +1,2 @@
1
+ import type { AdapterFormats } from "@mui/x-date-pickers";
2
+ export declare const defaultFormats: AdapterFormats;
@@ -0,0 +1,25 @@
1
+ export const defaultFormats = {
2
+ year: "yyyy",
3
+ month: "MMMM",
4
+ monthShort: "MMM",
5
+ dayOfMonth: "d",
6
+ // Full day of the month format (i.e. 3rd) is not supported
7
+ // Falling back to regular format
8
+ dayOfMonthFull: "d",
9
+ weekday: "cccc",
10
+ weekdayShort: "ccc",
11
+ hours24h: "HH",
12
+ hours12h: "hh",
13
+ meridiem: "a",
14
+ minutes: "mm",
15
+ seconds: "ss",
16
+ fullDate: "lfd",
17
+ keyboardDate: "lkd",
18
+ shortDate: "lsd",
19
+ normalDate: "lnd",
20
+ normalDateWithWeekday: "lndw",
21
+ fullTime12h: "lfta",
22
+ fullTime24h: "lftd",
23
+ keyboardDateTime12h: "lkdta",
24
+ keyboardDateTime24h: "lkdtd",
25
+ };
@@ -0,0 +1,97 @@
1
+ import type { AdapterFormats, AdapterOptions, DateBuilderReturnType, FieldFormatTokenMap, MuiPickersAdapter, PickersTimezone } from "@mui/x-date-pickers";
2
+ import { LocaleSpecs } from "../locale/specs.js";
3
+ import { type AdapterComparisonOperations, type AdapterConversionOperations, type AdapterDateOperations, type AdapterTimeOperations, type AdapterTimezoneOperations } from "./operations.js";
4
+ export type ValidTemporal = Temporal.PlainTime | Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime;
5
+ export type ValidTimeTemporal = Temporal.PlainTime | Temporal.PlainDateTime | Temporal.ZonedDateTime;
6
+ export type ValidDateTemporal = Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime;
7
+ declare module "@mui/x-date-pickers/models" {
8
+ interface PickerValidDateLookup {
9
+ temporal: ValidTemporal;
10
+ }
11
+ }
12
+ type AdapterTemporalOptions<T extends ValidTemporal> = {
13
+ conversionOperations: AdapterConversionOperations<T>;
14
+ comparisonOperations: AdapterComparisonOperations<T>;
15
+ dateOperations?: AdapterDateOperations<T>;
16
+ timeOperations?: AdapterTimeOperations<T>;
17
+ timezoneOperations?: AdapterTimezoneOperations<T>;
18
+ };
19
+ export declare abstract class AdapterTemporalBase<TTemporal extends ValidTemporal> implements MuiPickersAdapter<Intl.Locale> {
20
+ readonly isMUIAdapter = true;
21
+ readonly isTimezoneCompatible = true;
22
+ readonly lib = "temporal";
23
+ readonly locale: Intl.Locale;
24
+ readonly formats: AdapterFormats;
25
+ readonly escapedCharacters: {
26
+ start: string;
27
+ end: string;
28
+ };
29
+ abstract readonly formatTokenMap: FieldFormatTokenMap;
30
+ protected readonly localeSpecs: LocaleSpecs;
31
+ protected readonly conversionOperations: AdapterConversionOperations<TTemporal>;
32
+ protected readonly comparisonOperations: AdapterComparisonOperations<TTemporal>;
33
+ protected readonly dateOperations: AdapterDateOperations<TTemporal>;
34
+ protected readonly timeOperations: AdapterTimeOperations<TTemporal>;
35
+ protected readonly timezoneOperations: AdapterTimezoneOperations<TTemporal>;
36
+ protected constructor({ locale, formats, conversionOperations, comparisonOperations, dateOperations, timeOperations, timezoneOperations, }: AdapterOptions<Intl.Locale | string, never> & AdapterTemporalOptions<TTemporal>);
37
+ date<T extends string | null | undefined>(value?: T, timezone?: PickersTimezone): DateBuilderReturnType<T>;
38
+ toJsDate(value: TTemporal): Date;
39
+ parse(value: string, format: string): TTemporal | null;
40
+ isEqual(value: TTemporal | null, comparing: TTemporal | null): boolean;
41
+ isSameYear(value: TTemporal, comparing: TTemporal): boolean;
42
+ isSameMonth(value: TTemporal, comparing: TTemporal): boolean;
43
+ isSameDay(value: TTemporal, comparing: TTemporal): boolean;
44
+ isSameHour(value: TTemporal, comparing: TTemporal): boolean;
45
+ isAfter(value: TTemporal, comparing: TTemporal): boolean;
46
+ isAfterYear(value: TTemporal, comparing: TTemporal): boolean;
47
+ isAfterDay(value: TTemporal, comparing: TTemporal): boolean;
48
+ isBefore(value: TTemporal, comparing: TTemporal): boolean;
49
+ isBeforeYear(value: TTemporal, comparing: TTemporal): boolean;
50
+ isBeforeDay(value: TTemporal, comparing: TTemporal): boolean;
51
+ getInvalidDate(): TTemporal;
52
+ getTimezone(value: TTemporal | null): PickersTimezone;
53
+ setTimezone(value: TTemporal, timezone: PickersTimezone): TTemporal;
54
+ getCurrentLocaleCode(): string;
55
+ is12HourCycleInCurrentLocale(): boolean;
56
+ expandFormat(format: string): string;
57
+ isValid(value: TTemporal | null): value is TTemporal;
58
+ format(value: TTemporal, formatKey: keyof AdapterFormats): string;
59
+ formatByString(value: TTemporal, format: string): string;
60
+ formatNumber(numberToFormat: string): string;
61
+ isWithinRange(value: TTemporal, [start, end]: [TTemporal, TTemporal]): boolean;
62
+ startOfYear(value: TTemporal): TTemporal;
63
+ startOfMonth(value: TTemporal): TTemporal;
64
+ startOfWeek(value: TTemporal): TTemporal;
65
+ startOfDay(value: TTemporal): TTemporal;
66
+ endOfYear(value: TTemporal): TTemporal;
67
+ endOfMonth(value: TTemporal): TTemporal;
68
+ endOfWeek(value: TTemporal): TTemporal;
69
+ endOfDay(value: TTemporal): TTemporal;
70
+ addYears(value: TTemporal, amount: number): TTemporal;
71
+ addMonths(value: TTemporal, amount: number): TTemporal;
72
+ addWeeks(value: TTemporal, amount: number): TTemporal;
73
+ addDays(value: TTemporal, amount: number): TTemporal;
74
+ addHours(value: TTemporal, amount: number): TTemporal;
75
+ addMinutes(value: TTemporal, amount: number): TTemporal;
76
+ addSeconds(value: TTemporal, amount: number): TTemporal;
77
+ getYear(value: TTemporal): number;
78
+ getMonth(value: TTemporal): number;
79
+ getDate(value: TTemporal): number;
80
+ getHours(value: TTemporal): number;
81
+ getMinutes(value: TTemporal): number;
82
+ getSeconds(value: TTemporal): number;
83
+ getMilliseconds(value: TTemporal): number;
84
+ getDaysInMonth(value: TTemporal): number;
85
+ getWeekNumber(value: TTemporal): number;
86
+ getDayOfWeek(value: TTemporal): number;
87
+ setYear(value: TTemporal, year: number): TTemporal;
88
+ setMonth(value: TTemporal, month: number): TTemporal;
89
+ setDate(value: TTemporal, date: number): TTemporal;
90
+ setHours(value: TTemporal, hours: number): TTemporal;
91
+ setMinutes(value: TTemporal, minutes: number): TTemporal;
92
+ setSeconds(value: TTemporal, seconds: number): TTemporal;
93
+ setMilliseconds(value: TTemporal, milliseconds: number): TTemporal;
94
+ getWeekArray(value: TTemporal): TTemporal[][];
95
+ getYearRange(range: [TTemporal, TTemporal]): TTemporal[];
96
+ }
97
+ export {};
@@ -0,0 +1,216 @@
1
+ import { LocaleSpecs } from "../locale/specs.js";
2
+ import { defaultFormats } from "./adapter-formats.js";
3
+ import { noopAdapterDateOperations, noopAdapterTimeOperations, noopAdapterTimezoneOperations, } from "./operations.js";
4
+ export class AdapterTemporalBase {
5
+ isMUIAdapter = true;
6
+ isTimezoneCompatible = true;
7
+ lib = "temporal";
8
+ locale;
9
+ formats;
10
+ escapedCharacters = { start: "'", end: "'" };
11
+ localeSpecs;
12
+ conversionOperations;
13
+ comparisonOperations;
14
+ dateOperations;
15
+ timeOperations;
16
+ timezoneOperations;
17
+ constructor({ locale = new Intl.Locale("en-US"), formats, conversionOperations, comparisonOperations, dateOperations = noopAdapterDateOperations, timeOperations = noopAdapterTimeOperations, timezoneOperations = noopAdapterTimezoneOperations, }) {
18
+ this.locale = typeof locale === "string" ? new Intl.Locale(locale) : locale;
19
+ this.localeSpecs = LocaleSpecs.get(this.locale);
20
+ this.formats = { ...defaultFormats, ...formats };
21
+ this.conversionOperations = conversionOperations;
22
+ this.comparisonOperations = comparisonOperations;
23
+ this.dateOperations = dateOperations;
24
+ this.timeOperations = timeOperations;
25
+ this.timezoneOperations = timezoneOperations;
26
+ }
27
+ date(value, timezone) {
28
+ return this.conversionOperations.date(value, timezone);
29
+ }
30
+ toJsDate(value) {
31
+ return this.conversionOperations.toJsDate(value);
32
+ }
33
+ parse(value, format) {
34
+ return this.conversionOperations.parse(value, format, this.localeSpecs);
35
+ }
36
+ isEqual(value, comparing) {
37
+ if (value === null && comparing === null) {
38
+ return true;
39
+ }
40
+ if (value === null || comparing === null) {
41
+ return false;
42
+ }
43
+ return this.comparisonOperations.isEqual(value, comparing);
44
+ }
45
+ isSameYear(value, comparing) {
46
+ return this.comparisonOperations.isSameYear(value, comparing);
47
+ }
48
+ isSameMonth(value, comparing) {
49
+ return this.comparisonOperations.isSameMonth(value, comparing);
50
+ }
51
+ isSameDay(value, comparing) {
52
+ return this.comparisonOperations.isSameDay(value, comparing);
53
+ }
54
+ isSameHour(value, comparing) {
55
+ return this.comparisonOperations.isSameHour(value, comparing);
56
+ }
57
+ isAfter(value, comparing) {
58
+ return this.comparisonOperations.isAfter(value, comparing);
59
+ }
60
+ isAfterYear(value, comparing) {
61
+ return this.comparisonOperations.isAfterYear(value, comparing);
62
+ }
63
+ isAfterDay(value, comparing) {
64
+ return this.comparisonOperations.isAfterDay(value, comparing);
65
+ }
66
+ isBefore(value, comparing) {
67
+ return this.comparisonOperations.isBefore(value, comparing);
68
+ }
69
+ isBeforeYear(value, comparing) {
70
+ return this.comparisonOperations.isBeforeYear(value, comparing);
71
+ }
72
+ isBeforeDay(value, comparing) {
73
+ return this.comparisonOperations.isBeforeDay(value, comparing);
74
+ }
75
+ getInvalidDate() {
76
+ return null;
77
+ }
78
+ getTimezone(value) {
79
+ return this.timezoneOperations.getTimezone(value);
80
+ }
81
+ setTimezone(value, timezone) {
82
+ return this.timezoneOperations.setTimezone(value, timezone);
83
+ }
84
+ getCurrentLocaleCode() {
85
+ return this.locale.toString();
86
+ }
87
+ is12HourCycleInCurrentLocale() {
88
+ return this.localeSpecs.hour12;
89
+ }
90
+ expandFormat(format) {
91
+ return this.localeSpecs.formatter.expandFormat(format);
92
+ }
93
+ isValid(value) {
94
+ return value !== null;
95
+ }
96
+ format(value, formatKey) {
97
+ return this.formatByString(value, this.formats[formatKey]);
98
+ }
99
+ formatByString(value, format) {
100
+ if (format === "s" && value instanceof Temporal.PlainDate) {
101
+ // This is MUI-X collecting localized digits. It allows us to return "0" here, which makes it fall back to
102
+ // non-localized digits!
103
+ return "0";
104
+ }
105
+ return this.localeSpecs.formatter.format(value, format);
106
+ }
107
+ formatNumber(numberToFormat) {
108
+ return numberToFormat;
109
+ }
110
+ isWithinRange(value, [start, end]) {
111
+ return !(this.comparisonOperations.isBefore(value, start) ||
112
+ this.comparisonOperations.isAfter(value, end));
113
+ }
114
+ startOfYear(value) {
115
+ return this.dateOperations.startOfYear(value);
116
+ }
117
+ startOfMonth(value) {
118
+ return this.dateOperations.startOfMonth(value);
119
+ }
120
+ startOfWeek(value) {
121
+ return this.dateOperations.startOfWeek(value, this.locale);
122
+ }
123
+ startOfDay(value) {
124
+ return this.timeOperations.startOfDay(value);
125
+ }
126
+ endOfYear(value) {
127
+ return this.dateOperations.endOfYear(value);
128
+ }
129
+ endOfMonth(value) {
130
+ return this.dateOperations.endOfMonth(value);
131
+ }
132
+ endOfWeek(value) {
133
+ return this.dateOperations.endOfWeek(value, this.locale);
134
+ }
135
+ endOfDay(value) {
136
+ return this.timeOperations.endOfDay(value);
137
+ }
138
+ addYears(value, amount) {
139
+ return this.dateOperations.addYears(value, amount);
140
+ }
141
+ addMonths(value, amount) {
142
+ return this.dateOperations.addMonths(value, amount);
143
+ }
144
+ addWeeks(value, amount) {
145
+ return this.dateOperations.addWeeks(value, amount);
146
+ }
147
+ addDays(value, amount) {
148
+ return this.dateOperations.addDays(value, amount);
149
+ }
150
+ addHours(value, amount) {
151
+ return this.timeOperations.addHours(value, amount);
152
+ }
153
+ addMinutes(value, amount) {
154
+ return this.timeOperations.addMinutes(value, amount);
155
+ }
156
+ addSeconds(value, amount) {
157
+ return this.timeOperations.addSeconds(value, amount);
158
+ }
159
+ getYear(value) {
160
+ return this.dateOperations.getYear(value);
161
+ }
162
+ getMonth(value) {
163
+ return this.dateOperations.getMonth(value);
164
+ }
165
+ getDate(value) {
166
+ return this.dateOperations.getDate(value);
167
+ }
168
+ getHours(value) {
169
+ return this.timeOperations.getHours(value);
170
+ }
171
+ getMinutes(value) {
172
+ return this.timeOperations.getMinutes(value);
173
+ }
174
+ getSeconds(value) {
175
+ return this.timeOperations.getSeconds(value);
176
+ }
177
+ getMilliseconds(value) {
178
+ return this.timeOperations.getMilliseconds(value);
179
+ }
180
+ getDaysInMonth(value) {
181
+ return this.dateOperations.getDaysInMonth(value);
182
+ }
183
+ getWeekNumber(value) {
184
+ return this.dateOperations.getWeekNumber(value, this.locale);
185
+ }
186
+ getDayOfWeek(value) {
187
+ return this.dateOperations.getDayOfWeek(value);
188
+ }
189
+ setYear(value, year) {
190
+ return this.dateOperations.setYear(value, year);
191
+ }
192
+ setMonth(value, month) {
193
+ return this.dateOperations.setMonth(value, month);
194
+ }
195
+ setDate(value, date) {
196
+ return this.dateOperations.setDate(value, date);
197
+ }
198
+ setHours(value, hours) {
199
+ return this.timeOperations.setHours(value, hours);
200
+ }
201
+ setMinutes(value, minutes) {
202
+ return this.timeOperations.setMinutes(value, minutes);
203
+ }
204
+ setSeconds(value, seconds) {
205
+ return this.timeOperations.setSeconds(value, seconds);
206
+ }
207
+ setMilliseconds(value, milliseconds) {
208
+ return this.timeOperations.setMilliseconds(value, milliseconds);
209
+ }
210
+ getWeekArray(value) {
211
+ return this.dateOperations.getWeekArray(value, this);
212
+ }
213
+ getYearRange(range) {
214
+ return this.dateOperations.getYearRange(range, this);
215
+ }
216
+ }
@@ -0,0 +1,70 @@
1
+ import type { DateBuilderReturnType, PickersTimezone } from "@mui/x-date-pickers";
2
+ import type { LocaleSpecs } from "../locale/specs.js";
3
+ import type { AdapterTemporalBase, ValidDateTemporal, ValidTemporal, ValidTimeTemporal } from "./base.js";
4
+ export type AdapterConversionOperations<T extends ValidTemporal> = {
5
+ date: <T extends string | null | undefined>(value?: T, timezone?: PickersTimezone) => DateBuilderReturnType<T>;
6
+ toJsDate: (value: T) => Date;
7
+ parse: (value: string, format: string, localeSpecs: LocaleSpecs) => T | null;
8
+ };
9
+ export type AdapterComparisonOperations<T extends ValidTemporal> = {
10
+ isEqual: (value: T, comparing: T) => boolean;
11
+ isSameYear: (value: T, comparing: T) => boolean;
12
+ isSameMonth: (value: T, comparing: T) => boolean;
13
+ isSameDay: (value: T, comparing: T) => boolean;
14
+ isSameHour: (value: T, comparing: T) => boolean;
15
+ isAfter: (value: T, comparing: T) => boolean;
16
+ isAfterYear: (value: T, comparing: T) => boolean;
17
+ isAfterDay: (value: T, comparing: T) => boolean;
18
+ isBefore: (value: T, comparing: T) => boolean;
19
+ isBeforeYear: (value: T, comparing: T) => boolean;
20
+ isBeforeDay: (value: T, comparing: T) => boolean;
21
+ };
22
+ export type AdapterDateOperations<T extends ValidTemporal> = {
23
+ startOfYear: (value: T) => T;
24
+ startOfMonth: (value: T) => T;
25
+ startOfWeek: (value: T, locale: Intl.Locale) => T;
26
+ endOfYear: (value: T) => T;
27
+ endOfMonth: (value: T) => T;
28
+ endOfWeek: (value: T, locale: Intl.Locale) => T;
29
+ addYears: (value: T, amount: number) => T;
30
+ addMonths: (value: T, amount: number) => T;
31
+ addWeeks: (value: T, amount: number) => T;
32
+ addDays: (value: T, amount: number) => T;
33
+ getYear: (value: T) => number;
34
+ getMonth: (value: T) => number;
35
+ getDate: (value: T) => number;
36
+ getDaysInMonth: (value: T) => number;
37
+ getWeekNumber: (value: T, locale: Intl.Locale) => number;
38
+ getDayOfWeek: (value: T) => number;
39
+ setYear: (value: T, year: number) => T;
40
+ setMonth: (value: T, month: number) => T;
41
+ setDate: (value: T, date: number) => T;
42
+ getWeekArray: (value: T, adapter: AdapterTemporalBase<T>) => T[][];
43
+ getYearRange: ([start, end]: [T, T], adapter: AdapterTemporalBase<T>) => T[];
44
+ };
45
+ export declare const noopAdapterDateOperations: AdapterDateOperations<ValidTemporal>;
46
+ export declare const defaultAdapterDateOperations: AdapterDateOperations<ValidDateTemporal>;
47
+ export type AdapterTimeOperations<T extends ValidTemporal> = {
48
+ startOfDay: (value: T) => T;
49
+ endOfDay: (value: T) => T;
50
+ addHours: (value: T, amount: number) => T;
51
+ addMinutes: (value: T, amount: number) => T;
52
+ addSeconds: (value: T, amount: number) => T;
53
+ setHours: (value: T, hours: number) => T;
54
+ setMinutes: (value: T, minutes: number) => T;
55
+ setSeconds: (value: T, seconds: number) => T;
56
+ setMilliseconds: (value: T, milliseconds: number) => T;
57
+ getHours: (value: T) => number;
58
+ getMinutes: (value: T) => number;
59
+ getSeconds: (value: T) => number;
60
+ getMilliseconds: (value: T) => number;
61
+ };
62
+ export declare const noopAdapterTimeOperations: AdapterTimeOperations<ValidTemporal>;
63
+ export declare const defaultAdapterTimeOperations: AdapterTimeOperations<ValidTimeTemporal>;
64
+ export type AdapterTimezoneOperations<T extends ValidTemporal> = {
65
+ getTimezone: (value: T | null) => PickersTimezone;
66
+ setTimezone: (value: T, timezone: PickersTimezone) => T;
67
+ };
68
+ export declare const noopAdapterTimezoneOperations: AdapterTimezoneOperations<ValidTemporal>;
69
+ export declare const resolveTimeZoneId: (timezone?: PickersTimezone) => string;
70
+ export declare const defaultAdapterTimezoneOperations: AdapterTimezoneOperations<Temporal.ZonedDateTime>;
@@ -0,0 +1,120 @@
1
+ import { firstDayOfMonth, firstDayOfWeek, firstDayOfYear, lastDayOfMonth, lastDayOfWeek, lastDayOfYear, localeAwareWeekNumber, } from "temporal-extra";
2
+ export const noopAdapterDateOperations = {
3
+ startOfYear: (value) => value,
4
+ startOfMonth: (value) => value,
5
+ startOfWeek: (value) => value,
6
+ endOfYear: (value) => value,
7
+ endOfMonth: (value) => value,
8
+ endOfWeek: (value) => value,
9
+ addYears: (value) => value,
10
+ addMonths: (value) => value,
11
+ addWeeks: (value) => value,
12
+ addDays: (value) => value,
13
+ getYear: () => 2000,
14
+ getMonth: () => 1,
15
+ getDate: () => 1,
16
+ getDaysInMonth: () => 30,
17
+ getWeekNumber: () => 1,
18
+ getDayOfWeek: () => 1,
19
+ setYear: (value) => value,
20
+ setMonth: (value) => value,
21
+ setDate: (value) => value,
22
+ getWeekArray: () => [],
23
+ getYearRange: () => [],
24
+ };
25
+ export const defaultAdapterDateOperations = {
26
+ startOfYear: (value) => firstDayOfYear(value),
27
+ startOfMonth: (value) => firstDayOfMonth(value),
28
+ startOfWeek: (value, locale) => firstDayOfWeek(value, locale),
29
+ endOfYear: (value) => lastDayOfYear(value),
30
+ endOfMonth: (value) => lastDayOfMonth(value),
31
+ endOfWeek: (value, locale) => lastDayOfWeek(value, locale),
32
+ addYears: (value, amount) => value.add({ years: amount }),
33
+ addMonths: (value, amount) => value.add({ months: amount }),
34
+ addWeeks: (value, amount) => value.add({ weeks: amount }),
35
+ addDays: (value, amount) => value.add({ days: amount }),
36
+ getYear: (value) => value.year,
37
+ getMonth: (value) => value.month,
38
+ getDate: (value) => value.day,
39
+ getDaysInMonth: (value) => value.daysInMonth,
40
+ getWeekNumber: (value, locale) => localeAwareWeekNumber(value, locale),
41
+ getDayOfWeek: (value) => value.dayOfWeek,
42
+ setYear: (value, year) => value.with({ year }),
43
+ setMonth: (value, month) => value.with({ month }),
44
+ setDate: (value, date) => value.with({ day: date }),
45
+ getWeekArray: (value, adapter) => {
46
+ const start = adapter.startOfWeek(adapter.startOfMonth(value));
47
+ const end = adapter.endOfWeek(adapter.endOfMonth(value));
48
+ let count = 0;
49
+ let current = start;
50
+ const nestedWeeks = [];
51
+ while (!adapter.isAfter(current, end)) {
52
+ const weekNumber = Math.floor(count / 7);
53
+ nestedWeeks[weekNumber] = nestedWeeks[weekNumber] ?? [];
54
+ nestedWeeks[weekNumber].push(current);
55
+ current = adapter.addDays(current, 1);
56
+ count += 1;
57
+ }
58
+ return nestedWeeks;
59
+ },
60
+ getYearRange: ([start, end], adapter) => {
61
+ const startDate = adapter.startOfYear(start);
62
+ const endDate = adapter.endOfYear(end);
63
+ const years = [];
64
+ let current = startDate;
65
+ while (adapter.isBeforeYear(current, endDate)) {
66
+ years.push(current);
67
+ current = adapter.addYears(current, 1);
68
+ }
69
+ return years;
70
+ },
71
+ };
72
+ export const noopAdapterTimeOperations = {
73
+ startOfDay: (value) => value,
74
+ endOfDay: (value) => value,
75
+ addHours: (value) => value,
76
+ addMinutes: (value) => value,
77
+ addSeconds: (value) => value,
78
+ setHours: (value) => value,
79
+ setMinutes: (value) => value,
80
+ setSeconds: (value) => value,
81
+ setMilliseconds: (value) => value,
82
+ getHours: () => 0,
83
+ getMinutes: () => 0,
84
+ getSeconds: () => 0,
85
+ getMilliseconds: () => 0,
86
+ };
87
+ export const defaultAdapterTimeOperations = {
88
+ startOfDay: (value) => value.with({ hour: 0, minute: 0, second: 0, millisecond: 0 }),
89
+ endOfDay: (value) => value.with({
90
+ hour: 23,
91
+ minute: 59,
92
+ second: 59,
93
+ millisecond: 999,
94
+ }),
95
+ addHours: (value, amount) => value.add({ hours: amount }),
96
+ addMinutes: (value, amount) => value.add({ minutes: amount }),
97
+ addSeconds: (value, amount) => value.add({ seconds: amount }),
98
+ setHours: (value, hours) => value.with({ hour: hours }),
99
+ setMinutes: (value, minutes) => value.with({ minute: minutes }),
100
+ setSeconds: (value, seconds) => value.with({ second: seconds }),
101
+ setMilliseconds: (value, milliseconds) => value.with({ millisecond: milliseconds }),
102
+ getHours: (value) => value.hour,
103
+ getMinutes: (value) => value.minute,
104
+ getSeconds: (value) => value.second,
105
+ getMilliseconds: (value) => value.millisecond,
106
+ };
107
+ export const noopAdapterTimezoneOperations = {
108
+ getTimezone: () => "default",
109
+ setTimezone: (value) => value,
110
+ };
111
+ export const resolveTimeZoneId = (timezone) => {
112
+ if (!timezone || timezone === "default" || timezone === "system") {
113
+ return Temporal.Now.timeZoneId();
114
+ }
115
+ return timezone;
116
+ };
117
+ export const defaultAdapterTimezoneOperations = {
118
+ getTimezone: (value) => (value === null ? "default" : value.timeZoneId),
119
+ setTimezone: (value, timezone) => value.withTimeZone(resolveTimeZoneId(timezone)),
120
+ };