@proyecto-viviana/solid-stately 0.2.7 → 0.4.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.
- package/README.md +30 -283
- package/dist/autocomplete/createAutocompleteState.d.ts +2 -2
- package/dist/autocomplete/index.d.ts +1 -1
- package/dist/calendar/IncompleteDate.d.ts +61 -0
- package/dist/calendar/createCalendarState.d.ts +41 -16
- package/dist/calendar/createDateFieldState.d.ts +39 -9
- package/dist/calendar/createDatePickerState.d.ts +60 -0
- package/dist/calendar/createRangeCalendarState.d.ts +37 -10
- package/dist/calendar/createTimeFieldState.d.ts +34 -7
- package/dist/calendar/index.d.ts +7 -6
- package/dist/checkbox/createCheckboxGroupState.d.ts +6 -6
- package/dist/checkbox/index.d.ts +1 -1
- package/dist/collections/ListCollection.d.ts +1 -1
- package/dist/collections/createListState.d.ts +11 -8
- package/dist/collections/createMenuState.d.ts +7 -7
- package/dist/collections/createSelectionState.d.ts +22 -10
- package/dist/collections/getChildNodes.d.ts +11 -0
- package/dist/collections/index.d.ts +6 -5
- package/dist/collections/types.d.ts +12 -12
- package/dist/color/Color.d.ts +1 -1
- package/dist/color/createColorAreaState.d.ts +4 -2
- package/dist/color/createColorFieldState.d.ts +38 -12
- package/dist/color/createColorSliderState.d.ts +9 -2
- package/dist/color/createColorWheelState.d.ts +13 -2
- package/dist/color/getColorChannels.d.ts +1 -1
- package/dist/color/index.d.ts +6 -6
- package/dist/color/types.d.ts +4 -4
- package/dist/combobox/createComboBoxState.d.ts +34 -13
- package/dist/combobox/index.d.ts +1 -1
- package/dist/data/createAsyncList.d.ts +4 -4
- package/dist/data/createListData.d.ts +2 -2
- package/dist/data/createTreeData.d.ts +6 -2
- package/dist/data/index.d.ts +3 -3
- package/dist/datepicker/index.d.ts +2 -4
- package/dist/disclosure/createDisclosureState.d.ts +2 -2
- package/dist/disclosure/index.d.ts +1 -1
- package/dist/dnd/createDragState.d.ts +2 -2
- package/dist/dnd/createDraggableCollectionState.d.ts +2 -2
- package/dist/dnd/createDropState.d.ts +2 -2
- package/dist/dnd/createDroppableCollectionState.d.ts +3 -3
- package/dist/dnd/index.d.ts +5 -5
- package/dist/dnd/types.d.ts +19 -17
- package/dist/form/createFormValidationState.d.ts +3 -3
- package/dist/form/index.d.ts +1 -1
- package/dist/grid/createGridState.d.ts +2 -2
- package/dist/grid/index.d.ts +2 -2
- package/dist/grid/types.d.ts +27 -11
- package/dist/index.d.ts +31 -30
- package/dist/index.js +9077 -7246
- package/dist/index.js.map +1 -1
- package/dist/menu/index.d.ts +2 -2
- package/dist/numberfield/createNumberFieldState.d.ts +2 -2
- package/dist/numberfield/index.d.ts +1 -1
- package/dist/overlays/createOverlayTriggerState.d.ts +2 -2
- package/dist/overlays/index.d.ts +1 -1
- package/dist/radio/createRadioGroupState.d.ts +7 -7
- package/dist/radio/index.d.ts +1 -1
- package/dist/searchfield/createSearchFieldState.d.ts +2 -2
- package/dist/searchfield/index.d.ts +2 -2
- package/dist/select/createSelectState.d.ts +14 -8
- package/dist/select/index.d.ts +1 -1
- package/dist/selection/Selection.d.ts +16 -0
- package/dist/selection/SelectionManager.d.ts +110 -0
- package/dist/selection/createMultipleSelectionState.d.ts +59 -0
- package/dist/selection/index.d.ts +6 -5
- package/dist/slider/createSliderState.d.ts +3 -3
- package/dist/slider/index.d.ts +2 -2
- package/dist/steplist/createStepListState.d.ts +48 -0
- package/dist/steplist/index.d.ts +1 -0
- package/dist/table/TableCollection.d.ts +33 -3
- package/dist/table/createTableColumnResizeState.d.ts +54 -0
- package/dist/table/createTableState.d.ts +2 -2
- package/dist/table/createTreeGridState.d.ts +15 -0
- package/dist/table/index.d.ts +6 -3
- package/dist/table/types.d.ts +68 -10
- package/dist/tabs/createTabListState.d.ts +5 -5
- package/dist/tabs/index.d.ts +1 -1
- package/dist/textfield/createTextFieldState.d.ts +2 -2
- package/dist/textfield/index.d.ts +1 -1
- package/dist/toast/createToastState.d.ts +24 -2
- package/dist/toast/index.d.ts +1 -1
- package/dist/toggle/createToggleGroupState.d.ts +4 -4
- package/dist/toggle/createToggleState.d.ts +2 -2
- package/dist/toggle/index.d.ts +2 -2
- package/dist/tooltip/createTooltipTriggerState.d.ts +2 -2
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tree/TreeCollection.d.ts +2 -2
- package/dist/tree/createTreeState.d.ts +2 -2
- package/dist/tree/index.d.ts +3 -3
- package/dist/tree/types.d.ts +27 -13
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/reactivity.d.ts +1 -1
- package/package.json +29 -30
- package/src/autocomplete/createAutocompleteState.d.ts +19 -17
- package/src/autocomplete/createAutocompleteState.ts +24 -30
- package/src/autocomplete/index.d.ts +6 -2
- package/src/autocomplete/index.ts +1 -1
- package/src/calendar/IncompleteDate.ts +430 -0
- package/src/calendar/createCalendarState.d.ts +139 -117
- package/src/calendar/createCalendarState.ts +308 -94
- package/src/calendar/createDateFieldState.d.ts +130 -95
- package/src/calendar/createDateFieldState.ts +447 -334
- package/src/calendar/createDatePickerState.ts +347 -0
- package/src/calendar/createRangeCalendarState.d.ts +154 -129
- package/src/calendar/createRangeCalendarState.ts +411 -85
- package/src/calendar/createTimeFieldState.d.ts +81 -79
- package/src/calendar/createTimeFieldState.ts +187 -108
- package/src/calendar/index.d.ts +80 -7
- package/src/calendar/index.ts +23 -12
- package/src/checkbox/createCheckboxGroupState.d.ts +57 -55
- package/src/checkbox/createCheckboxGroupState.ts +20 -29
- package/src/checkbox/index.d.ts +6 -2
- package/src/checkbox/index.ts +1 -1
- package/src/collections/ListCollection.d.ts +25 -22
- package/src/collections/ListCollection.ts +6 -6
- package/src/collections/createListState.d.ts +73 -58
- package/src/collections/createListState.ts +67 -35
- package/src/collections/createMenuState.d.ts +36 -31
- package/src/collections/createMenuState.ts +21 -12
- package/src/collections/createSelectionState.d.ts +78 -65
- package/src/collections/createSelectionState.ts +66 -52
- package/src/collections/getChildNodes.ts +98 -0
- package/src/collections/index.d.ts +38 -6
- package/src/collections/index.ts +14 -10
- package/src/collections/types.d.ts +101 -101
- package/src/collections/types.ts +12 -12
- package/src/color/Color.d.ts +20 -5
- package/src/color/Color.ts +357 -254
- package/src/color/createColorAreaState.d.ts +67 -65
- package/src/color/createColorAreaState.ts +21 -13
- package/src/color/createColorFieldState.d.ts +46 -44
- package/src/color/createColorFieldState.ts +285 -149
- package/src/color/createColorSliderState.d.ts +58 -56
- package/src/color/createColorSliderState.ts +45 -14
- package/src/color/createColorWheelState.d.ts +42 -40
- package/src/color/createColorWheelState.ts +101 -64
- package/src/color/getColorChannels.ts +7 -5
- package/src/color/index.d.ts +36 -7
- package/src/color/index.ts +6 -9
- package/src/color/types.d.ts +68 -63
- package/src/color/types.ts +11 -19
- package/src/combobox/createComboBoxState.d.ts +107 -105
- package/src/combobox/createComboBoxState.ts +184 -89
- package/src/combobox/index.d.ts +10 -2
- package/src/combobox/index.ts +1 -1
- package/src/data/createAsyncList.ts +89 -63
- package/src/data/createListData.ts +67 -67
- package/src/data/createTreeData.ts +304 -91
- package/src/data/index.ts +3 -3
- package/src/datepicker/index.ts +6 -10
- package/src/disclosure/createDisclosureState.d.ts +47 -43
- package/src/disclosure/createDisclosureState.ts +7 -21
- package/src/disclosure/index.d.ts +10 -2
- package/src/disclosure/index.ts +1 -1
- package/src/dnd/createDragState.d.ts +51 -42
- package/src/dnd/createDragState.ts +12 -14
- package/src/dnd/createDraggableCollectionState.d.ts +52 -41
- package/src/dnd/createDraggableCollectionState.ts +14 -21
- package/src/dnd/createDropState.d.ts +64 -45
- package/src/dnd/createDropState.ts +22 -32
- package/src/dnd/createDroppableCollectionState.d.ts +88 -59
- package/src/dnd/createDroppableCollectionState.ts +40 -43
- package/src/dnd/index.d.ts +55 -6
- package/src/dnd/index.ts +6 -18
- package/src/dnd/types.d.ts +170 -157
- package/src/dnd/types.ts +24 -22
- package/src/form/createFormValidationState.d.ts +47 -45
- package/src/form/createFormValidationState.ts +30 -63
- package/src/form/index.d.ts +16 -2
- package/src/form/index.ts +1 -1
- package/src/grid/createGridState.d.ts +7 -4
- package/src/grid/createGridState.ts +78 -51
- package/src/grid/index.d.ts +3 -3
- package/src/grid/index.ts +2 -8
- package/src/grid/types.d.ts +136 -129
- package/src/grid/types.ts +34 -18
- package/src/index.d.ts +311 -26
- package/src/index.ts +59 -89
- package/src/menu/index.ts +2 -4
- package/src/numberfield/createNumberFieldState.d.ts +56 -54
- package/src/numberfield/createNumberFieldState.ts +26 -31
- package/src/numberfield/index.d.ts +6 -2
- package/src/numberfield/index.ts +1 -1
- package/src/overlays/createOverlayTriggerState.d.ts +22 -20
- package/src/overlays/createOverlayTriggerState.ts +3 -4
- package/src/overlays/index.d.ts +6 -2
- package/src/overlays/index.ts +1 -1
- package/src/radio/createRadioGroupState.d.ts +54 -52
- package/src/radio/createRadioGroupState.ts +27 -29
- package/src/radio/index.d.ts +7 -2
- package/src/radio/index.ts +1 -1
- package/src/searchfield/createSearchFieldState.d.ts +16 -14
- package/src/searchfield/createSearchFieldState.ts +5 -11
- package/src/searchfield/index.d.ts +3 -3
- package/src/searchfield/index.ts +2 -5
- package/src/select/createSelectState.d.ts +63 -61
- package/src/select/createSelectState.ts +42 -29
- package/src/select/index.d.ts +2 -2
- package/src/select/index.ts +1 -5
- package/src/selection/Selection.ts +28 -0
- package/src/selection/SelectionManager.ts +526 -0
- package/src/selection/createMultipleSelectionState.ts +247 -0
- package/src/selection/index.ts +12 -7
- package/src/slider/createSliderState.d.ts +60 -60
- package/src/slider/createSliderState.ts +55 -33
- package/src/slider/index.d.ts +3 -3
- package/src/slider/index.ts +2 -6
- package/src/ssr/index.d.ts +1 -1
- package/src/ssr/index.ts +2 -2
- package/src/steplist/createStepListState.ts +191 -0
- package/src/steplist/index.ts +5 -0
- package/src/table/TableCollection.d.ts +42 -40
- package/src/table/TableCollection.ts +266 -99
- package/src/table/createTableColumnResizeState.ts +242 -0
- package/src/table/createTableState.d.ts +7 -4
- package/src/table/createTableState.ts +30 -7
- package/src/table/createTreeGridState.ts +146 -0
- package/src/table/index.d.ts +14 -4
- package/src/table/index.ts +13 -3
- package/src/table/types.d.ts +98 -92
- package/src/table/types.ts +83 -13
- package/src/tabs/createTabListState.d.ts +59 -57
- package/src/tabs/createTabListState.ts +34 -39
- package/src/tabs/index.d.ts +8 -2
- package/src/tabs/index.ts +1 -1
- package/src/textfield/createTextFieldState.d.ts +16 -14
- package/src/textfield/createTextFieldState.ts +7 -18
- package/src/textfield/index.d.ts +6 -2
- package/src/textfield/index.ts +1 -1
- package/src/toast/createToastState.d.ts +92 -86
- package/src/toast/createToastState.ts +90 -52
- package/src/toast/index.d.ts +12 -2
- package/src/toast/index.ts +2 -1
- package/src/toggle/createToggleGroupState.ts +11 -21
- package/src/toggle/createToggleState.d.ts +19 -19
- package/src/toggle/createToggleState.ts +2 -16
- package/src/toggle/index.d.ts +2 -2
- package/src/toggle/index.ts +2 -6
- package/src/tooltip/createTooltipTriggerState.d.ts +17 -17
- package/src/tooltip/createTooltipTriggerState.ts +12 -11
- package/src/tooltip/index.d.ts +7 -2
- package/src/tooltip/index.ts +1 -1
- package/src/tree/TreeCollection.d.ts +26 -23
- package/src/tree/TreeCollection.ts +29 -22
- package/src/tree/createTreeState.d.ts +7 -4
- package/src/tree/createTreeState.ts +70 -41
- package/src/tree/index.d.ts +10 -4
- package/src/tree/index.ts +3 -3
- package/src/tree/types.d.ts +131 -126
- package/src/tree/types.ts +30 -13
- package/src/utils/index.d.ts +2 -2
- package/src/utils/index.ts +1 -1
- package/src/utils/reactivity.d.ts +2 -2
- package/src/utils/reactivity.ts +3 -3
|
@@ -4,37 +4,29 @@
|
|
|
4
4
|
* Based on @react-stately/autocomplete useAutocompleteState.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { createSignal, type Accessor } from
|
|
8
|
-
import { access, type MaybeAccessor } from
|
|
9
|
-
|
|
10
|
-
// ============================================
|
|
11
|
-
// TYPES
|
|
12
|
-
// ============================================
|
|
7
|
+
import { createSignal, type Accessor } from "solid-js";
|
|
8
|
+
import { access, type MaybeAccessor } from "../utils";
|
|
13
9
|
|
|
14
10
|
export interface AutocompleteState {
|
|
15
11
|
/** The current value of the autocomplete input. */
|
|
16
|
-
inputValue: Accessor<string
|
|
12
|
+
inputValue: Accessor<string>;
|
|
17
13
|
/** Sets the value of the autocomplete input. */
|
|
18
|
-
setInputValue(value: string): void
|
|
14
|
+
setInputValue(value: string): void;
|
|
19
15
|
/** The id of the current aria-activedescendant of the autocomplete input. */
|
|
20
|
-
focusedNodeId: Accessor<string | null
|
|
16
|
+
focusedNodeId: Accessor<string | null>;
|
|
21
17
|
/** Sets the id of the current aria-activedescendant of the autocomplete input. */
|
|
22
|
-
setFocusedNodeId(value: string | null): void
|
|
18
|
+
setFocusedNodeId(value: string | null): void;
|
|
23
19
|
}
|
|
24
20
|
|
|
25
21
|
export interface AutocompleteStateOptions {
|
|
26
22
|
/** The value of the autocomplete input (controlled). */
|
|
27
|
-
inputValue?: string
|
|
23
|
+
inputValue?: string;
|
|
28
24
|
/** The default value of the autocomplete input (uncontrolled). */
|
|
29
|
-
defaultInputValue?: string
|
|
25
|
+
defaultInputValue?: string;
|
|
30
26
|
/** Handler that is called when the autocomplete input value changes. */
|
|
31
|
-
onInputChange?: (value: string) => void
|
|
27
|
+
onInputChange?: (value: string) => void;
|
|
32
28
|
}
|
|
33
29
|
|
|
34
|
-
// ============================================
|
|
35
|
-
// CREATE AUTOCOMPLETE STATE
|
|
36
|
-
// ============================================
|
|
37
|
-
|
|
38
30
|
/**
|
|
39
31
|
* Provides state management for an autocomplete component.
|
|
40
32
|
*
|
|
@@ -56,34 +48,36 @@ export interface AutocompleteStateOptions {
|
|
|
56
48
|
* ```
|
|
57
49
|
*/
|
|
58
50
|
export function createAutocompleteState(
|
|
59
|
-
props: MaybeAccessor<AutocompleteStateOptions> = {}
|
|
51
|
+
props: MaybeAccessor<AutocompleteStateOptions> = {},
|
|
60
52
|
): AutocompleteState {
|
|
61
|
-
const getProps = () => access(props)
|
|
53
|
+
const getProps = () => access(props);
|
|
62
54
|
|
|
63
55
|
// Track focused node ID for aria-activedescendant
|
|
64
|
-
const [focusedNodeId, setFocusedNodeId] = createSignal<string | null>(null)
|
|
56
|
+
const [focusedNodeId, setFocusedNodeId] = createSignal<string | null>(null);
|
|
65
57
|
|
|
66
58
|
// Handle controlled vs uncontrolled input value
|
|
67
|
-
const isControlled = () => getProps().inputValue !== undefined
|
|
68
|
-
const [uncontrolledValue, setUncontrolledValue] = createSignal(
|
|
59
|
+
const isControlled = () => getProps().inputValue !== undefined;
|
|
60
|
+
const [uncontrolledValue, setUncontrolledValue] = createSignal(
|
|
61
|
+
getProps().defaultInputValue ?? "",
|
|
62
|
+
);
|
|
69
63
|
|
|
70
64
|
const inputValue: Accessor<string> = () => {
|
|
71
|
-
const p = getProps()
|
|
72
|
-
return isControlled() ? (p.inputValue ??
|
|
73
|
-
}
|
|
65
|
+
const p = getProps();
|
|
66
|
+
return isControlled() ? (p.inputValue ?? "") : uncontrolledValue();
|
|
67
|
+
};
|
|
74
68
|
|
|
75
69
|
const setInputValue = (value: string) => {
|
|
76
|
-
const p = getProps()
|
|
70
|
+
const p = getProps();
|
|
77
71
|
if (!isControlled()) {
|
|
78
|
-
setUncontrolledValue(value)
|
|
72
|
+
setUncontrolledValue(value);
|
|
79
73
|
}
|
|
80
|
-
p.onInputChange?.(value)
|
|
81
|
-
}
|
|
74
|
+
p.onInputChange?.(value);
|
|
75
|
+
};
|
|
82
76
|
|
|
83
77
|
return {
|
|
84
78
|
inputValue,
|
|
85
79
|
setInputValue,
|
|
86
80
|
focusedNodeId,
|
|
87
81
|
setFocusedNodeId,
|
|
88
|
-
}
|
|
82
|
+
};
|
|
89
83
|
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
1
|
+
export {
|
|
2
|
+
createAutocompleteState,
|
|
3
|
+
type AutocompleteState,
|
|
4
|
+
type AutocompleteStateOptions,
|
|
5
|
+
} from "./createAutocompleteState";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IncompleteDate for Solid-Stately
|
|
3
|
+
*
|
|
4
|
+
* Represents a date that is incomplete or otherwise invalid as a result of user
|
|
5
|
+
* editing (for example February 31st, if the day is edited before the month).
|
|
6
|
+
* This lets a date field hold an invalid intermediate value while typing and
|
|
7
|
+
* only constrain it on blur, matching upstream behavior.
|
|
8
|
+
*
|
|
9
|
+
* Based on @react-stately/datepicker IncompleteDate
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
type AnyDateTime,
|
|
14
|
+
type Calendar,
|
|
15
|
+
CalendarDate,
|
|
16
|
+
type DateValue,
|
|
17
|
+
ZonedDateTime,
|
|
18
|
+
} from "@internationalized/date";
|
|
19
|
+
import type { DateSegmentType } from "./createDateFieldState";
|
|
20
|
+
|
|
21
|
+
type HourCycle = "h12" | "h11" | "h23" | "h24";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* This class represents a date that is incomplete or otherwise invalid as a result of user editing.
|
|
25
|
+
* For example, it can represent temporary dates such as February 31st if the user edits the day
|
|
26
|
+
* before the month. Times are represented according to an hour cycle rather than always in 24 hour
|
|
27
|
+
* time. This enables the user to adjust the day period (e.g. am/pm) independently from the hour.
|
|
28
|
+
*/
|
|
29
|
+
export class IncompleteDate {
|
|
30
|
+
calendar: Calendar;
|
|
31
|
+
era: string | null;
|
|
32
|
+
year: number | null;
|
|
33
|
+
month: number | null;
|
|
34
|
+
day: number | null;
|
|
35
|
+
hour: number | null;
|
|
36
|
+
hourCycle: HourCycle;
|
|
37
|
+
dayPeriod: number | null;
|
|
38
|
+
minute: number | null;
|
|
39
|
+
second: number | null;
|
|
40
|
+
millisecond: number | null;
|
|
41
|
+
offset: number | null;
|
|
42
|
+
|
|
43
|
+
constructor(
|
|
44
|
+
calendar: Calendar,
|
|
45
|
+
hourCycle: HourCycle,
|
|
46
|
+
dateValue?: Partial<Omit<AnyDateTime, "copy">> | null,
|
|
47
|
+
) {
|
|
48
|
+
this.era = dateValue?.era ?? null;
|
|
49
|
+
this.calendar = calendar;
|
|
50
|
+
this.year = dateValue?.year ?? null;
|
|
51
|
+
this.month = dateValue?.month ?? null;
|
|
52
|
+
this.day = dateValue?.day ?? null;
|
|
53
|
+
this.hour = dateValue?.hour ?? null;
|
|
54
|
+
this.hourCycle = hourCycle;
|
|
55
|
+
this.dayPeriod = null;
|
|
56
|
+
this.minute = dateValue?.minute ?? null;
|
|
57
|
+
this.second = dateValue?.second ?? null;
|
|
58
|
+
this.millisecond = dateValue?.millisecond ?? null;
|
|
59
|
+
this.offset = "offset" in (dateValue ?? {}) ? (dateValue as { offset: number }).offset : null;
|
|
60
|
+
|
|
61
|
+
// Convert the hour from 24 hour time to the given hour cycle.
|
|
62
|
+
if (this.hour != null) {
|
|
63
|
+
const [dayPeriod, hour] = toHourCycle(this.hour, hourCycle);
|
|
64
|
+
this.dayPeriod = dayPeriod;
|
|
65
|
+
this.hour = hour;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
copy(): IncompleteDate {
|
|
70
|
+
const res = new IncompleteDate(this.calendar, this.hourCycle);
|
|
71
|
+
res.era = this.era;
|
|
72
|
+
res.year = this.year;
|
|
73
|
+
res.month = this.month;
|
|
74
|
+
res.day = this.day;
|
|
75
|
+
res.hour = this.hour;
|
|
76
|
+
res.dayPeriod = this.dayPeriod;
|
|
77
|
+
res.minute = this.minute;
|
|
78
|
+
res.second = this.second;
|
|
79
|
+
res.millisecond = this.millisecond;
|
|
80
|
+
res.offset = this.offset;
|
|
81
|
+
return res;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Checks whether all the specified segments have a value. */
|
|
85
|
+
isComplete(segments: DateSegmentType[]): boolean {
|
|
86
|
+
return segments.every((segment) => this[segment as keyof IncompleteDate] != null);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Checks whether the given date value matches this value for the specified segments. */
|
|
90
|
+
validate(dt: DateValue, segments: DateSegmentType[]): boolean {
|
|
91
|
+
return segments.every((segment) => {
|
|
92
|
+
if ((segment === "hour" || segment === "dayPeriod") && "hour" in dt) {
|
|
93
|
+
const [dayPeriod, hour] = toHourCycle(dt.hour, this.hourCycle);
|
|
94
|
+
return this.dayPeriod === dayPeriod && this.hour === hour;
|
|
95
|
+
}
|
|
96
|
+
return this[segment as keyof IncompleteDate] === dt[segment as keyof DateValue];
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Checks if the date is empty (i.e. all specified segments are null). */
|
|
101
|
+
isCleared(segments: DateSegmentType[]): boolean {
|
|
102
|
+
return segments.every((segment) => this[segment as keyof IncompleteDate] === null);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Sets the given field. */
|
|
106
|
+
set(field: DateSegmentType, value: number | string, placeholder: DateValue): IncompleteDate {
|
|
107
|
+
const result = this.copy();
|
|
108
|
+
(result as unknown as Record<string, unknown>)[field] = value;
|
|
109
|
+
if (field === "hour" && result.dayPeriod == null && "hour" in placeholder) {
|
|
110
|
+
result.dayPeriod = toHourCycle(placeholder.hour, this.hourCycle)[0];
|
|
111
|
+
}
|
|
112
|
+
if (field === "year" && result.era == null) {
|
|
113
|
+
result.era = placeholder.era;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// clear offset when a date/time field changes since it may no longer be valid
|
|
117
|
+
if (field !== "second" && field !== "literal" && field !== "timeZoneName") {
|
|
118
|
+
result.offset = null;
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Sets the given field to null. */
|
|
124
|
+
clear(field: DateSegmentType): IncompleteDate {
|
|
125
|
+
const result = this.copy();
|
|
126
|
+
(result as unknown as Record<string, unknown>)[field] = null;
|
|
127
|
+
if (field === "year") {
|
|
128
|
+
result.era = null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// clear offset when a field is cleared since it may no longer be valid
|
|
132
|
+
result.offset = null;
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Increments or decrements the given field. If it is null, then it is set to the placeholder
|
|
138
|
+
* value.
|
|
139
|
+
*/
|
|
140
|
+
cycle(
|
|
141
|
+
field: DateSegmentType,
|
|
142
|
+
amount: number,
|
|
143
|
+
placeholder: DateValue,
|
|
144
|
+
displaySegments: DateSegmentType[],
|
|
145
|
+
): IncompleteDate {
|
|
146
|
+
const res = this.copy();
|
|
147
|
+
|
|
148
|
+
// If field is null, default to placeholder.
|
|
149
|
+
if (res[field as keyof IncompleteDate] == null && field !== "dayPeriod" && field !== "era") {
|
|
150
|
+
if (field === "hour" && "hour" in placeholder) {
|
|
151
|
+
const [dayPeriod, hour] = toHourCycle(placeholder.hour, this.hourCycle);
|
|
152
|
+
res.dayPeriod = dayPeriod;
|
|
153
|
+
res.hour = hour;
|
|
154
|
+
} else {
|
|
155
|
+
(res as unknown as Record<string, unknown>)[field] = placeholder[field as keyof DateValue];
|
|
156
|
+
}
|
|
157
|
+
if (field === "year" && res.era == null) {
|
|
158
|
+
res.era = placeholder.era;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return res;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
switch (field) {
|
|
165
|
+
case "era": {
|
|
166
|
+
const eras = this.calendar.getEras();
|
|
167
|
+
let index = eras.indexOf(res.era!);
|
|
168
|
+
index = cycleValue(index, amount, 0, eras.length - 1);
|
|
169
|
+
res.era = eras[index];
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
case "year": {
|
|
173
|
+
// Use CalendarDate to cycle so that we update the era when going between 1 AD and 1 BC.
|
|
174
|
+
let date = new CalendarDate(
|
|
175
|
+
this.calendar,
|
|
176
|
+
this.era ?? placeholder.era,
|
|
177
|
+
this.year ?? placeholder.year,
|
|
178
|
+
this.month ?? 1,
|
|
179
|
+
this.day ?? 1,
|
|
180
|
+
);
|
|
181
|
+
date = date.cycle(field, amount, { round: field === "year" });
|
|
182
|
+
res.era = date.era;
|
|
183
|
+
res.year = date.year;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case "month":
|
|
187
|
+
res.month = cycleValue(res.month ?? 1, amount, 1, this.calendar.getMaximumMonthsInYear());
|
|
188
|
+
break;
|
|
189
|
+
case "day":
|
|
190
|
+
// Allow incrementing up to the maximum number of days in any month.
|
|
191
|
+
res.day = cycleValue(res.day ?? 1, amount, 1, this.calendar.getMaximumDaysInMonth());
|
|
192
|
+
break;
|
|
193
|
+
case "hour": {
|
|
194
|
+
// if date is fully defined or it is just a time field, and we have a time zone, use toValue to get a ZonedDateTime to cycle
|
|
195
|
+
// so DST fallback is properly handled
|
|
196
|
+
const hasDateSegements = displaySegments.some((s) => ["year", "month", "day"].includes(s));
|
|
197
|
+
if (
|
|
198
|
+
"timeZone" in placeholder &&
|
|
199
|
+
(!hasDateSegements || (res.year != null && res.month != null && res.day != null))
|
|
200
|
+
) {
|
|
201
|
+
let date = this.toValue(placeholder) as ZonedDateTime;
|
|
202
|
+
date = date.cycle("hour", amount, {
|
|
203
|
+
hourCycle: this.hourCycle === "h12" ? 12 : 24,
|
|
204
|
+
round: false,
|
|
205
|
+
});
|
|
206
|
+
const [dayPeriod, adjustedHour] = toHourCycle(date.hour, this.hourCycle);
|
|
207
|
+
res.hour = adjustedHour;
|
|
208
|
+
res.dayPeriod = dayPeriod;
|
|
209
|
+
res.offset = date.offset;
|
|
210
|
+
} else {
|
|
211
|
+
const hours = res.hour ?? 0;
|
|
212
|
+
const limits = this.getSegmentLimits("hour")!;
|
|
213
|
+
res.hour = cycleValue(hours, amount, limits.minValue, limits.maxValue);
|
|
214
|
+
if (res.dayPeriod == null && "hour" in placeholder) {
|
|
215
|
+
res.dayPeriod = toHourCycle(placeholder.hour, this.hourCycle)[0];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case "dayPeriod":
|
|
221
|
+
res.dayPeriod = cycleValue(res.dayPeriod ?? 0, amount, 0, 1);
|
|
222
|
+
break;
|
|
223
|
+
case "minute":
|
|
224
|
+
res.minute = cycleValue(res.minute ?? 0, amount, 0, 59, true);
|
|
225
|
+
break;
|
|
226
|
+
case "second":
|
|
227
|
+
res.second = cycleValue(res.second ?? 0, amount, 0, 59, true);
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return res;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Converts the incomplete date to a full date value, using the provided value for any unset
|
|
236
|
+
* fields.
|
|
237
|
+
*/
|
|
238
|
+
toValue(value: DateValue): DateValue {
|
|
239
|
+
if ("hour" in value) {
|
|
240
|
+
let hour = this.hour;
|
|
241
|
+
if (hour != null) {
|
|
242
|
+
hour = fromHourCycle(hour, this.dayPeriod ?? 0, this.hourCycle);
|
|
243
|
+
} else if (this.hourCycle === "h12" || this.hourCycle === "h11") {
|
|
244
|
+
hour = this.dayPeriod === 1 ? 12 : 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let res = value.set({
|
|
248
|
+
era: this.era ?? value.era,
|
|
249
|
+
year: this.year ?? value.year,
|
|
250
|
+
month: this.month ?? value.month,
|
|
251
|
+
day: this.day ?? value.day,
|
|
252
|
+
hour: hour ?? value.hour,
|
|
253
|
+
minute: this.minute ?? value.minute,
|
|
254
|
+
second: this.second ?? value.second,
|
|
255
|
+
millisecond: this.millisecond ?? value.millisecond,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
if ("offset" in res && this.offset != null && res.offset !== this.offset) {
|
|
259
|
+
res = res.add({ milliseconds: res.offset - this.offset });
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return res;
|
|
263
|
+
} else {
|
|
264
|
+
return value.set({
|
|
265
|
+
era: this.era ?? value.era,
|
|
266
|
+
year: this.year ?? value.year,
|
|
267
|
+
month: this.month ?? value.month,
|
|
268
|
+
day: this.day ?? value.day,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
getSegmentLimits(
|
|
274
|
+
type: string,
|
|
275
|
+
): { value: number | null; minValue: number; maxValue: number } | undefined {
|
|
276
|
+
switch (type) {
|
|
277
|
+
case "era": {
|
|
278
|
+
const eras = this.calendar.getEras();
|
|
279
|
+
return {
|
|
280
|
+
value: this.era != null ? eras.indexOf(this.era) : eras.length - 1,
|
|
281
|
+
minValue: 0,
|
|
282
|
+
maxValue: eras.length - 1,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
case "year":
|
|
286
|
+
return {
|
|
287
|
+
value: this.year,
|
|
288
|
+
minValue: 1,
|
|
289
|
+
maxValue: 9999,
|
|
290
|
+
};
|
|
291
|
+
case "month":
|
|
292
|
+
return {
|
|
293
|
+
value: this.month,
|
|
294
|
+
minValue: 1,
|
|
295
|
+
maxValue: this.calendar.getMaximumMonthsInYear(),
|
|
296
|
+
};
|
|
297
|
+
case "day":
|
|
298
|
+
return {
|
|
299
|
+
value: this.day,
|
|
300
|
+
minValue: 1,
|
|
301
|
+
maxValue: this.calendar.getMaximumDaysInMonth(),
|
|
302
|
+
};
|
|
303
|
+
case "dayPeriod": {
|
|
304
|
+
return {
|
|
305
|
+
value: this.dayPeriod,
|
|
306
|
+
minValue: 0,
|
|
307
|
+
maxValue: 1,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
case "hour": {
|
|
311
|
+
let minValue = 0;
|
|
312
|
+
let maxValue = 23;
|
|
313
|
+
if (this.hourCycle === "h12") {
|
|
314
|
+
minValue = 1;
|
|
315
|
+
maxValue = 12;
|
|
316
|
+
} else if (this.hourCycle === "h11") {
|
|
317
|
+
minValue = 0;
|
|
318
|
+
maxValue = 11;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
value: this.hour,
|
|
323
|
+
minValue,
|
|
324
|
+
maxValue,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
case "minute":
|
|
328
|
+
return {
|
|
329
|
+
value: this.minute,
|
|
330
|
+
minValue: 0,
|
|
331
|
+
maxValue: 59,
|
|
332
|
+
};
|
|
333
|
+
case "second":
|
|
334
|
+
return {
|
|
335
|
+
value: this.second,
|
|
336
|
+
minValue: 0,
|
|
337
|
+
maxValue: 59,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function cycleValue(
|
|
344
|
+
value: number,
|
|
345
|
+
amount: number,
|
|
346
|
+
min: number,
|
|
347
|
+
max: number,
|
|
348
|
+
round = false,
|
|
349
|
+
): number {
|
|
350
|
+
if (round) {
|
|
351
|
+
value += Math.sign(amount);
|
|
352
|
+
|
|
353
|
+
if (value < min) {
|
|
354
|
+
value = max;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const div = Math.abs(amount);
|
|
358
|
+
if (amount > 0) {
|
|
359
|
+
value = Math.ceil(value / div) * div;
|
|
360
|
+
} else {
|
|
361
|
+
value = Math.floor(value / div) * div;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (value > max) {
|
|
365
|
+
value = min;
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
value += amount;
|
|
369
|
+
if (value < min) {
|
|
370
|
+
value = max - (min - value - 1);
|
|
371
|
+
} else if (value > max) {
|
|
372
|
+
value = min + (value - max - 1);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return value;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function toHourCycle(hour: number, hourCycle: HourCycle): [number | null, number] {
|
|
380
|
+
let dayPeriod: number | null = hour >= 12 ? 1 : 0;
|
|
381
|
+
switch (hourCycle) {
|
|
382
|
+
case "h11":
|
|
383
|
+
// Hours are numbered from 0 to 11. Used in Japan.
|
|
384
|
+
if (hour >= 12) {
|
|
385
|
+
hour -= 12;
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
case "h12":
|
|
389
|
+
// Hours are numbered from 12 (representing 0) to 11.
|
|
390
|
+
if (hour === 0) {
|
|
391
|
+
hour = 12;
|
|
392
|
+
} else if (hour > 12) {
|
|
393
|
+
hour -= 12;
|
|
394
|
+
}
|
|
395
|
+
break;
|
|
396
|
+
case "h23":
|
|
397
|
+
// 24 hour time, numbered 0 to 23.
|
|
398
|
+
dayPeriod = null;
|
|
399
|
+
break;
|
|
400
|
+
case "h24":
|
|
401
|
+
// 24 hour time numbered 24 to 23. Unused but supported by Intl.DateTimeFormat.
|
|
402
|
+
hour += 1;
|
|
403
|
+
dayPeriod = null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return [dayPeriod, hour];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function fromHourCycle(hour: number, dayPeriod: number, hourCycle: HourCycle): number {
|
|
410
|
+
switch (hourCycle) {
|
|
411
|
+
case "h11":
|
|
412
|
+
if (dayPeriod === 1) {
|
|
413
|
+
hour += 12;
|
|
414
|
+
}
|
|
415
|
+
break;
|
|
416
|
+
case "h12":
|
|
417
|
+
if (hour === 12) {
|
|
418
|
+
hour = 0;
|
|
419
|
+
}
|
|
420
|
+
if (dayPeriod === 1) {
|
|
421
|
+
hour += 12;
|
|
422
|
+
}
|
|
423
|
+
break;
|
|
424
|
+
case "h24":
|
|
425
|
+
hour -= 1;
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return hour;
|
|
430
|
+
}
|