@proyecto-viviana/solid-stately 0.6.0-rc.0 → 0.6.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +59 -29
  2. package/dist/calendar/createCalendarState.d.ts +3 -1
  3. package/dist/calendar/createCalendarState.d.ts.map +1 -1
  4. package/dist/calendar/createDatePickerState.d.ts +2 -0
  5. package/dist/calendar/createDatePickerState.d.ts.map +1 -1
  6. package/dist/calendar/createRangeCalendarState.d.ts +2 -0
  7. package/dist/calendar/createRangeCalendarState.d.ts.map +1 -1
  8. package/dist/calendar/createTimeFieldState.d.ts +1 -1
  9. package/dist/calendar/createTimeFieldState.d.ts.map +1 -1
  10. package/dist/checkbox/createCheckboxGroupState.d.ts +2 -0
  11. package/dist/checkbox/createCheckboxGroupState.d.ts.map +1 -1
  12. package/dist/collections/createListState.d.ts.map +1 -1
  13. package/dist/collections/createMenuState.d.ts +46 -2
  14. package/dist/collections/createMenuState.d.ts.map +1 -1
  15. package/dist/collections/createSelectionState.d.ts.map +1 -1
  16. package/dist/collections/index.d.ts +1 -1
  17. package/dist/collections/index.d.ts.map +1 -1
  18. package/dist/color/createColorAreaState.d.ts +4 -0
  19. package/dist/color/createColorAreaState.d.ts.map +1 -1
  20. package/dist/color/createColorFieldState.d.ts +2 -0
  21. package/dist/color/createColorFieldState.d.ts.map +1 -1
  22. package/dist/color/createColorSliderState.d.ts +2 -0
  23. package/dist/color/createColorSliderState.d.ts.map +1 -1
  24. package/dist/color/createColorWheelState.d.ts.map +1 -1
  25. package/dist/combobox/createComboBoxState.d.ts +90 -23
  26. package/dist/combobox/createComboBoxState.d.ts.map +1 -1
  27. package/dist/combobox/index.d.ts +1 -1
  28. package/dist/combobox/index.d.ts.map +1 -1
  29. package/dist/data/createAsyncList.d.ts.map +1 -1
  30. package/dist/data/createListData.d.ts.map +1 -1
  31. package/dist/data/createTreeData.d.ts.map +1 -1
  32. package/dist/dnd/createDraggableCollectionState.d.ts +5 -1
  33. package/dist/dnd/createDraggableCollectionState.d.ts.map +1 -1
  34. package/dist/dnd/createDroppableCollectionState.d.ts +6 -0
  35. package/dist/dnd/createDroppableCollectionState.d.ts.map +1 -1
  36. package/dist/form/createFormValidationState.d.ts.map +1 -1
  37. package/dist/grid/createGridState.d.ts +2 -2
  38. package/dist/grid/createGridState.d.ts.map +1 -1
  39. package/dist/index.d.ts +5 -5
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +1012 -471
  42. package/dist/index.js.map +1 -1
  43. package/dist/menu/index.d.ts +2 -1
  44. package/dist/menu/index.d.ts.map +1 -1
  45. package/dist/numberfield/createNumberFieldState.d.ts +6 -3
  46. package/dist/numberfield/createNumberFieldState.d.ts.map +1 -1
  47. package/dist/private/flags/flags.d.ts.map +1 -0
  48. package/dist/private/flags/flags.js +1 -1
  49. package/dist/private/flags/flags.js.map +1 -1
  50. package/dist/radio/createRadioGroupState.d.ts.map +1 -1
  51. package/dist/select/createSelectState.d.ts +85 -29
  52. package/dist/select/createSelectState.d.ts.map +1 -1
  53. package/dist/select/index.d.ts +1 -1
  54. package/dist/select/index.d.ts.map +1 -1
  55. package/dist/selection/SelectionManager.d.ts.map +1 -1
  56. package/dist/selection/createMultipleSelectionState.d.ts.map +1 -1
  57. package/dist/slider/createSliderState.d.ts +35 -9
  58. package/dist/slider/createSliderState.d.ts.map +1 -1
  59. package/dist/ssr/index.d.ts +0 -6
  60. package/dist/ssr/index.d.ts.map +1 -1
  61. package/dist/steplist/createStepListState.d.ts +8 -13
  62. package/dist/steplist/createStepListState.d.ts.map +1 -1
  63. package/dist/table/createTableColumnResizeState.d.ts.map +1 -1
  64. package/dist/table/createTableState.d.ts +2 -2
  65. package/dist/table/createTableState.d.ts.map +1 -1
  66. package/dist/table/createTreeGridState.d.ts +2 -2
  67. package/dist/table/createTreeGridState.d.ts.map +1 -1
  68. package/dist/table/types.d.ts +2 -2
  69. package/dist/table/types.d.ts.map +1 -1
  70. package/dist/tabs/createTabListState.d.ts.map +1 -1
  71. package/dist/tokenfield/TokenFieldValue.d.ts +28 -4
  72. package/dist/tokenfield/TokenFieldValue.d.ts.map +1 -1
  73. package/dist/tokenfield/index.d.ts +1 -1
  74. package/dist/tokenfield/index.d.ts.map +1 -1
  75. package/dist/tree/createTreeState.d.ts +2 -2
  76. package/dist/tree/createTreeState.d.ts.map +1 -1
  77. package/dist/utils/index.d.ts +1 -1
  78. package/dist/utils/index.d.ts.map +1 -1
  79. package/dist/utils/reactivity.d.ts +5 -0
  80. package/dist/utils/reactivity.d.ts.map +1 -1
  81. package/package.json +2 -2
  82. package/src/calendar/createCalendarState.ts +139 -58
  83. package/src/calendar/createDatePickerState.ts +14 -11
  84. package/src/calendar/createRangeCalendarState.ts +43 -17
  85. package/src/calendar/createTimeFieldState.ts +1 -1
  86. package/src/checkbox/createCheckboxGroupState.ts +16 -0
  87. package/src/collections/createListState.ts +4 -4
  88. package/src/collections/createMenuState.ts +134 -4
  89. package/src/collections/createSelectionState.ts +2 -2
  90. package/src/collections/index.ts +4 -0
  91. package/src/color/createColorAreaState.ts +19 -0
  92. package/src/color/createColorFieldState.ts +76 -26
  93. package/src/color/createColorSliderState.ts +25 -2
  94. package/src/color/createColorWheelState.ts +9 -5
  95. package/src/combobox/createComboBoxState.ts +371 -121
  96. package/src/combobox/index.ts +4 -0
  97. package/src/data/createAsyncList.ts +19 -4
  98. package/src/data/createListData.ts +8 -2
  99. package/src/data/createTreeData.ts +11 -3
  100. package/src/dnd/createDraggableCollectionState.ts +8 -1
  101. package/src/dnd/createDroppableCollectionState.ts +10 -0
  102. package/src/form/createFormValidationState.ts +17 -3
  103. package/src/grid/createGridState.ts +15 -8
  104. package/src/index.ts +18 -2
  105. package/src/menu/index.ts +5 -0
  106. package/src/numberfield/createNumberFieldState.ts +97 -35
  107. package/src/radio/createRadioGroupState.ts +4 -1
  108. package/src/select/createSelectState.ts +253 -131
  109. package/src/select/index.ts +8 -1
  110. package/src/selection/SelectionManager.ts +3 -1
  111. package/src/selection/createMultipleSelectionState.ts +2 -2
  112. package/src/slider/createSliderState.ts +227 -103
  113. package/src/ssr/index.ts +11 -4
  114. package/src/steplist/createStepListState.ts +156 -123
  115. package/src/table/createTableColumnResizeState.ts +51 -11
  116. package/src/table/createTableState.ts +5 -4
  117. package/src/table/createTreeGridState.ts +3 -4
  118. package/src/table/types.ts +2 -2
  119. package/src/tabs/createTabListState.ts +8 -31
  120. package/src/tokenfield/TokenFieldValue.ts +75 -16
  121. package/src/tokenfield/index.ts +1 -0
  122. package/src/tree/createTreeState.ts +15 -8
  123. package/src/utils/index.ts +1 -0
  124. package/src/utils/reactivity.ts +8 -0
  125. package/dist/flags/flags.d.ts.map +0 -1
  126. /package/dist/{flags → private/flags}/flags.d.ts +0 -0
  127. /package/src/{flags → private/flags}/flags.ts +0 -0
