@shipfox/react-ui 0.22.0 → 0.23.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 (54) hide show
  1. package/dist/components/dashboard/context/dashboard-context.d.ts +12 -8
  2. package/dist/components/dashboard/context/dashboard-context.js +42 -7
  3. package/dist/components/dashboard/context/index.d.ts +2 -2
  4. package/dist/components/dashboard/context/index.js +1 -1
  5. package/dist/components/dashboard/context/types.d.ts +9 -7
  6. package/dist/components/dashboard/index.d.ts +2 -4
  7. package/dist/components/dashboard/index.js +1 -2
  8. package/dist/components/dashboard/pages/analytics-page.js +2 -9
  9. package/dist/components/dashboard/pages/jobs-page.js +2 -4
  10. package/dist/components/dashboard/toolbar/filter-button.d.ts +6 -10
  11. package/dist/components/dashboard/toolbar/filter-button.js +109 -76
  12. package/dist/components/dashboard/toolbar/page-toolbar.d.ts +7 -19
  13. package/dist/components/dashboard/toolbar/page-toolbar.js +11 -99
  14. package/dist/components/dashboard/toolbar/toolbar-actions.js +3 -3
  15. package/dist/components/index.d.ts +1 -0
  16. package/dist/components/index.js +1 -0
  17. package/dist/components/interval-selector/hooks/index.d.ts +4 -0
  18. package/dist/components/interval-selector/hooks/index.js +5 -0
  19. package/dist/components/interval-selector/hooks/use-interval-selector-input.d.ts +30 -0
  20. package/dist/components/interval-selector/hooks/use-interval-selector-input.js +125 -0
  21. package/dist/components/interval-selector/hooks/use-interval-selector-navigation.d.ts +21 -0
  22. package/dist/components/interval-selector/hooks/use-interval-selector-navigation.js +58 -0
  23. package/dist/components/interval-selector/hooks/use-interval-selector.d.ts +25 -0
  24. package/dist/components/interval-selector/hooks/use-interval-selector.js +75 -0
  25. package/dist/components/interval-selector/index.d.ts +3 -0
  26. package/dist/components/interval-selector/index.js +4 -0
  27. package/dist/components/interval-selector/interval-selector-calendar.d.ts +7 -0
  28. package/dist/components/interval-selector/interval-selector-calendar.js +47 -0
  29. package/dist/components/interval-selector/interval-selector-input.d.ts +8 -0
  30. package/dist/components/interval-selector/interval-selector-input.js +34 -0
  31. package/dist/components/interval-selector/interval-selector-suggestions.d.ts +11 -0
  32. package/dist/components/interval-selector/interval-selector-suggestions.js +107 -0
  33. package/dist/components/interval-selector/interval-selector.d.ts +12 -0
  34. package/dist/components/interval-selector/interval-selector.js +56 -0
  35. package/dist/components/interval-selector/interval-selector.stories.js +232 -0
  36. package/dist/components/interval-selector/types.d.ts +19 -0
  37. package/dist/components/interval-selector/types.js +3 -0
  38. package/dist/components/interval-selector/utils/constants.d.ts +24 -0
  39. package/dist/components/interval-selector/utils/constants.js +129 -0
  40. package/dist/components/interval-selector/utils/format.d.ts +16 -0
  41. package/dist/components/interval-selector/utils/format.js +23 -0
  42. package/dist/components/interval-selector/utils/index.d.ts +3 -0
  43. package/dist/components/interval-selector/utils/index.js +4 -0
  44. package/dist/components/popover/popover.d.ts +3 -1
  45. package/dist/components/popover/popover.js +2 -1
  46. package/dist/styles.css +1 -1
  47. package/dist/utils/date.js +130 -22
  48. package/dist/utils/format/date.d.ts +1 -0
  49. package/dist/utils/format/date.js +11 -4
  50. package/package.json +3 -2
  51. package/dist/components/dashboard/filters/expression-filter-bar.d.ts +0 -42
  52. package/dist/components/dashboard/filters/expression-filter-bar.js +0 -80
  53. package/dist/components/dashboard/filters/index.d.ts +0 -6
  54. package/dist/components/dashboard/filters/index.js +0 -5
