@servicetitan/anvil2 1.45.1 → 1.46.0

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 (171) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/{Calendar-Dq_of5A3.js → Calendar-BQ5F2ENO.js} +1173 -166
  3. package/dist/Calendar-BQ5F2ENO.js.map +1 -0
  4. package/dist/Calendar.css +83 -47
  5. package/dist/Calendar.js +1 -1
  6. package/dist/{Checkbox-3y2d9mBd.js → Checkbox-DDrmVC-u.js} +2 -2
  7. package/dist/{Checkbox-3y2d9mBd.js.map → Checkbox-DDrmVC-u.js.map} +1 -1
  8. package/dist/{Checkbox-BiOzGpgJ.js → Checkbox-Dl4KTwEJ.js} +3 -3
  9. package/dist/{Checkbox-BiOzGpgJ.js.map → Checkbox-Dl4KTwEJ.js.map} +1 -1
  10. package/dist/Checkbox.js +2 -2
  11. package/dist/{useInfiniteCombobox-BN2uGhBh.js → Combobox-B9nesJuc.js} +19 -186
  12. package/dist/Combobox-B9nesJuc.js.map +1 -0
  13. package/dist/Combobox.js +2 -1
  14. package/dist/Combobox.js.map +1 -1
  15. package/dist/{DateField-B2mnasH5.js → DateField-DXxPsRtf.js} +4 -4
  16. package/dist/{DateField-B2mnasH5.js.map → DateField-DXxPsRtf.js.map} +1 -1
  17. package/dist/DateField.js +1 -1
  18. package/dist/{DateFieldRange-DPbyzuHb.js → DateFieldRange-Xauviu1w.js} +34 -28
  19. package/dist/DateFieldRange-Xauviu1w.js.map +1 -0
  20. package/dist/DateFieldRange.js +1 -1
  21. package/dist/{DateFieldSingle-CfAJDcx9.js → DateFieldSingle-yLnwpVzd.js} +27 -27
  22. package/dist/DateFieldSingle-yLnwpVzd.js.map +1 -0
  23. package/dist/DateFieldSingle.js +1 -1
  24. package/dist/{DateFieldYearless-ydxcsmRV.js → DateFieldYearless-Ba7HiTiI.js} +2 -2
  25. package/dist/{DateFieldYearless-ydxcsmRV.js.map → DateFieldYearless-Ba7HiTiI.js.map} +1 -1
  26. package/dist/DateFieldYearless.js +1 -1
  27. package/dist/{DaysOfTheWeek-BYvE9QK5.js → DaysOfTheWeek-BYSYZySH.js} +2 -2
  28. package/dist/{DaysOfTheWeek-BYvE9QK5.js.map → DaysOfTheWeek-BYSYZySH.js.map} +1 -1
  29. package/dist/DaysOfTheWeek.js +1 -1
  30. package/dist/{Dialog-DpH2Qvbd.js → Dialog-CgkrvrQu.js} +2 -2
  31. package/dist/{Dialog-DpH2Qvbd.js.map → Dialog-CgkrvrQu.js.map} +1 -1
  32. package/dist/Dialog.js +1 -1
  33. package/dist/Dnd.js +1 -1
  34. package/dist/DndSort.js +1 -1
  35. package/dist/{Drawer-DI_k6W2k.js → Drawer-CM4ZbAro.js} +2 -2
  36. package/dist/{Drawer-DI_k6W2k.js.map → Drawer-CM4ZbAro.js.map} +1 -1
  37. package/dist/Drawer.js +1 -1
  38. package/dist/{FieldLabel-BfnCXung.js → FieldLabel-BsbTTyom.js} +3 -14
  39. package/dist/FieldLabel-BsbTTyom.js.map +1 -0
  40. package/dist/FieldLabel.js +1 -1
  41. package/dist/{InputMask-O_qi1p_3.js → InputMask-_F139qFu.js} +2 -2
  42. package/dist/{InputMask-O_qi1p_3.js.map → InputMask-_F139qFu.js.map} +1 -1
  43. package/dist/InputMask.js +1 -1
  44. package/dist/{ListView-jR2ZkBB7.js → ListView-pb3rIcze.js} +2 -2
  45. package/dist/{ListView-jR2ZkBB7.js.map → ListView-pb3rIcze.js.map} +1 -1
  46. package/dist/ListView.js +1 -1
  47. package/dist/{NumberField-1_gRsWT4.js → NumberField-CkZZrkYC.js} +5 -5
  48. package/dist/{NumberField-1_gRsWT4.js.map → NumberField-CkZZrkYC.js.map} +1 -1
  49. package/dist/NumberField.js +1 -1
  50. package/dist/{Page-CY6QRlvb.js → Page-cKXkjMmd.js} +2 -2
  51. package/dist/{Page-CY6QRlvb.js.map → Page-cKXkjMmd.js.map} +1 -1
  52. package/dist/Page.js +1 -1
  53. package/dist/{ProgressBar-BnXuQ6Bx.js → ProgressBar-DXcXZEJ2.js} +2 -2
  54. package/dist/{ProgressBar-BnXuQ6Bx.js.map → ProgressBar-DXcXZEJ2.js.map} +1 -1
  55. package/dist/ProgressBar.js +1 -1
  56. package/dist/{Radio-CwmRUIzo.js → Radio-C89VCMXd.js} +2 -2
  57. package/dist/{Radio-CwmRUIzo.js.map → Radio-C89VCMXd.js.map} +1 -1
  58. package/dist/Radio.js +2 -2
  59. package/dist/{RadioGroup-BNCWIHOG.js → RadioGroup-C_4buUtG.js} +2 -2
  60. package/dist/{RadioGroup-BNCWIHOG.js.map → RadioGroup-C_4buUtG.js.map} +1 -1
  61. package/dist/{SearchField-BKXkoWPs.js → SearchField-Bb0uObwG.js} +2 -2
  62. package/dist/{SearchField-BKXkoWPs.js.map → SearchField-Bb0uObwG.js.map} +1 -1
  63. package/dist/SearchField.js +1 -1
  64. package/dist/{SelectCard-DOGCG0zr.js → SelectCard-BTYZg9TG.js} +3 -3
  65. package/dist/{SelectCard-DOGCG0zr.js.map → SelectCard-BTYZg9TG.js.map} +1 -1
  66. package/dist/SelectCard.js +1 -1
  67. package/dist/{SelectTrigger-BMo0e-F7.js → SelectTrigger-f1hvRrSC.js} +2 -2
  68. package/dist/{SelectTrigger-BMo0e-F7.js.map → SelectTrigger-f1hvRrSC.js.map} +1 -1
  69. package/dist/SelectTrigger.js +1 -1
  70. package/dist/{SelectTriggerBase-BMMxnXrw.js → SelectTriggerBase-DP9fmRSo.js} +2 -2
  71. package/dist/{SelectTriggerBase-BMMxnXrw.js.map → SelectTriggerBase-DP9fmRSo.js.map} +1 -1
  72. package/dist/{TextField-CwgE_JJU.js → TextField-BiHxlzE3.js} +2 -2
  73. package/dist/{TextField-CwgE_JJU.js.map → TextField-BiHxlzE3.js.map} +1 -1
  74. package/dist/{TextField-DlsZEkS0.js → TextField-D8fow9j7.js} +2 -2
  75. package/dist/{TextField-DlsZEkS0.js.map → TextField-D8fow9j7.js.map} +1 -1
  76. package/dist/TextField.js +1 -1
  77. package/dist/{Textarea-DU-SpoDL.js → Textarea-BdVJJlbP.js} +2 -2
  78. package/dist/{Textarea-DU-SpoDL.js.map → Textarea-BdVJJlbP.js.map} +1 -1
  79. package/dist/Textarea.js +1 -1
  80. package/dist/{TimeField-CfhyRfX9.js → TimeField-CmbErrsZ.js} +2 -2
  81. package/dist/{TimeField-CfhyRfX9.js.map → TimeField-CmbErrsZ.js.map} +1 -1
  82. package/dist/TimeField.js +1 -1
  83. package/dist/Toast.js +2 -2
  84. package/dist/{Toaster-BgjT0p8b.js → Toaster-9cpG_tWR.js} +2 -2
  85. package/dist/{Toaster-BgjT0p8b.js.map → Toaster-9cpG_tWR.js.map} +1 -1
  86. package/dist/{Toaster-CfC9wod0.js → Toaster-B7zUwJOt.js} +2 -2
  87. package/dist/{Toaster-CfC9wod0.js.map → Toaster-B7zUwJOt.js.map} +1 -1
  88. package/dist/Toolbar-D4zuUFhb.js +2077 -0
  89. package/dist/Toolbar-D4zuUFhb.js.map +1 -0
  90. package/dist/Toolbar.css +139 -28
  91. package/dist/Toolbar.d.ts +3 -3
  92. package/dist/Toolbar.js +1 -1
  93. package/dist/beta/components/Toolbar/Filters/FilterButton.d.ts +30 -0
  94. package/dist/beta/components/Toolbar/Filters/FilterDateRange.d.ts +37 -0
  95. package/dist/beta/components/Toolbar/Filters/FilterDateSingle.d.ts +30 -0
  96. package/dist/beta/components/Toolbar/Filters/FilterDrawer.d.ts +15 -0
  97. package/dist/beta/components/Toolbar/Filters/FilterGroup.d.ts +25 -0
  98. package/dist/beta/components/Toolbar/Filters/FilterItemWrapper.d.ts +24 -0
  99. package/dist/beta/components/Toolbar/Filters/FilterSelect.d.ts +29 -0
  100. package/dist/beta/components/Toolbar/Filters/FilterToggleButton.d.ts +24 -0
  101. package/dist/beta/components/Toolbar/Filters/internal/FilterGroupContext.d.ts +40 -0
  102. package/dist/beta/components/Toolbar/Filters/internal/types.d.ts +130 -0
  103. package/dist/beta/components/Toolbar/Filters/internal/utils/filter-state.d.ts +40 -0
  104. package/dist/beta/components/Toolbar/Filters/internal/utils/test.d.ts +57 -0
  105. package/dist/beta/components/Toolbar/Toolbar.d.ts +302 -0
  106. package/dist/beta/components/Toolbar/ToolbarButton.d.ts +41 -0
  107. package/dist/beta/components/Toolbar/ToolbarButtonLink.d.ts +43 -0
  108. package/dist/beta/components/Toolbar/ToolbarButtonToggle.d.ts +42 -0
  109. package/dist/beta/components/Toolbar/ToolbarControlGroup.d.ts +20 -0
  110. package/dist/beta/components/Toolbar/ToolbarSearchField.d.ts +20 -0
  111. package/dist/beta/components/Toolbar/ToolbarSelect.d.ts +108 -0
  112. package/dist/beta/components/Toolbar/index.d.ts +9 -0
  113. package/dist/beta/components/Toolbar/internal/ToolbarItemOverflowContext.d.ts +19 -0
  114. package/dist/beta/components/Toolbar/internal/ToolbarItemWrapper.d.ts +40 -0
  115. package/dist/beta/components/Toolbar/internal/ToolbarOverflowContext.d.ts +35 -0
  116. package/dist/beta/components/Toolbar/internal/ToolbarOverflowMenu.d.ts +29 -0
  117. package/dist/beta/components/Toolbar/internal/utils/accessibility.d.ts +26 -0
  118. package/dist/beta/components/Toolbar/internal/utils/test.d.ts +29 -0
  119. package/dist/beta/components/Toolbar/types.d.ts +50 -0
  120. package/dist/beta/components/index.d.ts +1 -0
  121. package/dist/beta/index.d.ts +1 -0
  122. package/dist/beta.d.ts +2 -0
  123. package/dist/beta.js +2 -0
  124. package/dist/beta.js.map +1 -0
  125. package/dist/components/Combobox/ComboboxTypes.d.ts +8 -0
  126. package/dist/components/DateFieldRange/DateFieldRange.d.ts +2 -2
  127. package/dist/components/DateFieldRange/internal/DateFieldRangeCalendar.d.ts +1 -1
  128. package/dist/components/DateFieldRange/internal/useDateFieldRangeState.d.ts +2 -7
  129. package/dist/components/DateFieldSingle/DateFieldSingle.d.ts +2 -2
  130. package/dist/components/DateFieldSingle/internal/useDateFieldSingleState.d.ts +2 -7
  131. package/dist/components/Dialog/index.d.ts +1 -1
  132. package/dist/components/NumberField/NumberField.d.ts +4 -4
  133. package/dist/{indeterminate_check_box-Bg24oeHy.js → indeterminate_check_box-RY9zr3xS.js} +17 -17
  134. package/dist/{indeterminate_check_box-Bg24oeHy.js.map → indeterminate_check_box-RY9zr3xS.js.map} +1 -1
  135. package/dist/indeterminate_check_box.css +72 -66
  136. package/dist/{index-CqdP5W00.js → index-V5Ez2gq_.js} +2 -2
  137. package/dist/{index-CqdP5W00.js.map → index-V5Ez2gq_.js.map} +1 -1
  138. package/dist/index.css +125 -26
  139. package/dist/index.js +773 -41
  140. package/dist/index.js.map +1 -1
  141. package/dist/index2.css +88 -105
  142. package/dist/internal/components/YearSelector/YearSelector.d.ts +67 -0
  143. package/dist/internal/components/YearSelector/index.d.ts +1 -0
  144. package/dist/internal/components/YearSelector/internal/YearItem.d.ts +10 -0
  145. package/dist/internal/components/YearSelector/internal/useYearSelectorKeys.d.ts +19 -0
  146. package/dist/internal/hooks/index.d.ts +1 -0
  147. package/dist/internal/hooks/useContainerQuery/index.d.ts +1 -0
  148. package/dist/internal/hooks/useContainerQuery/useContainerQuery.d.ts +46 -0
  149. package/dist/internal/hooks/useFocusWithin/useFocusWithin.d.ts +11 -16
  150. package/dist/types/PassThroughProps.d.ts +4 -0
  151. package/dist/types/index.d.ts +1 -0
  152. package/dist/{useDateFieldOrchestration-Cqa7dxtr.js → useDateFieldOrchestration-BNJCsRkS.js} +2 -2
  153. package/dist/{useDateFieldOrchestration-Cqa7dxtr.js.map → useDateFieldOrchestration-BNJCsRkS.js.map} +1 -1
  154. package/dist/useFocusWithin-BhhgRXdZ.js +32 -0
  155. package/dist/useFocusWithin-BhhgRXdZ.js.map +1 -0
  156. package/dist/useInfiniteCombobox-WcRgC9p6.js +179 -0
  157. package/dist/useInfiniteCombobox-WcRgC9p6.js.map +1 -0
  158. package/dist/useIntersectionObserver-BEmMDO3P.js +70 -0
  159. package/dist/useIntersectionObserver-BEmMDO3P.js.map +1 -0
  160. package/package.json +3 -1
  161. package/dist/Calendar-Dq_of5A3.js.map +0 -1
  162. package/dist/DateFieldRange-DPbyzuHb.js.map +0 -1
  163. package/dist/DateFieldSingle-CfAJDcx9.js.map +0 -1
  164. package/dist/FieldLabel-BfnCXung.js.map +0 -1
  165. package/dist/Toolbar-DK7tXy_W.js +0 -807
  166. package/dist/Toolbar-DK7tXy_W.js.map +0 -1
  167. package/dist/components/Calendar/internal/CalendarYearSelection.d.ts +0 -25
  168. package/dist/useFocusWithin-BhU7hoAD.js +0 -56
  169. package/dist/useFocusWithin-BhU7hoAD.js.map +0 -1
  170. package/dist/useInfiniteCombobox-BN2uGhBh.js.map +0 -1
  171. /package/dist/{useInfiniteCombobox.css → Combobox.css} +0 -0
