@shipfox/react-ui 0.18.0 → 0.20.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.
- package/dist/components/calendar/calendar.js +12 -12
- package/dist/components/combobox/combobox.d.ts +21 -0
- package/dist/components/combobox/combobox.js +84 -0
- package/dist/components/combobox/combobox.stories.js +191 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/combobox/index.js +3 -0
- package/dist/components/command/command.d.ts +2 -1
- package/dist/components/command/command.js +9 -5
- package/dist/components/dashboard/components/kpi-card.js +4 -1
- package/dist/components/date-picker/date-picker.d.ts +1 -0
- package/dist/components/date-picker/date-picker.js +20 -4
- package/dist/components/date-picker/date-picker.stories.js +16 -0
- package/dist/components/date-time-range-picker/date-time-range-picker.d.ts +1 -0
- package/dist/components/date-time-range-picker/date-time-range-picker.js +51 -23
- package/dist/components/dropdown-input/dropdown-input.d.ts +25 -0
- package/dist/components/dropdown-input/dropdown-input.js +188 -0
- package/dist/components/dropdown-input/dropdown-input.stories.js +240 -0
- package/dist/components/dropdown-input/index.d.ts +2 -0
- package/dist/components/dropdown-input/index.js +3 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +3 -0
- package/dist/components/input/input.d.ts +6 -3
- package/dist/components/input/input.js +27 -11
- package/dist/components/input/input.stories.js +66 -0
- package/dist/components/scroll-area/index.d.ts +2 -0
- package/dist/components/scroll-area/index.js +3 -0
- package/dist/components/scroll-area/scroll-area.d.ts +6 -0
- package/dist/components/scroll-area/scroll-area.js +34 -0
- package/dist/styles.css +1 -1
- package/package.json +2 -2
|
@@ -5,34 +5,34 @@ import { cn } from '../../utils/cn.js';
|
|
|
5
5
|
export function Calendar({ className, classNames, showOutsideDays = true, ...props }) {
|
|
6
6
|
return /*#__PURE__*/ _jsx(DayPicker, {
|
|
7
7
|
showOutsideDays: showOutsideDays,
|
|
8
|
-
className: cn('
|
|
8
|
+
className: cn('transition-colors', className),
|
|
9
9
|
classNames: {
|
|
10
|
-
months: 'flex flex-col sm:flex-row gap-
|
|
11
|
-
month: 'space-y-16 relative',
|
|
12
|
-
month_caption: 'flex items-center justify-center mb-8 px-4 relative h-32',
|
|
10
|
+
months: 'flex flex-col sm:flex-row gap-0',
|
|
11
|
+
month: 'space-y-16 relative p-16 border-r border-border-neutral-base-component last:border-r-0',
|
|
12
|
+
month_caption: 'flex items-center justify-center mb-8 px-4 relative h-32 bg-background-field-base rounded-8 shadow-tooltip',
|
|
13
13
|
caption_label: 'text-sm font-medium text-foreground-neutral-base',
|
|
14
14
|
nav: 'flex items-center gap-4 fixed left-0 top-16 w-full z-10',
|
|
15
|
-
button_previous: cn('size-32 bg-transparent p-0 absolute left-16 top-0', 'inline-flex items-center justify-center rounded-6', 'text-foreground-neutral-
|
|
16
|
-
button_next: cn('size-32 bg-transparent p-0 absolute right-16 top-0', 'inline-flex items-center justify-center rounded-6', 'text-foreground-neutral-
|
|
15
|
+
button_previous: cn('size-32 bg-transparent p-0 absolute left-16 top-0 cursor-pointer', 'inline-flex items-center justify-center rounded-6', 'text-foreground-neutral-muted', 'hover:bg-transparent hover:text-foreground-neutral-subtle', 'active:bg-transparent', 'transition-colors outline-none', 'focus-visible:shadow-border-interactive-with-active', 'disabled:pointer-events-none disabled:opacity-50'),
|
|
16
|
+
button_next: cn('size-32 bg-transparent p-0 absolute right-16 top-0 cursor-pointer', 'inline-flex items-center justify-center rounded-6', 'text-foreground-neutral-muted', 'hover:bg-transparent hover:text-foreground-neutral-subtle', 'active:bg-transparent', 'transition-colors outline-none', 'focus-visible:shadow-border-interactive-with-active', 'disabled:pointer-events-none disabled:opacity-50'),
|
|
17
17
|
month_grid: 'w-full border-collapse mt-8',
|
|
18
|
-
weekdays: 'flex
|
|
18
|
+
weekdays: 'flex gap-8',
|
|
19
19
|
weekday: 'text-foreground-neutral-subtle text-xs font-medium w-36 h-32 flex items-center justify-center',
|
|
20
|
-
week: 'flex mt-
|
|
20
|
+
week: 'flex mt-8 gap-8',
|
|
21
21
|
day: cn('relative text-center size-36 p-0 text-sm font-normal [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none', '[&:last-child[data-selected=true]_button]:rounded-r-6', props.showWeekNumber ? '[&:nth-child(2)[data-selected=true]_button]:rounded-l-6' : '[&:first-child[data-selected=true]_button]:rounded-l-6'),
|
|
22
22
|
day_button: cn('size-36 p-0 text-sm font-normal rounded-6', 'inline-flex items-center justify-center', 'hover:bg-background-button-transparent-hover', 'focus-visible:shadow-border-interactive-with-active', 'transition-colors outline-none', 'aria-selected:opacity-100'),
|
|
23
23
|
range_start: 'day-range-start rounded-6',
|
|
24
24
|
range_end: 'day-range-end rounded-6',
|
|
25
|
-
selected: cn('bg-foreground-highlight-interactive/80 !text-foreground-neutral-
|
|
26
|
-
today: cn('
|
|
25
|
+
selected: cn('bg-foreground-highlight-interactive/80 !text-foreground-neutral-on-inverted font-medium rounded-6', 'hover:bg-foreground-highlight-interactive-hover/80', 'focus:bg-foreground-highlight-interactive/80'),
|
|
26
|
+
today: cn('relative font-medium rounded-6', 'after:absolute after:bottom-[6px] after:left-1/2 after:-translate-x-1/2', 'after:size-[3px] after:rounded-full after:bg-[var(--color-primary-400)]'),
|
|
27
27
|
outside: 'day-outside text-foreground-neutral-muted',
|
|
28
28
|
disabled: 'text-foreground-neutral-disabled opacity-30 cursor-not-allowed',
|
|
29
|
-
range_middle: cn('aria-selected:bg-
|
|
29
|
+
range_middle: cn('aria-selected:bg-background-highlight-base aria-selected:!text-foreground-highlight-interactive'),
|
|
30
30
|
hidden: 'invisible',
|
|
31
31
|
...classNames
|
|
32
32
|
},
|
|
33
33
|
components: {
|
|
34
34
|
Chevron: ({ orientation })=>{
|
|
35
|
-
const iconName = orientation === 'left' ? '
|
|
35
|
+
const iconName = orientation === 'left' ? 'arrowLeftSFill' : 'arrowRightSFill';
|
|
36
36
|
return /*#__PURE__*/ _jsx(Icon, {
|
|
37
37
|
name: iconName,
|
|
38
38
|
className: "size-20"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type CommandTriggerProps } from '../command';
|
|
3
|
+
export type ComboboxOption = {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
};
|
|
7
|
+
export type ComboboxProps = Omit<CommandTriggerProps, 'children' | 'placeholder'> & {
|
|
8
|
+
options: ComboboxOption[];
|
|
9
|
+
value?: string;
|
|
10
|
+
onValueChange?: (value: string) => void;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
emptyState?: string | React.ReactNode;
|
|
13
|
+
searchPlaceholder?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
popoverClassName?: string;
|
|
16
|
+
align?: 'start' | 'center' | 'end';
|
|
17
|
+
sideOffset?: number;
|
|
18
|
+
isLoading?: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare function Combobox({ options, value, onValueChange, placeholder, emptyState, searchPlaceholder, className, popoverClassName, align, sideOffset, variant, size, isLoading, ...triggerProps }: ComboboxProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
//# sourceMappingURL=combobox.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ScrollArea } from '../../components/scroll-area/index.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../utils/cn.js';
|
|
5
|
+
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandTrigger } from '../command/index.js';
|
|
6
|
+
import { Icon } from '../icon/index.js';
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger } from '../popover/index.js';
|
|
8
|
+
export function Combobox({ options, value, onValueChange, placeholder = 'Select option...', emptyState = 'No option found.', searchPlaceholder = 'Search...', className, popoverClassName, align = 'start', sideOffset = 4, variant, size, isLoading, ...triggerProps }) {
|
|
9
|
+
const [open, setOpen] = React.useState(false);
|
|
10
|
+
const [internalValue, setInternalValue] = React.useState('');
|
|
11
|
+
const isControlled = value !== undefined;
|
|
12
|
+
const currentValue = isControlled ? value : internalValue;
|
|
13
|
+
const handleValueChange = React.useCallback((newValue)=>{
|
|
14
|
+
if (!isControlled) {
|
|
15
|
+
setInternalValue(newValue);
|
|
16
|
+
}
|
|
17
|
+
onValueChange?.(newValue);
|
|
18
|
+
}, [
|
|
19
|
+
isControlled,
|
|
20
|
+
onValueChange
|
|
21
|
+
]);
|
|
22
|
+
const selectedOption = options.find((option)=>option.value === currentValue);
|
|
23
|
+
return /*#__PURE__*/ _jsxs(Popover, {
|
|
24
|
+
open: open,
|
|
25
|
+
onOpenChange: setOpen,
|
|
26
|
+
children: [
|
|
27
|
+
/*#__PURE__*/ _jsx(PopoverTrigger, {
|
|
28
|
+
asChild: true,
|
|
29
|
+
children: /*#__PURE__*/ _jsx(CommandTrigger, {
|
|
30
|
+
variant: variant,
|
|
31
|
+
size: size,
|
|
32
|
+
placeholder: placeholder,
|
|
33
|
+
className: className,
|
|
34
|
+
isLoading: isLoading,
|
|
35
|
+
...triggerProps,
|
|
36
|
+
children: selectedOption?.label
|
|
37
|
+
})
|
|
38
|
+
}),
|
|
39
|
+
/*#__PURE__*/ _jsx(PopoverContent, {
|
|
40
|
+
className: cn('w-(--radix-popover-trigger-width) p-0', popoverClassName),
|
|
41
|
+
align: align,
|
|
42
|
+
sideOffset: sideOffset,
|
|
43
|
+
onWheel: (e)=>e.stopPropagation(),
|
|
44
|
+
onTouchStart: (e)=>e.stopPropagation(),
|
|
45
|
+
onTouchMove: (e)=>e.stopPropagation(),
|
|
46
|
+
children: /*#__PURE__*/ _jsxs(Command, {
|
|
47
|
+
children: [
|
|
48
|
+
/*#__PURE__*/ _jsx(CommandInput, {
|
|
49
|
+
placeholder: searchPlaceholder
|
|
50
|
+
}),
|
|
51
|
+
/*#__PURE__*/ _jsx(ScrollArea, {
|
|
52
|
+
children: /*#__PURE__*/ _jsxs(CommandList, {
|
|
53
|
+
className: "max-h-300",
|
|
54
|
+
children: [
|
|
55
|
+
/*#__PURE__*/ _jsx(CommandEmpty, {
|
|
56
|
+
children: emptyState
|
|
57
|
+
}),
|
|
58
|
+
/*#__PURE__*/ _jsx(CommandGroup, {
|
|
59
|
+
children: options.map((option)=>/*#__PURE__*/ _jsxs(CommandItem, {
|
|
60
|
+
value: option.value,
|
|
61
|
+
onSelect: (selectedValue)=>{
|
|
62
|
+
handleValueChange(currentValue === selectedValue ? '' : selectedValue);
|
|
63
|
+
setOpen(false);
|
|
64
|
+
},
|
|
65
|
+
children: [
|
|
66
|
+
/*#__PURE__*/ _jsx(Icon, {
|
|
67
|
+
name: "check",
|
|
68
|
+
className: cn('size-16 mr-8', currentValue === option.value ? 'opacity-100' : 'opacity-0')
|
|
69
|
+
}),
|
|
70
|
+
option.label
|
|
71
|
+
]
|
|
72
|
+
}, option.value))
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
]
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=combobox.js.map
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Label } from '../../components/label/index.js';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Combobox } from './combobox.js';
|
|
5
|
+
const sampleItems = [
|
|
6
|
+
{
|
|
7
|
+
value: 'apache',
|
|
8
|
+
label: 'apache'
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
value: 'apache-superset',
|
|
12
|
+
label: 'apache-superset'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
value: 'apaleo',
|
|
16
|
+
label: 'apaleo'
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: 'apollo',
|
|
20
|
+
label: 'apollo'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: 'apple',
|
|
24
|
+
label: 'apple'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: 'apache-kafka',
|
|
28
|
+
label: 'apache-kafka'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'apex',
|
|
32
|
+
label: 'apex'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
value: 'appsmith',
|
|
36
|
+
label: 'appsmith'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
value: 'applitools',
|
|
40
|
+
label: 'applitools'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: 'approzium',
|
|
44
|
+
label: 'approzium'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: 'apify',
|
|
48
|
+
label: 'apify'
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
value: 'apicurio',
|
|
52
|
+
label: 'apicurio'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
value: 'apitable',
|
|
56
|
+
label: 'apitable'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
value: 'apollographql',
|
|
60
|
+
label: 'apollographql'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
value: 'aptos',
|
|
64
|
+
label: 'aptos'
|
|
65
|
+
}
|
|
66
|
+
];
|
|
67
|
+
const meta = {
|
|
68
|
+
title: 'Components/Combobox',
|
|
69
|
+
component: Combobox,
|
|
70
|
+
tags: [
|
|
71
|
+
'autodocs'
|
|
72
|
+
],
|
|
73
|
+
parameters: {
|
|
74
|
+
layout: 'centered'
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
export default meta;
|
|
78
|
+
export const Default = {
|
|
79
|
+
args: {},
|
|
80
|
+
render: ()=>{
|
|
81
|
+
const [value, setValue] = useState('');
|
|
82
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
83
|
+
className: "w-[80vw] md:w-500",
|
|
84
|
+
children: [
|
|
85
|
+
/*#__PURE__*/ _jsx(Label, {
|
|
86
|
+
htmlFor: "combobox-default",
|
|
87
|
+
children: "Search repositories"
|
|
88
|
+
}),
|
|
89
|
+
/*#__PURE__*/ _jsx(Combobox, {
|
|
90
|
+
id: "combobox-default",
|
|
91
|
+
options: sampleItems,
|
|
92
|
+
value: value,
|
|
93
|
+
onValueChange: setValue,
|
|
94
|
+
placeholder: "Type to search...",
|
|
95
|
+
searchPlaceholder: "Search repositories...",
|
|
96
|
+
emptyState: "No repository found."
|
|
97
|
+
})
|
|
98
|
+
]
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
export const EmptyState = {
|
|
103
|
+
args: {},
|
|
104
|
+
render: ()=>{
|
|
105
|
+
const [value, setValue] = useState('abcxyz');
|
|
106
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
107
|
+
className: "w-[80vw] md:w-500",
|
|
108
|
+
children: [
|
|
109
|
+
/*#__PURE__*/ _jsx(Label, {
|
|
110
|
+
htmlFor: "combobox-empty",
|
|
111
|
+
children: "No results"
|
|
112
|
+
}),
|
|
113
|
+
/*#__PURE__*/ _jsx(Combobox, {
|
|
114
|
+
id: "combobox-empty",
|
|
115
|
+
options: [],
|
|
116
|
+
value: value,
|
|
117
|
+
onValueChange: setValue,
|
|
118
|
+
placeholder: "Type to search...",
|
|
119
|
+
searchPlaceholder: "Search repositories...",
|
|
120
|
+
emptyState: /*#__PURE__*/ _jsxs("p", {
|
|
121
|
+
className: "px-4 whitespace-pre-wrap",
|
|
122
|
+
children: [
|
|
123
|
+
"Repository list is limited to 100.",
|
|
124
|
+
' ',
|
|
125
|
+
/*#__PURE__*/ _jsx("a", {
|
|
126
|
+
href: "https://support.example.com",
|
|
127
|
+
target: "_blank",
|
|
128
|
+
rel: "noopener noreferrer",
|
|
129
|
+
className: "underline text-foreground-neutral-base",
|
|
130
|
+
children: "Contact us"
|
|
131
|
+
}),
|
|
132
|
+
' ',
|
|
133
|
+
"for support."
|
|
134
|
+
]
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
export const LoadingState = {
|
|
142
|
+
args: {},
|
|
143
|
+
render: ()=>{
|
|
144
|
+
const [value, setValue] = useState('');
|
|
145
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
146
|
+
className: "w-[80vw] md:w-500",
|
|
147
|
+
children: [
|
|
148
|
+
/*#__PURE__*/ _jsx(Label, {
|
|
149
|
+
htmlFor: "combobox-loading",
|
|
150
|
+
children: "Loading"
|
|
151
|
+
}),
|
|
152
|
+
/*#__PURE__*/ _jsx(Combobox, {
|
|
153
|
+
id: "combobox-loading",
|
|
154
|
+
options: sampleItems,
|
|
155
|
+
value: value,
|
|
156
|
+
onValueChange: setValue,
|
|
157
|
+
placeholder: "Type to search...",
|
|
158
|
+
searchPlaceholder: "Search repositories...",
|
|
159
|
+
isLoading: true
|
|
160
|
+
})
|
|
161
|
+
]
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
export const DisabledState = {
|
|
166
|
+
args: {},
|
|
167
|
+
render: ()=>{
|
|
168
|
+
const [value, setValue] = useState('apache');
|
|
169
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
170
|
+
className: "w-[80vw] md:w-500",
|
|
171
|
+
children: [
|
|
172
|
+
/*#__PURE__*/ _jsx(Label, {
|
|
173
|
+
htmlFor: "combobox-disabled",
|
|
174
|
+
children: "Disabled"
|
|
175
|
+
}),
|
|
176
|
+
/*#__PURE__*/ _jsx(Combobox, {
|
|
177
|
+
id: "combobox-disabled",
|
|
178
|
+
options: sampleItems,
|
|
179
|
+
value: value,
|
|
180
|
+
onValueChange: setValue,
|
|
181
|
+
disabled: true,
|
|
182
|
+
placeholder: "Disabled input",
|
|
183
|
+
searchPlaceholder: "Search repositories...",
|
|
184
|
+
emptyState: "No results found"
|
|
185
|
+
})
|
|
186
|
+
]
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
//# sourceMappingURL=combobox.stories.js.map
|
|
@@ -8,6 +8,7 @@ declare const commandTriggerVariants: (props?: ({
|
|
|
8
8
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
9
9
|
type CommandTriggerProps = ComponentProps<'button'> & VariantProps<typeof commandTriggerVariants> & {
|
|
10
10
|
placeholder?: string;
|
|
11
|
+
isLoading?: boolean;
|
|
11
12
|
};
|
|
12
13
|
declare const CommandTrigger: import("react").ForwardRefExoticComponent<Omit<CommandTriggerProps, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
|
|
13
14
|
declare function Command({ className, ...props }: ComponentProps<typeof CommandPrimitive>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -18,7 +19,7 @@ type CommandInputProps = ComponentProps<typeof CommandPrimitive.Input> & {
|
|
|
18
19
|
};
|
|
19
20
|
declare function CommandInput({ className, value, onValueChange, onClear, showClearButton, ...props }: CommandInputProps): import("react/jsx-runtime").JSX.Element;
|
|
20
21
|
declare function CommandList({ className, ...props }: ComponentProps<typeof CommandPrimitive.List>): import("react/jsx-runtime").JSX.Element;
|
|
21
|
-
declare function CommandEmpty({ className, ...props }: ComponentProps<typeof CommandPrimitive.Empty>): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
declare function CommandEmpty({ className, children, ...props }: ComponentProps<typeof CommandPrimitive.Empty>): import("react/jsx-runtime").JSX.Element;
|
|
22
23
|
declare function CommandGroup({ className, ...props }: ComponentProps<typeof CommandPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
|
|
23
24
|
declare function CommandSeparator({ className, ...props }: ComponentProps<typeof CommandPrimitive.Separator>): import("react/jsx-runtime").JSX.Element;
|
|
24
25
|
declare function CommandItem({ className, ...props }: ComponentProps<typeof CommandPrimitive.Item>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -29,7 +29,7 @@ const commandTriggerVariants = cva([
|
|
|
29
29
|
size: 'base'
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
|
-
const CommandTrigger = /*#__PURE__*/ forwardRef(({ className, variant, size, placeholder, children, ...props }, ref)=>{
|
|
32
|
+
const CommandTrigger = /*#__PURE__*/ forwardRef(({ className, variant, size, placeholder, children, isLoading, ...props }, ref)=>{
|
|
33
33
|
const hasValue = Boolean(children);
|
|
34
34
|
return /*#__PURE__*/ _jsxs("button", {
|
|
35
35
|
ref: ref,
|
|
@@ -46,8 +46,11 @@ const CommandTrigger = /*#__PURE__*/ forwardRef(({ className, variant, size, pla
|
|
|
46
46
|
className: "flex-1 text-left truncate",
|
|
47
47
|
children: hasValue ? children : placeholder
|
|
48
48
|
}),
|
|
49
|
-
/*#__PURE__*/ _jsx(Icon, {
|
|
50
|
-
name: "
|
|
49
|
+
isLoading ? /*#__PURE__*/ _jsx(Icon, {
|
|
50
|
+
name: "spinner",
|
|
51
|
+
className: "size-16 text-foreground-neutral-base shrink-0"
|
|
52
|
+
}) : /*#__PURE__*/ _jsx(Icon, {
|
|
53
|
+
name: "expandUpDownLine",
|
|
51
54
|
className: "size-16 text-foreground-neutral-muted shrink-0"
|
|
52
55
|
})
|
|
53
56
|
]
|
|
@@ -149,11 +152,12 @@ function CommandList({ className, ...props }) {
|
|
|
149
152
|
...props
|
|
150
153
|
});
|
|
151
154
|
}
|
|
152
|
-
function CommandEmpty({ className, ...props }) {
|
|
155
|
+
function CommandEmpty({ className, children, ...props }) {
|
|
153
156
|
return /*#__PURE__*/ _jsx(CommandPrimitive.Empty, {
|
|
154
157
|
"data-slot": "command-empty",
|
|
155
158
|
className: cn('py-24 text-center text-sm text-foreground-neutral-muted', className),
|
|
156
|
-
...props
|
|
159
|
+
...props,
|
|
160
|
+
children: children
|
|
157
161
|
});
|
|
158
162
|
}
|
|
159
163
|
function CommandGroup({ className, ...props }) {
|
|
@@ -29,10 +29,13 @@ export function KpiCard({ label, value, variant = 'neutral', isLoading, classNam
|
|
|
29
29
|
}),
|
|
30
30
|
isLoading ? /*#__PURE__*/ _jsx(Skeleton, {
|
|
31
31
|
className: "w-48 h-20 rounded-4"
|
|
32
|
-
}) : /*#__PURE__*/ _jsx(Text, {
|
|
32
|
+
}) : typeof value === 'string' || typeof value === 'number' ? /*#__PURE__*/ _jsx(Text, {
|
|
33
33
|
size: "sm",
|
|
34
34
|
className: "font-medium text-foreground-neutral-base",
|
|
35
35
|
children: value
|
|
36
|
+
}) : /*#__PURE__*/ _jsx("div", {
|
|
37
|
+
className: "text-sm font-medium text-foreground-neutral-base",
|
|
38
|
+
children: value
|
|
36
39
|
})
|
|
37
40
|
]
|
|
38
41
|
})
|
|
@@ -14,6 +14,7 @@ export type DatePickerProps = Omit<ComponentProps<'input'>, 'size' | 'type'> & V
|
|
|
14
14
|
rightIcon?: ReactNode;
|
|
15
15
|
onClear?: () => void;
|
|
16
16
|
closeOnSelect?: boolean;
|
|
17
|
+
maxDisabledOffsetDays?: number;
|
|
17
18
|
};
|
|
18
19
|
export declare const DatePicker: import("react").ForwardRefExoticComponent<Omit<DatePickerProps, "ref"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
19
20
|
//# sourceMappingURL=date-picker.d.ts.map
|
|
@@ -3,8 +3,8 @@ import { cva } from 'class-variance-authority';
|
|
|
3
3
|
import { Calendar } from '../../components/calendar/index.js';
|
|
4
4
|
import { Icon } from '../../components/icon/index.js';
|
|
5
5
|
import { Popover, PopoverContent, PopoverTrigger } from '../../components/popover/index.js';
|
|
6
|
-
import { format } from 'date-fns';
|
|
7
|
-
import { forwardRef, useState } from 'react';
|
|
6
|
+
import { addDays, format, subDays } from 'date-fns';
|
|
7
|
+
import { forwardRef, useMemo, useState } from 'react';
|
|
8
8
|
import { cn } from '../../utils/cn.js';
|
|
9
9
|
export const datePickerVariants = cva('relative flex items-center rounded-6 shadow-button-neutral transition-[background-color,box-shadow] outline-none', {
|
|
10
10
|
variants: {
|
|
@@ -28,10 +28,22 @@ export const datePickerVariants = cva('relative flex items-center rounded-6 shad
|
|
|
28
28
|
state: 'default'
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
-
export const DatePicker = /*#__PURE__*/ forwardRef(({ className, variant, size, state, date, onDateSelect, placeholder = 'DD/MM/YYYY', dateFormat = 'dd/MM/yyyy', leftIcon, rightIcon, onClear, disabled, closeOnSelect = false, ...props }, ref)=>{
|
|
31
|
+
export const DatePicker = /*#__PURE__*/ forwardRef(({ className, variant, size, state, date, onDateSelect, placeholder = 'DD/MM/YYYY', dateFormat = 'dd/MM/yyyy', leftIcon, rightIcon, onClear, disabled, closeOnSelect = false, maxDisabledOffsetDays, ...props }, ref)=>{
|
|
32
32
|
const [open, setOpen] = useState(false);
|
|
33
33
|
const isDisabled = disabled || state === 'disabled';
|
|
34
34
|
const displayValue = date ? format(date, dateFormat) : '';
|
|
35
|
+
// Disable dates beyond maxDisabledDays before and after today
|
|
36
|
+
const disabledDates = useMemo(()=>{
|
|
37
|
+
if (!maxDisabledOffsetDays) return undefined;
|
|
38
|
+
const today = new Date();
|
|
39
|
+
const minDate = subDays(today, maxDisabledOffsetDays);
|
|
40
|
+
const maxDate = addDays(today, maxDisabledOffsetDays);
|
|
41
|
+
return (date)=>{
|
|
42
|
+
return date < minDate || date > maxDate;
|
|
43
|
+
};
|
|
44
|
+
}, [
|
|
45
|
+
maxDisabledOffsetDays
|
|
46
|
+
]);
|
|
35
47
|
const handleSelect = (selectedDate)=>{
|
|
36
48
|
onDateSelect?.(selectedDate);
|
|
37
49
|
if (closeOnSelect) {
|
|
@@ -103,7 +115,11 @@ export const DatePicker = /*#__PURE__*/ forwardRef(({ className, variant, size,
|
|
|
103
115
|
children: /*#__PURE__*/ _jsx(Calendar, {
|
|
104
116
|
mode: "single",
|
|
105
117
|
selected: date,
|
|
106
|
-
onSelect: handleSelect
|
|
118
|
+
onSelect: handleSelect,
|
|
119
|
+
disabled: disabledDates,
|
|
120
|
+
formatters: {
|
|
121
|
+
formatWeekdayName: (date)=>format(date, 'EEEEE')
|
|
122
|
+
}
|
|
107
123
|
})
|
|
108
124
|
})
|
|
109
125
|
]
|
|
@@ -51,6 +51,22 @@ export const DatePickerStory = {
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
|
+
export const DatePickerWithThresholdStory = {
|
|
55
|
+
play: (ctx)=>openCalendarAndScreenshot(ctx, 'DatePicker With Threshold Calendar Open'),
|
|
56
|
+
render: ()=>{
|
|
57
|
+
const [date, setDate] = useState(new Date());
|
|
58
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
59
|
+
className: "relative flex h-600 w-500 items-center justify-center rounded-16 bg-background-subtle-base shadow-tooltip overflow-visible",
|
|
60
|
+
children: /*#__PURE__*/ _jsx(DatePicker, {
|
|
61
|
+
date: date,
|
|
62
|
+
onDateSelect: setDate,
|
|
63
|
+
onClear: ()=>setDate(undefined),
|
|
64
|
+
placeholder: "DD/MM/YYYY",
|
|
65
|
+
maxDisabledOffsetDays: 30
|
|
66
|
+
})
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
};
|
|
54
70
|
export const DateRangePickerStory = {
|
|
55
71
|
play: (ctx)=>openCalendarAndScreenshot(ctx, 'DateRangePicker Calendar Open'),
|
|
56
72
|
render: ()=>{
|
|
@@ -19,6 +19,7 @@ export type DateTimeRangePickerProps = Omit<ComponentProps<'input'>, 'size' | 't
|
|
|
19
19
|
onClear?: () => void;
|
|
20
20
|
numberOfMonths?: number;
|
|
21
21
|
closeOnSelect?: boolean;
|
|
22
|
+
maxRangeDays?: number;
|
|
22
23
|
};
|
|
23
24
|
export declare const DateTimeRangePicker: import("react").ForwardRefExoticComponent<Omit<DateTimeRangePickerProps, "ref"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
24
25
|
//# sourceMappingURL=date-time-range-picker.d.ts.map
|
|
@@ -3,8 +3,8 @@ import { cva } from 'class-variance-authority';
|
|
|
3
3
|
import { Calendar } from '../../components/calendar/index.js';
|
|
4
4
|
import { Icon } from '../../components/icon/index.js';
|
|
5
5
|
import { Popover, PopoverContent, PopoverTrigger } from '../../components/popover/index.js';
|
|
6
|
-
import { format } from 'date-fns';
|
|
7
|
-
import { forwardRef, useState } from 'react';
|
|
6
|
+
import { addDays, differenceInDays, format } from 'date-fns';
|
|
7
|
+
import { forwardRef, useMemo, useState } from 'react';
|
|
8
8
|
import { cn } from '../../utils/cn.js';
|
|
9
9
|
export const dateTimeRangePickerVariants = cva('min-w-240 relative flex items-center rounded-6 shadow-button-neutral transition-[background-color,box-shadow] outline-none', {
|
|
10
10
|
variants: {
|
|
@@ -28,28 +28,52 @@ export const dateTimeRangePickerVariants = cva('min-w-240 relative flex items-ce
|
|
|
28
28
|
state: 'default'
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
-
export const DateTimeRangePicker = /*#__PURE__*/ forwardRef(({ className, variant, size, state, dateRange, onDateRangeSelect, placeholder = 'DD/MM/YYYY - DD/MM/YYYY', dateFormat = 'dd/MM/yyyy', leftIcon, rightIcon, onClear, disabled, numberOfMonths = 2, closeOnSelect = false, ...props }, ref)=>{
|
|
31
|
+
export const DateTimeRangePicker = /*#__PURE__*/ forwardRef(({ className, variant, size, state, dateRange, onDateRangeSelect, placeholder = 'DD/MM/YYYY - DD/MM/YYYY', dateFormat = 'dd/MM/yyyy', leftIcon, rightIcon, onClear, disabled, numberOfMonths = 2, closeOnSelect = false, maxRangeDays, ...props }, ref)=>{
|
|
32
32
|
const [open, setOpen] = useState(false);
|
|
33
33
|
const isDisabled = disabled || state === 'disabled';
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const startDate = dateRange?.start;
|
|
35
|
+
const endDate = dateRange?.end;
|
|
36
|
+
const hasRange = Boolean(startDate && endDate);
|
|
37
|
+
// Format display value
|
|
38
|
+
const displayValue = hasRange && startDate && endDate ? `${format(startDate, dateFormat)} - ${format(endDate, dateFormat)}` : '';
|
|
39
|
+
// Convert to react-day-picker format
|
|
40
|
+
const dayPickerRange = startDate || endDate ? {
|
|
41
|
+
from: startDate,
|
|
42
|
+
to: endDate
|
|
40
43
|
} : undefined;
|
|
44
|
+
// Get default month for calendar (prioritize selected start date, then today)
|
|
45
|
+
const defaultMonth = startDate ?? new Date();
|
|
46
|
+
// Disable dates beyond maxRangeDays (only if maxRangeDays is provided)
|
|
47
|
+
const disabledDates = useMemo(()=>{
|
|
48
|
+
if (!startDate || maxRangeDays === undefined) return undefined;
|
|
49
|
+
return (date)=>{
|
|
50
|
+
const daysFromStart = differenceInDays(date, startDate);
|
|
51
|
+
return daysFromStart > maxRangeDays;
|
|
52
|
+
};
|
|
53
|
+
}, [
|
|
54
|
+
startDate,
|
|
55
|
+
maxRangeDays
|
|
56
|
+
]);
|
|
41
57
|
const handleSelect = (selectedRange)=>{
|
|
42
|
-
if (selectedRange) {
|
|
43
|
-
onDateRangeSelect?.({
|
|
44
|
-
start: selectedRange.from,
|
|
45
|
-
end: selectedRange.to
|
|
46
|
-
});
|
|
47
|
-
// Only close if both dates are selected and closeOnSelect is true
|
|
48
|
-
if (closeOnSelect && selectedRange.from && selectedRange.to) {
|
|
49
|
-
setOpen(false);
|
|
50
|
-
}
|
|
51
|
-
} else {
|
|
58
|
+
if (!selectedRange) {
|
|
52
59
|
onDateRangeSelect?.(undefined);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const { from, to } = selectedRange;
|
|
63
|
+
let finalEndDate = to;
|
|
64
|
+
// Cap end date to maxRangeDays if both dates are selected and maxRangeDays is provided
|
|
65
|
+
if (from && to && maxRangeDays !== undefined) {
|
|
66
|
+
const daysFromStart = differenceInDays(to, from);
|
|
67
|
+
if (daysFromStart > maxRangeDays) {
|
|
68
|
+
finalEndDate = addDays(from, maxRangeDays);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
onDateRangeSelect?.({
|
|
72
|
+
start: from,
|
|
73
|
+
end: finalEndDate
|
|
74
|
+
});
|
|
75
|
+
if (closeOnSelect && from && finalEndDate) {
|
|
76
|
+
setOpen(false);
|
|
53
77
|
}
|
|
54
78
|
};
|
|
55
79
|
const handleClear = (e)=>{
|
|
@@ -98,11 +122,11 @@ export const DateTimeRangePicker = /*#__PURE__*/ forwardRef(({ className, varian
|
|
|
98
122
|
/*#__PURE__*/ _jsx("button", {
|
|
99
123
|
type: "button",
|
|
100
124
|
onClick: handleClear,
|
|
101
|
-
className: cn('flex items-center justify-center shrink-0 transition-colors hover:text-foreground-neutral-base', size === 'small' ? 'size-28' : 'size-32', hasRange && onClear && !isDisabled ? 'visible' : 'invisible'),
|
|
125
|
+
className: cn('flex items-center justify-center shrink-0 transition-colors hover:text-foreground-neutral-base cursor-pointer', size === 'small' ? 'size-28' : 'size-32', hasRange && onClear && !isDisabled ? 'visible' : 'invisible'),
|
|
102
126
|
"aria-label": "Clear date range",
|
|
103
127
|
children: /*#__PURE__*/ _jsx(Icon, {
|
|
104
128
|
name: "closeLine",
|
|
105
|
-
className: "size-16 text-foreground-neutral-muted"
|
|
129
|
+
className: "size-16 text-foreground-neutral-muted hover:text-foreground-neutral-subtle transition-colors"
|
|
106
130
|
})
|
|
107
131
|
}),
|
|
108
132
|
rightIcon && !hasRange && /*#__PURE__*/ _jsx("div", {
|
|
@@ -116,10 +140,14 @@ export const DateTimeRangePicker = /*#__PURE__*/ forwardRef(({ className, varian
|
|
|
116
140
|
align: "start",
|
|
117
141
|
children: /*#__PURE__*/ _jsx(Calendar, {
|
|
118
142
|
mode: "range",
|
|
119
|
-
defaultMonth:
|
|
143
|
+
defaultMonth: defaultMonth,
|
|
120
144
|
selected: dayPickerRange,
|
|
121
145
|
onSelect: handleSelect,
|
|
122
|
-
numberOfMonths: numberOfMonths
|
|
146
|
+
numberOfMonths: numberOfMonths,
|
|
147
|
+
disabled: disabledDates,
|
|
148
|
+
formatters: {
|
|
149
|
+
formatWeekdayName: (date)=>format(date, 'EEEEE')
|
|
150
|
+
}
|
|
123
151
|
})
|
|
124
152
|
})
|
|
125
153
|
]
|