bits-ui 1.3.5 → 1.3.7

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.
@@ -33,7 +33,9 @@ type CalendarRootStateProps = WithRefProps<WritableBoxedValues<{
33
33
  * is selected. It is not intended to be used by the user.
34
34
  */
35
35
  onDateSelect?: () => void;
36
- }>>;
36
+ }> & {
37
+ defaultPlaceholder: DateValue;
38
+ }>;
37
39
  export declare class CalendarRootState {
38
40
  readonly opts: CalendarRootStateProps;
39
41
  months: Month<DateValue>[];
@@ -2,12 +2,12 @@ import { getLocalTimeZone, isSameDay, isSameMonth, isToday, } from "@internation
2
2
  import { DEV } from "esm-env";
3
3
  import { untrack } from "svelte";
4
4
  import { useRefById } from "svelte-toolbelt";
5
- import { Context } from "runed";
5
+ import { Context, watch } from "runed";
6
6
  import { getAriaDisabled, getAriaHidden, getAriaReadonly, getAriaSelected, getDataDisabled, getDataReadonly, getDataSelected, getDataUnavailable, } from "../../internal/attrs.js";
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, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.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
11
  import { isBefore, toDate } from "../../internal/date-time/utils.js";
12
12
  export class CalendarRootState {
13
13
  opts;
@@ -106,22 +106,27 @@ export class CalendarRootState {
106
106
  /**
107
107
  * Synchronize the placeholder value with the current value.
108
108
  */
109
- $effect(() => {
110
- this.opts.value.current;
111
- untrack(() => {
112
- const value = this.opts.value.current;
113
- if (Array.isArray(value) && value.length) {
114
- const lastValue = value[value.length - 1];
115
- if (lastValue && this.opts.placeholder.current !== lastValue) {
116
- this.opts.placeholder.current = lastValue;
117
- }
118
- }
119
- else if (!Array.isArray(value) &&
120
- value &&
121
- this.opts.placeholder.current !== value) {
122
- this.opts.placeholder.current = value;
109
+ watch(() => this.opts.value.current, () => {
110
+ const value = this.opts.value.current;
111
+ if (Array.isArray(value) && value.length) {
112
+ const lastValue = value[value.length - 1];
113
+ if (lastValue && this.opts.placeholder.current !== lastValue) {
114
+ this.opts.placeholder.current = lastValue;
123
115
  }
124
- });
116
+ }
117
+ else if (!Array.isArray(value) &&
118
+ value &&
119
+ this.opts.placeholder.current !== value) {
120
+ this.opts.placeholder.current = value;
121
+ }
122
+ });
123
+ useEnsureNonDisabledPlaceholder({
124
+ placeholder: opts.placeholder,
125
+ defaultPlaceholder: opts.defaultPlaceholder,
126
+ isDateDisabled: opts.isDateDisabled,
127
+ maxValue: opts.maxValue,
128
+ minValue: opts.minValue,
129
+ ref: opts.ref,
125
130
  });
126
131
  }
127
132
  setMonths(months) {
@@ -445,11 +450,11 @@ class CalendarDayState {
445
450
  this.onclick = this.onclick.bind(this);
446
451
  useRefById(opts);
447
452
  }
448
- #tabindex = $derived.by(() => this.cell.isFocusedDate
449
- ? 0
450
- : (this.cell.isOutsideMonth && this.cell.root.opts.disableDaysOutsideMonth.current) ||
451
- this.cell.isDisabled
452
- ? undefined
453
+ #tabindex = $derived.by(() => (this.cell.isOutsideMonth && this.cell.root.opts.disableDaysOutsideMonth.current) ||
454
+ this.cell.isDisabled
455
+ ? undefined
456
+ : this.cell.isFocusedDate
457
+ ? 0
453
458
  : -1);
454
459
  onclick(e) {
455
460
  if (this.cell.isDisabled)
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { box, mergeProps } from "svelte-toolbelt";
3
- import type { DateValue } from "@internationalized/date";
3
+ import { type DateValue } from "@internationalized/date";
4
4
  import { useCalendarRoot } from "../calendar.svelte.js";
5
5
  import type { CalendarRootProps } from "../types.js";
6
6
  import { useId } from "../../../internal/use-id.js";
@@ -36,11 +36,11 @@
36
36
  ...restProps
37
37
  }: CalendarRootProps = $props();
38
38
 
39
+ const defaultPlaceholder = getDefaultDate({
40
+ defaultValue: value,
41
+ });
42
+
39
43
  if (placeholder === undefined) {
40
- const defaultPlaceholder = getDefaultDate({
41
- defaultPlaceholder: undefined,
42
- defaultValue: value,
43
- });
44
44
  placeholder = defaultPlaceholder;
45
45
  }
46
46
 
@@ -88,6 +88,7 @@
88
88
  }
89
89
  ),
90
90
  type: box.with(() => type),
91
+ defaultPlaceholder,
91
92
  });
92
93
 
93
94
  const mergedProps = $derived(mergeProps(restProps, rootState.props));
@@ -30,7 +30,6 @@
30
30
  if (placeholder === undefined) {
31
31
  const defaultPlaceholder = getDefaultDate({
32
32
  granularity,
33
- defaultPlaceholder: undefined,
34
33
  defaultValue: value,
35
34
  });
36
35
 
@@ -41,6 +41,7 @@
41
41
  value: datePickerRootState.opts.value,
42
42
  onDateSelect: datePickerRootState.opts.onDateSelect,
43
43
  initialFocus: datePickerRootState.opts.initialFocus,
44
+ defaultPlaceholder: datePickerRootState.opts.defaultPlaceholder,
44
45
  });