@@ -0,0 +1,67 @@
1
+ import { PassThroughProps } from '../../../types';
2
+ export interface YearSelectorProps {
3
+ /**
4
+ * The minimum selectable year
5
+ * Defaults to 1900.
6
+ */
7
+ min?: number;
8
+ /**
9
+ * The maximum selectable year.
10
+ * Defaults to 2200.
11
+ */
12
+ max?: number;
13
+ /**
14
+ * The currently selected year
15
+ */
16
+ value?: number | null;
17
+ /**
18
+ * The default value of the selected year
19
+ */
20
+ defaultValue?: number;
21
+ /**
22
+ * The function to call when the selected year changes
23
+ *
24
+ * @param year - The year that is selected.
25
+ */
26
+ onChange?: (year: number | null) => void;
27
+ /**
28
+ * The function to call when the selected year is affirmatively changed.
29
+ * This is called when the user confirms the selection by pressing Enter, pressing Space, or clicking.
30
+ *
31
+ * @param year - The year that is selected.
32
+ */
33
+ onConfirm?: (year: number | null) => void;
34
+ /**
35
+ * If a `value` or `defaultValue` is not provided, this will be used as the starting scroll position (and initial focus for accessibility).
36
+ */
37
+ startingYear?: number;
38
+ /**
39
+ * The number of columns to display.
40
+ * @default 2
41
+ */
42
+ columns?: number;
43
+ /**
44
+ * The class name to apply to the component.
45
+ */
46
+ className?: string;
47
+ /**
48
+ * Controls whether a year can be deselected, i.e. set to null.
49
+ * @default false
50
+ */
51
+ required?: boolean;
52
+ /**
53
+ * Controls whether the component allows the user to select a year.
54
+ * @default false
55
+ */
56
+ disabled?: boolean;
57
+ /**
58
+ * The aria-label for the component.
59
+ * @default "Year selection"
60
+ */
61
+ ariaLabel?: string;
62
+ /**
63
+ * Props forwarded onto the root element of the component.
64
+ */
65
+ rootProps?: PassThroughProps<"div">;
66
+ }
67
+ export declare const YearSelector: import('react').ForwardRefExoticComponent<YearSelectorProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ export { YearSelector, type YearSelectorProps } from './YearSelector';
@@ -0,0 +1,10 @@
1
+ import { ComponentPropsWithoutRef } from 'react';
2
+ type YearItemProps = Omit<ComponentPropsWithoutRef<"div">, "onChange"> & {
3
+ year: number;
4
+ onChange: (year: number) => void;
5
+ selected: boolean;
6
+ pseudoFocused: boolean;
7
+ disabled: boolean;
8
+ };
9
+ export declare const YearItem: ({ year, onChange, selected, pseudoFocused, disabled, onFocus, ...rest }: YearItemProps) => import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,19 @@
1
+ export type UseYearSelectorKeysParams = {
2
+ columns: number;
3
+ scrollToYear: (year: number, { focus }: {
4
+ focus?: boolean;
5
+ }) => void;
6
+ initialFocus: number;
7
+ onSelect: (year: number | null) => void;
8
+ onConfirm: () => void;
9
+ min: number;
10
+ max: number;
11
+ disabled: boolean;
12
+ pseudoFocused: number;
13
+ setPseudoFocused: (year: number) => void;
14
+ required: boolean;
15
+ };
16
+ export type UseYearSelectorKeysReturn = {
17
+ listRef: React.RefObject<HTMLDivElement>;
18
+ };
19
+ export declare const useYearSelectorKeys: ({ columns, scrollToYear, initialFocus, onSelect, onConfirm, pseudoFocused, setPseudoFocused, min, max, disabled, required, }: UseYearSelectorKeysParams) => UseYearSelectorKeysReturn;
@@ -14,4 +14,5 @@ export * from './usePopoverCloseDelayWorkaround';
14
14
  export * from './usePopoverSupport';
