@syscore/ui-library 1.27.3 → 2.0.0-beta-publish-workflow-beta.1
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/client/App.tsx +0 -2
- package/client/assets/alert/icon-clear.svg +4 -0
- package/client/assets/alert/icon-done.svg +3 -0
- package/client/assets/avatar-identity/photo.png +0 -0
- package/client/assets/avatar-identity/placeholder-icon.svg +8 -0
- package/client/assets/breadcrumb/icon-ellipsis.svg +5 -0
- package/client/assets/breadcrumb/icon-home.svg +3 -0
- package/client/assets/breadcrumb/icon-separator.svg +3 -0
- package/client/assets/button-v01/icon-back.svg +4 -0
- package/client/assets/button-v01/icon-check.svg +3 -0
- package/client/assets/button-v01/icon-close.svg +4 -0
- package/client/assets/button-v01/icon-delete.svg +3 -0
- package/client/assets/button-v01/icon-device.svg +3 -0
- package/client/assets/dropdown/icon-carrot-contract.svg +3 -0
- package/client/assets/dropdown/icon-carrot-expand.svg +3 -0
- package/client/assets/dropdown/icon-clear.svg +4 -0
- package/client/assets/dropdown/icon-enter.svg +3 -0
- package/client/components/icons/UtilityChangeType.tsx +21 -0
- package/client/components/ui/alert-dialog-panel.tsx +246 -0
- package/client/components/ui/alert-v02.tsx +214 -0
- package/client/components/ui/app-bar.tsx +299 -0
- package/client/components/ui/avatar-identity.tsx +122 -0
- package/client/components/ui/banner.tsx +108 -0
- package/client/components/ui/bottom-navigation.tsx +223 -0
- package/client/components/ui/breadcrumb-trail.tsx +170 -0
- package/client/components/ui/button-v01.tsx +238 -0
- package/client/components/ui/button.tsx +2 -0
- package/client/components/ui/card.tsx +108 -26
- package/client/components/ui/code-badge.tsx +62 -0
- package/client/components/ui/date-picker.tsx +188 -0
- package/client/components/ui/dropdown.tsx +448 -0
- package/client/components/ui/empty-state.tsx +197 -0
- package/client/components/ui/file-upload.tsx +214 -0
- package/client/components/ui/footer.tsx +179 -0
- package/client/components/ui/layout.tsx +1182 -0
- package/client/components/ui/pagination-v01.tsx +157 -0
- package/client/components/ui/password-field-v01.tsx +67 -0
- package/client/components/ui/search-field-v01.tsx +192 -0
- package/client/components/ui/section-heading.tsx +49 -0
- package/client/components/ui/sidebar.tsx +2 -3
- package/client/components/ui/stepper.tsx +148 -0
- package/client/components/ui/switch-v01.tsx +71 -0
- package/client/components/ui/system-bar.tsx +119 -0
- package/client/components/ui/table-v01.tsx +230 -0
- package/client/components/ui/tabs-v01.tsx +99 -0
- package/client/components/ui/tag-v02.tsx +113 -0
- package/client/components/ui/text-area-v01.tsx +33 -0
- package/client/components/ui/text-field-v01.tsx +108 -0
- package/client/components/ui/timeline.tsx +181 -0
- package/client/components/ui/toast-v01.tsx +206 -0
- package/client/components/ui/tooltip.tsx +264 -71
- package/client/global.css +9565 -4378
- package/client/storybook.css +125 -0
- package/client/ui/Accordion.stories.tsx +1 -1
- package/client/ui/AlertDialogPanel/AlertDialogPanel.stories.tsx +150 -0
- package/client/ui/AlertV02/AlertV02.stories.tsx +188 -0
- package/client/ui/AppBar/app-bar.stories.tsx +280 -0
- package/client/ui/AspectRatio.stories.tsx +1 -1
- package/client/ui/AvatarIdentity/AvatarIdentity.stories.tsx +77 -0
- package/client/ui/Banner/banner.stories.tsx +238 -0
- package/client/ui/BottomNavigation/bottom-navigation.stories.tsx +285 -0
- package/client/ui/BreadcrumbTrail/BreadcrumbTrail.stories.tsx +232 -0
- package/client/ui/Button.stories.tsx +1 -1
- package/client/ui/ButtonV01/ButtonV01.stories.tsx +417 -0
- package/client/ui/Calendar/Calendar.stories.tsx +1 -1
- package/client/ui/Card.stories.tsx +285 -168
- package/client/ui/Carousel/Carousel.stories.tsx +1 -1
- package/client/ui/Chart/Chart.stories.tsx +1 -1
- package/client/ui/Checkbox.stories.tsx +1 -1
- package/client/ui/Collapsible/Collapsible.stories.tsx +1 -1
- package/client/ui/Colors.stories.tsx +1 -1
- package/client/ui/Command/Command.stories.tsx +1 -1
- package/client/ui/ContextMenu/ContextMenu.stories.tsx +1 -1
- package/client/ui/DatePicker/DatePicker.stories.tsx +293 -0
- package/client/ui/Dialog.stories.tsx +1 -1
- package/client/ui/Drawer/Drawer.stories.tsx +1 -1
- package/client/ui/Dropdown/Dropdown.stories.tsx +205 -0
- package/client/ui/EmptyState/empty-state.stories.tsx +251 -0
- package/client/ui/FileUpload/FileUpload.stories.tsx +218 -0
- package/client/ui/Footer/footer.stories.tsx +194 -0
- package/client/ui/Form/Form.stories.tsx +1 -1
- package/client/ui/Hero.stories.tsx +1 -1
- package/client/ui/HoverCard/HoverCard.stories.tsx +1 -1
- package/client/ui/Icons.stories.tsx +1 -1
- package/client/ui/Input.stories.tsx +1 -1
- package/client/ui/InputOTP/InputOTP.stories.tsx +1 -1
- package/client/ui/Label.stories.tsx +1 -1
- package/client/ui/Layout/Center.stories.tsx +100 -0
- package/client/ui/Layout/Columns.stories.tsx +136 -0
- package/client/ui/Layout/Container.stories.tsx +104 -0
- package/client/ui/Layout/FormLayout.stories.tsx +144 -0
- package/client/ui/Layout/Grid.stories.tsx +158 -0
- package/client/ui/Layout/GridSpan.stories.tsx +75 -0
- package/client/ui/Layout/HStack.stories.tsx +128 -0
- package/client/ui/Layout/Layout.stories.tsx +287 -0
- package/client/ui/Layout/LayoutContent.stories.tsx +91 -0
- package/client/ui/Layout/LayoutFooter.stories.tsx +77 -0
- package/client/ui/Layout/LayoutHeader.stories.tsx +104 -0
- package/client/ui/Layout/LayoutPanel.stories.tsx +143 -0
- package/client/ui/Layout/Positioned.stories.tsx +113 -0
- package/client/ui/Layout/Section.stories.tsx +84 -0
- package/client/ui/Layout/ShowHide.stories.tsx +99 -0
- package/client/ui/Layout/Spacer.stories.tsx +149 -0
- package/client/ui/Layout/Stack.stories.tsx +69 -0
- package/client/ui/Layout/StackItem.stories.tsx +124 -0
- package/client/ui/Layout/VStack.stories.tsx +101 -0
- package/client/ui/Layout/controls.ts +33 -0
- package/client/ui/Layout/demo.tsx +37 -0
- package/client/ui/Menubar/Menubar.stories.tsx +1 -1
- package/client/ui/MobileNav.stories.tsx +1 -1
- package/client/ui/Navigation.stories.tsx +1 -1
- package/client/ui/NavigationMenu/NavigationMenu.stories.tsx +1 -1
- package/client/ui/PageHeader.stories.tsx +13 -13
- package/client/ui/Pagination/Pagination.stories.tsx +178 -98
- package/client/ui/Pagination/PaginationLegacy.stories.tsx +121 -0
- package/client/ui/Panel.stories.tsx +1 -1
- package/client/ui/Popover/Popover.stories.tsx +1 -1
- package/client/ui/Progress/Progress.stories.tsx +1 -1
- package/client/ui/RadioGroup/RadioGroup.stories.tsx +1 -1
- package/client/ui/Resizable/Resizable.stories.tsx +1 -1
- package/client/ui/ScrollArea/ScrollArea.stories.tsx +1 -1
- package/client/ui/SearchField/SearchField.stories.tsx +153 -0
- package/client/ui/{SearchField.stories.tsx → SearchField/SearchFieldLegacy.stories.tsx} +2 -2
- package/client/ui/SectionBadge.stories.tsx +1 -1
- package/client/ui/Select.stories.tsx +1 -1
- package/client/ui/Separator/Separator.stories.tsx +1 -1
- package/client/ui/Sheet/Sheet.stories.tsx +1 -1
- package/client/ui/Sidebar/Sidebar.stories.tsx +57 -8
- package/client/ui/Skeleton/Skeleton.stories.tsx +1 -1
- package/client/ui/Slider/Slider.stories.tsx +1 -1
- package/client/ui/StandardNavigation.stories.tsx +1 -1
- package/client/ui/Stepper/Stepper.stories.tsx +344 -0
- package/client/ui/Switch.stories.tsx +1 -1
- package/client/ui/SwitchV01/SwitchV01.stories.tsx +152 -0
- package/client/ui/SystemBar/system-bar.stories.tsx +179 -0
- package/client/ui/Table/TableV01.stories.tsx +256 -0
- package/client/ui/Tabs.stories.tsx +1 -1
- package/client/ui/TabsV01/TabsV01.stories.tsx +144 -0
- package/client/ui/Tag.stories.tsx +1 -1
- package/client/ui/TagV02/TagStatusV02.stories.tsx +132 -0
- package/client/ui/TagV02/TagV02.stories.tsx +142 -0
- package/client/ui/TextAreaV01/TextAreaV01.stories.tsx +146 -0
- package/client/ui/TextFieldV01/PasswordFieldV01.stories.tsx +161 -0
- package/client/ui/TextFieldV01/TextFieldV01.stories.tsx +160 -0
- package/client/ui/Textarea.stories.tsx +1 -1
- package/client/ui/Timeline/timeline.stories.tsx +404 -0
- package/client/ui/Toast/Toast.stories.tsx +1 -1
- package/client/ui/ToastV01/ToastV01.stories.tsx +201 -0
- package/client/ui/Toaster/Toaster.stories.tsx +1 -1
- package/client/ui/Toggle.stories.tsx +1 -1
- package/client/ui/Tooltip.stories.tsx +287 -114
- package/client/ui/Typography.stories.tsx +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +649 -13
- package/dist/index.es.js +4401 -651
- package/package.json +1 -1
- package/client/components/ui/badge.tsx +0 -33
- package/client/components/ui/sonner.tsx +0 -26
- package/client/components/ui/toggle-group.tsx +0 -76
- package/client/ui/Alert/Alert.stories.tsx +0 -82
- package/client/ui/AlertDialog/AlertDialog.stories.tsx +0 -106
- package/client/ui/Avatar/Avatar.stories.tsx +0 -94
- package/client/ui/Badge/Badge.stories.tsx +0 -60
- package/client/ui/Breadcrumb/Breadcrumb.stories.tsx +0 -97
- package/client/ui/DropdownMenu/DropdownMenu.stories.tsx +0 -139
- package/client/ui/Sonner/Sonner.stories.tsx +0 -48
- package/client/ui/Table/Table.stories.tsx +0 -135
- package/client/ui/ToggleGroup/ToggleGroup.stories.tsx +0 -88
|
@@ -1,18 +1,37 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2
3
|
|
|
3
4
|
import { cn } from "@/lib/utils";
|
|
4
5
|
import { Text } from "./typography";
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
const cardVariants = cva("card", {
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: "card--default",
|
|
11
|
+
outlined: "card--outlined",
|
|
12
|
+
elevated: "card--elevated",
|
|
13
|
+
filled: "card--filled",
|
|
14
|
+
interactive: "card--interactive",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
variant: "default",
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
interface CardProps
|
|
23
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
24
|
+
VariantProps<typeof cardVariants> {}
|
|
25
|
+
|
|
26
|
+
const Card = React.forwardRef<HTMLDivElement, CardProps>(
|
|
27
|
+
({ className, variant, ...props }, ref) => (
|
|
28
|
+
<div
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={cn(cardVariants({ variant }), className)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
),
|
|
34
|
+
);
|
|
16
35
|
Card.displayName = "Card";
|
|
17
36
|
|
|
18
37
|
const CardHeader = React.forwardRef<
|
|
@@ -71,6 +90,65 @@ const CardFooter = React.forwardRef<
|
|
|
71
90
|
));
|
|
72
91
|
CardFooter.displayName = "CardFooter";
|
|
73
92
|
|
|
93
|
+
const CardMedia = React.forwardRef<
|
|
94
|
+
HTMLDivElement,
|
|
95
|
+
React.HTMLAttributes<HTMLDivElement> & { src?: string; alt?: string; height?: number }
|
|
96
|
+
>(({ className, src, alt = "", height = 200, children, ...props }, ref) => (
|
|
97
|
+
<div ref={ref} className={cn("card-media", className)} style={{ height }} {...props}>
|
|
98
|
+
{src ? (
|
|
99
|
+
<img src={src} alt={alt} className="card-media__img" />
|
|
100
|
+
) : (
|
|
101
|
+
children
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
));
|
|
105
|
+
CardMedia.displayName = "CardMedia";
|
|
106
|
+
|
|
107
|
+
interface CardBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
108
|
+
color?: "default" | "success" | "warning" | "error" | "info";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const CardBadge = React.forwardRef<HTMLSpanElement, CardBadgeProps>(
|
|
112
|
+
({ className, color = "default", ...props }, ref) => (
|
|
113
|
+
<span
|
|
114
|
+
ref={ref}
|
|
115
|
+
className={cn("card-badge", `card-badge--${color}`, className)}
|
|
116
|
+
{...props}
|
|
117
|
+
/>
|
|
118
|
+
),
|
|
119
|
+
);
|
|
120
|
+
CardBadge.displayName = "CardBadge";
|
|
121
|
+
|
|
122
|
+
const CardActions = React.forwardRef<
|
|
123
|
+
HTMLDivElement,
|
|
124
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
125
|
+
>(({ className, ...props }, ref) => (
|
|
126
|
+
<div ref={ref} className={cn("card-actions", className)} {...props} />
|
|
127
|
+
));
|
|
128
|
+
CardActions.displayName = "CardActions";
|
|
129
|
+
|
|
130
|
+
interface CardMetricProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
131
|
+
value: string | number;
|
|
132
|
+
label: string;
|
|
133
|
+
trend?: "up" | "down" | "neutral";
|
|
134
|
+
trendValue?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const CardMetric = React.forwardRef<HTMLDivElement, CardMetricProps>(
|
|
138
|
+
({ className, value, label, trend, trendValue, ...props }, ref) => (
|
|
139
|
+
<div ref={ref} className={cn("card-metric", className)} {...props}>
|
|
140
|
+
<span className="card-metric__value">{value}</span>
|
|
141
|
+
<span className="card-metric__label">{label}</span>
|
|
142
|
+
{trend && trendValue && (
|
|
143
|
+
<span className={cn("card-metric__trend", `card-metric__trend--${trend}`)}>
|
|
144
|
+
{trend === "up" ? "↑" : trend === "down" ? "↓" : "→"} {trendValue}
|
|
145
|
+
</span>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
CardMetric.displayName = "CardMetric";
|
|
151
|
+
|
|
74
152
|
interface CardWithIconProps {
|
|
75
153
|
icon?: React.ComponentType<React.SVGProps<SVGSVGElement> | { className?: string }>;
|
|
76
154
|
title: string;
|
|
@@ -78,22 +156,22 @@ interface CardWithIconProps {
|
|
|
78
156
|
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
|
79
157
|
}
|
|
80
158
|
|
|
81
|
-
const CardWithIcon = React.forwardRef<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
)
|
|
159
|
+
const CardWithIcon = React.forwardRef<HTMLDivElement, CardWithIconProps>(
|
|
160
|
+
({ icon: Icon, title, description, onClick }, ref) => (
|
|
161
|
+
<Card
|
|
162
|
+
ref={ref}
|
|
163
|
+
variant="interactive"
|
|
164
|
+
className="card-with-icon"
|
|
165
|
+
onClick={onClick}
|
|
166
|
+
>
|
|
167
|
+
<div className="card-with-icon__header">
|
|
168
|
+
{Icon && <Icon className="card-with-icon__icon" />}
|
|
169
|
+
<Text as="h3" variant="overline-large">{title}</Text>
|
|
170
|
+
</div>
|
|
171
|
+
<Text as="p" variant="body-base">{description}</Text>
|
|
172
|
+
</Card>
|
|
173
|
+
),
|
|
174
|
+
);
|
|
97
175
|
CardWithIcon.displayName = "CardWithIcon";
|
|
98
176
|
|
|
99
177
|
export {
|
|
@@ -103,5 +181,9 @@ export {
|
|
|
103
181
|
CardTitle,
|
|
104
182
|
CardDescription,
|
|
105
183
|
CardContent,
|
|
184
|
+
CardMedia,
|
|
185
|
+
CardBadge,
|
|
186
|
+
CardActions,
|
|
187
|
+
CardMetric,
|
|
106
188
|
CardWithIcon,
|
|
107
189
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
/** Figma `code_theme_*` / `code_strategy_*`. */
|
|
6
|
+
export type CodeBadgeConcept =
|
|
7
|
+
| "mind"
|
|
8
|
+
| "community"
|
|
9
|
+
| "movement"
|
|
10
|
+
| "water"
|
|
11
|
+
| "air"
|
|
12
|
+
| "light"
|
|
13
|
+
| "thermal-comfort"
|
|
14
|
+
| "nourishment"
|
|
15
|
+
| "sound"
|
|
16
|
+
| "materials"
|
|
17
|
+
| "inactive";
|
|
18
|
+
|
|
19
|
+
/** `theme` is the filled chip, `strategy` the tinted one. */
|
|
20
|
+
export type CodeBadgeVariant = "theme" | "strategy";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Strategy chips are tinted at different strengths depending on where they
|
|
24
|
+
* sit. Breadcrumbs use 8%/16%; tables use 12%/24% (which is also what
|
|
25
|
+
* client/lib/concept-colors.ts records). Figma specifies both — neither is a
|
|
26
|
+
* mistake, so the strength is a variant rather than a constant.
|
|
27
|
+
*/
|
|
28
|
+
export type CodeBadgeTone = "trail" | "table";
|
|
29
|
+
|
|
30
|
+
export interface CodeBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
31
|
+
concept?: CodeBadgeConcept;
|
|
32
|
+
variant?: CodeBadgeVariant;
|
|
33
|
+
tone?: CodeBadgeTone;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CodeBadge = React.forwardRef<HTMLSpanElement, CodeBadgeProps>(
|
|
37
|
+
(
|
|
38
|
+
{
|
|
39
|
+
className,
|
|
40
|
+
variant = "theme",
|
|
41
|
+
concept = "community",
|
|
42
|
+
tone = "trail",
|
|
43
|
+
...props
|
|
44
|
+
},
|
|
45
|
+
ref,
|
|
46
|
+
) => (
|
|
47
|
+
<span
|
|
48
|
+
ref={ref}
|
|
49
|
+
className={cn(
|
|
50
|
+
"code-badge number-small font-semibold",
|
|
51
|
+
variant === "theme" ? "code-badge--theme" : "code-badge--strategy",
|
|
52
|
+
`code-badge--${concept}`,
|
|
53
|
+
tone === "table" && "code-badge--tone-table",
|
|
54
|
+
className,
|
|
55
|
+
)}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
CodeBadge.displayName = "CodeBadge";
|
|
61
|
+
|
|
62
|
+
export { CodeBadge };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { format } from "date-fns";
|
|
3
|
+
import { Calendar } from "@/components/ui/calendar";
|
|
4
|
+
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
export interface DatePickerProps {
|
|
8
|
+
value?: Date;
|
|
9
|
+
onChange?: (date: Date | undefined) => void;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
disabledDates?: (date: Date) => boolean;
|
|
13
|
+
fromDate?: Date;
|
|
14
|
+
toDate?: Date;
|
|
15
|
+
dateFormat?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
align?: "start" | "center" | "end";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
|
|
21
|
+
(
|
|
22
|
+
{
|
|
23
|
+
value,
|
|
24
|
+
onChange,
|
|
25
|
+
placeholder = "Select date",
|
|
26
|
+
disabled = false,
|
|
27
|
+
disabledDates,
|
|
28
|
+
fromDate,
|
|
29
|
+
toDate,
|
|
30
|
+
dateFormat = "MMM d, yyyy",
|
|
31
|
+
className,
|
|
32
|
+
align = "start",
|
|
33
|
+
},
|
|
34
|
+
ref,
|
|
35
|
+
) => {
|
|
36
|
+
const [open, setOpen] = React.useState(false);
|
|
37
|
+
|
|
38
|
+
const handleSelect = (date: Date | undefined) => {
|
|
39
|
+
onChange?.(date);
|
|
40
|
+
setOpen(false);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
45
|
+
<PopoverTrigger asChild>
|
|
46
|
+
<button
|
|
47
|
+
ref={ref}
|
|
48
|
+
type="button"
|
|
49
|
+
disabled={disabled}
|
|
50
|
+
aria-haspopup="dialog"
|
|
51
|
+
aria-expanded={open}
|
|
52
|
+
className={cn(
|
|
53
|
+
"date-picker-trigger",
|
|
54
|
+
!value && "date-picker-trigger--placeholder",
|
|
55
|
+
disabled && "date-picker-trigger--disabled",
|
|
56
|
+
className,
|
|
57
|
+
)}
|
|
58
|
+
>
|
|
59
|
+
<span className="date-picker-icon" aria-hidden="true">
|
|
60
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
61
|
+
<rect x="1" y="3" width="14" height="12" rx="2" stroke="currentColor" strokeWidth="1.5" />
|
|
62
|
+
<path d="M1 7h14" stroke="currentColor" strokeWidth="1.5" />
|
|
63
|
+
<path d="M5 1v4M11 1v4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
|
64
|
+
</svg>
|
|
65
|
+
</span>
|
|
66
|
+
<span className="date-picker-value">
|
|
67
|
+
{value ? format(value, dateFormat) : placeholder}
|
|
68
|
+
</span>
|
|
69
|
+
<span className="date-picker-chevron" aria-hidden="true">
|
|
70
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
71
|
+
<path d="M2 4l4 4 4-4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
72
|
+
</svg>
|
|
73
|
+
</span>
|
|
74
|
+
</button>
|
|
75
|
+
</PopoverTrigger>
|
|
76
|
+
<PopoverContent
|
|
77
|
+
className="date-picker-popover"
|
|
78
|
+
align={align}
|
|
79
|
+
sideOffset={6}
|
|
80
|
+
>
|
|
81
|
+
<Calendar
|
|
82
|
+
mode="single"
|
|
83
|
+
selected={value}
|
|
84
|
+
onSelect={handleSelect}
|
|
85
|
+
disabled={disabledDates}
|
|
86
|
+
fromDate={fromDate}
|
|
87
|
+
toDate={toDate}
|
|
88
|
+
initialFocus
|
|
89
|
+
/>
|
|
90
|
+
</PopoverContent>
|
|
91
|
+
</Popover>
|
|
92
|
+
);
|
|
93
|
+
},
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
DatePicker.displayName = "DatePicker";
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// DateRangePicker
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
export interface DateRange {
|
|
102
|
+
from: Date | undefined;
|
|
103
|
+
to?: Date | undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface DateRangePickerProps {
|
|
107
|
+
value?: DateRange;
|
|
108
|
+
onChange?: (range: DateRange | undefined) => void;
|
|
109
|
+
placeholder?: string;
|
|
110
|
+
disabled?: boolean;
|
|
111
|
+
dateFormat?: string;
|
|
112
|
+
className?: string;
|
|
113
|
+
align?: "start" | "center" | "end";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const DateRangePicker = React.forwardRef<HTMLButtonElement, DateRangePickerProps>(
|
|
117
|
+
(
|
|
118
|
+
{
|
|
119
|
+
value,
|
|
120
|
+
onChange,
|
|
121
|
+
placeholder = "Select date range",
|
|
122
|
+
disabled = false,
|
|
123
|
+
dateFormat = "MMM d, yyyy",
|
|
124
|
+
className,
|
|
125
|
+
align = "start",
|
|
126
|
+
},
|
|
127
|
+
ref,
|
|
128
|
+
) => {
|
|
129
|
+
const [open, setOpen] = React.useState(false);
|
|
130
|
+
|
|
131
|
+
const label = React.useMemo(() => {
|
|
132
|
+
if (!value?.from) return null;
|
|
133
|
+
if (!value.to) return format(value.from, dateFormat);
|
|
134
|
+
return `${format(value.from, dateFormat)} — ${format(value.to, dateFormat)}`;
|
|
135
|
+
}, [value, dateFormat]);
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
139
|
+
<PopoverTrigger asChild>
|
|
140
|
+
<button
|
|
141
|
+
ref={ref}
|
|
142
|
+
type="button"
|
|
143
|
+
disabled={disabled}
|
|
144
|
+
aria-haspopup="dialog"
|
|
145
|
+
aria-expanded={open}
|
|
146
|
+
className={cn(
|
|
147
|
+
"date-picker-trigger",
|
|
148
|
+
!label && "date-picker-trigger--placeholder",
|
|
149
|
+
disabled && "date-picker-trigger--disabled",
|
|
150
|
+
className,
|
|
151
|
+
)}
|
|
152
|
+
>
|
|
153
|
+
<span className="date-picker-icon" aria-hidden="true">
|
|
154
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
155
|
+
<rect x="1" y="3" width="14" height="12" rx="2" stroke="currentColor" strokeWidth="1.5" />
|
|
156
|
+
<path d="M1 7h14" stroke="currentColor" strokeWidth="1.5" />
|
|
157
|
+
<path d="M5 1v4M11 1v4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
|
|
158
|
+
</svg>
|
|
159
|
+
</span>
|
|
160
|
+
<span className="date-picker-value">{label ?? placeholder}</span>
|
|
161
|
+
<span className="date-picker-chevron" aria-hidden="true">
|
|
162
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
163
|
+
<path d="M2 4l4 4 4-4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
164
|
+
</svg>
|
|
165
|
+
</span>
|
|
166
|
+
</button>
|
|
167
|
+
</PopoverTrigger>
|
|
168
|
+
<PopoverContent
|
|
169
|
+
className="date-picker-popover"
|
|
170
|
+
align={align}
|
|
171
|
+
sideOffset={6}
|
|
172
|
+
>
|
|
173
|
+
<Calendar
|
|
174
|
+
mode="range"
|
|
175
|
+
selected={value}
|
|
176
|
+
onSelect={onChange as (range: DateRange | undefined) => void}
|
|
177
|
+
numberOfMonths={2}
|
|
178
|
+
initialFocus
|
|
179
|
+
/>
|
|
180
|
+
</PopoverContent>
|
|
181
|
+
</Popover>
|
|
182
|
+
);
|
|
183
|
+
},
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
187
|
+
|
|
188
|
+
export { DatePicker, DateRangePicker };
|