45
46
 
46
47
  const mergedProps = $derived(mergeProps(restProps, calendarState.props));
@@ -45,13 +45,12 @@
45
45
  children,
46
46
  }: DatePickerRootProps = $props();
47
47
 
48
- if (placeholder === undefined) {
49
- const defaultPlaceholder = getDefaultDate({
50
- granularity,
51
- defaultPlaceholder: undefined,
52
- defaultValue: value,
53
- });
48
+ const defaultPlaceholder = getDefaultDate({
49
+ granularity,
50
+ defaultValue: value,
51
+ });
54
52
 
53
+ if (placeholder === undefined) {
55
54
  placeholder = defaultPlaceholder;
56
55
  }
57
56
 
@@ -105,6 +104,7 @@
105
104
  numberOfMonths: box.with(() => numberOfMonths),
106
105
  initialFocus: box.with(() => initialFocus),
107
106
  onDateSelect: box.with(() => onDateSelect),
107
+ defaultPlaceholder,
108
108
  });
109
109
 
110
110
  usePopoverRoot({
@@ -30,7 +30,9 @@ type DatePickerRootStateProps = WritableBoxedValues<{
30
30
  disableDaysOutsideMonth: boolean;
31
31
  initialFocus: boolean;
32
32
  onDateSelect?: () => void;
33
- }>;
33
+ }> & {
34
+ defaultPlaceholder: DateValue;
35
+ };
34
36
  declare class DatePickerRootState {
35
37
  readonly opts: DatePickerRootStateProps;
36
38
  constructor(opts: DatePickerRootStateProps);
@@ -41,7 +41,6 @@
41
41
  if (placeholder === undefined) {
42
42
  const defaultPlaceholder = getDefaultDate({
43
43
  granularity,
44
- defaultPlaceholder: undefined,
45
44
  defaultValue: value?.start,
46
45
  });
47
46
 
@@ -41,6 +41,7 @@
41
41
  onRangeSelect: dateRangePickerRootState.opts.onRangeSelect,
42
42
  startValue: dateRangePickerRootState.opts.startValue,
43
43
  endValue: dateRangePickerRootState.opts.endValue,
44
+ defaultPlaceholder: dateRangePickerRootState.opts.defaultPlaceholder,
44
45
  });
45
46
 
46
47
  const mergedProps = $derived(mergeProps(restProps, rangeCalendarState.props));
@@ -57,14 +57,12 @@
57
57
  if (value === undefined) {
58
58
  value = { start: undefined, end: undefined };
59
59
  }
60
+ const defaultPlaceholder = getDefaultDate({
61
+ granularity,
62
+ defaultValue: value?.start,
63
+ });
60
64
 
61
65
  if (placeholder === undefined) {
62
- const defaultPlaceholder = getDefaultDate({
63
- granularity,
64
- defaultPlaceholder: undefined,
65
- defaultValue: value?.start,
66
- });
67
-
68
66
  placeholder = defaultPlaceholder;
69
67
  }
70
68
 
@@ -131,6 +129,7 @@
131
129
  onEndValueChange(v);
132
130
  }
