@proyecto-viviana/solid-stately 0.3.0 → 0.4.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.
- package/dist/calendar/IncompleteDate.d.ts +61 -0
- package/dist/calendar/createCalendarState.d.ts +20 -10
- package/dist/calendar/createDateFieldState.d.ts +65 -20
- package/dist/calendar/createRangeCalendarState.d.ts +20 -2
- package/dist/calendar/createTimeFieldState.d.ts +38 -67
- package/dist/calendar/index.d.ts +1 -1
- package/dist/calendar/intl/index.d.ts +10 -0
- package/dist/collections/ListCollection.d.ts +8 -0
- package/dist/collections/createListState.d.ts +16 -1
- package/dist/collections/createSelectionState.d.ts +17 -5
- package/dist/collections/getChildNodes.d.ts +19 -0
- package/dist/collections/index.d.ts +3 -2
- package/dist/collections/types.d.ts +9 -0
- package/dist/color/intl/index.d.ts +14 -0
- package/dist/combobox/createComboBoxState.d.ts +7 -0
- package/dist/dnd/createDroppableCollectionState.d.ts +17 -2
- package/dist/dnd/index.d.ts +1 -1
- package/dist/dnd/types.d.ts +3 -1
- package/dist/grid/types.d.ts +17 -3
- package/dist/index.d.ts +6 -6
- package/dist/index.js +4372 -1087
- package/dist/index.js.map +1 -1
- package/dist/select/createSelectState.d.ts +6 -0
- package/dist/selection/Selection.d.ts +16 -0
- package/dist/selection/SelectionManager.d.ts +119 -0
- package/dist/selection/createMultipleSelectionState.d.ts +59 -0
- package/dist/selection/index.d.ts +1 -0
- package/dist/table/TableCollection.d.ts +30 -0
- package/dist/table/createTreeGridState.d.ts +15 -0
- package/dist/table/index.d.ts +2 -1
- package/dist/table/types.d.ts +58 -0
- package/dist/toast/createToastState.d.ts +16 -0
- package/dist/toast/index.d.ts +1 -1
- package/dist/tree/types.d.ts +14 -6
- package/package.json +1 -1
- package/src/calendar/IncompleteDate.ts +430 -0
- package/src/calendar/createCalendarState.ts +129 -40
- package/src/calendar/createDateFieldState.ts +633 -477
- package/src/calendar/createRangeCalendarState.ts +343 -30
- package/src/calendar/createTimeFieldState.ts +179 -467
- package/src/calendar/index.ts +2 -0
- package/src/calendar/intl/index.ts +364 -0
- package/src/collections/ListCollection.ts +31 -0
- package/src/collections/createListState.ts +139 -17
- package/src/collections/createMenuState.ts +3 -0
- package/src/collections/createSelectionState.ts +38 -28
- package/src/collections/getChildNodes.ts +129 -0
- package/src/collections/index.ts +12 -0
- package/src/collections/types.ts +10 -0
- package/src/color/Color.ts +104 -133
- package/src/color/intl/index.ts +1409 -0
- package/src/combobox/createComboBoxState.ts +38 -13
- package/src/dnd/createDroppableCollectionState.ts +125 -6
- package/src/dnd/index.d.ts +1 -0
- package/src/dnd/index.ts +1 -0
- package/src/dnd/types.d.ts +3 -1
- package/src/dnd/types.ts +4 -1
- package/src/grid/createGridState.ts +36 -2
- package/src/grid/types.ts +17 -3
- package/src/index.d.ts +1 -0
- package/src/index.ts +14 -0
- package/src/select/createSelectState.ts +15 -2
- package/src/selection/Selection.ts +28 -0
- package/src/selection/SelectionManager.ts +541 -0
- package/src/selection/createMultipleSelectionState.ts +247 -0
- package/src/selection/index.ts +6 -0
- package/src/steplist/createStepListState.ts +27 -4
- package/src/table/TableCollection.ts +213 -43
- package/src/table/createTableState.ts +20 -0
- package/src/table/createTreeGridState.ts +146 -0
- package/src/table/index.ts +3 -0
- package/src/table/types.ts +66 -0
- package/src/tabs/createTabListState.ts +11 -9
- package/src/toast/createToastState.ts +43 -10
- package/src/toast/index.ts +1 -0
- package/src/tree/createTreeState.ts +37 -6
- package/src/tree/types.ts +14 -6
|
@@ -35,13 +35,23 @@ export type CalendarDayOfWeek = "sun" | "mon" | "tue" | "wed" | "thu" | "fri" |
|
|
|
35
35
|
|
|
36
36
|
const dayOfWeekNames: CalendarDayOfWeek[] = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
37
37
|
|
|
38
|
-
export
|
|
38
|
+
export type CalendarSelectionMode = "single" | "multiple";
|
|
39
|
+
export type CalendarValueType<T, M extends CalendarSelectionMode> = M extends "single"
|
|
40
|
+
? T
|
|
41
|
+
: readonly T[];
|
|
42
|
+
|
|
43
|
+
export interface CalendarStateProps<
|
|
44
|
+
T extends DateValue = DateValue,
|
|
45
|
+
M extends CalendarSelectionMode = "single",
|
|
46
|
+
> {
|
|
39
47
|
/** The current value (controlled). */
|
|
40
|
-
value?: MaybeAccessor<T | null>;
|
|
48
|
+
value?: MaybeAccessor<CalendarValueType<T | null, M> | undefined>;
|
|
41
49
|
/** The default value (uncontrolled). */
|
|
42
|
-
defaultValue?: T | null;
|
|
50
|
+
defaultValue?: CalendarValueType<T | null, M> | null;
|
|
43
51
|
/** Handler called when the value changes. */
|
|
44
|
-
onChange?: (value: T | null) => void;
|
|
52
|
+
onChange?: (value: CalendarValueType<T | null, M>) => void;
|
|
53
|
+
/** Whether single or multiple date selection is enabled. */
|
|
54
|
+
selectionMode?: MaybeAccessor<M>;
|
|
45
55
|
/** The minimum allowed date. */
|
|
46
56
|
minValue?: MaybeAccessor<DateValue | undefined>;
|
|
47
57
|
/** The maximum allowed date. */
|
|
@@ -82,15 +92,24 @@ export interface CalendarStateProps<T extends DateValue = DateValue> {
|
|
|
82
92
|
firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
83
93
|
}
|
|
84
94
|
|
|
85
|
-
export interface CalendarState<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
export interface CalendarState<
|
|
96
|
+
T extends DateValue = DateValue,
|
|
97
|
+
M extends CalendarSelectionMode = "single",
|
|
98
|
+
> {
|
|
99
|
+
/** Whether single or multiple selection is enabled. */
|
|
100
|
+
selectionMode: Accessor<CalendarSelectionMode>;
|
|
101
|
+
/** The currently selected date(s). */
|
|
102
|
+
value: Accessor<CalendarValueType<T | null, M>>;
|
|
103
|
+
/** Sets the selected date(s). */
|
|
104
|
+
setValue: (value: CalendarValueType<T | null, M>) => void;
|
|
90
105
|
/** The currently focused date. */
|
|
91
106
|
focusedDate: Accessor<CalendarDate>;
|
|
92
107
|
/** Sets the focused date. */
|
|
93
108
|
setFocusedDate: (date: CalendarDate) => void;
|
|
109
|
+
/** The minimum allowed date that a user may select. */
|
|
110
|
+
minValue: Accessor<DateValue | null>;
|
|
111
|
+
/** The maximum allowed date that a user may select. */
|
|
112
|
+
maxValue: Accessor<DateValue | null>;
|
|
94
113
|
/** Whether the calendar is disabled. */
|
|
95
114
|
isDisabled: Accessor<boolean>;
|
|
96
115
|
/** Whether the calendar is read-only. */
|
|
@@ -164,11 +183,17 @@ export interface CalendarState<T extends DateValue = DateValue> {
|
|
|
164
183
|
/**
|
|
165
184
|
* Provides state management for a calendar component.
|
|
166
185
|
*/
|
|
167
|
-
export function createCalendarState<
|
|
168
|
-
|
|
169
|
-
|
|
186
|
+
export function createCalendarState<
|
|
187
|
+
T extends DateValue = CalendarDate,
|
|
188
|
+
M extends CalendarSelectionMode = "single",
|
|
189
|
+
>(props: CalendarStateProps<T, M> = {}): CalendarState<T, M> {
|
|
170
190
|
const timeZone = getLocalTimeZone();
|
|
171
191
|
const locale = createMemo(() => access(props.locale) ?? "en-US");
|
|
192
|
+
const minValueState = createMemo(() => access(props.minValue) ?? null);
|
|
193
|
+
const maxValueState = createMemo(() => access(props.maxValue) ?? null);
|
|
194
|
+
const selectionMode = createMemo<CalendarSelectionMode>(
|
|
195
|
+
() => access(props.selectionMode) ?? "single",
|
|
196
|
+
);
|
|
172
197
|
const resolvedOptions = createMemo(() => new DateFormatter(locale()).resolvedOptions());
|
|
173
198
|
const calendar = createMemo(() =>
|
|
174
199
|
(props.createCalendar ?? intlCreateCalendar)(resolvedOptions().calendar as CalendarIdentifier),
|
|
@@ -181,19 +206,21 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
181
206
|
intlToCalendar(toCalendarDate(date), calendar());
|
|
182
207
|
|
|
183
208
|
const selectionAlignmentOffset = (): number => {
|
|
209
|
+
// Mirrors @react-stately/calendar useCalendarState, where selectionAlignment
|
|
210
|
+
// defaults to "center" (alignCenter) when not provided.
|
|
184
211
|
switch (props.selectionAlignment) {
|
|
212
|
+
case "start":
|
|
213
|
+
return 0;
|
|
185
214
|
case "end":
|
|
186
215
|
return Math.max(visibleMonths - 1, 0);
|
|
187
|
-
case "center":
|
|
216
|
+
case "center":
|
|
217
|
+
default: {
|
|
188
218
|
let halfDuration = Math.floor(visibleMonths / 2);
|
|
189
219
|
if (halfDuration > 0 && visibleMonths % 2 === 0) {
|
|
190
220
|
halfDuration--;
|
|
191
221
|
}
|
|
192
222
|
return halfDuration;
|
|
193
223
|
}
|
|
194
|
-
case "start":
|
|
195
|
-
default:
|
|
196
|
-
return 0;
|
|
197
224
|
}
|
|
198
225
|
};
|
|
199
226
|
|
|
@@ -238,32 +265,44 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
238
265
|
return toDisplayCalendarDate(props.defaultFocusedValue);
|
|
239
266
|
}
|
|
240
267
|
const controlledValue = access(props.value);
|
|
241
|
-
|
|
242
|
-
|
|
268
|
+
const controlledFirst = Array.isArray(controlledValue) ? controlledValue[0] : controlledValue;
|
|
269
|
+
if (controlledFirst) {
|
|
270
|
+
return toDisplayCalendarDate(controlledFirst);
|
|
243
271
|
}
|
|
244
|
-
|
|
245
|
-
|
|
272
|
+
const defaultFirst = Array.isArray(props.defaultValue)
|
|
273
|
+
? props.defaultValue[0]
|
|
274
|
+
: props.defaultValue;
|
|
275
|
+
if (defaultFirst) {
|
|
276
|
+
return toDisplayCalendarDate(defaultFirst);
|
|
246
277
|
}
|
|
247
278
|
return intlToCalendar(today(timeZone), calendar());
|
|
248
279
|
};
|
|
249
280
|
|
|
250
281
|
// State signals
|
|
251
282
|
const initialFocusedDate = constrainDate(getInitialFocusedDate());
|
|
252
|
-
const [internalValue, setInternalValue] = createSignal<T | null>(
|
|
283
|
+
const [internalValue, setInternalValue] = createSignal<T | T[] | null>(
|
|
284
|
+
(props.defaultValue as T | T[] | null) ?? null,
|
|
285
|
+
);
|
|
253
286
|
const [focusedDate, setFocusedDateInternal] = createSignal<CalendarDate>(initialFocusedDate);
|
|
254
287
|
const [visibleRangeStart, setVisibleRangeStart] = createSignal<CalendarDate>(
|
|
255
288
|
alignVisibleRangeStart(initialFocusedDate),
|
|
256
289
|
);
|
|
257
|
-
|
|
290
|
+
// Init from autoFocus, mirroring @react-stately useCalendarState
|
|
291
|
+
// (`useState(props.autoFocus || false)`). Without autoFocus the calendar
|
|
292
|
+
// mounts unfocused and never steals DOM focus.
|
|
293
|
+
const [isFocused, setFocused] = createSignal(props.autoFocus ?? false);
|
|
258
294
|
const [isPaginating, setIsPaginating] = createSignal(false);
|
|
259
295
|
|
|
260
296
|
// Controlled vs uncontrolled value
|
|
261
|
-
const sourceValue = createMemo<T | null>(() => {
|
|
297
|
+
const sourceValue = createMemo<T | T[] | null>(() => {
|
|
262
298
|
const controlled = access(props.value);
|
|
263
|
-
return controlled !== undefined ? controlled : internalValue();
|
|
299
|
+
return controlled !== undefined ? (controlled as T | T[] | null) : internalValue();
|
|
264
300
|
});
|
|
265
|
-
const value = createMemo<T | null>(() => {
|
|
301
|
+
const value = createMemo<T | T[] | null>(() => {
|
|
266
302
|
const currentValue = sourceValue();
|
|
303
|
+
if (Array.isArray(currentValue)) {
|
|
304
|
+
return currentValue.map((v) => toDisplayCalendarDate(v) as unknown as T);
|
|
305
|
+
}
|
|
267
306
|
return currentValue ? (toDisplayCalendarDate(currentValue) as unknown as T) : null;
|
|
268
307
|
});
|
|
269
308
|
|
|
@@ -370,13 +409,22 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
370
409
|
});
|
|
371
410
|
|
|
372
411
|
// Set value with onChange callback
|
|
373
|
-
const setValue = (newValue: T | null) => {
|
|
412
|
+
const setValue = (newValue: T | T[] | null) => {
|
|
374
413
|
if (isDisabled() || isReadOnly()) return;
|
|
375
414
|
|
|
376
415
|
const oldValue = sourceValue();
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
416
|
+
const referenceValue = Array.isArray(oldValue) ? (oldValue[0] ?? null) : oldValue;
|
|
417
|
+
|
|
418
|
+
let nextValue: T | T[] | null;
|
|
419
|
+
if (newValue == null) {
|
|
420
|
+
nextValue = selectionMode() === "multiple" ? ([] as T[]) : null;
|
|
421
|
+
} else if (Array.isArray(newValue)) {
|
|
422
|
+
nextValue = newValue.map(
|
|
423
|
+
(v) => convertValue(constrainDate(toDisplayCalendarDate(v)), referenceValue) as T,
|
|
424
|
+
);
|
|
425
|
+
} else {
|
|
426
|
+
nextValue = convertValue(constrainDate(toDisplayCalendarDate(newValue)), referenceValue) as T;
|
|
427
|
+
}
|
|
380
428
|
|
|
381
429
|
const controlled = access(props.value);
|
|
382
430
|
if (controlled === undefined) {
|
|
@@ -384,7 +432,7 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
384
432
|
}
|
|
385
433
|
|
|
386
434
|
if (!Object.is(oldValue, nextValue) && props.onChange) {
|
|
387
|
-
props.onChange(nextValue);
|
|
435
|
+
props.onChange(nextValue as CalendarValueType<T | null, M>);
|
|
388
436
|
}
|
|
389
437
|
};
|
|
390
438
|
|
|
@@ -404,13 +452,21 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
404
452
|
// Check if a date is selected
|
|
405
453
|
const isSelected = (date: DateValue): boolean => {
|
|
406
454
|
const v = value();
|
|
407
|
-
if (
|
|
408
|
-
|
|
455
|
+
if (v == null) return false;
|
|
456
|
+
const target = toDisplayCalendarDate(date);
|
|
457
|
+
if (Array.isArray(v)) {
|
|
458
|
+
return v.some((d) => isSameDay(target, toDisplayCalendarDate(d)));
|
|
459
|
+
}
|
|
460
|
+
return isSameDay(target, toDisplayCalendarDate(v));
|
|
409
461
|
};
|
|
410
462
|
|
|
411
|
-
// Check if a date is focused
|
|
463
|
+
// Check if a date is focused. Mirrors @react-stately/calendar isCellFocused
|
|
464
|
+
// (`isFocused && focusedDate && isSameDay(date, focusedDate)`): the
|
|
465
|
+
// calendar-level `isFocused` flag gates cell focus so the calendar does NOT
|
|
466
|
+
// steal DOM focus on mount. The roving tabbable cell is tracked separately by
|
|
467
|
+
// the cell's `tabIndex` (isSameDay against focusedDate, ungated).
|
|
412
468
|
const isCellFocused = (date: DateValue): boolean => {
|
|
413
|
-
return isSameDay(toDisplayCalendarDate(date), focusedDate());
|
|
469
|
+
return isFocused() && isSameDay(toDisplayCalendarDate(date), focusedDate());
|
|
414
470
|
};
|
|
415
471
|
|
|
416
472
|
// Check if a date is unavailable
|
|
@@ -427,6 +483,15 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
427
483
|
const maxValue = access(props.maxValue);
|
|
428
484
|
const calDate = toDisplayCalendarDate(date);
|
|
429
485
|
|
|
486
|
+
// Dates outside the visible range are disabled, mirroring
|
|
487
|
+
// @react-stately/calendar isCellDisabled (`date.compare(startDate) < 0 ||
|
|
488
|
+
// date.compare(endDate) > 0` over the visible range). This is what marks the
|
|
489
|
+
// leading/trailing padding cells (days from the adjacent months that fill out
|
|
490
|
+
// the first/last grid weeks) as aria-disabled.
|
|
491
|
+
const range = visibleRange();
|
|
492
|
+
if (calDate.compare(toDisplayCalendarDate(range.start)) < 0) return true;
|
|
493
|
+
if (calDate.compare(toDisplayCalendarDate(range.end)) > 0) return true;
|
|
494
|
+
|
|
430
495
|
if (minValue && calDate.compare(toDisplayCalendarDate(minValue)) < 0) return true;
|
|
431
496
|
if (maxValue && calDate.compare(toDisplayCalendarDate(maxValue)) > 0) return true;
|
|
432
497
|
|
|
@@ -502,17 +567,38 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
502
567
|
const selectFocusedDate = () => {
|
|
503
568
|
if (isReadOnly() || isDisabled()) return;
|
|
504
569
|
const date = focusedDate();
|
|
505
|
-
if (!
|
|
506
|
-
|
|
570
|
+
if (!isCellUnavailable(date)) {
|
|
571
|
+
selectDate(date);
|
|
507
572
|
}
|
|
508
573
|
};
|
|
509
574
|
|
|
510
575
|
const selectDate = (date: CalendarDate) => {
|
|
576
|
+
// Mirror @react-stately/calendar `selectDate(date) { setValue(date); }`:
|
|
577
|
+
// no isCellDisabled/isCellUnavailable guard here. Upstream gates selection
|
|
578
|
+
// at the cell layer (createCalendarCell handlePointerDown/handleClick guard
|
|
579
|
+
// on isDisabled/isUnavailable before calling selectDate); the state method
|
|
580
|
+
// only refuses when the whole calendar is disabled/readOnly (setValue's
|
|
581
|
+
// guard). Double-guarding here also broke programmatic selection of dates
|
|
582
|
+
// outside the current visible range.
|
|
511
583
|
if (isReadOnly() || isDisabled()) return;
|
|
512
|
-
|
|
584
|
+
|
|
585
|
+
if (selectionMode() === "multiple") {
|
|
586
|
+
const current = value();
|
|
587
|
+
const base: CalendarDate[] = Array.isArray(current)
|
|
588
|
+
? current.map((v) => toDisplayCalendarDate(v))
|
|
589
|
+
: current != null
|
|
590
|
+
? [toDisplayCalendarDate(current)]
|
|
591
|
+
: [];
|
|
592
|
+
const target = toDisplayCalendarDate(date);
|
|
593
|
+
const index = base.findIndex((d) => isSameDay(d, target));
|
|
594
|
+
const nextValue =
|
|
595
|
+
index >= 0 ? [...base.slice(0, index), ...base.slice(index + 1)] : [...base, target];
|
|
596
|
+
setValue(nextValue as unknown as T[]);
|
|
597
|
+
} else {
|
|
513
598
|
setValue(date as unknown as T);
|
|
514
|
-
setFocusedDate(date);
|
|
515
599
|
}
|
|
600
|
+
|
|
601
|
+
setFocusedDate(date);
|
|
516
602
|
};
|
|
517
603
|
|
|
518
604
|
// Get dates in a specific week
|
|
@@ -548,8 +634,9 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
548
634
|
};
|
|
549
635
|
|
|
550
636
|
return {
|
|
551
|
-
|
|
552
|
-
|
|
637
|
+
selectionMode,
|
|
638
|
+
value: value as unknown as Accessor<CalendarValueType<T | null, M>>,
|
|
639
|
+
setValue: setValue as unknown as (value: CalendarValueType<T | null, M>) => void,
|
|
553
640
|
focusedDate,
|
|
554
641
|
setFocusedDate,
|
|
555
642
|
isDisabled,
|
|
@@ -557,6 +644,8 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
557
644
|
visibleRange,
|
|
558
645
|
timeZone,
|
|
559
646
|
locale,
|
|
647
|
+
minValue: minValueState,
|
|
648
|
+
maxValue: maxValueState,
|
|
560
649
|
firstDayOfWeek: firstDayOfWeekName,
|
|
561
650
|
validationState,
|
|
562
651
|
isValueInvalid,
|