@borisj74/bv-ds 0.1.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/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/index.cjs +33885 -0
- package/dist/index.d.cts +2715 -0
- package/dist/index.d.ts +2715 -0
- package/dist/index.js +33717 -0
- package/package.json +67 -0
- package/src/components/ActivityFeed/ActivityFeed.tsx +48 -0
- package/src/components/ActivityFeed/index.ts +2 -0
- package/src/components/ActivityGauge/ActivityGauge.tsx +155 -0
- package/src/components/ActivityGauge/index.ts +7 -0
- package/src/components/AdvancedFilterBar/AdvancedFilterBar.tsx +80 -0
- package/src/components/AdvancedFilterBar/index.ts +2 -0
- package/src/components/Alert/Alert.tsx +210 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/Avatar/Avatar.tsx +111 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/AvatarAddButton/AvatarAddButton.tsx +65 -0
- package/src/components/AvatarAddButton/index.ts +5 -0
- package/src/components/AvatarGroup/AvatarGroup.tsx +79 -0
- package/src/components/AvatarGroup/index.ts +6 -0
- package/src/components/AvatarLabelGroup/AvatarLabelGroup.tsx +62 -0
- package/src/components/AvatarLabelGroup/index.ts +5 -0
- package/src/components/AvatarProfilePhoto/AvatarProfilePhoto.tsx +117 -0
- package/src/components/AvatarProfilePhoto/index.ts +5 -0
- package/src/components/Badge/ColorBadge.tsx +36 -0
- package/src/components/Badge/ModernBadge.tsx +38 -0
- package/src/components/Badge/PillBadge.tsx +36 -0
- package/src/components/Badge/badgeShared.tsx +139 -0
- package/src/components/Badge/index.ts +7 -0
- package/src/components/BadgeCloseX/BadgeCloseX.tsx +64 -0
- package/src/components/BadgeCloseX/index.ts +2 -0
- package/src/components/BadgeGroup/BadgeGroup.tsx +61 -0
- package/src/components/BadgeGroup/index.ts +7 -0
- package/src/components/BreadcrumbButtonBase/BreadcrumbButtonBase.tsx +75 -0
- package/src/components/BreadcrumbButtonBase/index.ts +5 -0
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +62 -0
- package/src/components/Breadcrumbs/index.ts +2 -0
- package/src/components/Button/Button.tsx +71 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/ButtonCloseX/ButtonCloseX.tsx +54 -0
- package/src/components/ButtonCloseX/index.ts +2 -0
- package/src/components/ButtonDestructive/ButtonDestructive.tsx +67 -0
- package/src/components/ButtonDestructive/index.ts +6 -0
- package/src/components/ButtonGroup/ButtonGroup.tsx +28 -0
- package/src/components/ButtonGroup/index.ts +2 -0
- package/src/components/ButtonGroupSegment/ButtonGroupSegment.tsx +54 -0
- package/src/components/ButtonGroupSegment/index.ts +5 -0
- package/src/components/ButtonUtility/ButtonUtility.tsx +67 -0
- package/src/components/ButtonUtility/index.ts +6 -0
- package/src/components/CalendarCell/CalendarCell.tsx +82 -0
- package/src/components/CalendarCell/index.ts +2 -0
- package/src/components/CalendarCellDayWeekView/CalendarCellDayWeekView.tsx +56 -0
- package/src/components/CalendarCellDayWeekView/index.ts +2 -0
- package/src/components/CalendarColumnHeader/CalendarColumnHeader.tsx +45 -0
- package/src/components/CalendarColumnHeader/index.ts +5 -0
- package/src/components/CalendarDateIcon/CalendarDateIcon.tsx +25 -0
- package/src/components/CalendarDateIcon/index.ts +2 -0
- package/src/components/CalendarEvent/CalendarEvent.tsx +76 -0
- package/src/components/CalendarEvent/index.ts +2 -0
- package/src/components/CalendarEventDayWeekView/CalendarEventDayWeekView.tsx +76 -0
- package/src/components/CalendarEventDayWeekView/index.ts +2 -0
- package/src/components/CalendarHeader/CalendarHeader.tsx +47 -0
- package/src/components/CalendarHeader/index.ts +2 -0
- package/src/components/CalendarRowLabel/CalendarRowLabel.tsx +21 -0
- package/src/components/CalendarRowLabel/index.ts +2 -0
- package/src/components/CalendarTimemarker/CalendarTimemarker.tsx +46 -0
- package/src/components/CalendarTimemarker/index.ts +5 -0
- package/src/components/CalendarViewDropdown/CalendarViewDropdown.tsx +101 -0
- package/src/components/CalendarViewDropdown/index.ts +6 -0
- package/src/components/CardHeader/CardHeader.tsx +57 -0
- package/src/components/CardHeader/index.ts +2 -0
- package/src/components/CarouselArrow/CarouselArrow.tsx +47 -0
- package/src/components/CarouselArrow/index.ts +6 -0
- package/src/components/CarouselImage/CarouselImage.tsx +60 -0
- package/src/components/CarouselImage/index.ts +2 -0
- package/src/components/Change/Change.tsx +73 -0
- package/src/components/Change/index.ts +2 -0
- package/src/components/ChartLegend/ChartLegend.tsx +38 -0
- package/src/components/ChartLegend/index.ts +2 -0
- package/src/components/ChartMarker/ChartMarker.tsx +54 -0
- package/src/components/ChartMarker/index.ts +2 -0
- package/src/components/ChartMini/ChartMini.tsx +86 -0
- package/src/components/ChartMini/index.ts +2 -0
- package/src/components/ChartTooltip/ChartTooltip.tsx +44 -0
- package/src/components/ChartTooltip/index.ts +2 -0
- package/src/components/Checkbox/Checkbox.tsx +65 -0
- package/src/components/Checkbox/checkboxBase.tsx +81 -0
- package/src/components/Checkbox/index.ts +3 -0
- package/src/components/CodeSnippet/CodeSnippet.tsx +94 -0
- package/src/components/CodeSnippet/index.ts +2 -0
- package/src/components/CodeSnippetTabs/CodeSnippetTabs.tsx +44 -0
- package/src/components/CodeSnippetTabs/index.ts +2 -0
- package/src/components/CommandBar/CommandBar.tsx +80 -0
- package/src/components/CommandBar/index.ts +2 -0
- package/src/components/CommandBarFooter/CommandBarFooter.tsx +125 -0
- package/src/components/CommandBarFooter/index.ts +5 -0
- package/src/components/CommandBarMenuSection/CommandBarMenuSection.tsx +28 -0
- package/src/components/CommandBarMenuSection/index.ts +2 -0
- package/src/components/CommandBarNavigationIcon/CommandBarNavigationIcon.tsx +47 -0
- package/src/components/CommandBarNavigationIcon/index.ts +2 -0
- package/src/components/CommandDropdownMenuItem/CommandDropdownMenuItem.tsx +51 -0
- package/src/components/CommandDropdownMenuItem/index.ts +2 -0
- package/src/components/CommandInput/CommandInput.tsx +74 -0
- package/src/components/CommandInput/index.ts +2 -0
- package/src/components/CommandShortcut/CommandShortcut.tsx +26 -0
- package/src/components/CommandShortcut/index.ts +2 -0
- package/src/components/ContentDivider/ContentDivider.tsx +80 -0
- package/src/components/ContentDivider/index.ts +6 -0
- package/src/components/ContentFeatureText/ContentFeatureText.tsx +60 -0
- package/src/components/ContentFeatureText/index.ts +5 -0
- package/src/components/ContentHeading/ContentHeading.tsx +43 -0
- package/src/components/ContentHeading/index.ts +5 -0
- package/src/components/ContentParagraph/ContentParagraph.tsx +39 -0
- package/src/components/ContentParagraph/index.ts +5 -0
- package/src/components/ContentQuote/ContentQuote.tsx +114 -0
- package/src/components/ContentQuote/index.ts +6 -0
- package/src/components/ContentRule/ContentRule.tsx +31 -0
- package/src/components/ContentRule/index.ts +2 -0
- package/src/components/ContextMenu/ContextMenu.tsx +67 -0
- package/src/components/ContextMenu/index.ts +7 -0
- package/src/components/ContextMenu/useContextMenu.ts +41 -0
- package/src/components/DatePickerCell/DatePickerCell.tsx +77 -0
- package/src/components/DatePickerCell/index.ts +2 -0
- package/src/components/DatePickerListItem/DatePickerListItem.tsx +39 -0
- package/src/components/DatePickerListItem/index.ts +2 -0
- package/src/components/DatePickerMenu/DatePickerMenu.tsx +131 -0
- package/src/components/DatePickerMenu/index.ts +2 -0
- package/src/components/DropdownAccountListItem/DropdownAccountListItem.tsx +69 -0
- package/src/components/DropdownAccountListItem/index.ts +2 -0
- package/src/components/DropdownMenuFooter/DropdownMenuFooter.tsx +50 -0
- package/src/components/DropdownMenuFooter/index.ts +5 -0
- package/src/components/DropdownMenuHeader/DropdownMenuHeader.tsx +93 -0
- package/src/components/DropdownMenuHeader/index.ts +5 -0
- package/src/components/DropdownMenuItemInsetIcon/DropdownMenuItemInsetIcon.tsx +89 -0
- package/src/components/DropdownMenuItemInsetIcon/index.ts +5 -0
- package/src/components/DropdownMenuListItem/DropdownMenuListItem.tsx +84 -0
- package/src/components/DropdownMenuListItem/index.ts +2 -0
- package/src/components/EmptyState/EmptyState.tsx +65 -0
- package/src/components/EmptyState/index.ts +2 -0
- package/src/components/FeedItemBase/FeedItemBase.tsx +135 -0
- package/src/components/FeedItemBase/index.ts +2 -0
- package/src/components/FileUpload/FileUpload.tsx +112 -0
- package/src/components/FileUpload/index.ts +2 -0
- package/src/components/FileUploadBase/FileUploadBase.tsx +69 -0
- package/src/components/FileUploadBase/index.ts +2 -0
- package/src/components/FileUploadItemBase/FileUploadItemBase.tsx +190 -0
- package/src/components/FileUploadItemBase/index.ts +7 -0
- package/src/components/FilterBar/FilterBar.tsx +62 -0
- package/src/components/FilterBar/index.ts +2 -0
- package/src/components/FilterTabs/FilterTabs.tsx +41 -0
- package/src/components/FilterTabs/index.ts +2 -0
- package/src/components/FiltersDropdownMenu/FiltersDropdownMenu.tsx +104 -0
- package/src/components/FiltersDropdownMenu/index.ts +2 -0
- package/src/components/FiltersSlideoutMenu/FiltersSlideoutMenu.tsx +71 -0
- package/src/components/FiltersSlideoutMenu/index.ts +2 -0
- package/src/components/HeaderNavigation/HeaderNavigation.tsx +178 -0
- package/src/components/HeaderNavigation/index.ts +6 -0
- package/src/components/HelpIcon/HelpIcon.tsx +49 -0
- package/src/components/HelpIcon/index.ts +2 -0
- package/src/components/InputField/InputField.tsx +108 -0
- package/src/components/InputField/index.ts +3 -0
- package/src/components/InputField/inputFieldShared.tsx +68 -0
- package/src/components/LeadingInputField/LeadingInputField.tsx +60 -0
- package/src/components/LeadingInputField/index.ts +2 -0
- package/src/components/LineAndBarChart/LineAndBarChart.tsx +96 -0
- package/src/components/LineAndBarChart/index.ts +2 -0
- package/src/components/LinkMessage/LinkMessage.tsx +52 -0
- package/src/components/LinkMessage/index.ts +2 -0
- package/src/components/LoadingIndicator/LoadingIndicator.tsx +108 -0
- package/src/components/LoadingIndicator/index.ts +6 -0
- package/src/components/MediaMessage/MediaMessage.tsx +109 -0
- package/src/components/MediaMessage/index.ts +2 -0
- package/src/components/MegaInputFieldBase/MegaInputFieldBase.tsx +49 -0
- package/src/components/MegaInputFieldBase/index.ts +5 -0
- package/src/components/Message/Message.tsx +85 -0
- package/src/components/Message/index.ts +3 -0
- package/src/components/Message/messageShared.tsx +73 -0
- package/src/components/MessageAction/MessageAction.tsx +221 -0
- package/src/components/MessageAction/index.ts +2 -0
- package/src/components/MessageActionButton/MessageActionButton.tsx +36 -0
- package/src/components/MessageActionButton/index.ts +2 -0
- package/src/components/MessageActionPanel/MessageActionPanel.tsx +36 -0
- package/src/components/MessageActionPanel/index.ts +2 -0
- package/src/components/MessageReaction/MessageReaction.tsx +37 -0
- package/src/components/MessageReaction/index.ts +2 -0
- package/src/components/MessageStatusIcon/MessageStatusIcon.tsx +54 -0
- package/src/components/MessageStatusIcon/index.ts +2 -0
- package/src/components/MetricItem/MetricItem.tsx +147 -0
- package/src/components/MetricItem/index.ts +2 -0
- package/src/components/ModalActions/ModalActions.tsx +57 -0
- package/src/components/ModalActions/index.ts +2 -0
- package/src/components/ModalHeader/ModalHeader.tsx +99 -0
- package/src/components/ModalHeader/index.ts +2 -0
- package/src/components/MultiSelect/MultiSelect.tsx +118 -0
- package/src/components/MultiSelect/index.ts +2 -0
- package/src/components/NavAccountCard/NavAccountCard.tsx +124 -0
- package/src/components/NavAccountCard/index.ts +2 -0
- package/src/components/NavAccountCardMenuItem/NavAccountCardMenuItem.tsx +101 -0
- package/src/components/NavAccountCardMenuItem/index.ts +5 -0
- package/src/components/NavButton/NavButton.tsx +50 -0
- package/src/components/NavButton/index.ts +2 -0
- package/src/components/NavFeaturedCard/NavFeaturedCard.tsx +82 -0
- package/src/components/NavFeaturedCard/index.ts +2 -0
- package/src/components/NavItemBase/NavItemBase.tsx +79 -0
- package/src/components/NavItemBase/index.ts +2 -0
- package/src/components/NavItemDropdownBase/NavItemDropdownBase.tsx +74 -0
- package/src/components/NavItemDropdownBase/index.ts +2 -0
- package/src/components/NavMenuButton/NavMenuButton.tsx +47 -0
- package/src/components/NavMenuButton/index.ts +2 -0
- package/src/components/Notification/Notification.tsx +102 -0
- package/src/components/Notification/index.ts +2 -0
- package/src/components/NumberInput/NumberInput.tsx +114 -0
- package/src/components/NumberInput/index.ts +2 -0
- package/src/components/PageHeader/PageHeader.tsx +88 -0
- package/src/components/PageHeader/index.ts +2 -0
- package/src/components/Pagination/Pagination.tsx +124 -0
- package/src/components/Pagination/index.ts +2 -0
- package/src/components/PaginationButtonGroupBase/PaginationButtonGroupBase.tsx +69 -0
- package/src/components/PaginationButtonGroupBase/index.ts +5 -0
- package/src/components/PaginationCards/PaginationCards.tsx +72 -0
- package/src/components/PaginationCards/index.ts +2 -0
- package/src/components/PaginationDotGroup/PaginationDotGroup.tsx +66 -0
- package/src/components/PaginationDotGroup/index.ts +2 -0
- package/src/components/PaginationDotIndicator/PaginationDotIndicator.tsx +39 -0
- package/src/components/PaginationDotIndicator/index.ts +6 -0
- package/src/components/PaginationNumberBase/PaginationNumberBase.tsx +42 -0
- package/src/components/PaginationNumberBase/index.ts +5 -0
- package/src/components/PieChart/PieChart.tsx +73 -0
- package/src/components/PieChart/index.ts +2 -0
- package/src/components/ProgressBar/ProgressBar.tsx +75 -0
- package/src/components/ProgressBar/index.ts +2 -0
- package/src/components/ProgressCircle/ProgressCircle.tsx +89 -0
- package/src/components/ProgressCircle/index.ts +6 -0
- package/src/components/RadarChart/RadarChart.tsx +62 -0
- package/src/components/RadarChart/index.ts +2 -0
- package/src/components/Radio/Radio.tsx +55 -0
- package/src/components/Radio/index.ts +2 -0
- package/src/components/RadioGroup/RadioGroup.tsx +54 -0
- package/src/components/RadioGroup/index.ts +2 -0
- package/src/components/RadioGroupItem/RadioGroupItem.tsx +118 -0
- package/src/components/RadioGroupItem/index.ts +6 -0
- package/src/components/SectionFooter/SectionFooter.tsx +40 -0
- package/src/components/SectionFooter/index.ts +2 -0
- package/src/components/SectionHeader/SectionHeader.tsx +44 -0
- package/src/components/SectionHeader/index.ts +2 -0
- package/src/components/SectionLabel/SectionLabel.tsx +51 -0
- package/src/components/SectionLabel/index.ts +2 -0
- package/src/components/Select/Select.tsx +121 -0
- package/src/components/Select/index.ts +2 -0
- package/src/components/SelectMenuItem/SelectMenuItem.tsx +85 -0
- package/src/components/SelectMenuItem/index.ts +2 -0
- package/src/components/SidebarNavigation/SidebarNavigation.tsx +100 -0
- package/src/components/SidebarNavigation/index.ts +2 -0
- package/src/components/SlideOutMenuHeader/SlideOutMenuHeader.tsx +56 -0
- package/src/components/SlideOutMenuHeader/index.ts +2 -0
- package/src/components/Slider/Slider.tsx +125 -0
- package/src/components/Slider/index.ts +2 -0
- package/src/components/SocialButton/SocialButton.tsx +88 -0
- package/src/components/SocialButton/index.ts +2 -0
- package/src/components/StatusIcon/StatusIcon.tsx +75 -0
- package/src/components/StatusIcon/index.ts +2 -0
- package/src/components/StepBase/StepBase.tsx +90 -0
- package/src/components/StepBase/index.ts +2 -0
- package/src/components/StepIconBase/StepIconBase.tsx +65 -0
- package/src/components/StepIconBase/index.ts +7 -0
- package/src/components/TabButtonBase/TabButtonBase.tsx +88 -0
- package/src/components/TabButtonBase/index.ts +2 -0
- package/src/components/TableCell/TableCell.tsx +44 -0
- package/src/components/TableCell/index.ts +2 -0
- package/src/components/TableHeaderCell/TableHeaderCell.tsx +34 -0
- package/src/components/TableHeaderCell/index.ts +2 -0
- package/src/components/TableHeaderLabel/TableHeaderLabel.tsx +37 -0
- package/src/components/TableHeaderLabel/index.ts +2 -0
- package/src/components/Tabs/Tabs.tsx +80 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Tag/Tag.tsx +91 -0
- package/src/components/Tag/index.ts +2 -0
- package/src/components/TagsInputField/TagsInputField.tsx +90 -0
- package/src/components/TagsInputField/index.ts +2 -0
- package/src/components/TextEditorToolbar/TextEditorToolbar.tsx +33 -0
- package/src/components/TextEditorToolbar/index.ts +2 -0
- package/src/components/TextEditorTooltip/TextEditorTooltip.tsx +28 -0
- package/src/components/TextEditorTooltip/index.ts +2 -0
- package/src/components/TextareaInputField/TextareaInputField.tsx +45 -0
- package/src/components/TextareaInputField/index.ts +2 -0
- package/src/components/Toggle/Toggle.tsx +87 -0
- package/src/components/Toggle/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.tsx +59 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/TrailingInputField/TrailingInputField.tsx +62 -0
- package/src/components/TrailingInputField/index.ts +2 -0
- package/src/components/TreeView/TreeView.tsx +86 -0
- package/src/components/TreeView/index.ts +2 -0
- package/src/components/TreeViewConnector/TreeViewConnector.tsx +36 -0
- package/src/components/TreeViewConnector/index.ts +2 -0
- package/src/components/TreeViewItem/TreeViewItem.tsx +111 -0
- package/src/components/TreeViewItem/index.ts +2 -0
- package/src/components/VerificationCodeInput/VerificationCodeInput.tsx +114 -0
- package/src/components/VerificationCodeInput/index.ts +2 -0
- package/src/illustrations/BoxIllustration.tsx +13 -0
- package/src/illustrations/CloudIllustration.tsx +18 -0
- package/src/illustrations/CreditCardIllustration.tsx +13 -0
- package/src/illustrations/DocumentsIllustration.tsx +13 -0
- package/src/illustrations/index.ts +4 -0
- package/src/index.ts +147 -0
- package/src/internal/chartTheme.ts +30 -0
- package/src/internal/ringBase.tsx +82 -0
- package/src/styles.css +3 -0
- package/tailwind-preset.js +295 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface FileUploadBaseProps extends HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
/** Emphasised action text. */
|
|
6
|
+
actionText?: ReactNode;
|
|
7
|
+
/** Trailing prompt after the action text. */
|
|
8
|
+
promptText?: ReactNode;
|
|
9
|
+
/** Constraints hint (e.g. "SVG, PNG, JPG or GIF (max. 800x400px)"). */
|
|
10
|
+
hint?: ReactNode;
|
|
11
|
+
/** Active drag-over styling (brand border). */
|
|
12
|
+
dragActive?: boolean;
|
|
13
|
+
/** Disabled styling + interaction. */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function UploadCloud() {
|
|
18
|
+
return (
|
|
19
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-5 text-fg-quaternary" aria-hidden>
|
|
20
|
+
<path
|
|
21
|
+
d="M6.667 13.333 10 10m0 0 3.333 3.333M10 10v7.5m6.667-3.548A4.583 4.583 0 0 0 14.167 5.5h-1.05A6.667 6.667 0 1 0 3.333 12.66"
|
|
22
|
+
stroke="currentColor"
|
|
23
|
+
strokeWidth="1.667"
|
|
24
|
+
strokeLinecap="round"
|
|
25
|
+
strokeLinejoin="round"
|
|
26
|
+
/>
|
|
27
|
+
</svg>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The drop-zone region of a file upload — featured upload icon, click/drag
|
|
33
|
+
* prompt, and a constraints hint. Wire up the actual file input / drag events
|
|
34
|
+
* on the consumer side (pass handlers via the standard div props).
|
|
35
|
+
*/
|
|
36
|
+
export function FileUploadBase({
|
|
37
|
+
actionText = "Click to upload",
|
|
38
|
+
promptText = "or drag and drop",
|
|
39
|
+
hint = "SVG, PNG, JPG or GIF (max. 800x400px)",
|
|
40
|
+
dragActive = false,
|
|
41
|
+
disabled = false,
|
|
42
|
+
className,
|
|
43
|
+
...rest
|
|
44
|
+
}: FileUploadBaseProps) {
|
|
45
|
+
return (
|
|
46
|
+
<div
|
|
47
|
+
className={clsx(
|
|
48
|
+
"flex w-full flex-col items-center gap-lg rounded-xl px-3xl py-xl text-center font-body",
|
|
49
|
+
dragActive
|
|
50
|
+
? "border-2 border-border-brand bg-bg-primary"
|
|
51
|
+
: "border border-border-secondary bg-bg-primary",
|
|
52
|
+
disabled && "pointer-events-none bg-bg-secondary opacity-60",
|
|
53
|
+
className,
|
|
54
|
+
)}
|
|
55
|
+
{...rest}
|
|
56
|
+
>
|
|
57
|
+
<span className="flex size-10 items-center justify-center rounded-md border border-border-primary bg-bg-primary shadow-xs">
|
|
58
|
+
<UploadCloud />
|
|
59
|
+
</span>
|
|
60
|
+
<div className="flex flex-col gap-xs">
|
|
61
|
+
<p className="text-sm">
|
|
62
|
+
<span className="font-semibold text-text-brand-secondary">{actionText}</span>{" "}
|
|
63
|
+
<span className="font-normal text-text-tertiary">{promptText}</span>
|
|
64
|
+
</p>
|
|
65
|
+
<p className="text-xs font-normal text-text-tertiary">{hint}</p>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type FileUploadItemStatus = "in-progress" | "complete" | "error";
|
|
5
|
+
export type FileUploadItemType = "bar" | "fill";
|
|
6
|
+
export type FileUploadItemIconType = "file-type" | "simple";
|
|
7
|
+
|
|
8
|
+
export interface FileUploadItemBaseProps {
|
|
9
|
+
/** File name. */
|
|
10
|
+
fileName: ReactNode;
|
|
11
|
+
/** Size / supporting line (e.g. "20 KB of 200 KB"). */
|
|
12
|
+
meta?: ReactNode;
|
|
13
|
+
/** Upload status. */
|
|
14
|
+
status?: FileUploadItemStatus;
|
|
15
|
+
/** Progress 0–100 (used when `type="bar"` and not errored). */
|
|
16
|
+
progress?: number;
|
|
17
|
+
/** "bar" shows a progress bar row; "fill" fills the row background. */
|
|
18
|
+
type?: FileUploadItemType;
|
|
19
|
+
/** File-type badge icon vs a simple file glyph. */
|
|
20
|
+
iconType?: FileUploadItemIconType;
|
|
21
|
+
/** Short extension label for the file-type icon (e.g. "PDF"). */
|
|
22
|
+
fileExt?: string;
|
|
23
|
+
/** Error message (status="error"). */
|
|
24
|
+
errorText?: ReactNode;
|
|
25
|
+
onDelete?: () => void;
|
|
26
|
+
onRetry?: () => void;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function StatusBits({
|
|
31
|
+
status,
|
|
32
|
+
errorText,
|
|
33
|
+
}: {
|
|
34
|
+
status: FileUploadItemStatus;
|
|
35
|
+
errorText?: ReactNode;
|
|
36
|
+
}) {
|
|
37
|
+
if (status === "complete") {
|
|
38
|
+
return (
|
|
39
|
+
<span className="flex items-center gap-xs text-sm font-medium text-text-success-primary">
|
|
40
|
+
<svg viewBox="0 0 16 16" fill="none" className="size-4" aria-hidden>
|
|
41
|
+
<path d="M14.667 8A6.667 6.667 0 1 1 8 1.333 6.667 6.667 0 0 1 14.667 8Zm-3.84-2.16L6.9 9.767 5.173 8.04" stroke="currentColor" strokeWidth="1.333" strokeLinecap="round" strokeLinejoin="round" />
|
|
42
|
+
</svg>
|
|
43
|
+
Complete
|
|
44
|
+
</span>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (status === "error") {
|
|
48
|
+
return (
|
|
49
|
+
<span className="flex items-center gap-xs text-sm font-medium text-text-error-primary">
|
|
50
|
+
<svg viewBox="0 0 16 16" fill="none" className="size-4" aria-hidden>
|
|
51
|
+
<path d="M8 5.333V8m0 2.667h.007M14.667 8A6.667 6.667 0 1 1 8 1.333 6.667 6.667 0 0 1 14.667 8Z" stroke="currentColor" strokeWidth="1.333" strokeLinecap="round" strokeLinejoin="round" />
|
|
52
|
+
</svg>
|
|
53
|
+
{errorText ?? "Failed"}
|
|
54
|
+
</span>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return (
|
|
58
|
+
<span className="flex items-center gap-xs text-sm font-medium text-text-quaternary">
|
|
59
|
+
<svg viewBox="0 0 16 16" fill="none" className="size-4" aria-hidden>
|
|
60
|
+
<path d="M5.333 10.667 8 8m0 0 2.667 2.667M8 8v6M13.333 11.16A3.667 3.667 0 0 0 11.333 4.4h-.84A5.333 5.333 0 1 0 2.667 10.13" stroke="currentColor" strokeWidth="1.333" strokeLinecap="round" strokeLinejoin="round" />
|
|
61
|
+
</svg>
|
|
62
|
+
Uploading...
|
|
63
|
+
</span>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function FileIcon({
|
|
68
|
+
iconType,
|
|
69
|
+
fileExt,
|
|
70
|
+
}: {
|
|
71
|
+
iconType: FileUploadItemIconType;
|
|
72
|
+
fileExt: string;
|
|
73
|
+
}) {
|
|
74
|
+
if (iconType === "simple") {
|
|
75
|
+
return (
|
|
76
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-5 shrink-0 text-fg-quaternary" aria-hidden>
|
|
77
|
+
<path d="M11.667 1.667H5A1.667 1.667 0 0 0 3.333 3.333v13.334A1.667 1.667 0 0 0 5 18.333h10a1.667 1.667 0 0 0 1.667-1.666V6.667m-5-5 5 5m-5-5v5h5" stroke="currentColor" strokeWidth="1.667" strokeLinecap="round" strokeLinejoin="round" />
|
|
78
|
+
</svg>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return (
|
|
82
|
+
<span className="relative flex h-10 w-8 shrink-0 items-end justify-center rounded-[2px] border border-border-secondary bg-bg-primary">
|
|
83
|
+
<span className="mb-1 rounded-[2px] bg-utility-red-600 px-1 py-[2px] text-[10px] font-bold text-text-white">
|
|
84
|
+
{fileExt}
|
|
85
|
+
</span>
|
|
86
|
+
</span>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* A single file row in an upload list — file icon, name, status line, progress,
|
|
92
|
+
* and delete/retry actions. Covers the Figma matrix (bar/fill × file-type/simple
|
|
93
|
+
* × in-progress/complete/error) via props. The `fill` type renders progress as
|
|
94
|
+
* a background fill (simplified vs the exact Figma overlay).
|
|
95
|
+
*/
|
|
96
|
+
export function FileUploadItemBase({
|
|
97
|
+
fileName,
|
|
98
|
+
meta,
|
|
99
|
+
status = "in-progress",
|
|
100
|
+
progress = 0,
|
|
101
|
+
type = "bar",
|
|
102
|
+
iconType = "file-type",
|
|
103
|
+
fileExt = "PDF",
|
|
104
|
+
errorText,
|
|
105
|
+
onDelete,
|
|
106
|
+
onRetry,
|
|
107
|
+
className,
|
|
108
|
+
}: FileUploadItemBaseProps) {
|
|
109
|
+
const isError = status === "error";
|
|
110
|
+
const showBar = type === "bar" && !isError;
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div
|
|
114
|
+
className={clsx(
|
|
115
|
+
"relative flex w-full items-start gap-lg overflow-hidden rounded-xl bg-bg-primary p-xl font-body",
|
|
116
|
+
isError ? "border-2 border-border-error" : "border border-border-secondary",
|
|
117
|
+
className,
|
|
118
|
+
)}
|
|
119
|
+
>
|
|
120
|
+
{type === "fill" && !isError ? (
|
|
121
|
+
<span
|
|
122
|
+
className="absolute inset-y-0 left-0 bg-bg-secondary"
|
|
123
|
+
style={{ width: `${progress}%` }}
|
|
124
|
+
aria-hidden
|
|
125
|
+
/>
|
|
126
|
+
) : null}
|
|
127
|
+
|
|
128
|
+
<div className="relative flex min-w-0 flex-1 items-start gap-lg">
|
|
129
|
+
<FileIcon iconType={iconType} fileExt={fileExt} />
|
|
130
|
+
<div className="flex min-w-0 flex-1 flex-col gap-xxs pr-7">
|
|
131
|
+
<p className="truncate text-sm font-medium text-text-secondary">
|
|
132
|
+
{fileName}
|
|
133
|
+
</p>
|
|
134
|
+
{isError && (type === "fill" || iconType === "simple") ? (
|
|
135
|
+
<p className="text-sm font-normal text-text-tertiary">
|
|
136
|
+
{errorText ?? "Upload failed, please try again."}
|
|
137
|
+
</p>
|
|
138
|
+
) : (
|
|
139
|
+
<div className="flex items-center gap-md">
|
|
140
|
+
{meta ? (
|
|
141
|
+
<span className="truncate text-sm font-normal text-text-tertiary">
|
|
142
|
+
{meta}
|
|
143
|
+
</span>
|
|
144
|
+
) : null}
|
|
145
|
+
{meta ? <span className="h-3 w-px bg-border-secondary" /> : null}
|
|
146
|
+
<StatusBits status={status} />
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
{showBar ? (
|
|
151
|
+
<div className="mt-xs flex items-center gap-lg">
|
|
152
|
+
<span className="relative h-2 flex-1 rounded-full bg-bg-quaternary">
|
|
153
|
+
<span
|
|
154
|
+
className="absolute inset-y-0 left-0 rounded-full bg-fg-brand-primary"
|
|
155
|
+
style={{ width: `${progress}%` }}
|
|
156
|
+
/>
|
|
157
|
+
</span>
|
|
158
|
+
<span className="text-sm font-medium text-text-secondary">
|
|
159
|
+
{progress}%
|
|
160
|
+
</span>
|
|
161
|
+
</div>
|
|
162
|
+
) : null}
|
|
163
|
+
|
|
164
|
+
{isError && onRetry ? (
|
|
165
|
+
<button
|
|
166
|
+
type="button"
|
|
167
|
+
onClick={onRetry}
|
|
168
|
+
className="mt-xs self-start text-sm font-semibold text-text-error-primary"
|
|
169
|
+
>
|
|
170
|
+
Try again
|
|
171
|
+
</button>
|
|
172
|
+
) : null}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
{onDelete ? (
|
|
177
|
+
<button
|
|
178
|
+
type="button"
|
|
179
|
+
onClick={onDelete}
|
|
180
|
+
aria-label="Delete file"
|
|
181
|
+
className="relative shrink-0 rounded-sm p-sm text-fg-quaternary outline-none transition-colors hover:text-fg-quaternary-hover focus-visible:ring-2 focus-visible:ring-border-brand"
|
|
182
|
+
>
|
|
183
|
+
<svg viewBox="0 0 16 16" fill="none" className="size-4" aria-hidden>
|
|
184
|
+
<path d="M10.667 4v-.533c0-.747 0-1.12-.146-1.405a1.333 1.333 0 0 0-.583-.583c-.286-.146-.659-.146-1.405-.146H7.467c-.747 0-1.12 0-1.406.146a1.333 1.333 0 0 0-.582.583C5.333 2.347 5.333 2.72 5.333 3.467V4M2 4h12M12.667 4v7.467c0 1.12 0 1.68-.219 2.108a2 2 0 0 1-.873.874c-.428.218-.988.218-2.108.218H6.533c-1.12 0-1.68 0-2.108-.218a2 2 0 0 1-.874-.874c-.218-.428-.218-.988-.218-2.108V4" stroke="currentColor" strokeWidth="1.333" strokeLinecap="round" strokeLinejoin="round" />
|
|
185
|
+
</svg>
|
|
186
|
+
</button>
|
|
187
|
+
) : null}
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface FilterBarProps {
|
|
5
|
+
/**
|
|
6
|
+
* Filter controls on the left (compose Select / MultiSelect / etc.).
|
|
7
|
+
* Covers the Dropdowns and Date filters types.
|
|
8
|
+
*/
|
|
9
|
+
filters?: ReactNode;
|
|
10
|
+
/** Show the date-picker slot in the trailing actions. */
|
|
11
|
+
withDatePicker?: boolean;
|
|
12
|
+
/** Date-picker trigger node, rendered when `withDatePicker`. */
|
|
13
|
+
datePicker?: ReactNode;
|
|
14
|
+
/** Extra trailing actions (e.g. a "More filters" button, search icon). */
|
|
15
|
+
actions?: ReactNode;
|
|
16
|
+
/** When set, renders the "Clear all" button. */
|
|
17
|
+
onClearAll?: () => void;
|
|
18
|
+
clearLabel?: ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Dropdown-driven filter bar — a row of filter controls with optional trailing
|
|
24
|
+
* date picker and actions. A layout shell: compose the actual Select/MultiSelect
|
|
25
|
+
* controls as `filters` and any trigger buttons as `datePicker`/`actions`.
|
|
26
|
+
* Covers the Figma "Dropdowns", "Dropdowns and date picker" and "Date filters"
|
|
27
|
+
* types. (The "Simple" type is just a SearchInput — use that directly.)
|
|
28
|
+
*/
|
|
29
|
+
export function FilterBar({
|
|
30
|
+
filters,
|
|
31
|
+
withDatePicker = false,
|
|
32
|
+
datePicker,
|
|
33
|
+
actions,
|
|
34
|
+
onClearAll,
|
|
35
|
+
clearLabel = "Clear all",
|
|
36
|
+
className,
|
|
37
|
+
}: FilterBarProps) {
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
className={clsx("flex w-full flex-wrap items-end gap-lg font-body", className)}
|
|
41
|
+
>
|
|
42
|
+
<div className="flex min-w-[280px] flex-1 items-end gap-lg">
|
|
43
|
+
{filters}
|
|
44
|
+
{onClearAll ? (
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
onClick={onClearAll}
|
|
48
|
+
className="shrink-0 rounded-md border border-border-primary bg-bg-primary px-lg py-md text-sm font-semibold text-text-secondary shadow-xs"
|
|
49
|
+
>
|
|
50
|
+
{clearLabel}
|
|
51
|
+
</button>
|
|
52
|
+
) : null}
|
|
53
|
+
</div>
|
|
54
|
+
{withDatePicker || actions ? (
|
|
55
|
+
<div className="flex shrink-0 items-center gap-lg">
|
|
56
|
+
{withDatePicker ? datePicker : null}
|
|
57
|
+
{actions}
|
|
58
|
+
</div>
|
|
59
|
+
) : null}
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface FilterTabsProps {
|
|
5
|
+
/** Tab strip on the left (compose your tab buttons / segmented control). */
|
|
6
|
+
tabs?: ReactNode;
|
|
7
|
+
/** Search input slot (the "Tabs and search" type). */
|
|
8
|
+
search?: ReactNode;
|
|
9
|
+
/** Date-picker trigger slot (the "Tabs and date picker" type). */
|
|
10
|
+
datePicker?: ReactNode;
|
|
11
|
+
/** When true, show `datePicker` in the trailing area instead of `search`. */
|
|
12
|
+
withDatePicker?: boolean;
|
|
13
|
+
/** Extra trailing actions (e.g. a Filters button). */
|
|
14
|
+
actions?: ReactNode;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Tab-based filter navigation — a tab strip on the left with a trailing search
|
|
20
|
+
* (or date picker) and optional actions. Layout shell: compose the tab control,
|
|
21
|
+
* search input, and date picker as slots. Covers the Figma "Tabs and search"
|
|
22
|
+
* and "Tabs and date picker" types.
|
|
23
|
+
*/
|
|
24
|
+
export function FilterTabs({
|
|
25
|
+
tabs,
|
|
26
|
+
search,
|
|
27
|
+
datePicker,
|
|
28
|
+
withDatePicker = false,
|
|
29
|
+
actions,
|
|
30
|
+
className,
|
|
31
|
+
}: FilterTabsProps) {
|
|
32
|
+
return (
|
|
33
|
+
<div className={clsx("flex w-full flex-wrap items-end gap-lg font-body", className)}>
|
|
34
|
+
<div className="flex min-w-0 flex-1 items-end">{tabs}</div>
|
|
35
|
+
<div className="flex shrink-0 items-center gap-lg">
|
|
36
|
+
{withDatePicker ? datePicker : search}
|
|
37
|
+
{actions}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
function FilterLines() {
|
|
5
|
+
return (
|
|
6
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
|
|
7
|
+
<path
|
|
8
|
+
d="M5 10h10M2.5 5h15M7.5 15h5"
|
|
9
|
+
stroke="currentColor"
|
|
10
|
+
strokeWidth="1.667"
|
|
11
|
+
strokeLinecap="round"
|
|
12
|
+
strokeLinejoin="round"
|
|
13
|
+
/>
|
|
14
|
+
</svg>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function ChevronDown() {
|
|
19
|
+
return (
|
|
20
|
+
<svg viewBox="0 0 16 16" fill="none" className="size-4" aria-hidden>
|
|
21
|
+
<path d="m4 6 4 4 4-4" stroke="currentColor" strokeWidth="1.333" strokeLinecap="round" strokeLinejoin="round" />
|
|
22
|
+
</svg>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface FiltersDropdownMenuProps {
|
|
27
|
+
/** Trigger label. */
|
|
28
|
+
label?: ReactNode;
|
|
29
|
+
/** Active-filter count — when > 0 the trigger gets the active styling + badge. */
|
|
30
|
+
count?: number;
|
|
31
|
+
/** Show the trailing chevron. */
|
|
32
|
+
chevron?: boolean;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
/** Whether the panel is open. */
|
|
35
|
+
open?: boolean;
|
|
36
|
+
onToggle?: () => void;
|
|
37
|
+
/** Panel alignment relative to the trigger. */
|
|
38
|
+
align?: "left" | "right";
|
|
39
|
+
/** Panel content (the filter list) — compose your own rows. */
|
|
40
|
+
children?: ReactNode;
|
|
41
|
+
/** Panel footer (e.g. Reset / Apply). */
|
|
42
|
+
footer?: ReactNode;
|
|
43
|
+
className?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* A "Filters" dropdown trigger button plus its panel. The trigger covers the
|
|
48
|
+
* default/hover/focus/disabled/active states (active when `count > 0`); the
|
|
49
|
+
* open panel content is a slot — compose the filter rows yourself.
|
|
50
|
+
*/
|
|
51
|
+
export function FiltersDropdownMenu({
|
|
52
|
+
label = "Filters",
|
|
53
|
+
count = 0,
|
|
54
|
+
chevron = true,
|
|
55
|
+
disabled = false,
|
|
56
|
+
open = false,
|
|
57
|
+
onToggle,
|
|
58
|
+
align = "left",
|
|
59
|
+
children,
|
|
60
|
+
footer,
|
|
61
|
+
className,
|
|
62
|
+
}: FiltersDropdownMenuProps) {
|
|
63
|
+
const active = count > 0;
|
|
64
|
+
return (
|
|
65
|
+
<div className={clsx("relative inline-flex flex-col font-body", className)}>
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
onClick={onToggle}
|
|
69
|
+
disabled={disabled}
|
|
70
|
+
aria-expanded={open}
|
|
71
|
+
className={clsx(
|
|
72
|
+
"flex items-center gap-xs rounded-md border px-lg py-md text-sm font-semibold shadow-xs outline-none",
|
|
73
|
+
active
|
|
74
|
+
? "border-border-brand bg-bg-brand-primary text-text-brand-secondary"
|
|
75
|
+
: "border-border-primary bg-bg-primary text-text-secondary",
|
|
76
|
+
"focus-visible:ring-2 focus-visible:ring-border-brand",
|
|
77
|
+
disabled && "pointer-events-none opacity-50",
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
<FilterLines />
|
|
81
|
+
<span>{label}</span>
|
|
82
|
+
{active ? (
|
|
83
|
+
<span className="rounded-full bg-bg-brand-solid px-1.5 text-xs font-medium text-text-white">
|
|
84
|
+
{count}
|
|
85
|
+
</span>
|
|
86
|
+
) : null}
|
|
87
|
+
{chevron ? <ChevronDown /> : null}
|
|
88
|
+
</button>
|
|
89
|
+
{open && children ? (
|
|
90
|
+
<div
|
|
91
|
+
className={clsx(
|
|
92
|
+
"absolute top-full z-40 mt-xs flex min-w-[280px] flex-col rounded-md border border-border-secondary-alt bg-bg-primary shadow-lg",
|
|
93
|
+
align === "right" ? "right-0" : "left-0",
|
|
94
|
+
)}
|
|
95
|
+
>
|
|
96
|
+
<div className="flex flex-col py-xs">{children}</div>
|
|
97
|
+
{footer ? (
|
|
98
|
+
<div className="border-t border-border-secondary-alt p-lg">{footer}</div>
|
|
99
|
+
) : null}
|
|
100
|
+
</div>
|
|
101
|
+
) : null}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface FiltersSlideoutMenuProps {
|
|
5
|
+
/** Panel title. */
|
|
6
|
+
title?: ReactNode;
|
|
7
|
+
/** Supporting text under the title. */
|
|
8
|
+
supportingText?: ReactNode;
|
|
9
|
+
/** Close handler → renders the header close button. */
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
/** Filter body — compose the filter groups (Empty/Inactive/Active states). */
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
/** Footer actions (e.g. Reset / Apply). */
|
|
14
|
+
footer?: ReactNode;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function XClose() {
|
|
19
|
+
return (
|
|
20
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
|
|
21
|
+
<path d="M15 5 5 15M5 5l10 10" stroke="currentColor" strokeWidth="1.667" strokeLinecap="round" strokeLinejoin="round" />
|
|
22
|
+
</svg>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A slide-out filter drawer — header (title + close), a scrollable filter body,
|
|
28
|
+
* and a footer for actions. The body is a slot: compose the empty / inactive /
|
|
29
|
+
* active filter content yourself. Structural shell (mobile/desktop differ only
|
|
30
|
+
* in width on the consumer side).
|
|
31
|
+
*/
|
|
32
|
+
export function FiltersSlideoutMenu({
|
|
33
|
+
title = "Filters",
|
|
34
|
+
supportingText,
|
|
35
|
+
onClose,
|
|
36
|
+
children,
|
|
37
|
+
footer,
|
|
38
|
+
className,
|
|
39
|
+
}: FiltersSlideoutMenuProps) {
|
|
40
|
+
return (
|
|
41
|
+
<aside
|
|
42
|
+
className={clsx(
|
|
43
|
+
"flex h-full w-[440px] max-w-full flex-col border-l border-border-secondary bg-bg-primary font-body shadow-xl",
|
|
44
|
+
className,
|
|
45
|
+
)}
|
|
46
|
+
>
|
|
47
|
+
<div className="flex items-start justify-between border-b border-border-secondary px-xl py-lg">
|
|
48
|
+
<div className="flex min-w-0 flex-col">
|
|
49
|
+
<p className="text-lg font-semibold text-text-primary">{title}</p>
|
|
50
|
+
{supportingText ? (
|
|
51
|
+
<p className="text-sm font-normal text-text-tertiary">{supportingText}</p>
|
|
52
|
+
) : null}
|
|
53
|
+
</div>
|
|
54
|
+
{onClose ? (
|
|
55
|
+
<button
|
|
56
|
+
type="button"
|
|
57
|
+
onClick={onClose}
|
|
58
|
+
aria-label="Close"
|
|
59
|
+
className="-mr-2 shrink-0 rounded-md p-md text-fg-quaternary outline-none transition-colors hover:text-fg-quaternary-hover focus-visible:ring-2 focus-visible:ring-border-brand"
|
|
60
|
+
>
|
|
61
|
+
<XClose />
|
|
62
|
+
</button>
|
|
63
|
+
) : null}
|
|
64
|
+
</div>
|
|
65
|
+
<div className="flex-1 overflow-y-auto p-xl">{children}</div>
|
|
66
|
+
{footer ? (
|
|
67
|
+
<div className="border-t border-border-secondary p-xl">{footer}</div>
|
|
68
|
+
) : null}
|
|
69
|
+
</aside>
|
|
70
|
+
);
|
|
71
|
+
}
|