bits-ui 1.3.17 → 1.3.19

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.
@@ -138,6 +138,7 @@ declare class CalendarCellState {
138
138
  readonly "data-focused": "" | undefined;
139
139
  readonly "data-selected": "" | undefined;
140
140
  readonly "data-value": string;
141
+ readonly "data-type": string;
141
142
  readonly "data-disabled": "" | undefined;
142
143
  };
143
144
  props: {
@@ -148,6 +149,7 @@ declare class CalendarCellState {
148
149
  readonly "data-focused": "" | undefined;
149
150
  readonly "data-selected": "" | undefined;
150
151
  readonly "data-value": string;
152
+ readonly "data-type": string;
151
153
  readonly "data-disabled": "" | undefined;
152
154
  readonly id: string;
153
155
  readonly role: "gridcell";
@@ -179,6 +181,7 @@ declare class CalendarDayState {
179
181
  readonly "data-focused": "" | undefined;
180
182
  readonly "data-selected": "" | undefined;
181
183
  readonly "data-value": string;
184
+ readonly "data-type": string;
182
185
  readonly "data-disabled": "" | undefined;
183
186
  readonly id: string;
184
187
  readonly role: "button";
@@ -7,8 +7,8 @@ import { getAriaDisabled, getAriaHidden, getAriaReadonly, getAriaSelected, getDa
7
7
  import { useId } from "../../internal/use-id.js";
8
8
  import { getAnnouncer } from "../../internal/date-time/announcer.js";
9
9
  import { createFormatter } from "../../internal/date-time/formatter.js";
10
- import { createAccessibleHeading, createMonths, getCalendarElementProps, getCalendarHeadingValue, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useEnsureNonDisabledPlaceholder, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
11
- import { isBefore, toDate } from "../../internal/date-time/utils.js";
10
+ import { createAccessibleHeading, createMonths, getCalendarElementProps, getCalendarHeadingValue, getDateWithPreviousTime, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useEnsureNonDisabledPlaceholder, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
11
+ import { getDateValueType, isBefore, toDate } from "../../internal/date-time/utils.js";
12
12
  export class CalendarRootState {
13
13
  opts;
14
14
  months = $state([]);
@@ -258,9 +258,7 @@ export class CalendarRootState {
258
258
  else if (!value) {
259
259
  return false;
260
260
  }
261
- else {
262
- return isSameDay(value, date);
263
- }
261
+ return isSameDay(value, date);
264
262
  }
265
263
  shiftFocus(node, add) {
266
264
  return shiftCalendarFocus({
@@ -275,13 +273,12 @@ export class CalendarRootState {
275
273
  });
276
274
  }
277
275
  handleCellClick(_, date) {
278
- const readonly = this.opts.readonly.current;
279
- if (readonly)
276
+ if (this.opts.readonly.current)
280
277
  return;
281
- const isDateDisabled = this.opts.isDateDisabled.current;
282
- const isDateUnavailable = this.opts.isDateUnavailable.current;
283
- if (isDateDisabled?.(date) || isDateUnavailable?.(date))
278
+ if (this.opts.isDateDisabled.current?.(date) ||
279
+ this.opts.isDateUnavailable.current?.(date)) {
284
280
  return;
281
+ }
285
282
  const prev = this.opts.value.current;
286
283
  const multiple = this.opts.type.current === "multiple";
287
284
  if (multiple) {
@@ -289,19 +286,17 @@ export class CalendarRootState {
289
286
  this.opts.value.current = this.handleMultipleUpdate(prev, date);
290
287
  }
291
288
  }
292
- else {
293
- if (!Array.isArray(prev)) {
294
- const next = this.handleSingleUpdate(prev, date);
295
- if (!next) {
296
- this.announcer.announce("Selected date is now empty.", "polite", 5000);
297
- }
298
- else {
299
- this.announcer.announce(`Selected Date: ${this.formatter.selectedDate(next, false)}`, "polite");
300
- }
301
- this.opts.value.current = next;
302
- if (next !== undefined) {
303
- this.opts.onDateSelect?.current?.();
304
- }
289
+ else if (!Array.isArray(prev)) {
290
+ const next = this.handleSingleUpdate(prev, date);
291
+ if (!next) {
292
+ this.announcer.announce("Selected date is now empty.", "polite", 5000);
293
+ }
294
+ else {
295
+ this.announcer.announce(`Selected Date: ${this.formatter.selectedDate(next, false)}`, "polite");
296
+ }
297
+ this.opts.value.current = getDateWithPreviousTime(next, prev);
298
+ if (next !== undefined) {
299
+ this.opts.onDateSelect?.current?.();
305
300
  }
306
301
  }
307
302
  }
@@ -429,6 +424,7 @@ class CalendarCellState {
429
424
  "data-focused": this.isFocusedDate ? "" : undefined,
430
425
  "data-selected": getDataSelected(this.isSelectedDate),
431
426
  "data-value": this.opts.date.current.toString(),
427
+ "data-type": getDateValueType(this.opts.date.current),
432
428
  "data-disabled": getDataDisabled(this.isDisabled ||
433
429
  (this.isOutsideMonth && this.root.opts.disableDaysOutsideMonth.current)),
434
430
  }));
@@ -45,7 +45,7 @@
45
45
  }
46
46
 
47
47
  if (value === undefined) {
48
- const defaultValue = type === "single" ? "" : [];
48
+ const defaultValue = type === "single" ? undefined : [];
49
49
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
50
  value = defaultValue as any;
51
51
  }
@@ -29,6 +29,20 @@ const COMMAND_VALID_ITEM_SELECTOR = `${COMMAND_ITEM_SELECTOR}:not([aria-disabled
29
29
  const CommandRootContext = new Context("Command.Root");
30
30
  const CommandListContext = new Context("Command.List");
31
31
  const CommandGroupContainerContext = new Context("Command.Group");
32
+ const defaultState = {
33
+ /** Value of the search query */
34
+ search: "",
35
+ /** Currently selected item value */
36
+ value: "",
37
+ filtered: {
38
+ /** The count of all visible items. */
39
+ count: 0,
40
+ /** Map from visible item id to its search store. */
41
+ items: new Map(),
42
+ /** Set of groups with at least one visible item. */
43
+ groups: new Set(),
44
+ },
45
+ };
32
46
  class CommandRootState {
33
47
  opts;
34
48
  #updateScheduled = false;
@@ -43,9 +57,9 @@ class CommandRootState {
43
57
  inputNode = $state(null);
44
58
  labelNode = $state(null);
45
59
  // published state that the components and other things can react to
46
- commandState = $state.raw(null);
60
+ commandState = $state.raw(defaultState);
47
61
  // internal state that we mutate in batches and publish to the `state` at once
48
- _commandState = $state(null);
62
+ _commandState = $state(defaultState);
49
63
  // whether the search has had a value other than ""
50
64
  searchHasHadValue = $state(false);
51
65
  #snapshot() {
@@ -89,22 +103,9 @@ class CommandRootState {
89
103
  }
90
104
  constructor(opts) {
91
105
  this.opts = opts;
92
- const defaultState = {
93
- /** Value of the search query */
94
- search: "",
95
- /** Currently selected item value */
96
- value: this.opts.value.current ?? "",
97
- filtered: {
98
- /** The count of all visible items. */
99
- count: 0,
100
- /** Map from visible item id to its search store. */
101
- items: new Map(),
102
- /** Set of groups with at least one visible item. */
103
- groups: new Set(),
104
- },
105
- };
106
- this._commandState = defaultState;
107
- this.commandState = defaultState;
106
+ const defaults = { ...this._commandState, value: this.opts.value.current ?? "" };
107
+ this._commandState = defaults;
108
+ this.commandState = defaults;
108
109
  useRefById(opts);
109
110
  this.onkeydown = this.onkeydown.bind(this);
110
111
  $effect(() => {
@@ -138,6 +138,7 @@ export declare class RangeCalendarCellState {
138
138
  readonly "data-highlighted": "" | undefined;
139
139
  readonly "data-selected": "" | undefined;
140
140
  readonly "data-value": string;
141
+ readonly "data-type": string;
141
142
  readonly "data-disabled": "" | undefined;
142
143
  };
143
144
  props: {
@@ -151,6 +152,7 @@ export declare class RangeCalendarCellState {
151
152
  readonly "data-highlighted": "" | undefined;
152
153
  readonly "data-selected": "" | undefined;
153
154
  readonly "data-value": string;
155
+ readonly "data-type": string;
154
156
  readonly "data-disabled": "" | undefined;
155
157
  readonly id: string;
156
158
  readonly role: "gridcell";
@@ -189,6 +191,7 @@ declare class RangeCalendarDayState {
189
191
  readonly "data-highlighted": "" | undefined;
190
192
  readonly "data-selected": "" | undefined;
191
193
  readonly "data-value": string;
194
+ readonly "data-type": string;
192
195
  readonly "data-disabled": "" | undefined;
193
196
  readonly id: string;
194
197
  readonly role: "button";
@@ -7,7 +7,7 @@ import { getAriaDisabled, getAriaSelected, getDataDisabled, getDataSelected, get
7
7
  import { getAnnouncer } from "../../internal/date-time/announcer.js";
8
8
  import { createFormatter } from "../../internal/date-time/formatter.js";
9
9
  import { createMonths, getCalendarElementProps, getCalendarHeadingValue, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useEnsureNonDisabledPlaceholder, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
10
- import { areAllDaysBetweenValid, isAfter, isBefore, isBetweenInclusive, toDate, } from "../../internal/date-time/utils.js";
10
+ import { areAllDaysBetweenValid, getDateValueType, isAfter, isBefore, isBetweenInclusive, toDate, } from "../../internal/date-time/utils.js";
11
11
  export class RangeCalendarRootState {
12
12
  opts;
13
13
  months = $state([]);
@@ -466,6 +466,7 @@ export class RangeCalendarCellState {
466
466
  "data-highlighted": this.isHighlighted ? "" : undefined,
467
467
  "data-selected": getDataSelected(this.isSelectedDate),
468
468
  "data-value": this.opts.date.current.toString(),
469
+ "data-type": getDateValueType(this.opts.date.current),
469
470
  "data-disabled": getDataDisabled(this.isDisabled ||
470
471
  (this.isOutsideMonth && this.root.opts.disableDaysOutsideMonth.current)),
471
472
  }));
@@ -1,4 +1,4 @@
1
- import { CalendarDate, type DateValue } from "@internationalized/date";
1
+ import { type DateValue } from "@internationalized/date";
2
2
  import { type ReadableBox, type WritableBox } from "svelte-toolbelt";
3
3
  import type { Formatter } from "./formatter.js";
4
4
  import type { DateMatcher, Month } from "../../shared/index.js";
@@ -183,7 +183,7 @@ export declare function getCalendarElementProps({ fullCalendarLabel, id, isInval
183
183
  };
184
184
  export type CalendarParts = "root" | "grid" | "cell" | "next-button" | "prev-button" | "day" | "grid-body" | "grid-head" | "grid-row" | "head-cell" | "header" | "heading";
185
185
  export declare function pickerOpenFocus(e: Event): void;
186
- export declare function getFirstNonDisabledDateInView(calendarRef: HTMLElement): CalendarDate | undefined;
186
+ export declare function getFirstNonDisabledDateInView(calendarRef: HTMLElement): DateValue | undefined;
187
187
  /**
188
188
  * Ensures the placeholder is not set to a disabled date,
189
189
  * which would prevent the user from entering the Calendar
@@ -197,4 +197,5 @@ export declare function useEnsureNonDisabledPlaceholder({ ref, placeholder, defa
197
197
  maxValue: ReadableBox<DateValue | undefined>;
198
198
  defaultPlaceholder: DateValue;
199
199
  }): void;
200
+ export declare function getDateWithPreviousTime(date: DateValue | undefined, prev: DateValue | undefined): DateValue | undefined;
200
201
  export {};
@@ -1,7 +1,7 @@
1
- import { CalendarDate, endOfMonth, isSameDay, isSameMonth, parseDate, startOfMonth, } from "@internationalized/date";
1
+ import { endOfMonth, isSameDay, isSameMonth, startOfMonth, } from "@internationalized/date";
2
2
  import { afterTick, styleToString } from "svelte-toolbelt";
3
3
  import { untrack } from "svelte";
4
- import { getDaysInMonth, getLastFirstDayOfWeek, getNextLastDayOfWeek, isAfter, isBefore, parseStringToDateValue, toDate, } from "./utils.js";
4
+ import { getDaysInMonth, getLastFirstDayOfWeek, getNextLastDayOfWeek, hasTime, isAfter, isBefore, parseAnyDateValue, parseStringToDateValue, toDate, } from "./utils.js";
5
5
  import { getDataDisabled, getDataInvalid, getDataReadonly } from "../attrs.js";
6
6
  import { chunk, isValidIndex } from "../arrays.js";
7
7
  import { isBrowser, isHTMLElement } from "../is.js";
@@ -450,10 +450,12 @@ export function getFirstNonDisabledDateInView(calendarRef) {
450
450
  const daysInView = Array.from(calendarRef.querySelectorAll("[data-bits-day]:not([aria-disabled=true])"));
451
451
  if (daysInView.length === 0)
452
452
  return;
453
- const value = daysInView[0]?.getAttribute("data-value");
454
- if (!value)
453
+ const element = daysInView[0];
454
+ const value = element?.getAttribute("data-value");
455
+ const type = element?.getAttribute("data-type");
456
+ if (!value || !type)
455
457
  return;
456
- return parseDate(value);
458
+ return parseAnyDateValue(value, type);
457
459
  }
458
460
  /**
459
461
  * Ensures the placeholder is not set to a disabled date,
@@ -493,3 +495,16 @@ export function useEnsureNonDisabledPlaceholder({ ref, placeholder, defaultPlace
493
495
  }
494
496
  });
495
497
  }
498
+ export function getDateWithPreviousTime(date, prev) {
499
+ if (!date || !prev)
500
+ return date;
501
+ if (hasTime(date) && hasTime(prev)) {
502
+ return date.set({
503
+ hour: prev.hour,
504
+ minute: prev.minute,
505
+ millisecond: prev.millisecond,
506
+ second: prev.second,
507
+ });
508
+ }
509
+ return date;
510
+ }
@@ -29,6 +29,8 @@ export declare function parseStringToDateValue(dateStr: string, referenceVal: Da
29
29
  * If no timezone is provided, the date will be converted to the local timezone.
30
30
  */
31
31
  export declare function toDate(dateValue: DateValue, tz?: string): Date;
32
+ export declare function getDateValueType(date: DateValue): string;
33
+ export declare function parseAnyDateValue(value: string, type: string): DateValue;
32
34
  export declare function isZonedDateTime(dateValue: DateValue): dateValue is ZonedDateTime;
33
35
  export declare function hasTime(dateValue: DateValue): dateValue is CalendarDateTime | ZonedDateTime;
34
36
  /**
@@ -70,6 +70,27 @@ export function toDate(dateValue, tz = getLocalTimeZone()) {
70
70
  return dateValue.toDate(tz);
71
71
  }
72
72
  }
73
+ export function getDateValueType(date) {
74
+ if (date instanceof CalendarDate)
75
+ return "date";
76
+ if (date instanceof CalendarDateTime)
77
+ return "datetime";
78
+ if (date instanceof ZonedDateTime)
79
+ return "zoneddatetime";
80
+ throw new Error("Unknown date type");
81
+ }
82
+ export function parseAnyDateValue(value, type) {
83
+ switch (type) {
84
+ case "date":
85
+ return parseDate(value);
86
+ case "datetime":
87
+ return parseDateTime(value);
88
+ case "zoneddatetime":
89
+ return parseZonedDateTime(value);
90
+ default:
91
+ throw new Error(`Unknown date type: ${type}`);
92
+ }
93
+ }
73
94
  function isCalendarDateTime(dateValue) {
74
95
  return dateValue instanceof CalendarDateTime;
75
96
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "1.3.17",
3
+ "version": "1.3.19",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",