133
131
  ),
132
+ defaultPlaceholder,
134
133
  });
135
134
 
136
135
  usePopoverRoot({
@@ -31,7 +31,9 @@ type DateRangePickerRootStateProps = WritableBoxedValues<{
31
31
  calendarLabel: string;
32
32
  disableDaysOutsideMonth: boolean;
33
33
  onRangeSelect?: () => void;
34
- }>;
34
+ }> & {
35
+ defaultPlaceholder: DateValue;
36
+ };
35
37
  declare class DateRangePickerRootState {
36
38
  readonly opts: DateRangePickerRootStateProps;
37
39
  constructor(opts: DateRangePickerRootStateProps);
@@ -464,7 +464,8 @@ class MenuSubTriggerState {
464
464
  return;
465
465
  if (!this.item.opts.disabled.current &&
466
466
  !this.submenu.opts.open.current &&
467
- !this.#openTimer) {
467
+ !this.#openTimer &&
468
+ !this.content.parentMenu.root.isPointerInTransit) {
468
469
  this.#openTimer = window.setTimeout(() => {
469
470
  this.submenu.onOpen();
470
471
  this.#clearOpenTimer();
@@ -215,11 +215,6 @@ class MenubarContentState {
215
215
  this.opts.onCloseAutoFocus.current(e);
216
216
  if (e.defaultPrevented)
217
217
  return;
218
- if (!this.root.opts.value.current &&
219
- !this.hasInteractedOutside &&
220
- !this.focusScopeContext.ignoreCloseAutoFocus) {
221
- this.menu.getTriggerNode()?.focus();
222
- }
223
218
  this.hasInteractedOutside = false;
224
219
  e.preventDefault();
225
220
  };
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { box, mergeProps } from "svelte-toolbelt";
3
- import type { DateValue } from "@internationalized/date";
3
+ import { type DateValue } from "@internationalized/date";
4
4
  import type { RangeCalendarRootProps } from "../types.js";
5
5
  import { useRangeCalendarRoot } from "../range-calendar.svelte.js";
6
6
  import { noop } from "../../../internal/noop.js";
@@ -39,11 +39,11 @@
39
39
  let startValue = $state<DateValue | undefined>(value?.start);
40
40
  let endValue = $state<DateValue | undefined>(value?.end);
41
41
 
42
+ const defaultPlaceholder = getDefaultDate({
43
+ defaultValue: value?.start,
44
+ });
45
+
42
46
  if (placeholder === undefined) {
43
- const defaultPlaceholder = getDefaultDate({
44
- defaultPlaceholder: undefined,
45
- defaultValue: value?.start,
46
- });
47
47
  placeholder = defaultPlaceholder;
48
48
  }
49
49
 
@@ -101,6 +101,7 @@
101
101
  onEndValueChange(v);
102
102
  }
103
103
  ),
104
+ defaultPlaceholder,
104
105
  });
105
106
 
