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

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 (134) 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 +1044 -478
  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/textfield/createTextFieldState.d.ts.map +1 -1
  72. package/dist/toggle/createToggleGroupState.d.ts +0 -8
  73. package/dist/toggle/createToggleGroupState.d.ts.map +1 -1
  74. package/dist/toggle/createToggleState.d.ts.map +1 -1
  75. package/dist/tokenfield/TokenFieldValue.d.ts +28 -4
  76. package/dist/tokenfield/TokenFieldValue.d.ts.map +1 -1
  77. package/dist/tokenfield/index.d.ts +1 -1
  78. package/dist/tokenfield/index.d.ts.map +1 -1
  79. package/dist/tree/createTreeState.d.ts +2 -2
  80. package/dist/tree/createTreeState.d.ts.map +1 -1
  81. package/dist/utils/index.d.ts +1 -1
  82. package/dist/utils/index.d.ts.map +1 -1
  83. package/dist/utils/reactivity.d.ts +5 -0
  84. package/dist/utils/reactivity.d.ts.map +1 -1
  85. package/package.json +2 -2
  86. package/src/calendar/createCalendarState.ts +139 -58
  87. package/src/calendar/createDatePickerState.ts +14 -11
  88. package/src/calendar/createRangeCalendarState.ts +43 -17
  89. package/src/calendar/createTimeFieldState.ts +1 -1
  90. package/src/checkbox/createCheckboxGroupState.ts +16 -0
  91. package/src/collections/createListState.ts +4 -4
  92. package/src/collections/createMenuState.ts +134 -4
  93. package/src/collections/createSelectionState.ts +2 -2
  94. package/src/collections/index.ts +4 -0
  95. package/src/color/createColorAreaState.ts +19 -0
  96. package/src/color/createColorFieldState.ts +76 -26
  97. package/src/color/createColorSliderState.ts +25 -2
  98. package/src/color/createColorWheelState.ts +9 -5
  99. package/src/combobox/createComboBoxState.ts +371 -121
  100. package/src/combobox/index.ts +4 -0
  101. package/src/data/createAsyncList.ts +19 -4
  102. package/src/data/createListData.ts +8 -2
  103. package/src/data/createTreeData.ts +11 -3
  104. package/src/dnd/createDraggableCollectionState.ts +8 -1
  105. package/src/dnd/createDroppableCollectionState.ts +10 -0
  106. package/src/form/createFormValidationState.ts +23 -5
  107. package/src/grid/createGridState.ts +15 -8
  108. package/src/index.ts +18 -2
  109. package/src/menu/index.ts +5 -0
  110. package/src/numberfield/createNumberFieldState.ts +97 -35
  111. package/src/radio/createRadioGroupState.ts +4 -1
  112. package/src/select/createSelectState.ts +253 -131
  113. package/src/select/index.ts +8 -1
  114. package/src/selection/SelectionManager.ts +3 -1
  115. package/src/selection/createMultipleSelectionState.ts +2 -2
  116. package/src/slider/createSliderState.ts +227 -103
  117. package/src/ssr/index.ts +11 -4
  118. package/src/steplist/createStepListState.ts +156 -123
  119. package/src/table/createTableColumnResizeState.ts +51 -11
  120. package/src/table/createTableState.ts +5 -4
  121. package/src/table/createTreeGridState.ts +3 -4
  122. package/src/table/types.ts +2 -2
  123. package/src/tabs/createTabListState.ts +8 -31
  124. package/src/textfield/createTextFieldState.ts +6 -3
  125. package/src/toggle/createToggleGroupState.ts +4 -2
  126. package/src/toggle/createToggleState.ts +5 -4
  127. package/src/tokenfield/TokenFieldValue.ts +75 -16
  128. package/src/tokenfield/index.ts +1 -0
  129. package/src/tree/createTreeState.ts +15 -8
  130. package/src/utils/index.ts +1 -0
  131. package/src/utils/reactivity.ts +8 -0
  132. package/dist/flags/flags.d.ts.map +0 -1
  133. /package/dist/{flags → private/flags}/flags.d.ts +0 -0
  134. /package/src/{flags → private/flags}/flags.ts +0 -0