@@ -15,30 +15,54 @@ export interface Position {
15
15
  /** Text offset within the segment in UTF-16 code units. */
16
16
  offset: number;
17
17
  }
18
+ /** Represents a text selection in a TokenField. */
19
+ export declare class SelectedRange {
20
+ /** The anchor position. */
21
+ anchor: Position;
22
+ /** The current (i.e. caret) position. */
23
+ current: Position;
24
+ /**
25
+ * Creates a new selection range. If only a single position is provided, the selection is
26
+ * collapsed.
27
+ */
28
+ constructor(anchor: Position, current?: Position);
29
+ /** Whether the selection is collapsed to a single caret position. */
30
+ get isCollapsed(): boolean;
31
+ /** The side of the selection closest to the start of the value. */
32
+ get start(): Position;
33
+ /** The side of the selection closest to the end of the value. */
34
+ get end(): Position;
35
+ /** Returns whether this selection is equal to another. */
36
+ isEqual(other: SelectedRange): boolean;
37
+ }
18
38
  declare enum Direction {
19
39
  Forward = 1,
20
40
  Backward = -1
21
41
  }
22
42
  export interface TokenFieldValueOptions {
23
- caretPosition?: Position | null;
43
+ selectedRange?: SelectedRange | null;
24
44
  }