@@ -7,26 +7,26 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  */ import { Button } from '../../../components/button/index.js';
8
8
  import { ButtonGroup, ButtonGroupSeparator } from '../../../components/button-group/index.js';
9
9
  import { Icon } from '../../../components/icon/index.js';
10
- import { Kbd } from '../../../components/kbd/index.js';
11
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../components/select/index.js';
10
+ import { IntervalSelector } from '../../../components/interval-selector/index.js';
12
11
  import { Header, Text } from '../../../components/typography/index.js';
13
12
  import { cn } from '../../../utils/cn.js';
13
+ import { useDashboardContext } from '../context/index.js';
14
14
  /**
15
15
  * Generic Page Toolbar
16
16
  *
17
17
  * A flexible toolbar component that can be used across different dashboard pages.
18
- * Supports title customization, time period selection, refresh indicator, and playback controls.
18
+ * Supports title customization, time interval selection, refresh indicator, and playback controls.
19
+ * Uses DashboardContext for interval state management.
19
20
  *
20
21
  * @example
21
22
  * ```tsx
22
23
  * <PageToolbar
23
24
  * title="Analytics"
24
- * timePeriod="2days"
25
- * onTimePeriodChange={setTimePeriod}
26
25
  * onRefresh={handleRefresh}
27
26
  * />
28
27
  * ```
29
- */ export function PageToolbar({ title, lastUpdated = '13s ago', timePeriod = '2days', onTimePeriodChange, onRefresh, showPlaybackControls = true, onRewind, onPlay, onSpeed, actions, children, className, ...props }) {
28
+ */ export function PageToolbar({ title, onRefresh, showPlaybackControls = true, onRewind, onPlay, onSpeed, actions, children, intervalSelectorContainer, className, ...props }) {
29
+ const { selection, setSelection, lastUpdated } = useDashboardContext();
30
30
  return /*#__PURE__*/ _jsxs("div", {
31
31
  className: cn('flex flex-wrap gap-12 items-center justify-between px-12 py-20 md:px-24 md:py-40', className),
32
32
  ...props,
@@ -66,99 +66,11 @@ import { cn } from '../../../utils/cn.js';
66
66
  ]
67
67
  })
68
68
  }),