15
15
  export * from './usePopoverTransitionStates';
16
16
  export * from './usePrevious';
17
+ export * from './useContainerQuery';
17
18
  export * from './useTypeAhead';
@@ -0,0 +1 @@
1
+ export { useContainerQuery, type ContainerQueryReturnProps, } from './useContainerQuery';
@@ -0,0 +1,46 @@
1
+ import { RefObject } from 'react';
2
+ /**
3
+ * Return type for the useContainerQuery hook
4
+ */
5
+ export type ContainerQueryReturnProps = {
6
+ /**
7
+ * The breakpoint name
8
+ */
9
+ name: "xs" | "sm" | "md" | "lg" | "xl" | "xxl";
10
+ /**
11
+ * Minimum width for this breakpoint
12
+ */
13
+ min: number | undefined;
14
+ /**
15
+ * Maximum width for this breakpoint
16
+ */
17
+ max: number | undefined;
18
+ /**
19
+ * Current container width
20
+ */
21
+ containerWidth: number;
22
+ /**
23
+ * Current container height
24
+ */
25
+ containerHeight: number;
26
+ };
27
+ /**
28
+ * Custom hook for detecting current breakpoint based on container dimensions.
29
+ *
30
+ * Features:
31
+ * - Detects current breakpoint based on container width instead of viewport width
32
+ * - Supports all standard breakpoints (xs, sm, md, lg, xl, xxl)
33
+ * - Provides container dimensions information
34
+ * - Uses hammer-token breakpoint values for consistency
35
+ * - Listens for container resize events using ResizeObserver
36
+ * - Supports optional disable functionality
37
+ * - Uses container element dimensions for accurate measurements
38
+ *
39
+ * @param containerRef - React ref to the container element to observe
40
+ * @param props - Optional configuration object
41
+ * @param props.disable - Whether to disable the hook
42
+ * @returns Current breakpoint information or undefined if disabled
43
+ */
44
+ export declare const useContainerQuery: (containerRef: RefObject<HTMLElement>, props?: {
45
+ disable?: boolean;
46
+ }) => ContainerQueryReturnProps | undefined;
@@ -1,33 +1,28 @@
1
+ import { FocusEventHandler } from 'react';
1
2
  export interface UseFocusWithinOptions {
2
- onFocus?: (event: FocusEvent) => void;
3
- onBlur?: (event: FocusEvent) => void;
3
+ onFocus?: (event: React.FocusEvent) => void;
4
+ onBlur?: (event: React.FocusEvent) => void;
4
5
  }
