@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,61 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import { PillBadge } from "../Badge";
|
|
4
|
+
import { ModernBadge } from "../Badge";
|
|
5
|
+
import type { BadgeColor } from "../Badge";
|
|
6
|
+
|
|
7
|
+
export type BadgeGroupSize = "md" | "lg";
|
|
8
|
+
export type BadgeGroupType = "pill" | "modern";
|
|
9
|
+
export type BadgeGroupBadgePosition = "leading" | "trailing";
|
|
10
|
+
|
|
11
|
+
export interface BadgeGroupProps {
|
|
12
|
+
/** Text inside the inner coloured badge (e.g. "New feature"). */
|
|
13
|
+
badgeLabel: string;
|
|
14
|
+
/** The main label alongside the badge. */
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
color?: BadgeColor;
|
|
17
|
+
size?: BadgeGroupSize;
|
|
18
|
+
/** Inner badge style. */
|
|
19
|
+
type?: BadgeGroupType;
|
|
20
|
+
/** Whether the badge sits before or after the label. */
|
|
21
|
+
badgePosition?: BadgeGroupBadgePosition;
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const sizeClasses: Record<BadgeGroupSize, string> = {
|
|
26
|
+
md: "py-xxs pl-xxs pr-lg text-sm gap-md",
|
|
27
|
+
lg: "py-xs pl-xs pr-xl text-sm gap-md",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function BadgeGroup({
|
|
31
|
+
badgeLabel,
|
|
32
|
+
children,
|
|
33
|
+
color = "brand",
|
|
34
|
+
size = "md",
|
|
35
|
+
type = "pill",
|
|
36
|
+
badgePosition = "leading",
|
|
37
|
+
className,
|
|
38
|
+
}: BadgeGroupProps) {
|
|
39
|
+
const InnerBadge = type === "modern" ? ModernBadge : PillBadge;
|
|
40
|
+
const badge = (
|
|
41
|
+
<InnerBadge color={color} size="sm">
|
|
42
|
+
{badgeLabel}
|
|
43
|
+
</InnerBadge>
|
|
44
|
+
);
|
|
45
|
+
const trailing = badgePosition === "trailing";
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<span
|
|
49
|
+
className={clsx(
|
|
50
|
+
"inline-flex items-center rounded-full border border-border-primary bg-bg-primary font-medium text-text-secondary shadow-xs font-body",
|
|
51
|
+
// mirror the asymmetric padding when the badge is trailing
|
|
52
|
+
trailing && "flex-row-reverse pl-lg pr-xxs",
|
|
53
|
+
sizeClasses[size],
|
|
54
|
+
className,
|
|
55
|
+
)}
|
|
56
|
+
>
|
|
57
|
+
{badge}
|
|
58
|
+
<span>{children}</span>
|
|
59
|
+
</span>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ReactNode, MouseEventHandler } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type BreadcrumbButtonType = "text" | "button";
|
|
5
|
+
|
|
6
|
+
export interface BreadcrumbButtonBaseProps {
|
|
7
|
+
/** Crumb label. Optional for an icon-only (home) crumb. */
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
/** Leading icon (e.g. a home glyph for the root crumb). */
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
type?: BreadcrumbButtonType;
|
|
12
|
+
/** Marks the active/last crumb (brand colour, aria-current). */
|
|
13
|
+
current?: boolean;
|
|
14
|
+
/** Renders as an anchor when set, otherwise a button. */
|
|
15
|
+
href?: string;
|
|
16
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function BreadcrumbButtonBase({
|
|
21
|
+
children,
|
|
22
|
+
icon,
|
|
23
|
+
type = "text",
|
|
24
|
+
current = false,
|
|
25
|
+
href,
|
|
26
|
+
onClick,
|
|
27
|
+
className,
|
|
28
|
+
}: BreadcrumbButtonBaseProps) {
|
|
29
|
+
const classes = clsx(
|
|
30
|
+
"inline-flex items-center gap-md text-sm font-semibold font-body transition-colors",
|
|
31
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-primary",
|
|
32
|
+
type === "button" && "rounded-sm px-md py-xs",
|
|
33
|
+
current
|
|
34
|
+
? clsx(
|
|
35
|
+
"text-text-brand-secondary",
|
|
36
|
+
type === "button" && "bg-bg-brand-primary",
|
|
37
|
+
)
|
|
38
|
+
: clsx(
|
|
39
|
+
"text-text-quaternary hover:text-text-tertiary-hover",
|
|
40
|
+
type === "button" && "hover:bg-bg-primary-hover",
|
|
41
|
+
),
|
|
42
|
+
className,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const content = (
|
|
46
|
+
<>
|
|
47
|
+
{icon ? <span className="shrink-0">{icon}</span> : null}
|
|
48
|
+
{children}
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (href) {
|
|
53
|
+
return (
|
|
54
|
+
<a
|
|
55
|
+
href={href}
|
|
56
|
+
onClick={onClick}
|
|
57
|
+
aria-current={current ? "page" : undefined}
|
|
58
|
+
className={classes}
|
|
59
|
+
>
|
|
60
|
+
{content}
|
|
61
|
+
</a>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
onClick={onClick}
|
|
69
|
+
aria-current={current ? "page" : undefined}
|
|
70
|
+
className={classes}
|
|
71
|
+
>
|
|
72
|
+
{content}
|
|
73
|
+
</button>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Children, isValidElement } from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
|
|
5
|
+
export type BreadcrumbsDivider = "slash" | "chevron";
|
|
6
|
+
|
|
7
|
+
export interface BreadcrumbsProps {
|
|
8
|
+
/** Separator between crumbs. */
|
|
9
|
+
divider?: BreadcrumbsDivider;
|
|
10
|
+
/** Crumb items — typically `BreadcrumbButtonBase` instances. */
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function Slash() {
|
|
16
|
+
return (
|
|
17
|
+
<span className="text-sm text-text-quaternary" aria-hidden>
|
|
18
|
+
/
|
|
19
|
+
</span>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Chevron() {
|
|
24
|
+
return (
|
|
25
|
+
<svg
|
|
26
|
+
viewBox="0 0 16 16"
|
|
27
|
+
fill="none"
|
|
28
|
+
className="size-4 text-fg-quaternary"
|
|
29
|
+
aria-hidden
|
|
30
|
+
>
|
|
31
|
+
<path
|
|
32
|
+
d="m6 12 4-4-4-4"
|
|
33
|
+
stroke="currentColor"
|
|
34
|
+
strokeWidth="1.333"
|
|
35
|
+
strokeLinecap="round"
|
|
36
|
+
strokeLinejoin="round"
|
|
37
|
+
/>
|
|
38
|
+
</svg>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function Breadcrumbs({
|
|
43
|
+
divider = "slash",
|
|
44
|
+
children,
|
|
45
|
+
className,
|
|
46
|
+
}: BreadcrumbsProps) {
|
|
47
|
+
const items = Children.toArray(children).filter(isValidElement);
|
|
48
|
+
const Sep = divider === "chevron" ? Chevron : Slash;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<nav aria-label="Breadcrumb" className={clsx("font-body", className)}>
|
|
52
|
+
<ol className="flex items-center gap-md">
|
|
53
|
+
{items.map((child, index) => (
|
|
54
|
+
<li key={child.key ?? index} className="flex items-center gap-md">
|
|
55
|
+
{index > 0 ? <Sep /> : null}
|
|
56
|
+
{child}
|
|
57
|
+
</li>
|
|
58
|
+
))}
|
|
59
|
+
</ol>
|
|
60
|
+
</nav>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type ButtonHierarchy =
|
|
5
|
+
| "Primary"
|
|
6
|
+
| "Secondary"
|
|
7
|
+
| "Tertiary"
|
|
8
|
+
| "Link color"
|
|
9
|
+
| "Link gray";
|
|
10
|
+
export type ButtonSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
11
|
+
|
|
12
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
13
|
+
hierarchy?: ButtonHierarchy;
|
|
14
|
+
size?: ButtonSize;
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// NOTE: this is a placeholder implementation to verify the build/Storybook
|
|
19
|
+
// pipeline end-to-end. The figma-to-react skill should overwrite this with
|
|
20
|
+
// the full per-hierarchy/per-size token mapping from design.md §3 (all 5
|
|
21
|
+
// sizes, all 5 hierarchies, skeuomorphic shadow stack on Primary/Secondary).
|
|
22
|
+
//
|
|
23
|
+
// Padding values below use Tailwind arbitrary values ([14px], [10px], etc)
|
|
24
|
+
// rather than the spacing-* scale on purpose — design.md §3 confirms the
|
|
25
|
+
// real Figma component uses raw px at md/lg/xl, not the nearest token.
|
|
26
|
+
// Don't "fix" these to spacing-md/spacing-lg; that would silently diverge
|
|
27
|
+
// from the source design.
|
|
28
|
+
|
|
29
|
+
const hierarchyClasses: Record<ButtonHierarchy, string> = {
|
|
30
|
+
Primary:
|
|
31
|
+
"bg-brand-solid text-white border-2 border-white/[0.12] hover:bg-bg-brand-solid-hover",
|
|
32
|
+
Secondary: "bg-bg-primary text-text-secondary border border-border-primary",
|
|
33
|
+
Tertiary: "bg-transparent text-text-tertiary border-0",
|
|
34
|
+
"Link color": "bg-transparent text-text-brand-secondary border-0 p-0",
|
|
35
|
+
"Link gray": "bg-transparent text-text-tertiary border-0 p-0",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const sizeClasses: Record<ButtonSize, string> = {
|
|
39
|
+
xs: "px-[10px] py-sm text-xs",
|
|
40
|
+
sm: "px-lg py-md text-xs",
|
|
41
|
+
md: "px-[14px] py-[10px] text-sm",
|
|
42
|
+
lg: "px-xl py-[10px] text-md",
|
|
43
|
+
xl: "px-[18px] py-lg text-md",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function Button({
|
|
47
|
+
hierarchy = "Primary",
|
|
48
|
+
size = "md",
|
|
49
|
+
loading = false,
|
|
50
|
+
disabled,
|
|
51
|
+
className,
|
|
52
|
+
children,
|
|
53
|
+
...rest
|
|
54
|
+
}: ButtonProps) {
|
|
55
|
+
return (
|
|
56
|
+
<button
|
|
57
|
+
className={clsx(
|
|
58
|
+
"font-body font-semibold rounded-md cursor-pointer transition-colors",
|
|
59
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
60
|
+
hierarchyClasses[hierarchy],
|
|
61
|
+
sizeClasses[size],
|
|
62
|
+
className,
|
|
63
|
+
)}
|
|
64
|
+
disabled={disabled || loading}
|
|
65
|
+
aria-disabled={disabled || loading}
|
|
66
|
+
{...rest}
|
|
67
|
+
>
|
|
68
|
+
{loading ? "Loading…" : children}
|
|
69
|
+
</button>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type ButtonCloseXSize = "sm" | "md" | "lg";
|
|
5
|
+
|
|
6
|
+
export interface ButtonCloseXProps
|
|
7
|
+
extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "size"> {
|
|
8
|
+
size?: ButtonCloseXSize;
|
|
9
|
+
/** Use the light-on-dark treatment (Figma `Dark background=True`). */
|
|
10
|
+
onDark?: boolean;
|
|
11
|
+
/** Accessible label (defaults to "Close"). */
|
|
12
|
+
label?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const sizeClass: Record<ButtonCloseXSize, string> = {
|
|
16
|
+
sm: "p-xs", // 4px
|
|
17
|
+
md: "p-sm", // 6px
|
|
18
|
+
lg: "p-md", // 8px
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function ButtonCloseX({
|
|
22
|
+
size = "md",
|
|
23
|
+
onDark = false,
|
|
24
|
+
label = "Close",
|
|
25
|
+
className,
|
|
26
|
+
...rest
|
|
27
|
+
}: ButtonCloseXProps) {
|
|
28
|
+
return (
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
aria-label={label}
|
|
32
|
+
className={clsx(
|
|
33
|
+
"inline-flex items-center justify-center rounded-md transition-colors",
|
|
34
|
+
onDark
|
|
35
|
+
? "text-fg-white hover:bg-white/10"
|
|
36
|
+
: "text-fg-quaternary hover:bg-bg-primary-hover hover:text-fg-quaternary-hover",
|
|
37
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-primary",
|
|
38
|
+
sizeClass[size],
|
|
39
|
+
className,
|
|
40
|
+
)}
|
|
41
|
+
{...rest}
|
|
42
|
+
>
|
|
43
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
|
|
44
|
+
<path
|
|
45
|
+
d="m15 5-10 10M5 5l10 10"
|
|
46
|
+
stroke="currentColor"
|
|
47
|
+
strokeWidth="1.667"
|
|
48
|
+
strokeLinecap="round"
|
|
49
|
+
strokeLinejoin="round"
|
|
50
|
+
/>
|
|
51
|
+
</svg>
|
|
52
|
+
</button>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type ButtonDestructiveHierarchy =
|
|
5
|
+
| "Primary"
|
|
6
|
+
| "Secondary"
|
|
7
|
+
| "Tertiary"
|
|
8
|
+
| "Link";
|
|
9
|
+
export type ButtonDestructiveSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
10
|
+
|
|
11
|
+
export interface ButtonDestructiveProps
|
|
12
|
+
extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
13
|
+
hierarchy?: ButtonDestructiveHierarchy;
|
|
14
|
+
size?: ButtonDestructiveSize;
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Destructive palette (design.md §3 / Figma Button destructive 6218:85578).
|
|
19
|
+
// Primary/Secondary carry the skeuomorphic shadow stack; focus ring is the
|
|
20
|
+
// error ring (border-error).
|
|
21
|
+
const hierarchyClasses: Record<ButtonDestructiveHierarchy, string> = {
|
|
22
|
+
Primary:
|
|
23
|
+
"bg-error-solid text-white border-2 border-white/[0.12] shadow-skeuomorphic hover:bg-error-solid-hover",
|
|
24
|
+
Secondary:
|
|
25
|
+
"bg-bg-primary text-text-error-primary border border-border-error-subtle shadow-skeuomorphic hover:bg-bg-error-primary",
|
|
26
|
+
Tertiary:
|
|
27
|
+
"bg-transparent text-text-error-primary border-0 hover:bg-bg-error-primary",
|
|
28
|
+
Link: "bg-transparent text-text-error-primary border-0 p-0 hover:text-text-error-primary",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Padding mirrors Button.tsx — raw px at md/lg/xl per design.md §3, not the
|
|
32
|
+
// nearest spacing token. Don't "fix" these.
|
|
33
|
+
const sizeClasses: Record<ButtonDestructiveSize, string> = {
|
|
34
|
+
xs: "px-[10px] py-sm text-xs",
|
|
35
|
+
sm: "px-lg py-md text-xs",
|
|
36
|
+
md: "px-[14px] py-[10px] text-sm",
|
|
37
|
+
lg: "px-xl py-[10px] text-md",
|
|
38
|
+
xl: "px-[18px] py-lg text-md",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function ButtonDestructive({
|
|
42
|
+
hierarchy = "Primary",
|
|
43
|
+
size = "md",
|
|
44
|
+
loading = false,
|
|
45
|
+
disabled,
|
|
46
|
+
className,
|
|
47
|
+
children,
|
|
48
|
+
...rest
|
|
49
|
+
}: ButtonDestructiveProps) {
|
|
50
|
+
return (
|
|
51
|
+
<button
|
|
52
|
+
className={clsx(
|
|
53
|
+
"font-body font-semibold rounded-md cursor-pointer transition-colors",
|
|
54
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-error focus-visible:ring-offset-2 focus-visible:ring-offset-bg-primary",
|
|
55
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
56
|
+
hierarchyClasses[hierarchy],
|
|
57
|
+
hierarchy === "Link" ? "" : sizeClasses[size],
|
|
58
|
+
className,
|
|
59
|
+
)}
|
|
60
|
+
disabled={disabled || loading}
|
|
61
|
+
aria-disabled={disabled || loading}
|
|
62
|
+
{...rest}
|
|
63
|
+
>
|
|
64
|
+
{loading ? "Loading…" : children}
|
|
65
|
+
</button>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface ButtonGroupProps {
|
|
5
|
+
/** Segments — typically `ButtonGroupSegment` instances. */
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Segmented-control wrapper. Supplies the shared outer border, rounded ends,
|
|
12
|
+
* and the dividers between segments — segments themselves render borderless.
|
|
13
|
+
*/
|
|
14
|
+
export function ButtonGroup({ children, className }: ButtonGroupProps) {
|
|
15
|
+
return (
|
|
16
|
+
<div
|
|
17
|
+
role="group"
|
|
18
|
+
className={clsx(
|
|
19
|
+
"inline-flex overflow-hidden rounded-md border border-border-primary bg-bg-primary shadow-xs",
|
|
20
|
+
"[&>*:first-child]:rounded-l-md [&>*:last-child]:rounded-r-md",
|
|
21
|
+
"[&>*+*]:border-l [&>*+*]:border-border-primary",
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
{children}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type ButtonGroupSegmentSize = "sm" | "md";
|
|
5
|
+
|
|
6
|
+
export interface ButtonGroupSegmentProps
|
|
7
|
+
extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "size"> {
|
|
8
|
+
size?: ButtonGroupSegmentSize;
|
|
9
|
+
/** Active/pressed segment. */
|
|
10
|
+
current?: boolean;
|
|
11
|
+
/** Leading icon (or the only content for an icon-only segment). */
|
|
12
|
+
icon?: ReactNode;
|
|
13
|
+
/** Leading success dot. */
|
|
14
|
+
dot?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const sizeClasses: Record<ButtonGroupSegmentSize, string> = {
|
|
18
|
+
sm: "px-lg py-md text-sm",
|
|
19
|
+
md: "px-[14px] py-[10px] text-sm",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function ButtonGroupSegment({
|
|
23
|
+
size = "sm",
|
|
24
|
+
current = false,
|
|
25
|
+
icon,
|
|
26
|
+
dot = false,
|
|
27
|
+
children,
|
|
28
|
+
className,
|
|
29
|
+
...rest
|
|
30
|
+
}: ButtonGroupSegmentProps) {
|
|
31
|
+
return (
|
|
32
|
+
<button
|
|
33
|
+
type="button"
|
|
34
|
+
aria-pressed={current}
|
|
35
|
+
className={clsx(
|
|
36
|
+
"relative inline-flex items-center gap-md font-body font-semibold transition-colors",
|
|
37
|
+
"focus-visible:outline-none focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-border-brand",
|
|
38
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
39
|
+
current
|
|
40
|
+
? "bg-bg-secondary text-text-secondary-hover"
|
|
41
|
+
: "bg-bg-primary text-text-secondary hover:bg-bg-primary-hover",
|
|
42
|
+
sizeClasses[size],
|
|
43
|
+
className,
|
|
44
|
+
)}
|
|
45
|
+
{...rest}
|
|
46
|
+
>
|
|
47
|
+
{dot ? (
|
|
48
|
+
<span className="size-2 shrink-0 rounded-full bg-fg-success-secondary" aria-hidden />
|
|
49
|
+
) : null}
|
|
50
|
+
{icon ? <span className="shrink-0">{icon}</span> : null}
|
|
51
|
+
{children}
|
|
52
|
+
</button>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type ButtonUtilitySize = "xs" | "sm";
|
|
5
|
+
export type ButtonUtilityVariant = "outline" | "ghost";
|
|
6
|
+
|
|
7
|
+
export interface ButtonUtilityProps
|
|
8
|
+
extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "size"> {
|
|
9
|
+
/** Required icon glyph. */
|
|
10
|
+
icon: ReactNode;
|
|
11
|
+
/** Accessible label (also used as the tooltip when `tooltip` is true). */
|
|
12
|
+
label: string;
|
|
13
|
+
size?: ButtonUtilitySize;
|
|
14
|
+
variant?: ButtonUtilityVariant;
|
|
15
|
+
/** Show the hover/focus tooltip bubble. */
|
|
16
|
+
tooltip?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const sizeClasses: Record<ButtonUtilitySize, string> = {
|
|
20
|
+
xs: "p-xs rounded-sm", // 4px / radius-sm
|
|
21
|
+
sm: "p-sm rounded-md", // 6px / radius-md
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const variantClasses: Record<ButtonUtilityVariant, string> = {
|
|
25
|
+
outline:
|
|
26
|
+
"bg-bg-primary border border-border-primary text-fg-quaternary shadow-skeuomorphic hover:bg-bg-primary-hover hover:text-fg-quaternary-hover",
|
|
27
|
+
ghost:
|
|
28
|
+
"bg-transparent text-fg-quaternary hover:bg-bg-primary-hover hover:text-fg-quaternary-hover",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function ButtonUtility({
|
|
32
|
+
icon,
|
|
33
|
+
label,
|
|
34
|
+
size = "sm",
|
|
35
|
+
variant = "outline",
|
|
36
|
+
tooltip = false,
|
|
37
|
+
className,
|
|
38
|
+
...rest
|
|
39
|
+
}: ButtonUtilityProps) {
|
|
40
|
+
return (
|
|
41
|
+
<span className="group relative inline-flex">
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
aria-label={label}
|
|
45
|
+
className={clsx(
|
|
46
|
+
"inline-flex items-center justify-center transition-colors",
|
|
47
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-primary",
|
|
48
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
49
|
+
variantClasses[variant],
|
|
50
|
+
sizeClasses[size],
|
|
51
|
+
className,
|
|
52
|
+
)}
|
|
53
|
+
{...rest}
|
|
54
|
+
>
|
|
55
|
+
<span className="[&>svg]:size-5">{icon}</span>
|
|
56
|
+
</button>
|
|
57
|
+
{tooltip ? (
|
|
58
|
+
<span
|
|
59
|
+
role="tooltip"
|
|
60
|
+
className="pointer-events-none absolute bottom-full left-1/2 mb-xs -translate-x-1/2 whitespace-nowrap rounded-md bg-bg-primary-solid px-md py-xs text-xs font-semibold text-text-white opacity-0 shadow-lg transition-opacity group-hover:opacity-100 group-focus-within:opacity-100"
|
|
61
|
+
>
|
|
62
|
+
{label}
|
|
63
|
+
</span>
|
|
64
|
+
) : null}
|
|
65
|
+
</span>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface CalendarCellProps {
|
|
5
|
+
/** Day-of-month number. */
|
|
6
|
+
date: string | number;
|
|
7
|
+
/** Event chips for this day — typically `CalendarEvent` instances. */
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
/** "+N more" overflow count shown beneath the events. */
|
|
10
|
+
moreCount?: number;
|
|
11
|
+
/** Other-month / disabled styling. */
|
|
12
|
+
muted?: boolean;
|
|
13
|
+
/** Marks today (date number in brand). */
|
|
14
|
+
current?: boolean;
|
|
15
|
+
/** Renders a hover "+" add button bottom-right. */
|
|
16
|
+
onAdd?: () => void;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function PlusIcon() {
|
|
21
|
+
return (
|
|
22
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-4" aria-hidden>
|
|
23
|
+
<path
|
|
24
|
+
d="M10 4.167v11.666M4.167 10h11.666"
|
|
25
|
+
stroke="currentColor"
|
|
26
|
+
strokeWidth="1.667"
|
|
27
|
+
strokeLinecap="round"
|
|
28
|
+
strokeLinejoin="round"
|
|
29
|
+
/>
|
|
30
|
+
</svg>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A single day cell in the month grid. Composes CalendarEvent chips. */
|
|
35
|
+
export function CalendarCell({
|
|
36
|
+
date,
|
|
37
|
+
children,
|
|
38
|
+
moreCount,
|
|
39
|
+
muted = false,
|
|
40
|
+
current = false,
|
|
41
|
+
onAdd,
|
|
42
|
+
className,
|
|
43
|
+
}: CalendarCellProps) {
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
className={clsx(
|
|
47
|
+
"group relative flex min-h-[120px] flex-col gap-xs bg-bg-primary p-md font-body",
|
|
48
|
+
muted && "bg-bg-secondary",
|
|
49
|
+
className,
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
<span
|
|
53
|
+
className={clsx(
|
|
54
|
+
"text-xs font-semibold",
|
|
55
|
+
current
|
|
56
|
+
? "text-text-brand-secondary"
|
|
57
|
+
: muted
|
|
58
|
+
? "text-text-quaternary"
|
|
59
|
+
: "text-text-secondary",
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
{date}
|
|
63
|
+
</span>
|
|
64
|
+
{children ? <div className="flex flex-col gap-xs">{children}</div> : null}
|
|
65
|
+
{moreCount && moreCount > 0 ? (
|
|
66
|
+
<span className="text-xs font-medium text-text-tertiary">
|
|
67
|
+
{moreCount} more…
|
|
68
|
+
</span>
|
|
69
|
+
) : null}
|
|
70
|
+
{onAdd ? (
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
onClick={onAdd}
|
|
74
|
+
aria-label="Add event"
|
|
75
|
+
className="absolute bottom-md right-md hidden rounded-md border border-border-primary bg-bg-primary p-xs text-fg-quaternary shadow-xs transition-colors hover:bg-bg-primary-hover group-hover:flex focus-visible:flex focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand"
|
|
76
|
+
>
|
|
77
|
+
<PlusIcon />
|
|
78
|
+
</button>
|
|
79
|
+
) : null}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|