69
- /*#__PURE__*/ _jsxs(Select, {
70
- value: timePeriod,
71
- onValueChange: onTimePeriodChange,
72
- children: [
73
- /*#__PURE__*/ _jsx(SelectTrigger, {
74
- className: "w-full md:w-280",
75
- children: /*#__PURE__*/ _jsx("div", {
76
- className: "flex items-center gap-8 flex-1 min-w-0",
77
- children: /*#__PURE__*/ _jsx(SelectValue, {
78
- placeholder: "Select time range"
79
- })
80
- })
81
- }),
82
- /*#__PURE__*/ _jsxs(SelectContent, {
83
- children: [
84
- /*#__PURE__*/ _jsx(SelectItem, {
85
- value: "1hour",
86
- children: /*#__PURE__*/ _jsxs("div", {
87
- className: "flex items-center gap-8",
88
- children: [
89
- /*#__PURE__*/ _jsx(Kbd, {
90
- className: "h-16",
91
- children: "1h"
92
- }),
93
- /*#__PURE__*/ _jsx("span", {
94
- children: "Past 1 Hour"
95
- })
96
- ]
97
- })
98
- }),
99
- /*#__PURE__*/ _jsx(SelectItem, {
100
- value: "1day",
101
- children: /*#__PURE__*/ _jsxs("div", {
102
- className: "flex items-center gap-8",
103
- children: [
104
- /*#__PURE__*/ _jsx(Kbd, {
105
- className: "h-16",
106
- children: "1d"
107
- }),
108
- /*#__PURE__*/ _jsx("span", {
109
- children: "Past 1 Day"
110
- })
111
- ]
112
- })
113
- }),
114
- /*#__PURE__*/ _jsx(SelectItem, {
115
- value: "2days",
116
- children: /*#__PURE__*/ _jsxs("div", {
117
- className: "flex items-center gap-8",
118
- children: [
119
- /*#__PURE__*/ _jsx(Kbd, {
120
- className: "h-16",
121
- children: "2d"
122
- }),
123
- /*#__PURE__*/ _jsx("span", {
124
- children: "Past 2 Days"
125
- })
126
- ]
127
- })
128
- }),
129
- /*#__PURE__*/ _jsx(SelectItem, {
130
- value: "7days",
131
- children: /*#__PURE__*/ _jsxs("div", {
132
- className: "flex items-center gap-8",
133
- children: [
134
- /*#__PURE__*/ _jsx(Kbd, {
135
- className: "h-16",
136
- children: "7d"
137
- }),
138
- /*#__PURE__*/ _jsx("span", {
139
- children: "Past 7 Days"
140
- })
141
- ]
142
- })
143
- }),
144
- /*#__PURE__*/ _jsx(SelectItem, {
145
- value: "30days",
146
- children: /*#__PURE__*/ _jsxs("div", {
147
- className: "flex items-center gap-8",
148
- children: [
149
- /*#__PURE__*/ _jsx(Kbd, {
150
- className: "h-16",
151
- children: "30d"
152
- }),
153
- /*#__PURE__*/ _jsx("span", {
154
- children: "Past 30 Days"
155
- })
156
- ]
157
- })
158
- })
159
- ]
160
- })
161
- ]
69
+ /*#__PURE__*/ _jsx(IntervalSelector, {
70
+ selection: selection,
71
+ onSelectionChange: setSelection,
72
+ container: intervalSelectorContainer,
73
+ className: "w-[75vw] md:w-350"
162
74
  }),
163
75
  showPlaybackControls && /*#__PURE__*/ _jsxs(ButtonGroup, {
164
76
  "aria-label": "Playback controls",
@@ -26,14 +26,14 @@ import { ViewDropdown } from './view-dropdown.js';
26
26
  * </ToolbarActions>
27
27
  * ```
28
28
  */ export function ToolbarActions({ showFilter = true, showSearch = true, showView = true, searchPlaceholder = 'Try: job name, status, pipeline...', className, children, ...props }) {
29
- const { setSearchQuery, filters, setFilters, columns, setColumns } = useDashboardContext();
29
+ const { setSearchQuery, resourceType, setResourceType, columns, setColumns } = useDashboardContext();
30
30
  return /*#__PURE__*/ _jsxs("div", {
31
31
  className: cn('flex items-start md:items-center gap-8 md:gap-12', className),
32
32
  ...props,
33
33
  children: [
34
34
  showFilter && /*#__PURE__*/ _jsx(FilterButton, {
35
- filters: filters,
36
- onFiltersChange: setFilters
35
+ value: resourceType,
36
+ onValueChange: setResourceType
37
37
  }),
38
38
  showSearch && /*#__PURE__*/ _jsx(ToolbarSearch, {
39
39
  placeholder: searchPlaceholder,
@@ -23,6 +23,7 @@ export * from './form';
23
23
  export * from './icon';
24
24
  export * from './inline-tips';
25
25
  export * from './input';
26
+ export * from './interval-selector';
26
27
  export * from './item';
27
28
  export * from './kbd';
28
29
  export * from './label';
@@ -23,6 +23,7 @@ export * from './form/index.js';
23
23
  export * from './icon/index.js';
24
24
  export * from './inline-tips/index.js';
25
25
  export * from './input/index.js';
26
+ export * from './interval-selector/index.js';
26
27
  export * from './item/index.js';
27
28
  export * from './kbd/index.js';
28
29
  export * from './label/index.js';
@@ -0,0 +1,4 @@
1
+ export * from './use-interval-selector';
2
+ export * from './use-interval-selector-input';
3
+ export * from './use-interval-selector-navigation';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ export * from './use-interval-selector.js';
2
+ export * from './use-interval-selector-input.js';
3
+ export * from './use-interval-selector-navigation.js';
4
+
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,30 @@
1
+ import type { IntervalSelection } from '../types';
2
+ export interface UseNewIntervalSelectorInputProps {
3
+ onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
4
+ onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
5
+ onFocus?: () => void;
6
+ onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
7
+ onSelect: (selection: IntervalSelection) => void;
8
+ selection: IntervalSelection;
9
+ isNavigating: boolean;
10
+ inputRef: React.RefObject<HTMLInputElement | null>;
11
+ isFocused: boolean;
12
+ setIsFocused: (isFocused: boolean) => void;
13
+ }
14
+ export declare function useIntervalSelectorInput({ onChange: onChangeProp, onKeyDown: onKeyDownProp, onFocus: onFocusProp, onBlur: onBlurProp, onSelect, selection, isNavigating, inputRef, isFocused, setIsFocused, }: UseNewIntervalSelectorInputProps): {
15
+ value: string;
16
+ shouldShake: boolean;
17
+ isFocused: boolean;
18
+ isInvalid: boolean;
19
+ displayValue: string;
20
+ shortcutValue: string;
21
+ setValue: import("react").Dispatch<import("react").SetStateAction<string>>;
22
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
23
+ onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
24
+ onFocus: () => void;
25
+ onMouseDown: () => void;
26
+ onMouseUp: () => void;
27
+ onBlur: (e: React.FocusEvent<HTMLInputElement>) => void;
28
+ inputRef: import("react").RefObject<HTMLInputElement | null>;
29
+ };
30
+ //# sourceMappingURL=use-interval-selector-input.d.ts.map
@@ -0,0 +1,125 @@
1
+ import { useCallback, useRef, useState } from 'react';
2
+ import { parseTextDurationShortcut, parseTextInterval } from '../../../utils/date.js';
3
+ import { formatSelection, formatSelectionForInput, formatShortcut } from '../utils/format.js';
4
+ export function useIntervalSelectorInput({ onChange: onChangeProp, onKeyDown: onKeyDownProp, onFocus: onFocusProp, onBlur: onBlurProp, onSelect, selection, isNavigating, inputRef, isFocused, setIsFocused }) {
5
+ const [value, setValue] = useState('');
6
+ const [isInvalid, setIsInvalid] = useState(false);
7
+ const [shouldShake, setShouldShake] = useState(false);
8
+ const shakeTimeoutRef = useRef(null);
9
+ const isMouseDownOnInputRef = useRef(false);
10
+ const onChange = useCallback((e)=>{
11
+ const newValue = e.target.value;
12
+ setValue(newValue);
13
+ const shortcut = parseTextDurationShortcut(newValue);
14
+ const interval = parseTextInterval(newValue);
15
+ const isValid = shortcut || interval || newValue.trim() === '';
16
+ setIsInvalid(!isValid);
17
+ onChangeProp?.(e);
18
+ }, [
19
+ onChangeProp
20
+ ]);
21
+ const triggerShakeAnimation = useCallback(()=>{
22
+ if (shakeTimeoutRef.current) clearTimeout(shakeTimeoutRef.current);
23
+ setIsInvalid(true);
24
+ setShouldShake(true);
25
+ shakeTimeoutRef.current = setTimeout(()=>{
26
+ setShouldShake(false);
27
+ shakeTimeoutRef.current = null;
28
+ }, 500);
29
+ }, []);
30
+ const handleConfirmInput = useCallback(()=>{
31
+ const shortcut = parseTextDurationShortcut(value);
32
+ if (shortcut) return onSelect({
33
+ type: 'relative',
34
+ duration: shortcut
35
+ });
36
+ const interval = parseTextInterval(value);
37
+ if (interval) return onSelect({
38
+ type: 'interval',
39
+ interval
40
+ });
41
+ triggerShakeAnimation();
42
+ }, [
43
+ value,
44
+ onSelect,
45
+ triggerShakeAnimation
46
+ ]);
47
+ const onKeyDown = useCallback((e)=>{
48
+ if (!isNavigating && e.key === 'Enter') {
49
+ e.preventDefault();
50
+ handleConfirmInput();
51
+ }
52
+ onKeyDownProp?.(e);
53
+ }, [
54
+ isNavigating,
55
+ handleConfirmInput,
56
+ onKeyDownProp
57
+ ]);
58
+ const onFocus = useCallback(()=>{
59
+ setIsFocused(true);
60
+ setValue(formatSelectionForInput(selection));
61
+ setIsInvalid(false);
62
+ requestAnimationFrame(()=>{
63
+ inputRef.current?.select();
64
+ });
65
+ onFocusProp?.();
66
+ }, [
67
+ selection,
68
+ onFocusProp,
69
+ inputRef,
70
+ setIsFocused
71
+ ]);
72
+ const onMouseDown = useCallback(()=>{
73
+ isMouseDownOnInputRef.current = true;
74
+ }, []);
75
+ const onMouseUp = useCallback(()=>{
76
+ setTimeout(()=>{
77
+ isMouseDownOnInputRef.current = false;
78
+ });
79
+ }, []);
80
+ const onBlur = useCallback((e)=>{
81
+ const relatedTarget = e.relatedTarget;
82
+ if (relatedTarget?.closest('[role="dialog"]')) {
83
+ return;
84
+ }
85
+ if (isMouseDownOnInputRef.current) {
86
+ requestAnimationFrame(()=>{
87
+ inputRef.current?.focus();
88
+ });
89
+ }
90
+ setIsFocused(false);
91
+ onBlurProp?.(e);
92
+ }, [
93
+ onBlurProp,
94
+ inputRef,
95
+ setIsFocused
96
+ ]);
97
+ const displayValue = formatSelection({
98
+ selection,
99
+ isFocused: isFocused,
100
+ inputValue: value
101
+ });
102
+ const shortcutValue = formatShortcut({
103
+ selection,
104
+ inputValue: value,
105
+ isFocused: isFocused
106
+ });
107
+ return {
108
+ value,
109
+ shouldShake,
110
+ isFocused,
111
+ isInvalid,
112
+ displayValue,
113
+ shortcutValue,
114
+ setValue,
115
+ onChange,
116
+ onKeyDown,
117
+ onFocus,
118
+ onMouseDown,
119
+ onMouseUp,
120
+ onBlur,
121
+ inputRef
122
+ };
123
+ }
124
+
125
+ //# sourceMappingURL=use-interval-selector-input.js.map
@@ -0,0 +1,21 @@
1
+ import type { IntervalSelection, IntervalSuggestion, RelativeSuggestion } from '../types';
2
+ interface UseIntervalSelectorNavigationProps {
3
+ relativeSuggestions: RelativeSuggestion[];
4
+ intervalSuggestions: IntervalSuggestion[];
5
+ highlightedIndex: number;
6
+ setHighlightedIndex: (index: number) => void;
7
+ popoverOpen: boolean;
8
+ calendarOpen: boolean;
9
+ onOpenCalendar: () => void;
10
+ onSelect: (selection: IntervalSelection) => void;
11
+ }
12
+ export declare function useIntervalSelectorNavigation({ relativeSuggestions, intervalSuggestions, highlightedIndex, setHighlightedIndex, popoverOpen, calendarOpen, onOpenCalendar, onSelect, }: UseIntervalSelectorNavigationProps): {
13
+ allNavigableItems: (RelativeSuggestion | IntervalSuggestion | {
14
+ type: "calendar";
15
+ label: string;
16
+ })[];
17
+ onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
18
+ isNavigating: boolean;
19
+ };
20
+ export {};
21
+ //# sourceMappingURL=use-interval-selector-navigation.d.ts.map
@@ -0,0 +1,58 @@
1
+ import { useCallback, useMemo } from 'react';
2
+ export function useIntervalSelectorNavigation({ relativeSuggestions, intervalSuggestions, highlightedIndex, setHighlightedIndex, popoverOpen, calendarOpen, onOpenCalendar, onSelect }) {
3
+ const allNavigableItems = useMemo(()=>[
4
+ ...relativeSuggestions,
5
+ ...intervalSuggestions,
6
+ {
7
+ type: 'calendar',
8
+ label: 'Select from calendar'
9
+ }
10
+ ], [
11
+ relativeSuggestions,
12
+ intervalSuggestions
13
+ ]);
14
+ const canNavigate = popoverOpen && !calendarOpen;
15
+ const currentIndex = highlightedIndex;
16
+ const isNavigating = canNavigate && currentIndex >= 0 && currentIndex < allNavigableItems.length;
17
+ const onKeyDown = useCallback((e)=>{
18
+ if (!canNavigate) return;
19
+ const items = allNavigableItems;
20
+ if (e.key === 'ArrowDown') {
21
+ e.preventDefault();
22
+ const nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
23
+ setHighlightedIndex(nextIndex);
24
+ return;
25
+ }
26
+ if (e.key === 'ArrowUp') {
27
+ e.preventDefault();
28
+ const nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
29
+ setHighlightedIndex(nextIndex);
30
+ return;
31
+ }
32
+ if (e.key === 'Enter' && isNavigating) {
33
+ e.preventDefault();
34
+ const item = items[currentIndex];
35
+ if (item.type === 'calendar') {
36
+ onOpenCalendar();
37
+ } else {
38
+ onSelect(item);
39
+ }
40
+ return;
41
+ }
42
+ }, [
43
+ canNavigate,
44
+ isNavigating,
45
+ currentIndex,
46
+ allNavigableItems,
47
+ setHighlightedIndex,
48
+ onOpenCalendar,
49
+ onSelect
50
+ ]);
51
+ return {
52
+ allNavigableItems,
53
+ onKeyDown,
54
+ isNavigating
55
+ };
56
+ }
57
+
58
+ //# sourceMappingURL=use-interval-selector-navigation.js.map
@@ -0,0 +1,25 @@
1
+ import type { DismissableLayerProps } from '@radix-ui/react-dismissable-layer';
2
+ import type { IntervalSelectorProps } from '../interval-selector';
3
+ import type { IntervalSelection, IntervalSuggestion, RelativeSuggestion } from '../types';
4
+ export interface UseIntervalSelectorProps extends Pick<IntervalSelectorProps, 'onSelectionChange'> {
5
+ relativeSuggestions: RelativeSuggestion[];
6
+ intervalSuggestions: IntervalSuggestion[];
7
+ }
8
+ export declare function useIntervalSelector({ onSelectionChange, relativeSuggestions, intervalSuggestions, }: UseIntervalSelectorProps): {
9
+ onSelect: (selection: IntervalSelection) => void;
10
+ popoverOpen: boolean;
11
+ calendarOpen: boolean;
12
+ highlightedIndex: number;
13
+ inputRef: import("react").RefObject<HTMLInputElement | null>;
14
+ onFocus: () => void;
15
+ onBlur: () => void;
16
+ onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
17
+ onOpenCalendar: () => void;
18
+ onChange: () => void;
19
+ onInteractOutside: (e: Parameters<Required<DismissableLayerProps>["onInteractOutside"]>[0]) => void;
20
+ closeAll: () => void;
21
+ isNavigating: boolean;
22
+ isFocused: boolean;
23
+ setIsFocused: import("react").Dispatch<import("react").SetStateAction<boolean>>;
24
+ };
25
+ //# sourceMappingURL=use-interval-selector.d.ts.map
@@ -0,0 +1,75 @@
1
+ import { useCallback, useRef, useState } from 'react';
2
+ import { useIntervalSelectorNavigation } from './use-interval-selector-navigation.js';
3
+ export function useIntervalSelector({ onSelectionChange, relativeSuggestions, intervalSuggestions }) {
4
+ const [popoverOpen, setPopoverOpen] = useState(false);
5
+ const [calendarOpen, setCalendarOpen] = useState(false);
6
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
7
+ const [isFocused, setIsFocused] = useState(false);
8
+ const isSelectingRef = useRef(false);
9
+ const inputRef = useRef(null);
10
+ const closeAll = useCallback(()=>{
11
+ setPopoverOpen(false);
12
+ inputRef.current?.blur();
13
+ setCalendarOpen(false);
14
+ setHighlightedIndex(-1);
15
+ setIsFocused(false);
16
+ }, []);
17
+ const onSelect = useCallback((selection)=>{
18
+ isSelectingRef.current = true;
19
+ onSelectionChange(selection);
20
+ closeAll();
21
+ }, [
22
+ closeAll,
23
+ onSelectionChange
24
+ ]);
25
+ const onFocus = useCallback(()=>{
26
+ setPopoverOpen(true);
27
+ setHighlightedIndex(-1);
28
+ }, []);
29
+ const onBlur = useCallback(()=>{
30
+ if (!calendarOpen) setPopoverOpen(false);
31
+ }, [
32
+ calendarOpen
33
+ ]);
34
+ const onOpenCalendar = useCallback(()=>{
35
+ setCalendarOpen(true);
36
+ }, []);
37
+ const { onKeyDown, isNavigating } = useIntervalSelectorNavigation({
38
+ relativeSuggestions,
39
+ intervalSuggestions,
40
+ highlightedIndex,
41
+ setHighlightedIndex,
42
+ popoverOpen,
43
+ calendarOpen,
44
+ onOpenCalendar,
45
+ onSelect
46
+ });
47
+ const onInteractOutside = useCallback((e)=>{
48
+ e.preventDefault();
49
+ const target = e.target;
50
+ const isClickOnPopover = inputRef.current && (inputRef.current.contains(target) || target.closest('[data-radix-popover-trigger]'));
51
+ if (isClickOnPopover) return;
52
+ closeAll();
53
+ }, [
54
+ closeAll
55
+ ]);
56
+ return {
57
+ onSelect,
58
+ popoverOpen,
59
+ calendarOpen,
60
+ highlightedIndex,
61
+ inputRef,
62
+ onFocus,
63
+ onBlur,
64
+ onKeyDown,
65
+ onOpenCalendar,
66
+ onChange: ()=>setHighlightedIndex(-1),
67
+ onInteractOutside,
68
+ closeAll,
69
+ isNavigating,
70
+ isFocused,
71
+ setIsFocused
72
+ };
73
+ }
74
+
75
+ //# sourceMappingURL=use-interval-selector.js.map
@@ -0,0 +1,3 @@
1
+ export * from './interval-selector';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,4 @@
1
+ export * from './interval-selector.js';
2
+ export * from './types.js';
3
+
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ import type { IntervalSelection } from './types';
2
+ interface IntervalSelectorCalendarProps {
3
+ onSelect: (selection: IntervalSelection) => void;
4
+ }
5
+ export declare function IntervalSelectorCalendar({ onSelect }: IntervalSelectorCalendarProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=interval-selector-calendar.d.ts.map
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Calendar } from '../../components/calendar/index.js';
3
+ import { endOfDay, format, startOfDay } from 'date-fns';
4
+ import { useCallback, useState } from 'react';
5
+ export function IntervalSelectorCalendar({ onSelect }) {
6
+ const [selectedRange, setSelectedRange] = useState(undefined);
7
+ const handleSelect = useCallback((_, selectedDay)=>{
8
+ if (!selectedDay) return setSelectedRange(undefined);
9
+ if (!selectedRange?.from) return setSelectedRange({
10
+ from: selectedDay,
11
+ to: undefined
12
+ });
13
+ const start = selectedDay < selectedRange.from ? startOfDay(selectedDay) : startOfDay(selectedRange.from);
14
+ const end = selectedDay < selectedRange.from ? endOfDay(selectedRange.from) : endOfDay(selectedDay);
15
+ onSelect({
16
+ type: 'interval',
17
+ interval: {
18
+ start,
19
+ end
20
+ }
21
+ });
22
+ return setSelectedRange(undefined);
23
+ }, [
24
+ onSelect,
25
+ selectedRange
26
+ ]);
27
+ return /*#__PURE__*/ _jsx(Calendar, {
28
+ mode: "range",
29
+ selected: selectedRange,
30
+ onSelect: handleSelect,
31
+ numberOfMonths: 1,
32
+ formatters: {
33
+ formatWeekdayName: (date)=>format(date, 'EEEEE')
34
+ },
35
+ disabled: {
36
+ after: new Date()
37
+ },
38
+ classNames: {
39
+ root: 'relative w-full flex justify-center items-center',
40
+ months: 'w-full',
41
+ month_grid: 'flex flex-col justify-center items-center',
42
+ nav: 'flex items-center gap-4 absolute top-16 left-0 w-full z-10'
43
+ }
44
+ });
45
+ }
46
+
47
+ //# sourceMappingURL=interval-selector-calendar.js.map
@@ -0,0 +1,8 @@
1
+ import { type UseNewIntervalSelectorInputProps } from './hooks/use-interval-selector-input';
2
+ type IntervalSelectorInputProps = {
3
+ className?: string;
4
+ inputClassName?: string;
5
+ } & UseNewIntervalSelectorInputProps;
6
+ export declare function IntervalSelectorInput({ className, inputClassName, ...props }: IntervalSelectorInputProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=interval-selector-input.d.ts.map
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Input } from '../../components/input/index.js';
3
+ import { Kbd } from '../../components/kbd/index.js';
4
+ import { PopoverTrigger } from '../../components/popover/index.js';
5
+ import { cn } from '../../utils/cn.js';
6
+ import { useIntervalSelectorInput } from './hooks/use-interval-selector-input.js';
7
+ export function IntervalSelectorInput({ className, inputClassName, ...props }) {
8
+ const { displayValue, shortcutValue, isFocused, isInvalid, shouldShake, onChange, onKeyDown, onFocus, onBlur, onMouseDown, onMouseUp, inputRef } = useIntervalSelectorInput(props);
9
+ return /*#__PURE__*/ _jsx(PopoverTrigger, {
10
+ asChild: true,
11
+ children: /*#__PURE__*/ _jsx("div", {
12
+ className: cn('relative', className, shouldShake && 'animate-shake'),
13
+ children: /*#__PURE__*/ _jsx(Input, {
14
+ ref: inputRef,
15
+ value: displayValue,
16
+ onChange: isFocused ? onChange : undefined,
17
+ onFocus: onFocus,
18
+ onBlur: onBlur,
19
+ onMouseDown: onMouseDown,
20
+ onMouseUp: onMouseUp,
21
+ onKeyDown: onKeyDown,
22
+ readOnly: !isFocused,
23
+ "aria-invalid": isInvalid && isFocused,
24
+ iconLeft: /*#__PURE__*/ _jsx(Kbd, {
25
+ className: "h-16 shrink-0 min-w-36",
26
+ children: shortcutValue
27
+ }),
28
+ className: cn('w-full pl-50', inputClassName)
29
+ })
30
+ })
31
+ });
32
+ }
33
+
34
+ //# sourceMappingURL=interval-selector-input.js.map
@@ -0,0 +1,11 @@
1
+ import type { IntervalSelection, IntervalSuggestion, RelativeSuggestion } from './types';
2
+ interface IntervalSelectorSuggestionsProps {
3
+ relativeSuggestions: RelativeSuggestion[];
4
+ intervalSuggestions: IntervalSuggestion[];
5
+ onSelect: (selection: IntervalSelection) => void;
6
+ onOpenCalendar: () => void;
7
+ highlightedIndex: number;
8
+ }
9
+ export declare function IntervalSelectorSuggestions({ relativeSuggestions, intervalSuggestions, onSelect, onOpenCalendar, highlightedIndex, }: IntervalSelectorSuggestionsProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=interval-selector-suggestions.d.ts.map