25
45
  /**
26
46
  * A list of segments containing editable text and non-editable tokens.
27
47
  */
28
48
  export declare class TokenFieldValue<T = any> {
29
49
  static readonly Direction: typeof Direction;
50
+ static readonly SelectedRange: typeof SelectedRange;
30
51
  /** The text and token segments in the list. */
31
52
  readonly segments: readonly TokenFieldSegment<T>[];
32
- /** The caret position. */
33
- caretPosition: Position;
53
+ /** The selected range. */
54
+ selectedRange: SelectedRange;
34
55
  private previous;
35
56
  private next;
36
57
  private isCoalescing;
37
58
  /** Create a new list with the given segments. */
38
59
  constructor(tokens: readonly TokenFieldSegment<T>[], options?: TokenFieldValueOptions);
60
+ get caretPosition(): Position;
39
61
  protected createFieldValue(segments: readonly TokenFieldSegment<T>[]): this;
62
+ /** Create a new list with the selected range set to the given range. */
63
+ withSelectedRange(selectedRange: SelectedRange): this;
40
64
  /** Create a new list with the caret position set to the given position. */
41
- withCaretPosition(caretPosition: Position): this;
65
+ withCaretPosition(position: Position): this;
42
66
  private splitSegment;
43
67
  private createTextSegment;
44
68
  protected tokenize(text: string): TokenFieldSegment<T>[];
@@ -1 +1 @@
1
- {"version":3,"file":"TokenFieldValue.d.ts","sourceRoot":"","sources":["../../src/tokenfield/TokenFieldValue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TokenFieldValue.d.ts","sourceRoot":"","sources":["../../src/tokenfield/TokenFieldValue.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- export { TokenFieldValue, type TokenFieldSegment, type TextSegment, type TokenSegment, type Position, type TokenFieldValueOptions, } from "./TokenFieldValue";
1
+ export { TokenFieldValue, type TokenFieldSegment, type TextSegment, type TokenSegment, type Position, type SelectedRange, type TokenFieldValueOptions, } from "./TokenFieldValue";
2
2
  export { createTokenFieldState, type TokenFieldStateOptions, type TokenFieldState, } from "./createTokenFieldState";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokenfield/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokenfield/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC"}
@@ -1,8 +1,8 @@
1
- import type { Accessor } from "solid-js";
2
1
  import type { TreeState, TreeStateOptions, TreeCollection } from "./types";
2
+ import { type MaybeAccessor } from "../utils";
3
3
  /**
4
4
  * Creates state management for a tree component.
5
5
  * Handles expansion, selection, focus management, and keyboard navigation state.
6
6
  */
7
- export declare function createTreeState<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(options: Accessor<TreeStateOptions<T, C>>): TreeState<T, C>;
7
+ export declare function createTreeState<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(options: MaybeAccessor<TreeStateOptions<T, C>>): TreeState<T, C>;
8
8
  //# sourceMappingURL=createTreeState.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createTreeState.d.ts","sourceRoot":"","sources":["../../src/tree/createTreeState.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI3E;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,EAC/F,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACxC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CA8YjB"}
1
+ {"version":3,"file":"createTreeState.d.ts","sourceRoot":"","sources":["../../src/tree/createTreeState.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE3E,OAAO,EAAuC,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAEnF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,EAC/F,OAAO,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAC7C,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAsZjB"}
@@ -1,3 +1,3 @@
1
- export { access, createInternalSignal, isAccessor, readNow, type MaybeAccessor, type MaybeAccessorValue, } from "./reactivity";
1
+ export { access, createInternalSignal, isAccessor, propsAccessor, readNow, type MaybeAccessor, type MaybeAccessorValue, } from "./reactivity";
2
2
  export { useContextOptional } from "./owner";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,oBAAoB,EACpB,UAAU,EACV,OAAO,EACP,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,oBAAoB,EACpB,UAAU,EACV,aAAa,EACb,OAAO,EACP,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC"}
@@ -26,6 +26,11 @@ export type MaybeAccessorValue<T> = T | undefined | Accessor<T | undefined>;
26
26
  * Checks if a value is an accessor function.
27
27
  */
28
28
  export declare function isAccessor<T>(value: MaybeAccessor<T>): value is Accessor<T>;
29
+ /**
30
+ * Resolve a props bag once. Later reads call the accessor directly, so a
31
+ * function-valued field such as `getKey` is never treated as the bag.
32
+ */
33
+ export declare function propsAccessor<T extends object>(props: MaybeAccessor<T>): Accessor<T>;
29
34
  /**
30
35
  * Headless state is written from factory setup and from public setters that
31
36
  * tests (and some call sites) invoke inside `createRoot` / a component body.
@@ -1 +1 @@
1
- {"version":3,"file":"reactivity.d.ts","sourceRoot":"","sources":["../../src/utils/reactivity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAA6B,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEtD;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAEpD;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AAE5E;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,CAE3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAsBvF;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAEnD"}
1
+ {"version":3,"file":"reactivity.d.ts","sourceRoot":"","sources":["../../src/utils/reactivity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAA6B,MAAM,UAAU,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEtD;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAEpD;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AAE5E;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,CAE3E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAEpF;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAsBvF;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAEnD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proyecto-viviana/solid-stately",
3
- "version": "0.6.0-rc.0",
3
+ "version": "0.6.0-rc.1",
4
4
  "description": "A 1-1 SolidJS port of React Stately - headless state management for UI components",
5
5
  "keywords": [
6
6
  "headless",
@@ -38,7 +38,7 @@
38
38
  "default": "./dist/index.js"
39
39
  },
40
40
  "./private/flags/flags": {
41
- "types": "./dist/flags/flags.d.ts",
41
+ "types": "./dist/private/flags/flags.d.ts",
42
42
  "import": "./dist/private/flags/flags.js",
43
43
  "default": "./dist/private/flags/flags.js"
44
44
  },
@@ -42,7 +42,7 @@ import {
42
42
  toCalendarDate as intlToCalendarDate,
43
43
  minDate,
44
44
  } from "@internationalized/date";
45
- import { access, createInternalSignal, readNow, type MaybeAccessor } from "../utils";
45
+ import { access, createInternalSignal, propsAccessor, readNow, type MaybeAccessor } from "../utils";
46
46
 
47
47
  export type ValidationState = "valid" | "invalid";
48
48
  export type CalendarPageBehavior = "single" | "visible";
@@ -102,6 +102,8 @@ export interface CalendarStateProps<
102
102
  isDateDisabled?: (date: DateValue) => boolean;
103
103
  /** Validation state. */
104
104
  validationState?: MaybeAccessor<ValidationState | undefined>;
105
+ /** Whether the current selection is invalid according to application logic. */
106
+ isInvalid?: boolean;
105
107
  /** Error message. */
106
108
  errorMessage?: string;
107
109
  /** The first day of the week (0 = Sunday, 1 = Monday, etc.). */
@@ -206,21 +208,28 @@ export interface CalendarState<
206
208
  export function createCalendarState<
207
209
  T extends DateValue = CalendarDate,
208
210
  M extends CalendarSelectionMode = "single",
209
- >(props: CalendarStateProps<T, M> = {}): CalendarState<T, M> {
211
+ >(props: MaybeAccessor<CalendarStateProps<T, M>> = {}): CalendarState<T, M> {
212
+ const getProps = propsAccessor(props);
210
213
  const timeZone = getLocalTimeZone();
211
- const locale = createMemo(() => access(props.locale) ?? "en-US");
212
- const minValueState = createMemo(() => access(props.minValue) ?? null);
213
- const maxValueState = createMemo(() => access(props.maxValue) ?? null);
214
+ const locale = createMemo(() => access(getProps().locale) ?? "en-US");
215
+ const minValueState = createMemo(() => access(getProps().minValue) ?? null);
216
+ const maxValueState = createMemo(() => access(getProps().maxValue) ?? null);
214
217
  const selectionMode = createMemo<CalendarSelectionMode>(
215
- () => access(props.selectionMode) ?? "single",
218
+ () => access(getProps().selectionMode) ?? "single",
216
219
  );
217
220
  const resolvedOptions = createMemo(() => new DateFormatter(locale()).resolvedOptions());
218
221
  const calendar = createMemo(() =>
219
- (props.createCalendar ?? intlCreateCalendar)(resolvedOptions().calendar as CalendarIdentifier),
222
+ (getProps().createCalendar ?? intlCreateCalendar)(
223
+ resolvedOptions().calendar as CalendarIdentifier,
224
+ ),
220
225
  );
221
- const visibleMonths = createMemo(() => Math.max(1, Number(access(props.visibleMonths) ?? 1)));
222
- const firstDayOfWeekName = (): CalendarDayOfWeek | undefined =>
223
- props.firstDayOfWeek == null ? undefined : dayOfWeekNames[props.firstDayOfWeek];
226
+ const visibleMonths = createMemo(() =>
227
+ Math.max(1, Number(access(getProps().visibleMonths) ?? 1)),
228
+ );
229
+ const firstDayOfWeekName = (): CalendarDayOfWeek | undefined => {
230
+ const firstDayOfWeek = getProps().firstDayOfWeek;
231
+ return firstDayOfWeek == null ? undefined : dayOfWeekNames[firstDayOfWeek];
232
+ };
224
233
 
225
234
  const toDisplayCalendarDate = (date: DateValue): CalendarDate =>
226
235
  intlToCalendar(toCalendarDate(date), calendar());
@@ -228,7 +237,7 @@ export function createCalendarState<
228
237
  const selectionAlignmentOffset = (): number => {
229
238
  // Mirrors @react-stately/calendar useCalendarState, where selectionAlignment
230
239
  // defaults to "center" (alignCenter) when not provided.
231
- switch (props.selectionAlignment) {
240
+ switch (getProps().selectionAlignment) {
232
241
  case "start":
233
242
  return 0;
234
243
  case "end":
@@ -244,9 +253,44 @@ export function createCalendarState<
244
253
  }
245
254
  };
246
255
 
256
+ const rawAlignStart = (date: CalendarDate): CalendarDate => startOfMonth(date);
257
+
258
+ const rawAlignEnd = (date: CalendarDate, months: number): CalendarDate =>
259
+ startOfMonth(date).subtract({ months: Math.max(months - 1, 0) });
260
+
261
+ // Month-duration constrainStart. The focused date only gates the clamp.
262
+ // alignStart(min) and alignEnd(max) take no min/max of their own. Compare
263
+ // instead of maxDate/minDate so a cross-calendar null is not introduced.
264
+ const constrainVisibleRangeStart = (
265
+ date: CalendarDate,
266
+ aligned: CalendarDate,
267
+ months: number,
268
+ ): CalendarDate => {
269
+ const minValue = access(getProps().minValue);
270
+ const maxValue = access(getProps().maxValue);
271
+ let constrained = aligned;
272
+
273
+ if (minValue && date.compare(toDisplayCalendarDate(minValue)) >= 0) {
274
+ const minStart = rawAlignStart(toDisplayCalendarDate(minValue));
275
+ if (minStart.compare(constrained) > 0) {
276
+ constrained = minStart;
277
+ }
278
+ }
279
+
280
+ if (maxValue && date.compare(toDisplayCalendarDate(maxValue)) <= 0) {
281
+ const maxStart = rawAlignEnd(toDisplayCalendarDate(maxValue), months);
282
+ if (maxStart.compare(constrained) < 0) {
283
+ constrained = maxStart;
284
+ }
285
+ }
286
+
287
+ return constrained;
288
+ };
289
+
247
290
  const alignVisibleRangeStart = (date: CalendarDate): CalendarDate => {
248
291
  const offset = selectionAlignmentOffset();
249
- return startOfMonth(offset > 0 ? date.subtract({ months: offset }) : date);
292
+ const aligned = rawAlignStart(offset > 0 ? date.subtract({ months: offset }) : date);
293
+ return constrainVisibleRangeStart(date, aligned, visibleMonths());
250
294
  };
251
295
 
252
296
  const visibleRangeEnd = (start: CalendarDate): CalendarDate => {
@@ -260,8 +304,8 @@ export function createCalendarState<
260
304
  };
261
305
 
262
306
  const constrainDate = (date: CalendarDate): CalendarDate => {
263
- const minValue = access(props.minValue);
264
- const maxValue = access(props.maxValue);
307
+ const minValue = access(getProps().minValue);
308
+ const maxValue = access(getProps().maxValue);
265
309
 
266
310
  let constrained = date;
267
311
 
@@ -277,23 +321,28 @@ export function createCalendarState<
277
321
 
278
322
  // Determine the initially focused date
279
323
  const getInitialFocusedDate = (): CalendarDate => {
280
- const controlledFocused = access(props.focusedValue);
324
+ const controlledFocused = access(getProps().focusedValue);
281
325
  if (controlledFocused) {
282
326
  return toDisplayCalendarDate(controlledFocused);
283
327
  }
284
- if (props.defaultFocusedValue) {
285
- return toDisplayCalendarDate(props.defaultFocusedValue);
328
+ const defaultFocusedValue = getProps().defaultFocusedValue;
329
+ if (defaultFocusedValue) {
330
+ return toDisplayCalendarDate(defaultFocusedValue);
286
331
  }
287
- const controlledValue = access(props.value);
288
- const controlledFirst = Array.isArray(controlledValue) ? controlledValue[0] : controlledValue;
289
- if (controlledFirst) {
290
- return toDisplayCalendarDate(controlledFirst);
291
- }
292
- const defaultFirst = Array.isArray(props.defaultValue)
293
- ? props.defaultValue[0]
294
- : props.defaultValue;
295
- if (defaultFirst) {
296
- return toDisplayCalendarDate(defaultFirst);
332
+ // A controlled null is a cleared selection. Pin useControlledState treats
333
+ // `value !== undefined` as controlled, so null must not fall through to defaultValue.
334
+ const controlledValue = access(getProps().value);
335
+ if (controlledValue !== undefined) {
336
+ const controlledFirst = Array.isArray(controlledValue) ? controlledValue[0] : controlledValue;
337
+ if (controlledFirst) {
338
+ return toDisplayCalendarDate(controlledFirst);
339
+ }
340
+ } else {
341
+ const defaultValue = getProps().defaultValue;
342
+ const defaultFirst = Array.isArray(defaultValue) ? defaultValue[0] : defaultValue;
343
+ if (defaultFirst) {
344
+ return toDisplayCalendarDate(defaultFirst);
345
+ }
297
346
  }
298
347
  return intlToCalendar(today(timeZone), calendar());
299
348
  };
@@ -301,7 +350,7 @@ export function createCalendarState<
301
350
  // State signals
302
351
  const initialFocusedDate = constrainDate(getInitialFocusedDate());
303
352
  const [internalValue, setInternalValue] = createInternalSignal<T | T[] | null>(
304
- (props.defaultValue as T | T[] | null) ?? null,
353
+ (getProps().defaultValue as T | T[] | null) ?? null,
305
354
  );
306
355
  const [focusedDate, setFocusedDateInternal] =
307
356
  createInternalSignal<CalendarDate>(initialFocusedDate);
@@ -311,12 +360,12 @@ export function createCalendarState<
311
360
  // Init from autoFocus, mirroring @react-stately useCalendarState
312
361
  // (`useState(props.autoFocus || false)`). Without autoFocus the calendar
313
362
  // mounts unfocused and never steals DOM focus.
314
- const [isFocused, setFocused] = createInternalSignal(props.autoFocus ?? false);
363
+ const [isFocused, setFocused] = createInternalSignal(getProps().autoFocus ?? false);
315
364
  const [isPaginating, setIsPaginating] = createInternalSignal(false);
316
365
 
317
366
  // Controlled vs uncontrolled value
318
367
  const sourceValue = createMemo<T | T[] | null>(() => {
319
- const controlled = access(props.value);
368
+ const controlled = access(getProps().value);
320
369
  return controlled !== undefined ? (controlled as T | T[] | null) : internalValue();
321
370
  });
322
371
  const value = createMemo<T | T[] | null>(() => {
@@ -328,10 +377,34 @@ export function createCalendarState<
328
377
  });
329
378
 
330
379
  // Derived states
331
- const isDisabled = createMemo(() => access(props.isDisabled) ?? false);
332
- const isReadOnly = createMemo(() => access(props.isReadOnly) ?? false);
333
- const validationState = createMemo(() => access(props.validationState));
334
- const isValueInvalid = createMemo(() => validationState() === "invalid");
380
+ const isDisabled = createMemo(() => access(getProps().isDisabled) ?? false);
381
+ const isReadOnly = createMemo(() => access(getProps().isReadOnly) ?? false);
382
+ const validationState = createMemo(() => access(getProps().validationState));
383
+ // A value is invalid when the caller says so, validationState is invalid,
384
+ // or a selected date is unavailable or outside min/max. Mirrors useCalendarState.
385
+ const isInvalidSelection = createMemo(() => {
386
+ const current = value();
387
+ if (current == null) return false;
388
+ const dates = Array.isArray(current) ? current : [current];
389
+ const min = access(getProps().minValue);
390
+ const max = access(getProps().maxValue);
391
+ const minCal = min != null ? toDisplayCalendarDate(min) : null;
392
+ const maxCal = max != null ? toDisplayCalendarDate(max) : null;
393
+ return dates.some((date) => {
394
+ const cal = toDisplayCalendarDate(date);
395
+ return (
396
+ Boolean(getProps().isDateUnavailable?.(cal)) ||
397
+ (minCal != null && cal.compare(minCal) < 0) ||
398
+ (maxCal != null && cal.compare(maxCal) > 0)
399
+ );
400
+ });
401
+ });
402
+ const isValueInvalid = createMemo(
403
+ () =>
404
+ Boolean(access(getProps().isInvalid)) ||
405
+ validationState() === "invalid" ||
406
+ isInvalidSelection(),
407
+ );
335
408
 
336
409
  // Visible range based on the paged range start. Function (not memo) so
337
410
  // onFocusChange snapshots see the live page after a same-turn write.
@@ -348,15 +421,19 @@ export function createCalendarState<
348
421
  months: number,
349
422
  ) => {
350
423
  if (nextFocusedDate.compare(range.start) < 0) {
351
- setVisibleRangeStart(startOfMonth(nextFocusedDate.subtract({ months: months - 1 })));
424
+ setVisibleRangeStart(
425
+ constrainVisibleRangeStart(nextFocusedDate, rawAlignEnd(nextFocusedDate, months), months),
426
+ );
352
427
  } else if (nextFocusedDate.compare(range.end) > 0) {
353
- setVisibleRangeStart(startOfMonth(nextFocusedDate));
428
+ setVisibleRangeStart(
429
+ constrainVisibleRangeStart(nextFocusedDate, rawAlignStart(nextFocusedDate), months),
430
+ );
354
431
  }
355
432
  };
356
433
 
357
434
  createEffect(
358
435
  () => {
359
- const controlledFocused = access(props.focusedValue);
436
+ const controlledFocused = access(getProps().focusedValue);
360
437
  if (!controlledFocused) return null;
361
438
  return {
362
439
  nextFocusedDate: constrainDate(toDisplayCalendarDate(controlledFocused)),
@@ -380,7 +457,7 @@ export function createCalendarState<
380
457
 
381
458
  createEffect(
382
459
  () => {
383
- const controlledFocused = access(props.focusedValue);
460
+ const controlledFocused = access(getProps().focusedValue);
384
461
  if (controlledFocused) return null;
385
462
  const currentFocusedDate = focusedDate();
386
463
  const nextFocusedDate = constrainDate(currentFocusedDate);
@@ -401,7 +478,7 @@ export function createCalendarState<
401
478
  if (!data) return;
402
479
  syncVisibleRangeForFocusedDate(data.nextFocusedDate, data.range, data.months);
403
480
  setFocusedDateInternal(data.nextFocusedDate);
404
- props.onFocusChange?.(data.nextFocusedDate);
481
+ getProps().onFocusChange?.(data.nextFocusedDate);
405
482
  },
406
483
  );
407
484
 
@@ -455,12 +532,12 @@ export function createCalendarState<
455
532
  // selectable when isDateUnavailable is set. Mirrors useCalendarState.normalizeValue.
456
533
  const normalizeValue = (newValue: CalendarDate): T | null => {
457
534
  const constrained = constrainDate(newValue);
458
- const minBound = access(props.minValue);
535
+ const minBound = access(getProps().minValue);
459
536
  const lowerBound =
460
537
  minBound != null
461
538
  ? toDisplayCalendarDate(minBound)
462
539
  : (minDate(constrained, visibleRange().start) ?? constrained);
463
- const prev = previousAvailableDate(constrained, lowerBound, props.isDateUnavailable);
540
+ const prev = previousAvailableDate(constrained, lowerBound, getProps().isDateUnavailable);
464
541
  if (!prev) {
465
542
  return null;
466
543
  }
@@ -491,13 +568,13 @@ export function createCalendarState<
491
568
  nextValue = localValue;
492
569
  }
493
570
 
494
- const controlled = access(props.value);
571
+ const controlled = access(getProps().value);
495
572
  if (controlled === undefined) {
496
573
  setInternalValue(() => nextValue);
497
574
  }
498
575
 
499
- if (!Object.is(oldValue, nextValue) && props.onChange) {
500
- props.onChange(nextValue as CalendarValueType<T | null, M>);
576
+ if (!Object.is(oldValue, nextValue)) {
577
+ getProps().onChange?.(nextValue as CalendarValueType<T | null, M>);
501
578
  }
502
579
  };
503
580
 
@@ -511,7 +588,7 @@ export function createCalendarState<
511
588
 
512
589
  syncVisibleRangeForFocusedDate(constrained, visibleRange(), visibleMonths());
513
590
  setFocusedDateInternal(constrained);
514
- props.onFocusChange?.(constrained);
591
+ getProps().onFocusChange?.(constrained);
515
592
  };
516
593
 
517
594
  // Check if a date is selected
@@ -536,16 +613,16 @@ export function createCalendarState<
536
613
 
537
614
  // Check if a date is unavailable
538
615
  const isCellUnavailable = (date: DateValue): boolean => {
539
- return props.isDateUnavailable?.(date) ?? false;
616
+ return getProps().isDateUnavailable?.(date) ?? false;
540
617
  };
541
618
 
542
619
  // Check if a date is disabled
543
620
  const isCellDisabled = (date: DateValue): boolean => {
544
621
  if (isDisabled()) return true;
545
- if (props.isDateDisabled?.(date)) return true;
622
+ if (getProps().isDateDisabled?.(date)) return true;
546
623
 
547
- const minValue = access(props.minValue);
548
- const maxValue = access(props.maxValue);
624
+ const minValue = access(getProps().minValue);
625
+ const maxValue = access(getProps().maxValue);
549
626
  const calDate = toDisplayCalendarDate(date);
550
627
 
551
628
  // Dates outside the visible range are disabled, mirroring
@@ -601,21 +678,25 @@ export function createCalendarState<
601
678
  // Navigation methods
602
679
  const focusPreviousPage = () => {
603
680
  setIsPaginating(true);
604
- const pageMonths = props.pageBehavior === "single" ? 1 : visibleMonths();
605
- const nextFocusedDate = constrainDate(focusedDate().subtract({ months: pageMonths }));
681
+ const pageMonths = getProps().pageBehavior === "single" ? 1 : visibleMonths();
682
+ const currentFocused = focusedDate();
683
+ const nextFocusedDate = constrainDate(currentFocused.subtract({ months: pageMonths }));
684
+ const slidStart = startOfMonth(visibleRangeStart().subtract({ months: pageMonths }));
606
685
  setFocusedDateInternal(nextFocusedDate);
607
- setVisibleRangeStart(startOfMonth(visibleRangeStart().subtract({ months: pageMonths })));
608
- props.onFocusChange?.(nextFocusedDate);
686
+ setVisibleRangeStart(constrainVisibleRangeStart(currentFocused, slidStart, pageMonths));
687
+ getProps().onFocusChange?.(nextFocusedDate);
609
688
  setIsPaginating(false);
610
689
  };
611
690
 
612
691
  const focusNextPage = () => {
613
692
  setIsPaginating(true);
614
- const pageMonths = props.pageBehavior === "single" ? 1 : visibleMonths();
615
- const nextFocusedDate = constrainDate(focusedDate().add({ months: pageMonths }));
693
+ const pageMonths = getProps().pageBehavior === "single" ? 1 : visibleMonths();
694
+ const currentFocused = focusedDate();
695
+ const nextFocusedDate = constrainDate(currentFocused.add({ months: pageMonths }));
696
+ const slidStart = startOfMonth(visibleRangeStart().add({ months: pageMonths }));
616
697
  setFocusedDateInternal(nextFocusedDate);
617
- setVisibleRangeStart(startOfMonth(visibleRangeStart().add({ months: pageMonths })));
618
- props.onFocusChange?.(nextFocusedDate);
698
+ setVisibleRangeStart(constrainVisibleRangeStart(currentFocused, slidStart, pageMonths));
699
+ getProps().onFocusChange?.(nextFocusedDate);
619
700
  setIsPaginating(false);
620
701
  };
621
702
 
@@ -671,7 +752,7 @@ export function createCalendarState<
671
752
  if (isReadOnly() || isDisabled()) return;
672
753
 
673
754
  if (selectionMode() === "multiple") {
674
- const current = access(props.value) !== undefined ? value() : readNow(internalValue);
755
+ const current = access(getProps().value) !== undefined ? value() : readNow(internalValue);
675
756
  const base: CalendarDate[] = Array.isArray(current)
676
757
  ? current.map((v) => toDisplayCalendarDate(v))
677
758
  : current != null
@@ -64,8 +64,10 @@ export interface DatePickerState<T extends DateValue = DateValue> {
64
64
  value: Accessor<T | null>;
65
65
  defaultValue: T | null;
66
66
  setValue: (value: T | null) => void;
67
+ /** Committed value, or the in-progress date before the other half commits. */
67
68
  dateValue: Accessor<DateValue | null>;
68
69
  setDateValue: (value: DateValue) => void;
70
+ /** Committed value when it has a time; otherwise the in-progress time. */
69
71
  timeValue: Accessor<TimeValue | null>;
70
72
  setTimeValue: (value: TimeValue) => void;
71
73
  granularity: Granularity;
@@ -129,18 +131,19 @@ export function createDatePickerState<T extends DateValue = DateValue>(
129
131
  const validationState = createMemo(() => access(props.validationState));
130
132
  const isOpen: Accessor<boolean> = () => access(props.isOpen) ?? readNow(internalOpen);
131
133
 
132
- // Date and time portions of the current value
133
- const dateValue = createMemo<DateValue | null>(() => {
134
- const v = value();
135
- if (!v) return null;
136
- return toCalendarDate(v);
137
- });
134
+ // useDatePickerState shadows selectedDate/selectedTime with the committed
135
+ // value during render. Otherwise the popover reads the in-progress half.
136
+ const dateValue: Accessor<DateValue | null> = () => {
137
+ const committed = value();
138
+ if (committed) return committed;
139
+ return selectedDate();
140
+ };
138
141
 
139
- const timeValue = createMemo<TimeValue | null>(() => {
140
- const v = value();
141
- if (!v || !("hour" in v)) return null;
142
- return v as unknown as TimeValue;
143
- });
142
+ const timeValue: Accessor<TimeValue | null> = () => {
143
+ const committed = value();
144
+ if (committed && "hour" in committed) return committed as unknown as TimeValue;
145
+ return selectedTime();
146
+ };
144
147
 
145
148
  // Helper to resolve placeholder time (midnight fallback)
146
149
  const getPlaceholderTime = (): TimeValue => {