5
- export interface UseFocusWithinReturnValue<T extends HTMLElement = any> {
6
- ref: React.RefObject<T>;
7
- focused: boolean;
6
+ export interface UseFocusWithinReturnValue<T extends HTMLElement = HTMLElement> {
7
+ props: {
8
+ onFocus: FocusEventHandler<T>;
9
+ onBlur: FocusEventHandler<T>;
10
+ };
8
11
  }
9
12
  /**
10
13
  * Custom hook for tracking focus state within a DOM element.
11
14
  *
12
- * Features:
13
- * - Tracks whether any child element has focus
14
- * - Provides a ref object to attach to the target element
15
- * - Handles focus events with proper cleanup
16
- * - Supports custom onFocus and onBlur callbacks
17
- * - Prevents false blur events when focus moves between children
18
- * - Automatically cleans up event listeners on unmount
19
- *
20
15
  * @param options Configuration options for the hook
21
16
  * @param options.onFocus Optional callback when focus enters the element
22
17
  * @param options.onBlur Optional callback when focus leaves the element
23
- * @returns Object containing ref and focused state
18
+ * @returns Object containing props for the element
24
19
  *
25
20
  * @example
26
- * const { ref, focused } = useFocusWithin({
21
+ * const { props } = useFocusWithin({
27
22
  * onFocus: () => console.log('Focus entered'),
28
23
  * onBlur: () => console.log('Focus left')
29
24
  * });
30
25
  *
31
- * return <div ref={ref} className={focused ? 'focused' : ''}>Content</div>;
26
+ * return <div {...props}>Content</div>;
32
27
  */
33
28
  export declare function useFocusWithin<T extends HTMLElement = any>({ onBlur, onFocus, }?: UseFocusWithinOptions): UseFocusWithinReturnValue<T>;
@@ -0,0 +1,4 @@
1
+ import { ComponentPropsWithoutRef, ComponentPropsWithRef } from 'react';
2
+ export type DataAttributes = Record<`data-${string}`, string>;
3
+ export type PassThroughProps<T extends keyof JSX.IntrinsicElements> = ComponentPropsWithoutRef<T> & DataAttributes;
4
+ export type PassThroughPropsWithRef<T extends keyof JSX.IntrinsicElements> = ComponentPropsWithRef<T> & DataAttributes;
@@ -4,3 +4,4 @@ export { type MaxLengthCounterProps } from './MaxLengthCounterProps';
4
4
  export * from './ianaZones';
5
5
  export * from './locales';
6
6
  export * from './props';
7
+ export * from './PassThroughProps';
@@ -1,4 +1,4 @@
1
- import { D as DateTime } from './Calendar-Dq_of5A3.js';
1
+ import { D as DateTime } from './Calendar-BQ5F2ENO.js';
2
2
  import { useRef, useState } from 'react';
3
3
  import { a as useKeyboardFocusables } from './useOnClickOutside-BHEWMLa9.js';
4
4
 
@@ -135,4 +135,4 @@ const useDateFieldOrchestration = ({
135
135
  };
136
136
 
137
137
  export { DateModeToPlaceholderMap as D, DateModeToFormatMap as a, convertStringToDate as c, useDateFieldOrchestration as u, validateDate as v };
138
- //# sourceMappingURL=useDateFieldOrchestration-Cqa7dxtr.js.map
138
+ //# sourceMappingURL=useDateFieldOrchestration-BNJCsRkS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDateFieldOrchestration-Cqa7dxtr.js","sources":["../src/components/DateFieldSingle/internal/constants.ts","../src/components/DateFieldSingle/internal/utils.ts","../src/components/DateFieldSingle/internal/useDateFieldOrchestration.ts"],"sourcesContent":["import { DateMode } from \"../types\";\n\nexport const DateModeToFormatMap: Record<DateMode, string> = {\n \"mm/dd/yyyy\": \"MM/dd/yyyy\",\n \"dd/mm/yyyy\": \"dd/MM/yyyy\",\n \"yyyy/mm/dd\": \"yyyy/MM/dd\",\n};\n\nexport const DateModeToPlaceholderMap: Record<DateMode, string> = {\n \"dd/mm/yyyy\": \"__/__/____\",\n \"mm/dd/yyyy\": \"__/__/____\",\n \"yyyy/mm/dd\": \"____/__/__\",\n};\n","import { DateTime } from \"luxon\";\n\nexport function convertStringToDate(\n v: string | null | undefined,\n): DateTime | null | undefined {\n if (v === undefined || v === null) {\n return v;\n }\n const date = DateTime.fromISO(v, { setZone: true, zone: \"utc\" }).startOf(\n \"day\",\n );\n if (date.isValid) {\n return date;\n }\n return null;\n}\nexport function validateDate({\n date,\n constraints,\n}: {\n date: DateTime | null;\n constraints: {\n required?: boolean;\n unavailable?: {\n dates?: DateTime[];\n daysOfWeek?: number[];\n };\n minDate?: DateTime;\n maxDate?: DateTime;\n };\n}) {\n const { required, unavailable, minDate, maxDate } = constraints;\n if (!date) {\n return required ? false : true;\n }\n if (unavailable?.dates?.some((d) => d.equals(date))) {\n return false;\n }\n if (unavailable?.daysOfWeek?.includes(date.weekday)) {\n return false;\n }\n if (minDate && date < minDate) {\n return false;\n }\n if (maxDate && date > maxDate) {\n return false;\n }\n return true;\n}\n","import { KeyboardEventHandler, RefObject, useRef, useState } from \"react\";\nimport { useKeyboardFocusables } from \"../../../internal/hooks\";\n\n/**\n * Responsible for orchestrating the input and calendar popover states\n * @param inputRef - The ref to the input element\n * @returns calendarOpen, setCalendarOpen, handleCalendarKeyDown, handleInputKeyDown\n */\nexport const useDateFieldOrchestration = ({\n inputRef,\n calendarDefaultOpen,\n popoverContentRef,\n disableCalendar = false,\n}: {\n inputRef: RefObject<HTMLInputElement>;\n calendarDefaultOpen: boolean;\n popoverContentRef: RefObject<HTMLDivElement>;\n disableCalendar?: boolean;\n}) => {\n const documentRef = useRef<HTMLElement>(document.body);\n const [calendarOpen, setCalendarOpen] = useState(calendarDefaultOpen);\n\n const { focusables } = useKeyboardFocusables(documentRef, {\n observeChange: true,\n });\n\n const { focusables: popoverFocusables } = useKeyboardFocusables(\n popoverContentRef,\n {\n observeChange: true,\n },\n );\n\n const pageFocusables = focusables?.filter(\n (item) => !popoverFocusables?.includes(item),\n );\n\n const handleCalendarKeyDown = (\n event: React.KeyboardEvent<HTMLDivElement>,\n ) => {\n if (event.key === \"Escape\") {\n inputRef.current?.focus();\n }\n };\n\n const focusToCalendar = () => {\n if (popoverContentRef.current) {\n const currentFocusable =\n popoverContentRef.current.querySelectorAll('[tabindex = \"0\"]')[0];\n if (currentFocusable) {\n (currentFocusable as HTMLButtonElement).focus();\n }\n }\n };\n\n const handleInputKeyDown: KeyboardEventHandler<HTMLInputElement> = (ev) => {\n if (disableCalendar) {\n return;\n }\n let currentFocusIndex = 0;\n switch (ev.key) {\n case \"Escape\":\n setCalendarOpen(false);\n break;\n case \"Tab\":\n if (!calendarOpen || !pageFocusables?.length) {\n break;\n }\n ev.preventDefault();\n currentFocusIndex = pageFocusables.indexOf(inputRef.current!) || 0;\n setCalendarOpen(false);\n if (ev.shiftKey) {\n if (currentFocusIndex === 0) {\n requestAnimationFrame(() =>\n pageFocusables[pageFocusables.length - 1].focus(),\n );\n } else {\n requestAnimationFrame(() =>\n pageFocusables[currentFocusIndex - 1].focus(),\n );\n }\n break;\n }\n if (pageFocusables.length > currentFocusIndex + 1) {\n requestAnimationFrame(() =>\n pageFocusables[currentFocusIndex + 1].focus(),\n );\n } else {\n requestAnimationFrame(() => pageFocusables[0].focus());\n }\n break;\n case \"ArrowDown\":\n if (!calendarOpen) {\n setCalendarOpen(true);\n setTimeout(focusToCalendar, 200);\n } else {\n focusToCalendar();\n }\n }\n };\n\n return {\n calendarOpen,\n setCalendarOpen,\n handleCalendarKeyDown,\n handleInputKeyDown,\n };\n};\n"],"names":[],"mappings":";;;;AAEO,MAAM,mBAAgD,GAAA;AAAA,EAC3D,YAAc,EAAA,YAAA;AAAA,EACd,YAAc,EAAA,YAAA;AAAA,EACd,YAAc,EAAA;AAChB;AAEO,MAAM,wBAAqD,GAAA;AAAA,EAChE,YAAc,EAAA,YAAA;AAAA,EACd,YAAc,EAAA,YAAA;AAAA,EACd,YAAc,EAAA;AAChB;;ACVO,SAAS,oBACd,CAC6B,EAAA;AAC7B,EAAI,IAAA,CAAA,KAAM,MAAa,IAAA,CAAA,KAAM,IAAM,EAAA;AACjC,IAAO,OAAA,CAAA;AAAA;AAET,EAAM,MAAA,IAAA,GAAO,QAAS,CAAA,OAAA,CAAQ,CAAG,EAAA,EAAE,SAAS,IAAM,EAAA,IAAA,EAAM,KAAM,EAAC,CAAE,CAAA,OAAA;AAAA,IAC/D;AAAA,GACF;AACA,EAAA,IAAI,KAAK,OAAS,EAAA;AAChB,IAAO,OAAA,IAAA;AAAA;AAET,EAAO,OAAA,IAAA;AACT;AACO,SAAS,YAAa,CAAA;AAAA,EAC3B,IAAA;AAAA,EACA;AACF,CAWG,EAAA;AACD,EAAA,MAAM,EAAE,QAAA,EAAU,WAAa,EAAA,OAAA,EAAS,SAAY,GAAA,WAAA;AACpD,EAAA,IAAI,CAAC,IAAM,EAAA;AACT,IAAA,OAAO,WAAW,KAAQ,GAAA,IAAA;AAAA;AAE5B,EAAI,IAAA,WAAA,EAAa,OAAO,IAAK,CAAA,CAAC,MAAM,CAAE,CAAA,MAAA,CAAO,IAAI,CAAC,CAAG,EAAA;AACnD,IAAO,OAAA,KAAA;AAAA;AAET,EAAA,IAAI,WAAa,EAAA,UAAA,EAAY,QAAS,CAAA,IAAA,CAAK,OAAO,CAAG,EAAA;AACnD,IAAO,OAAA,KAAA;AAAA;AAET,EAAI,IAAA,OAAA,IAAW,OAAO,OAAS,EAAA;AAC7B,IAAO,OAAA,KAAA;AAAA;AAET,EAAI,IAAA,OAAA,IAAW,OAAO,OAAS,EAAA;AAC7B,IAAO,OAAA,KAAA;AAAA;AAET,EAAO,OAAA,IAAA;AACT;;ACxCO,MAAM,4BAA4B,CAAC;AAAA,EACxC,QAAA;AAAA,EACA,mBAAA;AAAA,EACA,iBAAA;AAAA,EACA,eAAkB,GAAA;AACpB,CAKM,KAAA;AACJ,EAAM,MAAA,WAAA,GAAc,MAAoB,CAAA,QAAA,CAAS,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,mBAAmB,CAAA;AAEpE,EAAA,MAAM,EAAE,UAAA,EAAe,GAAA,qBAAA,CAAsB,WAAa,EAAA;AAAA,IACxD,aAAe,EAAA;AAAA,GAChB,CAAA;AAED,EAAM,MAAA,EAAE,UAAY,EAAA,iBAAA,EAAsB,GAAA,qBAAA;AAAA,IACxC,iBAAA;AAAA,IACA;AAAA,MACE,aAAe,EAAA;AAAA;AACjB,GACF;AAEA,EAAA,MAAM,iBAAiB,UAAY,EAAA,MAAA;AAAA,IACjC,CAAC,IAAA,KAAS,CAAC,iBAAA,EAAmB,SAAS,IAAI;AAAA,GAC7C;AAEA,EAAM,MAAA,qBAAA,GAAwB,CAC5B,KACG,KAAA;AACH,IAAI,IAAA,KAAA,CAAM,QAAQ,QAAU,EAAA;AAC1B,MAAA,QAAA,CAAS,SAAS,KAAM,EAAA;AAAA;AAC1B,GACF;AAEA,EAAA,MAAM,kBAAkB,MAAM;AAC5B,IAAA,IAAI,kBAAkB,OAAS,EAAA;AAC7B,MAAA,MAAM,mBACJ,iBAAkB,CAAA,OAAA,CAAQ,gBAAiB,CAAA,kBAAkB,EAAE,CAAC,CAAA;AAClE,MAAA,IAAI,gBAAkB,EAAA;AACpB,QAAC,iBAAuC,KAAM,EAAA;AAAA;AAChD;AACF,GACF;AAEA,EAAM,MAAA,kBAAA,GAA6D,CAAC,EAAO,KAAA;AACzE,IAAA,IAAI,eAAiB,EAAA;AACnB,MAAA;AAAA;AAEF,IAAA,IAAI,iBAAoB,GAAA,CAAA;AACxB,IAAA,QAAQ,GAAG,GAAK;AAAA,MACd,KAAK,QAAA;AACH,QAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,QAAA;AAAA,MACF,KAAK,KAAA;AACH,QAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,cAAA,EAAgB,MAAQ,EAAA;AAC5C,UAAA;AAAA;AAEF,QAAA,EAAA,CAAG,cAAe,EAAA;AAClB,QAAA,iBAAA,GAAoB,cAAe,CAAA,OAAA,CAAQ,QAAS,CAAA,OAAQ,CAAK,IAAA,CAAA;AACjE,QAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,QAAA,IAAI,GAAG,QAAU,EAAA;AACf,UAAA,IAAI,sBAAsB,CAAG,EAAA;AAC3B,YAAA,qBAAA;AAAA,cAAsB,MACpB,cAAe,CAAA,cAAA,CAAe,MAAS,GAAA,CAAC,EAAE,KAAM;AAAA,aAClD;AAAA,WACK,MAAA;AACL,YAAA,qBAAA;AAAA,cAAsB,MACpB,cAAA,CAAe,iBAAoB,GAAA,CAAC,EAAE,KAAM;AAAA,aAC9C;AAAA;AAEF,UAAA;AAAA;AAEF,QAAI,IAAA,cAAA,CAAe,MAAS,GAAA,iBAAA,GAAoB,CAAG,EAAA;AACjD,UAAA,qBAAA;AAAA,YAAsB,MACpB,cAAA,CAAe,iBAAoB,GAAA,CAAC,EAAE,KAAM;AAAA,WAC9C;AAAA,SACK,MAAA;AACL,UAAA,qBAAA,CAAsB,MAAM,cAAA,CAAe,CAAC,CAAA,CAAE,OAAO,CAAA;AAAA;AAEvD,QAAA;AAAA,MACF,KAAK,WAAA;AACH,QAAA,IAAI,CAAC,YAAc,EAAA;AACjB,UAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,UAAA,UAAA,CAAW,iBAAiB,GAAG,CAAA;AAAA,SAC1B,MAAA;AACL,UAAgB,eAAA,EAAA;AAAA;AAClB;AACJ,GACF;AAEA,EAAO,OAAA;AAAA,IACL,YAAA;AAAA,IACA,eAAA;AAAA,IACA,qBAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"useDateFieldOrchestration-BNJCsRkS.js","sources":["../src/components/DateFieldSingle/internal/constants.ts","../src/components/DateFieldSingle/internal/utils.ts","../src/components/DateFieldSingle/internal/useDateFieldOrchestration.ts"],"sourcesContent":["import { DateMode } from \"../types\";\n\nexport const DateModeToFormatMap: Record<DateMode, string> = {\n \"mm/dd/yyyy\": \"MM/dd/yyyy\",\n \"dd/mm/yyyy\": \"dd/MM/yyyy\",\n \"yyyy/mm/dd\": \"yyyy/MM/dd\",\n};\n\nexport const DateModeToPlaceholderMap: Record<DateMode, string> = {\n \"dd/mm/yyyy\": \"__/__/____\",\n \"mm/dd/yyyy\": \"__/__/____\",\n \"yyyy/mm/dd\": \"____/__/__\",\n};\n","import { DateTime } from \"luxon\";\n\nexport function convertStringToDate(\n v: string | null | undefined,\n): DateTime | null | undefined {\n if (v === undefined || v === null) {\n return v;\n }\n const date = DateTime.fromISO(v, { setZone: true, zone: \"utc\" }).startOf(\n \"day\",\n );\n if (date.isValid) {\n return date;\n }\n return null;\n}\nexport function validateDate({\n date,\n constraints,\n}: {\n date: DateTime | null;\n constraints: {\n required?: boolean;\n unavailable?: {\n dates?: DateTime[];\n daysOfWeek?: number[];\n };\n minDate?: DateTime;\n maxDate?: DateTime;\n };\n}) {\n const { required, unavailable, minDate, maxDate } = constraints;\n if (!date) {\n return required ? false : true;\n }\n if (unavailable?.dates?.some((d) => d.equals(date))) {\n return false;\n }\n if (unavailable?.daysOfWeek?.includes(date.weekday)) {\n return false;\n }\n if (minDate && date < minDate) {\n return false;\n }\n if (maxDate && date > maxDate) {\n return false;\n }\n return true;\n}\n","import { KeyboardEventHandler, RefObject, useRef, useState } from \"react\";\nimport { useKeyboardFocusables } from \"../../../internal/hooks\";\n\n/**\n * Responsible for orchestrating the input and calendar popover states\n * @param inputRef - The ref to the input element\n * @returns calendarOpen, setCalendarOpen, handleCalendarKeyDown, handleInputKeyDown\n */\nexport const useDateFieldOrchestration = ({\n inputRef,\n calendarDefaultOpen,\n popoverContentRef,\n disableCalendar = false,\n}: {\n inputRef: RefObject<HTMLInputElement>;\n calendarDefaultOpen: boolean;\n popoverContentRef: RefObject<HTMLDivElement>;\n disableCalendar?: boolean;\n}) => {\n const documentRef = useRef<HTMLElement>(document.body);\n const [calendarOpen, setCalendarOpen] = useState(calendarDefaultOpen);\n\n const { focusables } = useKeyboardFocusables(documentRef, {\n observeChange: true,\n });\n\n const { focusables: popoverFocusables } = useKeyboardFocusables(\n popoverContentRef,\n {\n observeChange: true,\n },\n );\n\n const pageFocusables = focusables?.filter(\n (item) => !popoverFocusables?.includes(item),\n );\n\n const handleCalendarKeyDown = (\n event: React.KeyboardEvent<HTMLDivElement>,\n ) => {\n if (event.key === \"Escape\") {\n inputRef.current?.focus();\n }\n };\n\n const focusToCalendar = () => {\n if (popoverContentRef.current) {\n const currentFocusable =\n popoverContentRef.current.querySelectorAll('[tabindex = \"0\"]')[0];\n if (currentFocusable) {\n (currentFocusable as HTMLButtonElement).focus();\n }\n }\n };\n\n const handleInputKeyDown: KeyboardEventHandler<HTMLInputElement> = (ev) => {\n if (disableCalendar) {\n return;\n }\n let currentFocusIndex = 0;\n switch (ev.key) {\n case \"Escape\":\n setCalendarOpen(false);\n break;\n case \"Tab\":\n if (!calendarOpen || !pageFocusables?.length) {\n break;\n }\n ev.preventDefault();\n currentFocusIndex = pageFocusables.indexOf(inputRef.current!) || 0;\n setCalendarOpen(false);\n if (ev.shiftKey) {\n if (currentFocusIndex === 0) {\n requestAnimationFrame(() =>\n pageFocusables[pageFocusables.length - 1].focus(),\n );\n } else {\n requestAnimationFrame(() =>\n pageFocusables[currentFocusIndex - 1].focus(),\n );\n }\n break;\n }\n if (pageFocusables.length > currentFocusIndex + 1) {\n requestAnimationFrame(() =>\n pageFocusables[currentFocusIndex + 1].focus(),\n );\n } else {\n requestAnimationFrame(() => pageFocusables[0].focus());\n }\n break;\n case \"ArrowDown\":\n if (!calendarOpen) {\n setCalendarOpen(true);\n setTimeout(focusToCalendar, 200);\n } else {\n focusToCalendar();\n }\n }\n };\n\n return {\n calendarOpen,\n setCalendarOpen,\n handleCalendarKeyDown,\n handleInputKeyDown,\n };\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { useRef } from 'react';
2
+
3
+ function useFocusWithin({
4
+ onBlur,
5
+ onFocus
6
+ } = {}) {
7
+ const isFocusedRef = useRef(false);
8
+ const handleFocus = (event) => {
9
+ if (!isFocusedRef.current) {
10
+ isFocusedRef.current = true;
11
+ onFocus?.(event);
12
+ }
13
+ };
14
+ const handleBlur = (event) => {
15
+ if (isFocusedRef.current && !containsRelatedTarget(event)) {
16
+ isFocusedRef.current = false;
17
+ onBlur?.(event);
18
+ }
19
+ };
20
+ return {
21
+ props: { onFocus: handleFocus, onBlur: handleBlur }
22
+ };
23
+ }
24
+ function containsRelatedTarget(event) {
25
+ if (event.currentTarget instanceof HTMLElement && event.relatedTarget instanceof HTMLElement) {
26
+ return event.currentTarget.contains(event.relatedTarget);
27
+ }
28
+ return false;
29
+ }
30
+
31
+ export { useFocusWithin as u };
32
+ //# sourceMappingURL=useFocusWithin-BhhgRXdZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocusWithin-BhhgRXdZ.js","sources":["../src/internal/hooks/useFocusWithin/useFocusWithin.ts"],"sourcesContent":["import { FocusEventHandler, useRef } from \"react\";\nexport interface UseFocusWithinOptions {\n onFocus?: (event: React.FocusEvent) => void;\n onBlur?: (event: React.FocusEvent) => void;\n}\n\nexport interface UseFocusWithinReturnValue<\n T extends HTMLElement = HTMLElement,\n> {\n props: {\n onFocus: FocusEventHandler<T>;\n onBlur: FocusEventHandler<T>;\n };\n}\n\n/**\n * Custom hook for tracking focus state within a DOM element.\n *\n * @param options Configuration options for the hook\n * @param options.onFocus Optional callback when focus enters the element\n * @param options.onBlur Optional callback when focus leaves the element\n * @returns Object containing props for the element\n *\n * @example\n * const { props } = useFocusWithin({\n * onFocus: () => console.log('Focus entered'),\n * onBlur: () => console.log('Focus left')\n * });\n *\n * return <div {...props}>Content</div>;\n */\nexport function useFocusWithin<T extends HTMLElement = any>({\n onBlur,\n onFocus,\n}: UseFocusWithinOptions = {}): UseFocusWithinReturnValue<T> {\n const isFocusedRef = useRef(false);\n\n const handleFocus: FocusEventHandler<T> = (event) => {\n if (!isFocusedRef.current) {\n isFocusedRef.current = true;\n onFocus?.(event);\n }\n };\n\n const handleBlur: FocusEventHandler<T> = (event) => {\n if (isFocusedRef.current && !containsRelatedTarget(event)) {\n isFocusedRef.current = false;\n onBlur?.(event);\n }\n };\n\n return {\n props: { onFocus: handleFocus, onBlur: handleBlur },\n };\n}\n\nfunction containsRelatedTarget(event: React.FocusEvent) {\n if (\n event.currentTarget instanceof HTMLElement &&\n event.relatedTarget instanceof HTMLElement\n ) {\n return event.currentTarget.contains(event.relatedTarget);\n }\n\n return false;\n}\n"],"names":[],"mappings":";;AA+BO,SAAS,cAA4C,CAAA;AAAA,EAC1D,MAAA;AAAA,EACA;AACF,CAAA,GAA2B,EAAkC,EAAA;AAC3D,EAAM,MAAA,YAAA,GAAe,OAAO,KAAK,CAAA;AAEjC,EAAM,MAAA,WAAA,GAAoC,CAAC,KAAU,KAAA;AACnD,IAAI,IAAA,CAAC,aAAa,OAAS,EAAA;AACzB,MAAA,YAAA,CAAa,OAAU,GAAA,IAAA;AACvB,MAAA,OAAA,GAAU,KAAK,CAAA;AAAA;AACjB,GACF;AAEA,EAAM,MAAA,UAAA,GAAmC,CAAC,KAAU,KAAA;AAClD,IAAA,IAAI,YAAa,CAAA,OAAA,IAAW,CAAC,qBAAA,CAAsB,KAAK,CAAG,EAAA;AACzD,MAAA,YAAA,CAAa,OAAU,GAAA,KAAA;AACvB,MAAA,MAAA,GAAS,KAAK,CAAA;AAAA;AAChB,GACF;AAEA,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,EAAE,OAAS,EAAA,WAAA,EAAa,QAAQ,UAAW;AAAA,GACpD;AACF;AAEA,SAAS,sBAAsB,KAAyB,EAAA;AACtD,EAAA,IACE,KAAM,CAAA,aAAA,YAAyB,WAC/B,IAAA,KAAA,CAAM,yBAAyB,WAC/B,EAAA;AACA,IAAA,OAAO,KAAM,CAAA,aAAA,CAAc,QAAS,CAAA,KAAA,CAAM,aAAa,CAAA;AAAA;AAGzD,EAAO,OAAA,KAAA;AACT;;;;"}
@@ -0,0 +1,179 @@
1
+ import { useState, useDeferredValue, useRef, useEffect, useLayoutEffect, useCallback } from 'react';
2
+
3
+ const SCROLL_THRESHOLD = 0.64;
4
+ function useInfiniteCombobox({
5
+ query,
6
+ queryInitialItems,
7
+ initialItems = [],
8
+ initialPage = 0,
9
+ initialLoading = false,
10
+ initialInputValue,
11
+ defaultInputValue,
12
+ initialSelectedItem,
13
+ defaultSelectedItem,
14
+ initialSelectedItems,
15
+ defaultSelectedItems,
16
+ updateOnInputValueChange = true,
17
+ updateOnSelectedItemChange = true,
18
+ updateOnSelectedItemsChange = true,
19
+ queryOnFirstRender = false,
20
+ shouldTriggerQuery: shouldTriggerQueryProp
21
+ }) {
22
+ const [items, setItems] = useState(initialItems);
23
+ const deferredItems = useDeferredValue(items);
24
+ const [page, setPage] = useState(initialPage);
25
+ const [loading, setLoading] = useState(initialLoading);
26
+ const deferredLoading = useDeferredValue(loading);
27
+ const [inputValue, setInputValue] = useState(
28
+ initialInputValue ?? defaultInputValue ?? ""
29
+ );
30
+ const [selectedItem, setSelectedItem] = useState(
31
+ initialSelectedItem ?? defaultSelectedItem ?? null
32
+ );
33
+ const [selectedItems, setSelectedItems] = useState(
34
+ initialSelectedItems ?? defaultSelectedItems ?? []
35
+ );
36
+ const scrollerRef = useRef(null);
37
+ const defaultShouldTriggerQuery = (element) => {
38
+ const totalScrollHeight = element.scrollHeight - element.clientHeight;
39
+ return element.scrollTop / totalScrollHeight > SCROLL_THRESHOLD;
40
+ };
41
+ const [triggerQueryCount, setTriggerQueryCount] = useState(0);
42
+ const triggerQueryCountRef = useRef(0);
43
+ const triggerQuery = () => {
44
+ setTriggerQueryCount((x) => x + 1);
45
+ triggerQueryCountRef.current += 1;
46
+ };
47
+ const [done, setDone] = useState(false);
48
+ const firstRenderRef = useRef(true);
49
+ const scrollTimeoutRef = useRef(false);
50
+ const loadingRef = useRef(false);
51
+ const setLoadingStateAndRef = (isLoading) => {
52
+ setLoading(isLoading);
53
+ loadingRef.current = isLoading;
54
+ };
55
+ const queryRetryCountRef = useRef(0);
56
+ useEffect(() => {
57
+ if (firstRenderRef.current && queryInitialItems) {
58
+ setItems(queryInitialItems());
59
+ }
60
+ if (firstRenderRef.current && !queryOnFirstRender) {
61
+ firstRenderRef.current = false;
62
+ return;
63
+ }
64
+ setLoadingStateAndRef(true);
65
+ const timeoutID = setTimeout(() => {
66
+ if (triggerQueryCount < triggerQueryCountRef.current) return;
67
+ query({
68
+ page,
69
+ inputValue,
70
+ selectedItem,
71
+ selectedItems
72
+ }).then((res) => {
73
+ queryRetryCountRef.current = 0;
74
+ if (triggerQueryCount < triggerQueryCountRef.current) return;
75
+ setLoadingStateAndRef(false);
76
+ setPage((x) => x + 1);
77
+ if (res == null || page > 0 && res.length === 0) {
78
+ setDone(true);
79
+ } else if (page === 0) {
80
+ setItems(() => [...res]);
81
+ } else {
82
+ setItems((prevItems) => [...prevItems, ...res]);
83
+ }
84
+ }).catch(() => {
85
+ queryRetryCountRef.current += 1;
86
+ if (queryRetryCountRef.current > 7) {
87
+ queryRetryCountRef.current = 0;
88
+ return;
89
+ } else {
90
+ setTimeout(
91
+ () => {
92
+ triggerQuery();
93
+ },
94
+ 2 ** queryRetryCountRef.current * 160
95
+ );
96
+ }
97
+ });
98
+ }, 160);
99
+ return () => {
100
+ clearTimeout(timeoutID);
101
+ };
102
+ }, [triggerQueryCount]);
103
+ useLayoutEffect(() => {
104
+ setTimeout(() => {
105
+ if (scrollerRef.current && scrollerRef.current.scrollHeight > 0 && scrollerRef.current.clientHeight > 0 && scrollerRef.current.scrollHeight <= scrollerRef.current.clientHeight) {
106
+ triggerQuery();
107
+ }
108
+ }, 160);
109
+ }, [items]);
110
+ const isEmpty = items.length === 0 && page === 0;
111
+ const onStateChange = useCallback(
112
+ (changes) => {
113
+ if (isEmpty && "isOpen" in changes && changes.isOpen === true) {
114
+ triggerQuery();
115
+ }
116
+ const inputValueShouldUpdate = updateOnInputValueChange && "inputValue" in changes;
117
+ const selectedItemsShouldUpdate = updateOnSelectedItemsChange && "selectedItems" in changes && changes.selectedItems;
118
+ const selectedItemShouldUpdate = updateOnSelectedItemChange && "selectedItem" in changes && changes.selectedItem !== void 0;
119
+ if (inputValueShouldUpdate) {
120
+ setInputValue(changes.inputValue ?? "");
121
+ }
122
+ if (selectedItemsShouldUpdate) {
123
+ setSelectedItems(changes.selectedItems ?? []);
124
+ }
125
+ if (selectedItemShouldUpdate) {
126
+ setSelectedItem(changes.selectedItem);
127
+ }
128
+ if (inputValueShouldUpdate || selectedItemsShouldUpdate || selectedItemShouldUpdate) {
129
+ setPage(0);
130
+ setDone(false);
131
+ triggerQuery();
132
+ }
133
+ },
134
+ [
135
+ isEmpty,
136
+ updateOnInputValueChange,
137
+ updateOnSelectedItemsChange,
138
+ updateOnSelectedItemChange
139
+ ]
140
+ );
141
+ const onScroll = useCallback(
142
+ (e) => {
143
+ const element = e.currentTarget;
144
+ if (!scrollTimeoutRef.current && !loadingRef.current) {
145
+ setTimeout(() => {
146
+ const shouldTriggerQuery = shouldTriggerQueryProp ?? defaultShouldTriggerQuery;
147
+ if (shouldTriggerQuery(element) && !done) {
148
+ triggerQuery();
149
+ }
150
+ scrollTimeoutRef.current = false;
151
+ }, 40);
152
+ scrollTimeoutRef.current = true;
153
+ }
154
+ },
155
+ [done, shouldTriggerQueryProp]
156
+ );
157
+ return {
158
+ comboboxProps: {
159
+ items: deferredItems,
160
+ loading: deferredLoading,
161
+ initialInputValue,
162
+ defaultInputValue,
163
+ initialSelectedItem,
164
+ defaultSelectedItem,
165
+ initialSelectedItems,
166
+ defaultSelectedItems,
167
+ disableFilter: true,
168
+ // assume the query will return a filtered/sorted list
169
+ onStateChange
170
+ },
171
+ contentProps: {
172
+ onScroll,
173
+ scrollerRef
174
+ }
175
+ };
176
+ }
177
+
178
+ export { useInfiniteCombobox as u };
179
+ //# sourceMappingURL=useInfiniteCombobox-WcRgC9p6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInfiniteCombobox-WcRgC9p6.js","sources":["../src/components/Combobox/useInfiniteCombobox.ts"],"sourcesContent":["import {\n useState,\n useEffect,\n useLayoutEffect,\n useRef,\n useDeferredValue,\n type UIEvent,\n useCallback,\n} from \"react\";\nimport { UseInfiniteComboboxProps, type ComboboxProps } from \"./ComboboxTypes\";\n\nconst SCROLL_THRESHOLD = 0.64; // arbitrary number\n\n/**\n * Hook for implementing infinite scroll functionality in combobox components.\n *\n * Features:\n * - Automatic pagination with scroll-based loading\n * - Configurable query triggers (input change, selection change, scroll)\n * - Debounced query execution to prevent excessive API calls\n * - Automatic retry logic with exponential backoff\n * - Support for both single and multiple selection modes\n * - Customizable scroll threshold for triggering new queries\n * - Loading state management with deferred updates\n * - Automatic detection of pagination end\n * - Support for initial items or query-based initialization\n *\n * @param options Configuration options for the infinite combobox\n * @returns Object containing comboboxProps and contentProps for use with Combobox component\n *\n * @example\n * const { comboboxProps, contentProps } = useInfiniteCombobox({\n * initialItems: [],\n * initialPage: 0,\n * initialLoading: true,\n * query: async ({ page, inputValue, selectedItems }) => {\n * return await fetchItems({\n * page,\n * pageSize: 25,\n * searchTerm: inputValue,\n * excludeIds: selectedItems.map(item => item.id),\n * });\n * },\n * });\n *\n * return (\n * <Combobox {...comboboxProps}>\n * <Combobox.SearchField label=\"Search items\" />\n * <Combobox.Content {...contentProps}>\n * {({ items }) => (\n * <Combobox.List>\n * {items.map((item, i) => (\n * <Combobox.Item key={item.id} item={item} index={i}>\n * {item.name}\n * </Combobox.Item>\n * ))}\n * </Combobox.List>\n * )}\n * </Combobox.Content>\n * </Combobox>\n * );\n */\nexport function useInfiniteCombobox<Item = any>({\n query,\n queryInitialItems,\n initialItems = [],\n initialPage = 0,\n initialLoading = false,\n initialInputValue,\n defaultInputValue,\n initialSelectedItem,\n defaultSelectedItem,\n initialSelectedItems,\n defaultSelectedItems,\n updateOnInputValueChange = true,\n updateOnSelectedItemChange = true,\n updateOnSelectedItemsChange = true,\n queryOnFirstRender = false,\n shouldTriggerQuery: shouldTriggerQueryProp,\n}: UseInfiniteComboboxProps<Item>) {\n const [items, setItems] = useState(initialItems);\n const deferredItems = useDeferredValue(items);\n const [page, setPage] = useState(initialPage);\n const [loading, setLoading] = useState(initialLoading);\n const deferredLoading = useDeferredValue(loading);\n const [inputValue, setInputValue] = useState(\n initialInputValue ?? defaultInputValue ?? \"\",\n );\n const [selectedItem, setSelectedItem] = useState<Item | null>(\n initialSelectedItem ?? defaultSelectedItem ?? null,\n );\n const [selectedItems, setSelectedItems] = useState<Item[]>(\n initialSelectedItems ?? defaultSelectedItems ?? [],\n );\n\n const scrollerRef = useRef<HTMLDivElement>(null);\n\n const defaultShouldTriggerQuery = (element: EventTarget & HTMLElement) => {\n const totalScrollHeight = element.scrollHeight - element.clientHeight;\n return element.scrollTop / totalScrollHeight > SCROLL_THRESHOLD;\n };\n\n // using both state and ref here since the state will be \"behind\" the ref\n // if another query has been triggered while the current one is in flight\n const [triggerQueryCount, setTriggerQueryCount] = useState(0);\n const triggerQueryCountRef = useRef(0);\n const triggerQuery = () => {\n setTriggerQueryCount((x) => x + 1);\n triggerQueryCountRef.current += 1;\n };\n\n const [done, setDone] = useState(false);\n\n const firstRenderRef = useRef(true);\n const scrollTimeoutRef = useRef(false);\n\n // using a similar state/ref idea for managing loading as well, since we\n // need to know immediately if queries are in flight, but state won't be\n // updated in the onScroll handler fast enough\n const loadingRef = useRef(false);\n const setLoadingStateAndRef = (isLoading: boolean) => {\n setLoading(isLoading);\n loadingRef.current = isLoading;\n };\n\n const queryRetryCountRef = useRef(0);\n\n useEffect(() => {\n if (firstRenderRef.current && queryInitialItems) {\n setItems(queryInitialItems());\n }\n\n // don't run on initial render unless we explicitly choose to\n if (firstRenderRef.current && !queryOnFirstRender) {\n firstRenderRef.current = false;\n return;\n }\n\n setLoadingStateAndRef(true);\n\n // using a short debounce delay to batch updates\n const timeoutID = setTimeout(() => {\n // if this query is outdated, don't call it\n if (triggerQueryCount < triggerQueryCountRef.current) return;\n\n query({\n page,\n inputValue,\n selectedItem,\n selectedItems,\n })\n .then((res) => {\n queryRetryCountRef.current = 0;\n\n // if this query is outdated, throw away it's results\n if (triggerQueryCount < triggerQueryCountRef.current) return;\n\n setLoadingStateAndRef(false);\n setPage((x) => x + 1);\n\n // if the result is nullish or empty\n // assume we've reached the end of the pagination\n if (res == null || (page > 0 && res.length === 0)) {\n setDone(true);\n } else if (page === 0) {\n setItems(() => [...res]);\n } else {\n setItems((prevItems) => [...prevItems, ...res]);\n }\n })\n .catch(() => {\n // if we fail, retry up to 8 times with exponential back-off\n queryRetryCountRef.current += 1;\n\n if (queryRetryCountRef.current > 7) {\n queryRetryCountRef.current = 0;\n return;\n } else {\n setTimeout(\n () => {\n triggerQuery();\n },\n 2 ** queryRetryCountRef.current * 160,\n );\n }\n });\n }, 160);\n\n return () => {\n clearTimeout(timeoutID);\n };\n\n // only re-query when we manually call triggerQuery\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [triggerQueryCount]);\n\n // if the popover isn't scrollable, keep firing more queries\n useLayoutEffect(() => {\n setTimeout(() => {\n if (\n scrollerRef.current &&\n scrollerRef.current.scrollHeight > 0 &&\n scrollerRef.current.clientHeight > 0 &&\n scrollerRef.current.scrollHeight <= scrollerRef.current.clientHeight\n ) {\n triggerQuery();\n }\n }, 160);\n }, [items]);\n\n // making this separate variable to satisfy react hooks deps linter\n const isEmpty = items.length === 0 && page === 0;\n\n const onStateChange = useCallback(\n (changes: Parameters<NonNullable<ComboboxProps[\"onStateChange\"]>>[0]) => {\n // if the user interacts and we're empty, fire the first query\n if (isEmpty && \"isOpen\" in changes && changes.isOpen === true) {\n triggerQuery();\n }\n\n // otherwise, if inputValue or selectedItems changes, assume we need an\n // entirely new list back from the query\n const inputValueShouldUpdate =\n updateOnInputValueChange && \"inputValue\" in changes;\n const selectedItemsShouldUpdate =\n updateOnSelectedItemsChange &&\n \"selectedItems\" in changes &&\n changes.selectedItems;\n const selectedItemShouldUpdate =\n updateOnSelectedItemChange &&\n \"selectedItem\" in changes &&\n changes.selectedItem !== undefined;\n\n if (inputValueShouldUpdate) {\n setInputValue(changes.inputValue ?? \"\");\n }\n\n if (selectedItemsShouldUpdate) {\n setSelectedItems(changes.selectedItems ?? []);\n }\n\n if (selectedItemShouldUpdate) {\n setSelectedItem(changes.selectedItem);\n }\n\n if (\n inputValueShouldUpdate ||\n selectedItemsShouldUpdate ||\n selectedItemShouldUpdate\n ) {\n setPage(0);\n setDone(false);\n triggerQuery();\n }\n },\n [\n isEmpty,\n updateOnInputValueChange,\n updateOnSelectedItemsChange,\n updateOnSelectedItemChange,\n ],\n );\n\n const onScroll = useCallback(\n (e: UIEvent<HTMLElement>) => {\n // React events don't persist, so we need to store the element through the timeout\n const element = e.currentTarget;\n\n // using timeoutRef to throttle scroll calls\n // using loadingRef to not make additional queries if a query is already in flight\n if (!scrollTimeoutRef.current && !loadingRef.current) {\n setTimeout(() => {\n const shouldTriggerQuery =\n shouldTriggerQueryProp ?? defaultShouldTriggerQuery;\n\n if (shouldTriggerQuery(element) && !done) {\n triggerQuery();\n }\n\n scrollTimeoutRef.current = false;\n }, 40);\n\n scrollTimeoutRef.current = true;\n }\n },\n [done, shouldTriggerQueryProp],\n );\n\n return {\n comboboxProps: {\n items: deferredItems,\n loading: deferredLoading,\n initialInputValue,\n defaultInputValue,\n initialSelectedItem,\n defaultSelectedItem,\n initialSelectedItems,\n defaultSelectedItems,\n disableFilter: true, // assume the query will return a filtered/sorted list\n onStateChange,\n },\n contentProps: {\n onScroll,\n scrollerRef,\n },\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { useState, useRef, useEffect } from 'react';
2
+
3
+ function useIntersectionObserver({
4
+ threshold = 0,
5
+ root = null,
6
+ rootMargin = "0%",
7
+ freezeOnceVisible = false,
8
+ initialIsIntersecting = false,
9
+ onChange
10
+ } = {}) {
11
+ const [ref, setRef] = useState(null);
12
+ const [state, setState] = useState(() => ({
13
+ isIntersecting: initialIsIntersecting,
14
+ entry: void 0
15
+ }));
16
+ const callbackRef = useRef();
17
+ callbackRef.current = onChange;
18
+ const frozen = state.entry?.isIntersecting && freezeOnceVisible;
19
+ useEffect(() => {
20
+ if (!ref) return;
21
+ if (!("IntersectionObserver" in window)) return;
22
+ if (frozen) return;
23
+ const observer = new IntersectionObserver(
24
+ (entries) => {
25
+ const thresholds = Array.isArray(observer.thresholds) ? observer.thresholds : [observer.thresholds];
26
+ entries.forEach((entry) => {
27
+ const isIntersecting = entry.isIntersecting && thresholds.some(
28
+ (threshold2) => entry.intersectionRatio >= threshold2
29
+ );
30
+ setState({ isIntersecting, entry });
31
+ if (callbackRef.current) {
32
+ callbackRef.current(isIntersecting, entry);
33
+ }
34
+ });
35
+ },
36
+ { threshold, root, rootMargin }
37
+ );
38
+ observer.observe(ref);
39
+ return () => {
40
+ observer.disconnect();
41
+ };
42
+ }, [
43
+ ref,
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ JSON.stringify(threshold),
46
+ root,
47
+ rootMargin,
48
+ frozen,
49
+ freezeOnceVisible
50
+ ]);
51
+ const prevRef = useRef(null);
52
+ useEffect(() => {
53
+ if (!ref && state.entry?.target && !freezeOnceVisible && !frozen && prevRef.current !== state.entry.target) {
54
+ prevRef.current = state.entry.target;
55
+ setState({ isIntersecting: initialIsIntersecting, entry: void 0 });
56
+ }
57
+ }, [ref, state.entry, freezeOnceVisible, frozen, initialIsIntersecting]);
58
+ const result = [
59
+ setRef,
60
+ !!state.isIntersecting,
61
+ state.entry
62
+ ];
63
+ result.ref = result[0];
64
+ result.isIntersecting = result[1];
65
+ result.entry = result[2];
66
+ return result;
67
+ }
68
+
69
+ export { useIntersectionObserver as u };
70
+ //# sourceMappingURL=useIntersectionObserver-BEmMDO3P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useIntersectionObserver-BEmMDO3P.js","sources":["../src/internal/hooks/useIntersectionObserver/useIntersectionObserver.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Internal state type for intersection observer\n * @property {boolean} isIntersecting - Whether the element is intersecting\n * @property {IntersectionObserverEntry} [entry] - The intersection observer entry\n */\ntype State = {\n /**\n * Whether the element is intersecting\n */\n isIntersecting: boolean;\n /**\n * The intersection observer entry\n */\n entry?: IntersectionObserverEntry;\n};\n\n/**\n * Options for the useIntersectionObserver hook\n * @property {Element | Document | null} [root] - The root element for intersection calculations\n * @property {string} [rootMargin] - Margin around the root element\n * @property {number | number[]} [threshold] - Threshold values for intersection detection\n * @property {boolean} [freezeOnceVisible] - Whether to freeze once the element becomes visible\n * @property {(isIntersecting: boolean, entry: IntersectionObserverEntry) => void} [onChange] - Callback when intersection changes\n * @property {boolean} [initialIsIntersecting] - Initial intersection state\n */\nexport type UseIntersectionObserverOptions = {\n /**\n * The root element for intersection calculations\n */\n root?: Element | Document | null;\n /**\n * Margin around the root element\n */\n rootMargin?: string;\n /**\n * Threshold values for intersection detection\n */\n threshold?: number | number[];\n /**\n * Whether to freeze once the element becomes visible\n */\n freezeOnceVisible?: boolean;\n /**\n * Callback when intersection changes\n */\n onChange?: (\n isIntersecting: boolean,\n entry: IntersectionObserverEntry,\n ) => void;\n /**\n * Initial intersection state\n */\n initialIsIntersecting?: boolean;\n};\n\n/**\n * Return type for the useIntersectionObserver hook\n * @property {(node?: Element | null) => void} ref - Function to set the element to observe\n * @property {boolean} isIntersecting - Whether the element is intersecting\n * @property {IntersectionObserverEntry} [entry] - The intersection observer entry\n */\nexport type IntersectionReturn = [\n (node?: Element | null) => void,\n boolean,\n IntersectionObserverEntry | undefined,\n] & {\n ref: (node?: Element | null) => void;\n isIntersecting: boolean;\n entry?: IntersectionObserverEntry;\n};\n\n/**\n * Custom hook for observing element intersection with viewport or root element.\n *\n * Features:\n * - Observes element intersection with viewport or custom root element\n * - Supports configurable threshold values and root margins\n * - Provides intersection state and detailed entry information\n * - Supports freezing observation once element becomes visible\n * - Handles browser compatibility gracefully\n * - Provides both array and object destructuring support\n * - Automatically cleans up observer on unmount\n * - Supports onChange callback for custom intersection handling\n *\n * @param options - Configuration options for the intersection observer\n * @returns Array containing ref function, intersection state, and entry, with additional object properties\n */\nexport function useIntersectionObserver({\n threshold = 0,\n root = null,\n rootMargin = \"0%\",\n freezeOnceVisible = false,\n initialIsIntersecting = false,\n onChange,\n}: UseIntersectionObserverOptions = {}): IntersectionReturn {\n const [ref, setRef] = useState<Element | null>(null);\n\n const [state, setState] = useState<State>(() => ({\n isIntersecting: initialIsIntersecting,\n entry: undefined,\n }));\n\n const callbackRef = useRef<UseIntersectionObserverOptions[\"onChange\"]>();\n\n callbackRef.current = onChange;\n\n const frozen = state.entry?.isIntersecting && freezeOnceVisible;\n\n useEffect(() => {\n // Ensure we have a ref to observe\n if (!ref) return;\n\n // Ensure the browser supports the Intersection Observer API\n if (!(\"IntersectionObserver\" in window)) return;\n\n // Skip if frozen\n if (frozen) return;\n\n let unobserve: (() => void) | undefined;\n\n const observer = new IntersectionObserver(\n (entries: IntersectionObserverEntry[]): void => {\n const thresholds = Array.isArray(observer.thresholds)\n ? observer.thresholds\n : [observer.thresholds];\n\n entries.forEach((entry) => {\n const isIntersecting =\n entry.isIntersecting &&\n thresholds.some(\n (threshold) => entry.intersectionRatio >= threshold,\n );\n\n setState({ isIntersecting, entry });\n\n if (callbackRef.current) {\n callbackRef.current(isIntersecting, entry);\n }\n\n if (isIntersecting && freezeOnceVisible && unobserve) {\n unobserve();\n unobserve = undefined;\n }\n });\n },\n { threshold, root, rootMargin },\n );\n\n observer.observe(ref);\n\n return () => {\n observer.disconnect();\n };\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n ref,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(threshold),\n root,\n rootMargin,\n frozen,\n freezeOnceVisible,\n ]);\n\n // ensures that if the observed element changes, the intersection observer is reinitialized\n const prevRef = useRef<Element | null>(null);\n\n useEffect(() => {\n if (\n !ref &&\n state.entry?.target &&\n !freezeOnceVisible &&\n !frozen &&\n prevRef.current !== state.entry.target\n ) {\n prevRef.current = state.entry.target;\n setState({ isIntersecting: initialIsIntersecting, entry: undefined });\n }\n }, [ref, state.entry, freezeOnceVisible, frozen, initialIsIntersecting]);\n\n const result = [\n setRef,\n !!state.isIntersecting,\n state.entry,\n ] as IntersectionReturn;\n\n // Support object destructuring, by adding the specific values.\n result.ref = result[0];\n result.isIntersecting = result[1];\n result.entry = result[2];\n\n return result;\n}\n"],"names":["threshold"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/anvil2",
3
- "version": "1.45.1",
3
+ "version": "1.46.0",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",
@@ -15,6 +15,7 @@
15
15
  ],
16
16
  "exports": {
17
17
  ".": "./dist/index.js",
18
+ "./beta": "./dist/beta.js",
18
19
  "./assets/*": "./dist/assets/*",
19
20
  "./token": "./dist/token.js",
20
21
  "./token/*": "./dist/token/*",
@@ -32,6 +33,7 @@
32
33
  "@react-hook/merged-ref": "^1.3.2",
33
34
  "@react-hook/resize-observer": "^2.0.1",
34
35
  "@servicetitan/anvil-fonts": ">=14",
36
+ "@tanstack/react-virtual": "^3.13.12",
35
37
  "@types/big.js": "^6.2.2",
36
38
  "big.js": "^7.0.1",
37
39
  "classnames": "^2.5.1",