@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.
Files changed (254) hide show
  1. package/README.md +30 -283
  2. package/dist/autocomplete/createAutocompleteState.d.ts +2 -2
  3. package/dist/autocomplete/index.d.ts +1 -1
  4. package/dist/calendar/IncompleteDate.d.ts +61 -0
  5. package/dist/calendar/createCalendarState.d.ts +41 -16
  6. package/dist/calendar/createDateFieldState.d.ts +39 -9
  7. package/dist/calendar/createDatePickerState.d.ts +60 -0
  8. package/dist/calendar/createRangeCalendarState.d.ts +37 -10
  9. package/dist/calendar/createTimeFieldState.d.ts +34 -7
  10. package/dist/calendar/index.d.ts +7 -6
  11. package/dist/checkbox/createCheckboxGroupState.d.ts +6 -6
  12. package/dist/checkbox/index.d.ts +1 -1
  13. package/dist/collections/ListCollection.d.ts +1 -1
  14. package/dist/collections/createListState.d.ts +11 -8
  15. package/dist/collections/createMenuState.d.ts +7 -7
  16. package/dist/collections/createSelectionState.d.ts +22 -10
  17. package/dist/collections/getChildNodes.d.ts +11 -0
  18. package/dist/collections/index.d.ts +6 -5
  19. package/dist/collections/types.d.ts +12 -12
  20. package/dist/color/Color.d.ts +1 -1
  21. package/dist/color/createColorAreaState.d.ts +4 -2
  22. package/dist/color/createColorFieldState.d.ts +38 -12
  23. package/dist/color/createColorSliderState.d.ts +9 -2
  24. package/dist/color/createColorWheelState.d.ts +13 -2
  25. package/dist/color/getColorChannels.d.ts +1 -1
  26. package/dist/color/index.d.ts +6 -6
  27. package/dist/color/types.d.ts +4 -4
  28. package/dist/combobox/createComboBoxState.d.ts +34 -13
  29. package/dist/combobox/index.d.ts +1 -1
  30. package/dist/data/createAsyncList.d.ts +4 -4
  31. package/dist/data/createListData.d.ts +2 -2
  32. package/dist/data/createTreeData.d.ts +6 -2
  33. package/dist/data/index.d.ts +3 -3
  34. package/dist/datepicker/index.d.ts +2 -4
  35. package/dist/disclosure/createDisclosureState.d.ts +2 -2
  36. package/dist/disclosure/index.d.ts +1 -1
  37. package/dist/dnd/createDragState.d.ts +2 -2
  38. package/dist/dnd/createDraggableCollectionState.d.ts +2 -2
  39. package/dist/dnd/createDropState.d.ts +2 -2
  40. package/dist/dnd/createDroppableCollectionState.d.ts +3 -3
  41. package/dist/dnd/index.d.ts +5 -5
  42. package/dist/dnd/types.d.ts +19 -17
  43. package/dist/form/createFormValidationState.d.ts +3 -3
  44. package/dist/form/index.d.ts +1 -1
  45. package/dist/grid/createGridState.d.ts +2 -2
  46. package/dist/grid/index.d.ts +2 -2
  47. package/dist/grid/types.d.ts +27 -11
  48. package/dist/index.d.ts +31 -30
  49. package/dist/index.js +9077 -7246
  50. package/dist/index.js.map +1 -1
  51. package/dist/menu/index.d.ts +2 -2
  52. package/dist/numberfield/createNumberFieldState.d.ts +2 -2
  53. package/dist/numberfield/index.d.ts +1 -1
  54. package/dist/overlays/createOverlayTriggerState.d.ts +2 -2
  55. package/dist/overlays/index.d.ts +1 -1
  56. package/dist/radio/createRadioGroupState.d.ts +7 -7
  57. package/dist/radio/index.d.ts +1 -1
  58. package/dist/searchfield/createSearchFieldState.d.ts +2 -2
  59. package/dist/searchfield/index.d.ts +2 -2
  60. package/dist/select/createSelectState.d.ts +14 -8
  61. package/dist/select/index.d.ts +1 -1
  62. package/dist/selection/Selection.d.ts +16 -0
  63. package/dist/selection/SelectionManager.d.ts +110 -0
  64. package/dist/selection/createMultipleSelectionState.d.ts +59 -0
  65. package/dist/selection/index.d.ts +6 -5
  66. package/dist/slider/createSliderState.d.ts +3 -3
  67. package/dist/slider/index.d.ts +2 -2
  68. package/dist/steplist/createStepListState.d.ts +48 -0
  69. package/dist/steplist/index.d.ts +1 -0
  70. package/dist/table/TableCollection.d.ts +33 -3
  71. package/dist/table/createTableColumnResizeState.d.ts +54 -0
  72. package/dist/table/createTableState.d.ts +2 -2
  73. package/dist/table/createTreeGridState.d.ts +15 -0
  74. package/dist/table/index.d.ts +6 -3
  75. package/dist/table/types.d.ts +68 -10
  76. package/dist/tabs/createTabListState.d.ts +5 -5
  77. package/dist/tabs/index.d.ts +1 -1
  78. package/dist/textfield/createTextFieldState.d.ts +2 -2
  79. package/dist/textfield/index.d.ts +1 -1
  80. package/dist/toast/createToastState.d.ts +24 -2
  81. package/dist/toast/index.d.ts +1 -1
  82. package/dist/toggle/createToggleGroupState.d.ts +4 -4
  83. package/dist/toggle/createToggleState.d.ts +2 -2
  84. package/dist/toggle/index.d.ts +2 -2
  85. package/dist/tooltip/createTooltipTriggerState.d.ts +2 -2
  86. package/dist/tooltip/index.d.ts +1 -1
  87. package/dist/tree/TreeCollection.d.ts +2 -2
  88. package/dist/tree/createTreeState.d.ts +2 -2
  89. package/dist/tree/index.d.ts +3 -3
  90. package/dist/tree/types.d.ts +27 -13
  91. package/dist/utils/index.d.ts +1 -1
  92. package/dist/utils/reactivity.d.ts +1 -1
  93. package/package.json +29 -30
  94. package/src/autocomplete/createAutocompleteState.d.ts +19 -17
  95. package/src/autocomplete/createAutocompleteState.ts +24 -30
  96. package/src/autocomplete/index.d.ts +6 -2
  97. package/src/autocomplete/index.ts +1 -1
  98. package/src/calendar/IncompleteDate.ts +430 -0
  99. package/src/calendar/createCalendarState.d.ts +139 -117
  100. package/src/calendar/createCalendarState.ts +308 -94
  101. package/src/calendar/createDateFieldState.d.ts +130 -95
  102. package/src/calendar/createDateFieldState.ts +447 -334
  103. package/src/calendar/createDatePickerState.ts +347 -0
  104. package/src/calendar/createRangeCalendarState.d.ts +154 -129
  105. package/src/calendar/createRangeCalendarState.ts +411 -85
  106. package/src/calendar/createTimeFieldState.d.ts +81 -79
  107. package/src/calendar/createTimeFieldState.ts +187 -108
  108. package/src/calendar/index.d.ts +80 -7
  109. package/src/calendar/index.ts +23 -12
  110. package/src/checkbox/createCheckboxGroupState.d.ts +57 -55
  111. package/src/checkbox/createCheckboxGroupState.ts +20 -29
  112. package/src/checkbox/index.d.ts +6 -2
  113. package/src/checkbox/index.ts +1 -1
  114. package/src/collections/ListCollection.d.ts +25 -22
  115. package/src/collections/ListCollection.ts +6 -6
  116. package/src/collections/createListState.d.ts +73 -58
  117. package/src/collections/createListState.ts +67 -35
  118. package/src/collections/createMenuState.d.ts +36 -31
  119. package/src/collections/createMenuState.ts +21 -12
  120. package/src/collections/createSelectionState.d.ts +78 -65
  121. package/src/collections/createSelectionState.ts +66 -52
  122. package/src/collections/getChildNodes.ts +98 -0
  123. package/src/collections/index.d.ts +38 -6
  124. package/src/collections/index.ts +14 -10
  125. package/src/collections/types.d.ts +101 -101
  126. package/src/collections/types.ts +12 -12
  127. package/src/color/Color.d.ts +20 -5
  128. package/src/color/Color.ts +357 -254
  129. package/src/color/createColorAreaState.d.ts +67 -65
  130. package/src/color/createColorAreaState.ts +21 -13
  131. package/src/color/createColorFieldState.d.ts +46 -44
  132. package/src/color/createColorFieldState.ts +285 -149
  133. package/src/color/createColorSliderState.d.ts +58 -56
  134. package/src/color/createColorSliderState.ts +45 -14
  135. package/src/color/createColorWheelState.d.ts +42 -40
  136. package/src/color/createColorWheelState.ts +101 -64
  137. package/src/color/getColorChannels.ts +7 -5
  138. package/src/color/index.d.ts +36 -7
  139. package/src/color/index.ts +6 -9
  140. package/src/color/types.d.ts +68 -63
  141. package/src/color/types.ts +11 -19
  142. package/src/combobox/createComboBoxState.d.ts +107 -105
  143. package/src/combobox/createComboBoxState.ts +184 -89
  144. package/src/combobox/index.d.ts +10 -2
  145. package/src/combobox/index.ts +1 -1
  146. package/src/data/createAsyncList.ts +89 -63
  147. package/src/data/createListData.ts +67 -67
  148. package/src/data/createTreeData.ts +304 -91
  149. package/src/data/index.ts +3 -3
  150. package/src/datepicker/index.ts +6 -10
  151. package/src/disclosure/createDisclosureState.d.ts +47 -43
  152. package/src/disclosure/createDisclosureState.ts +7 -21
  153. package/src/disclosure/index.d.ts +10 -2
  154. package/src/disclosure/index.ts +1 -1
  155. package/src/dnd/createDragState.d.ts +51 -42
  156. package/src/dnd/createDragState.ts +12 -14
  157. package/src/dnd/createDraggableCollectionState.d.ts +52 -41
  158. package/src/dnd/createDraggableCollectionState.ts +14 -21
  159. package/src/dnd/createDropState.d.ts +64 -45
  160. package/src/dnd/createDropState.ts +22 -32
  161. package/src/dnd/createDroppableCollectionState.d.ts +88 -59
  162. package/src/dnd/createDroppableCollectionState.ts +40 -43
  163. package/src/dnd/index.d.ts +55 -6
  164. package/src/dnd/index.ts +6 -18
  165. package/src/dnd/types.d.ts +170 -157
  166. package/src/dnd/types.ts +24 -22
  167. package/src/form/createFormValidationState.d.ts +47 -45
  168. package/src/form/createFormValidationState.ts +30 -63
  169. package/src/form/index.d.ts +16 -2
  170. package/src/form/index.ts +1 -1
  171. package/src/grid/createGridState.d.ts +7 -4
  172. package/src/grid/createGridState.ts +78 -51
  173. package/src/grid/index.d.ts +3 -3
  174. package/src/grid/index.ts +2 -8
  175. package/src/grid/types.d.ts +136 -129
  176. package/src/grid/types.ts +34 -18
  177. package/src/index.d.ts +311 -26
  178. package/src/index.ts +59 -89
  179. package/src/menu/index.ts +2 -4
  180. package/src/numberfield/createNumberFieldState.d.ts +56 -54
  181. package/src/numberfield/createNumberFieldState.ts +26 -31
  182. package/src/numberfield/index.d.ts +6 -2
  183. package/src/numberfield/index.ts +1 -1
  184. package/src/overlays/createOverlayTriggerState.d.ts +22 -20
  185. package/src/overlays/createOverlayTriggerState.ts +3 -4
  186. package/src/overlays/index.d.ts +6 -2
  187. package/src/overlays/index.ts +1 -1
  188. package/src/radio/createRadioGroupState.d.ts +54 -52
  189. package/src/radio/createRadioGroupState.ts +27 -29
  190. package/src/radio/index.d.ts +7 -2
  191. package/src/radio/index.ts +1 -1
  192. package/src/searchfield/createSearchFieldState.d.ts +16 -14
  193. package/src/searchfield/createSearchFieldState.ts +5 -11
  194. package/src/searchfield/index.d.ts +3 -3
  195. package/src/searchfield/index.ts +2 -5
  196. package/src/select/createSelectState.d.ts +63 -61
  197. package/src/select/createSelectState.ts +42 -29
  198. package/src/select/index.d.ts +2 -2
  199. package/src/select/index.ts +1 -5
  200. package/src/selection/Selection.ts +28 -0
  201. package/src/selection/SelectionManager.ts +526 -0
  202. package/src/selection/createMultipleSelectionState.ts +247 -0
  203. package/src/selection/index.ts +12 -7
  204. package/src/slider/createSliderState.d.ts +60 -60
  205. package/src/slider/createSliderState.ts +55 -33
  206. package/src/slider/index.d.ts +3 -3
  207. package/src/slider/index.ts +2 -6
  208. package/src/ssr/index.d.ts +1 -1
  209. package/src/ssr/index.ts +2 -2
  210. package/src/steplist/createStepListState.ts +191 -0
  211. package/src/steplist/index.ts +5 -0
  212. package/src/table/TableCollection.d.ts +42 -40
  213. package/src/table/TableCollection.ts +266 -99
  214. package/src/table/createTableColumnResizeState.ts +242 -0
  215. package/src/table/createTableState.d.ts +7 -4
  216. package/src/table/createTableState.ts +30 -7
  217. package/src/table/createTreeGridState.ts +146 -0
  218. package/src/table/index.d.ts +14 -4
  219. package/src/table/index.ts +13 -3
  220. package/src/table/types.d.ts +98 -92
  221. package/src/table/types.ts +83 -13
  222. package/src/tabs/createTabListState.d.ts +59 -57
  223. package/src/tabs/createTabListState.ts +34 -39
  224. package/src/tabs/index.d.ts +8 -2
  225. package/src/tabs/index.ts +1 -1
  226. package/src/textfield/createTextFieldState.d.ts +16 -14
  227. package/src/textfield/createTextFieldState.ts +7 -18
  228. package/src/textfield/index.d.ts +6 -2
  229. package/src/textfield/index.ts +1 -1
  230. package/src/toast/createToastState.d.ts +92 -86
  231. package/src/toast/createToastState.ts +90 -52
  232. package/src/toast/index.d.ts +12 -2
  233. package/src/toast/index.ts +2 -1
  234. package/src/toggle/createToggleGroupState.ts +11 -21
  235. package/src/toggle/createToggleState.d.ts +19 -19
  236. package/src/toggle/createToggleState.ts +2 -16
  237. package/src/toggle/index.d.ts +2 -2
  238. package/src/toggle/index.ts +2 -6
  239. package/src/tooltip/createTooltipTriggerState.d.ts +17 -17
  240. package/src/tooltip/createTooltipTriggerState.ts +12 -11
  241. package/src/tooltip/index.d.ts +7 -2
  242. package/src/tooltip/index.ts +1 -1
  243. package/src/tree/TreeCollection.d.ts +26 -23
  244. package/src/tree/TreeCollection.ts +29 -22
  245. package/src/tree/createTreeState.d.ts +7 -4
  246. package/src/tree/createTreeState.ts +70 -41
  247. package/src/tree/index.d.ts +10 -4
  248. package/src/tree/index.ts +3 -3
  249. package/src/tree/types.d.ts +131 -126
  250. package/src/tree/types.ts +30 -13
  251. package/src/utils/index.d.ts +2 -2
  252. package/src/utils/index.ts +1 -1
  253. package/src/utils/reactivity.d.ts +2 -2
  254. 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 'solid-js'
8
- import { access, type MaybeAccessor } from '../utils'
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(getProps().defaultInputValue ?? '')
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 ?? '') : uncontrolledValue()
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 { createAutocompleteState, type AutocompleteState, type AutocompleteStateOptions, } from './createAutocompleteState';
2
- //# sourceMappingURL=index.d.ts.map
1
+ export {
2
+ createAutocompleteState,
3
+ type AutocompleteState,
4
+ type AutocompleteStateOptions,
5
+ } from "./createAutocompleteState";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -2,4 +2,4 @@ export {
2
2
  createAutocompleteState,
3
3
  type AutocompleteState,
4
4
  type AutocompleteStateOptions,
5
- } from './createAutocompleteState'
5
+ } from "./createAutocompleteState";
@@ -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
+ }