@@ -20,7 +20,7 @@
20
20
  * This is a 1:1 port of @react-stately/toggle's useToggleState.
21
21
  */
22
22
 
23
- import { Accessor } from "solid-js";
23
+ import { Accessor, untrack } from "solid-js";
24
24
  import { access, createInternalSignal, readNow, type MaybeAccessor } from "../utils";
25
25
 
26
26
  export interface ToggleStateOptions {
@@ -51,8 +51,9 @@ export interface ToggleState {
51
51
  export function createToggleState(props: MaybeAccessor<ToggleStateOptions> = {}): ToggleState {
52
52
  const getProps = () => access(props);
53
53
 
54
- const initialProps = getProps();
55
- const initialSelected = initialProps.isSelected ?? initialProps.defaultSelected ?? false;
54
+ // Seeds the uncontrolled state once, by definition.
55
+ const initialDefaultSelected = untrack(() => getProps().defaultSelected);
56
+ const initialSelected = untrack(() => getProps().isSelected) ?? initialDefaultSelected ?? false;
56
57
 
57
58
  const [internalSelected, setInternalSelected] = createInternalSignal(initialSelected);
58
59
 
@@ -88,7 +89,7 @@ export function createToggleState(props: MaybeAccessor<ToggleStateOptions> = {})
88
89
 
89
90
  return {
90
91
  isSelected,
91
- defaultSelected: initialProps.defaultSelected ?? initialSelected,
92
+ defaultSelected: initialDefaultSelected ?? initialSelected,
92
93
  setSelected,
93
94
  toggle,
94
95
  };
@@ -33,13 +33,66 @@ export interface Position {
33
33
  offset: number;
34
34
  }
35
35
 
36
+ /** Represents a text selection in a TokenField. */
37
+ export class SelectedRange {
38
+ /** The anchor position. */
39
+ anchor: Position;
40
+ /** The current (i.e. caret) position. */
41
+ current: Position;
42
+
43
+ /**
44
+ * Creates a new selection range. If only a single position is provided, the selection is
45
+ * collapsed.
46
+ */
47
+ constructor(anchor: Position, current: Position = anchor) {
48
+ this.anchor = anchor;
49
+ this.current = current;
50
+ }
51
+
52
+ /** Whether the selection is collapsed to a single caret position. */
53
+ get isCollapsed() {
54
+ return this.anchor.index === this.current.index && this.anchor.offset === this.current.offset;
55
+ }
56
+
57
+ /** The side of the selection closest to the start of the value. */
58
+ get start() {
59
+ return compare(this.anchor, this.current) < 0 ? this.anchor : this.current;
60
+ }
61
+
62
+ /** The side of the selection closest to the end of the value. */
63
+ get end() {
64
+ return compare(this.anchor, this.current) < 0 ? this.current : this.anchor;
65
+ }
66
+
67
+ /** Returns whether this selection is equal to another. */
68
+ isEqual(other: SelectedRange) {
69
+ if (this === other) {
70
+ return true;
71
+ }
72
+ return (
73
+ this.anchor.index === other.anchor.index &&
74
+ this.anchor.offset === other.anchor.offset &&
75
+ this.current.index === other.current.index &&
76
+ this.current.offset === other.current.offset
77
+ );
78
+ }
79
+ }
80
+
81
+ function compare(a: Position, b: Position) {
82
+ if (a.index === b.index) {
83
+ return a.offset - b.offset;
84
+ }
85
+
86
+ return a.index - b.index;
87
+ }
88
+
36
89
  enum Direction {
37
90
  Forward = 1,
38
91
  Backward = -1,
39
92
  }
40
93
 
41
94
  export interface TokenFieldValueOptions {
42
- caretPosition?: Position | null;
95
+ selectedRange?: SelectedRange | null;
43
96
  }
44
97
 
45
98
  /**
@@ -47,11 +100,12 @@ export interface TokenFieldValueOptions {
47
100
  */
48
101
  export class TokenFieldValue<T = any> {
49
102
  static readonly Direction = Direction;
103
+ static readonly SelectedRange = SelectedRange;
50
104
 
51
105
  /** The text and token segments in the list. */
52
106
  readonly segments: readonly TokenFieldSegment<T>[];
53
- /** The caret position. */
54
- caretPosition: Position = { index: 0, offset: 0 };
107
+ /** The selected range. */
108
+ selectedRange: SelectedRange;
55
109
  // Linked list representing the undo/redo history.
56
110
  private previous: this | null = null;
57
111
  private next: this | null = null;
@@ -60,7 +114,11 @@ export class TokenFieldValue<T = any> {
60
114
  /** Create a new list with the given segments. */
61
115
  constructor(tokens: readonly TokenFieldSegment<T>[], options?: TokenFieldValueOptions) {
62
116
  this.segments = tokens;
63
- this.caretPosition = options?.caretPosition ?? { index: 0, offset: 0 };
117
+ this.selectedRange = options?.selectedRange ?? new SelectedRange({ index: 0, offset: 0 });
118
+ }
119
+
120
+ get caretPosition(): Position {
121
+ return this.selectedRange.current;
64
122
  }
65
123
 
66
124
  protected createFieldValue(segments: readonly TokenFieldSegment<T>[]): this {
@@ -71,23 +129,25 @@ export class TokenFieldValue<T = any> {
71
129
  return new Constructor(segments);
72
130
  }
73
131
 
74
- /** Create a new list with the caret position set to the given position. */
75
- withCaretPosition(caretPosition: Position): this {
76
- if (
77
- this.caretPosition.index === caretPosition.index &&
78
- this.caretPosition.offset === caretPosition.offset
79
- ) {
132
+ /** Create a new list with the selected range set to the given range. */
133
+ withSelectedRange(selectedRange: SelectedRange): this {
134
+ if (this.selectedRange.isEqual(selectedRange)) {
80
135
  return this;
81
136
  }
82
137
 
83
138
  let result = this.createFieldValue(this.segments);
84
- result.caretPosition = caretPosition;
139
+ result.selectedRange = selectedRange;
85
140
  result.previous = this.previous;
86
141
  result.next = this.next;
87
142
  result.isCoalescing = this.isCoalescing;
88
143
  return result;
89
144
  }
90
145
 
146
+ /** Create a new list with the caret position set to the given position. */
147
+ withCaretPosition(position: Position): this {
148
+ return this.withSelectedRange(new SelectedRange(position));
149
+ }
150
+
91
151
  private splitSegment(
92
152
  segment: TokenFieldSegment | undefined,
93
153
  offset: number,
@@ -176,14 +236,14 @@ export class TokenFieldValue<T = any> {
176
236
  appendSegments(newSegments, this.segments.slice(end.index + 1));
177
237
 
178
238
  let segments = this.createFieldValue(newSegments);
179
- segments.caretPosition = caret;
239
+ segments.selectedRange = new SelectedRange(caret);
180
240
  segments.isCoalescing = coalesce;
181
241
  if (this.isCoalescing && coalesce && this.previous) {
182
242
  segments.previous = this.previous;
183
243
  segments.previous.next = segments;
184
244
  } else {
185
245
  segments.previous = this;
186
- this.caretPosition = end;
246
+ this.selectedRange = new SelectedRange(start, end);
187
247
  this.next = segments;
188
248
  }
189
249
  return segments;
@@ -306,8 +366,7 @@ export class TokenFieldValue<T = any> {
306
366
  );
307
367
  }
308
368
 
309
- this.caretPosition = position;
310
- return this;
369
+ return this.withSelectedRange(new SelectedRange(position));
311
370
  }
312
371
 
313
372
  /** Delete text to the next or previous line break. */
@@ -326,7 +385,7 @@ export class TokenFieldValue<T = any> {
326
385
  );
327
386
  }
328
387
 
329
- return this;
388
+ return this.withSelectedRange(new SelectedRange(position));
330
389
  }
331
390
 
332
391
  /** Create a new list containing a subset of the segments. */
@@ -4,6 +4,7 @@ export {
4
4
  type TextSegment,
5
5
  type TokenSegment,
6
6
  type Position,
7
+ type SelectedRange,
7
8
  type TokenFieldValueOptions,
8
9
  } from "./TokenFieldValue";
9
10
 
@@ -20,19 +20,18 @@
20
20
  */
21
21
 
22
22
  import { createEffect, createMemo } from "solid-js";
23
- import type { Accessor } from "solid-js";
24
23
  import type { TreeState, TreeStateOptions, TreeCollection } from "./types";
25
24
  import type { Key, FocusStrategy, Selection, SelectionBehavior } from "../collections/types";
26
- import { createInternalSignal } from "../utils";
25
+ import { createInternalSignal, propsAccessor, type MaybeAccessor } from "../utils";
27
26
 
28
27
  /**
29
28
  * Creates state management for a tree component.
30
29
  * Handles expansion, selection, focus management, and keyboard navigation state.
31
30
  */
32
31
  export function createTreeState<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(
33
- options: Accessor<TreeStateOptions<T, C>>,
32
+ options: MaybeAccessor<TreeStateOptions<T, C>>,
34
33
  ): TreeState<T, C> {
35
- const getOptions = () => options();
34
+ const getOptions = propsAccessor(options);
36
35
 
37
36
  // Disabled keys as a Set
38
37
  const disabledKeys = createMemo(() => {
@@ -92,18 +91,26 @@ export function createTreeState<T extends object, C extends TreeCollection<T> =
92
91
  const disallowEmptySelection = createMemo(() => getOptions().disallowEmptySelection ?? false);
93
92
  const disabledBehavior = createMemo(() => getOptions().disabledBehavior ?? "all");
94
93
 
94
+ let lastSelectionBehavior = selectionBehaviorProp();
95
95
  createEffect(selectionBehaviorProp, (behavior) => {
96
- setSelectionBehaviorState(behavior);
96
+ if (behavior !== lastSelectionBehavior) {
97
+ setSelectionBehaviorState(behavior);
98
+ lastSelectionBehavior = behavior;
99
+ }
97
100
  });
98
101
 
99
102
  createEffect(
100
103
  () => ({
101
104
  prop: selectionBehaviorProp(),
102
- state: selectionBehaviorState(),
103
105
  keys: selectedKeys(),
104
106
  }),
105
- ({ prop, state, keys }) => {
106
- if (prop === "replace" && state === "toggle" && keys !== "all" && keys.size === 0) {
107
+ ({ prop, keys }) => {
108
+ if (
109
+ prop === "replace" &&
110
+ selectionBehaviorState() === "toggle" &&
111
+ keys !== "all" &&
112
+ keys.size === 0
113
+ ) {
107
114
  setSelectionBehaviorState("replace");
108
115
  }
109
116
  },
@@ -2,6 +2,7 @@ export {
2
2
  access,
3
3
  createInternalSignal,
4
4
  isAccessor,
5
+ propsAccessor,
5
6
  readNow,
6
7
  type MaybeAccessor,
7
8
  type MaybeAccessorValue,
@@ -36,6 +36,14 @@ export function isAccessor<T>(value: MaybeAccessor<T>): value is Accessor<T> {
36
36
  return typeof value === "function";
37
37
  }
38
38
 
39
+ /**
40
+ * Resolve a props bag once. Later reads call the accessor directly, so a
41
+ * function-valued field such as `getKey` is never treated as the bag.
42
+ */
43
+ export function propsAccessor<T extends object>(props: MaybeAccessor<T>): Accessor<T> {
44
+ return typeof props === "function" ? props : () => props;
45
+ }
46
+
39
47
  /**
40
48
  * Headless state is written from factory setup and from public setters that
41
49
  * tests (and some call sites) invoke inside `createRoot` / a component body.
@@ -1 +0,0 @@
1
- {"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../../src/flags/flags.ts"],"names":[],"mappings":"AAgBA,gFAAgF;AAChF,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,IAAI,OAAO,CAEnC"}
File without changes
File without changes