106
107
  const mergedProps = $derived(mergeProps(restProps, rootState.props));
@@ -31,7 +31,9 @@ type RangeCalendarRootStateProps = WithRefProps<WritableBoxedValues<{
31
31
  * is selected. It is not intended to be used by the user.
32
32
  */
33
33
  onRangeSelect?: () => void;
34
- }>>;
34
+ }> & {
35
+ defaultPlaceholder: DateValue;
36
+ }>;
35
37
  export declare class RangeCalendarRootState {
36
38
  #private;
37
39
  readonly opts: RangeCalendarRootStateProps;
@@ -6,7 +6,7 @@ import { useId } from "../../internal/use-id.js";
6
6
  import { getAriaDisabled, getAriaSelected, getDataDisabled, getDataSelected, getDataUnavailable, } from "../../internal/attrs.js";
7
7
  import { getAnnouncer } from "../../internal/date-time/announcer.js";
8
8
  import { createFormatter } from "../../internal/date-time/formatter.js";
9
- import { createMonths, getCalendarElementProps, getCalendarHeadingValue, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
9
+ import { createMonths, getCalendarElementProps, getCalendarHeadingValue, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useEnsureNonDisabledPlaceholder, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
10
10
  import { areAllDaysBetweenValid, isAfter, isBefore, isBetweenInclusive, toDate, } from "../../internal/date-time/utils.js";
11
11
  export class RangeCalendarRootState {
12
12
  opts;
@@ -142,6 +142,14 @@ export class RangeCalendarRootState {
142
142
  this.isDateUnavailable = this.isDateUnavailable.bind(this);
143
143
  this.isOutsideVisibleMonths = this.isOutsideVisibleMonths.bind(this);
144
144
  this.isSelected = this.isSelected.bind(this);
145
+ useEnsureNonDisabledPlaceholder({
146
+ placeholder: opts.placeholder,
147
+ defaultPlaceholder: opts.defaultPlaceholder,
148
+ isDateDisabled: opts.isDateDisabled,
149
+ maxValue: opts.maxValue,
150
+ minValue: opts.minValue,
151
+ ref: opts.ref,
152
+ });
145
153
  }
146
154
  #updateValue(cb) {
147
155
  const value = this.opts.value.current;
@@ -481,11 +489,11 @@ class RangeCalendarDayState {
481
489
  this.onmouseenter = this.onmouseenter.bind(this);
482
490
  this.onfocusin = this.onfocusin.bind(this);
483
491
  }
484
- #tabindex = $derived.by(() => this.cell.isFocusedDate
485
- ? 0
486
- : (this.cell.isOutsideMonth && this.cell.root.opts.disableDaysOutsideMonth.current) ||
487
- this.cell.isDisabled
488
- ? undefined
492
+ #tabindex = $derived.by(() => (this.cell.isOutsideMonth && this.cell.root.opts.disableDaysOutsideMonth.current) ||
493
+ this.cell.isDisabled
494
+ ? undefined
495
+ : this.cell.isFocusedDate
496
+ ? 0
489
497
  : -1);
490
498
  onclick(e) {
491
499
  if (this.cell.isDisabled)
@@ -1,7 +1,7 @@
1
- import { type DateValue } from "@internationalized/date";
1
+ import { CalendarDate, type DateValue } from "@internationalized/date";
2
2
  import { type ReadableBox, type WritableBox } from "svelte-toolbelt";
3
3
  import type { Formatter } from "./formatter.js";
4
- import type { Month } from "../../shared/index.js";
4
+ import type { DateMatcher, Month } from "../../shared/index.js";
5
5
  /**
6
6
  * Checks if a given node is a calendar cell element.
7
7
  *
@@ -183,4 +183,18 @@ 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;
187
+ /**
188
+ * Ensures the placeholder is not set to a disabled date,
189
+ * which would prevent the user from entering the Calendar
190
+ * via the keyboard.
191
+ */
192
+ export declare function useEnsureNonDisabledPlaceholder({ ref, placeholder, defaultPlaceholder, minValue, maxValue, isDateDisabled, }: {
193
+ ref: WritableBox<HTMLElement | null>;
194
+ placeholder: WritableBox<DateValue | undefined>;
195
+ isDateDisabled: ReadableBox<DateMatcher>;
196
+ minValue: ReadableBox<DateValue | undefined>;
197
+ maxValue: ReadableBox<DateValue | undefined>;
198
+ defaultPlaceholder: DateValue;
199
+ }): void;
186
200
  export {};
@@ -1,11 +1,12 @@
1
- import { endOfMonth, isSameMonth, startOfMonth } from "@internationalized/date";
1
+ import { CalendarDate, endOfMonth, isSameDay, isSameMonth, parseDate, startOfMonth, } from "@internationalized/date";
2
2
  import { afterTick, styleToString } from "svelte-toolbelt";
3
3
  import { untrack } from "svelte";
4
4
  import { getDaysInMonth, getLastFirstDayOfWeek, getNextLastDayOfWeek, isAfter, isBefore, parseStringToDateValue, toDate, } from "./utils.js";
5
5
  import { getDataDisabled, getDataInvalid, getDataReadonly } from "../attrs.js";
6
6
  import { chunk, isValidIndex } from "../arrays.js";
7
- import { isHTMLElement } from "../is.js";
7
+ import { isBrowser, isHTMLElement } from "../is.js";
8
8
  import { kbd } from "../kbd.js";
9
+ import { watch } from "runed";
9
10
  /**
10
11
  * Checks if a given node is a calendar cell element.
11
12
  *
@@ -443,3 +444,52 @@ export function pickerOpenFocus(e) {
443
444
  nodeToFocus?.focus();
444
445
  }
445
446
  }
447
+ export function getFirstNonDisabledDateInView(calendarRef) {
448
+ if (!isBrowser)
449
+ return;
450
+ const daysInView = Array.from(calendarRef.querySelectorAll("[data-bits-day]:not([aria-disabled=true])"));
451
+ if (daysInView.length === 0)
452
+ return;
453
+ const value = daysInView[0]?.getAttribute("data-value");
454
+ if (!value)
455
+ return;
456
+ return parseDate(value);
457
+ }
458
+ /**
459
+ * Ensures the placeholder is not set to a disabled date,
460
+ * which would prevent the user from entering the Calendar
461
+ * via the keyboard.
462
+ */
463
+ export function useEnsureNonDisabledPlaceholder({ ref, placeholder, defaultPlaceholder, minValue, maxValue, isDateDisabled, }) {
464
+ function isDisabled(date) {
465
+ if (isDateDisabled.current(date))
466
+ return true;
467
+ if (minValue.current && isBefore(date, minValue.current))
468
+ return true;
469
+ if (maxValue.current && isBefore(maxValue.current, date))
470
+ return true;
471
+ return false;
472
+ }
473
+ watch(() => ref.current, () => {
474
+ if (!ref.current)
475
+ return;
476
+ /**
477
+ * If the placeholder is still the default placeholder and it's a disabled date, find
478
+ * the first available date in the calendar view and set it as the placeholder.
479
+ *
480
+ * This prevents the placeholder from being a disabled date and no date being tabbable
481
+ * preventing the user from entering the Calendar. If all dates in the view are
482
+ * disabled, currently that is considered an error on the developer's part and should
483
+ * be handled by them.
484
+ *
485
+ * Perhaps in the future we can introduce a dev-only log message to prevent this from
486
+ * being a silent error.
487
+ */
488
+ if (placeholder.current &&
489
+ isSameDay(placeholder.current, defaultPlaceholder) &&
490
+ isDisabled(defaultPlaceholder)) {
491
+ placeholder.current =
492
+ getFirstNonDisabledDateInView(ref.current) ?? defaultPlaceholder;
493
+ }
494
+ });
495
+ }
@@ -2,7 +2,6 @@ import { CalendarDateTime, type DateValue, ZonedDateTime } from "@internationali
2
2
  import type { DateMatcher, Granularity } from "../../shared/date/types.js";
3
3
  type GetDefaultDateProps = {
4
4
  defaultValue?: DateValue | DateValue[] | undefined;
5
- defaultPlaceholder?: DateValue | undefined;
6
5
  granularity?: Granularity;
7
6
  };
8
7
  /**
@@ -15,7 +14,7 @@ type GetDefaultDateProps = {
15
14
  * behavior the user expects based on the props they've provided.
16
15
  *
17
16
  */
18
- export declare function getDefaultDate(props?: GetDefaultDateProps): DateValue;
17
+ export declare function getDefaultDate(opts: GetDefaultDateProps): DateValue;
19
18
  /**
20
19
  * Given a date string and a reference `DateValue` object, parse the
21
20
  * string to the same type as the reference object.
@@ -1,7 +1,6 @@
1
1
  import { CalendarDate, CalendarDateTime, ZonedDateTime, getDayOfWeek, getLocalTimeZone, parseDate, parseDateTime, parseZonedDateTime, toCalendar, } from "@internationalized/date";
2
2
  const defaultDateDefaults = {
3
3
  defaultValue: undefined,
4
- defaultPlaceholder: undefined,
5
4
  granularity: "day",
6
5
  };
7
6
  /**
@@ -14,18 +13,15 @@ const defaultDateDefaults = {
14
13
  * behavior the user expects based on the props they've provided.
15
14
  *
16
15
  */
17
- export function getDefaultDate(props) {
18
- const withDefaults = { ...defaultDateDefaults, ...props };
19
- const { defaultValue, defaultPlaceholder, granularity } = withDefaults;
16
+ export function getDefaultDate(opts) {
17
+ const withDefaults = { ...defaultDateDefaults, ...opts };
18
+ const { defaultValue, granularity } = withDefaults;
20
19
  if (Array.isArray(defaultValue) && defaultValue.length) {
21
20
  return defaultValue[defaultValue.length - 1];
22
21
  }
23
22
  if (defaultValue && !Array.isArray(defaultValue)) {
24
23
  return defaultValue;
25
24
  }
26
- else if (defaultPlaceholder) {
27
- return defaultPlaceholder;
28
- }
29
25
  else {
30
26
  const date = new Date();
31
27
  const year = date.getFullYear();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",
@@ -27,7 +27,7 @@
27
27
  "jest-axe": "^9.0.0",
28
28
  "jsdom": "^24.1.3",
29
29
  "publint": "^0.2.12",
30
- "svelte": "^5.19.4",
30
+ "svelte": "^5.22.6",
31
31
  "svelte-check": "^4.1.4",
32
32
  "tslib": "^2.8.1",
33
33
  "typescript": "^5.6.3",
@@ -1,11 +0,0 @@
1
- import type { Getter } from "svelte-toolbelt";
2
- /**
3
- * Holds the previous value of a getter, with the initial value being
4
- * the value of the getter when the instance is created, rather than
5
- * `undefined`.
6
- */
7
- export declare class PreviousWithInit<T> {
8
- #private;
9
- constructor(getter: Getter<T>);
10
- get current(): T;
11
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Holds the previous value of a getter, with the initial value being
3
- * the value of the getter when the instance is created, rather than
4
- * `undefined`.
5
- */
6
- export class PreviousWithInit {
7
- #previous = $state(null);
8
- #curr;
9
- constructor(getter) {
10
- const init = getter();
11
- this.#previous = init;
12
- this.#curr = init;
13
- $effect(() => {
14
- this.#previous = this.#curr;
15
- this.#curr = getter();
16
- });
17
- }
18
- get current() {
19
- return this.#previous;
20
- }
21
- }