@fanvue/ui 2.21.0 → 3.0.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/dist/cjs/components/Accordion/AccordionContent.cjs +1 -1
- package/dist/cjs/components/Accordion/AccordionContent.cjs.map +1 -1
- package/dist/cjs/components/Accordion/AccordionTrigger.cjs +2 -2
- package/dist/cjs/components/Accordion/AccordionTrigger.cjs.map +1 -1
- package/dist/cjs/components/Alert/Alert.cjs +2 -2
- package/dist/cjs/components/Alert/Alert.cjs.map +1 -1
- package/dist/cjs/components/AudioUpload/AudioUpload.cjs +6 -6
- package/dist/cjs/components/AudioUpload/AudioUpload.cjs.map +1 -1
- package/dist/cjs/components/Autocomplete/Autocomplete.cjs +6 -6
- package/dist/cjs/components/Autocomplete/Autocomplete.cjs.map +1 -1
- package/dist/cjs/components/Autocomplete/AutocompleteDropdownContent.cjs +4 -4
- package/dist/cjs/components/Autocomplete/AutocompleteDropdownContent.cjs.map +1 -1
- package/dist/cjs/components/Autocomplete/AutocompleteOptionItem.cjs +1 -1
- package/dist/cjs/components/Autocomplete/AutocompleteOptionItem.cjs.map +1 -1
- package/dist/cjs/components/Autocomplete/AutocompleteTag.cjs +1 -1
- package/dist/cjs/components/Autocomplete/AutocompleteTag.cjs.map +1 -1
- package/dist/cjs/components/Badge/Badge.cjs +35 -21
- package/dist/cjs/components/Badge/Badge.cjs.map +1 -1
- package/dist/cjs/components/Banner/Banner.cjs +11 -11
- package/dist/cjs/components/Banner/Banner.cjs.map +1 -1
- package/dist/cjs/components/BottomNavigation/BottomNavigation.cjs +2 -2
- package/dist/cjs/components/BottomNavigation/BottomNavigation.cjs.map +1 -1
- package/dist/cjs/components/BottomNavigation/BottomNavigationAction.cjs +2 -2
- package/dist/cjs/components/BottomNavigation/BottomNavigationAction.cjs.map +1 -1
- package/dist/cjs/components/Breadcrumb/Breadcrumb.cjs +2 -2
- package/dist/cjs/components/Breadcrumb/Breadcrumb.cjs.map +1 -1
- package/dist/cjs/components/Button/Button.cjs +9 -9
- package/dist/cjs/components/Button/Button.cjs.map +1 -1
- package/dist/cjs/components/Card/Card.cjs +2 -2
- package/dist/cjs/components/Card/Card.cjs.map +1 -1
- package/dist/cjs/components/Chart/ChartCard.cjs +4 -4
- package/dist/cjs/components/Chart/ChartCard.cjs.map +1 -1
- package/dist/cjs/components/Chart/ChartPieLegend.cjs +2 -2
- package/dist/cjs/components/Chart/ChartPieLegend.cjs.map +1 -1
- package/dist/cjs/components/Chart/ChartSeriesToggle.cjs +1 -1
- package/dist/cjs/components/Chart/ChartSeriesToggle.cjs.map +1 -1
- package/dist/cjs/components/ChatInput/ChatInput.cjs +4 -4
- package/dist/cjs/components/ChatInput/ChatInput.cjs.map +1 -1
- package/dist/cjs/components/Checkbox/Checkbox.cjs +3 -3
- package/dist/cjs/components/Checkbox/Checkbox.cjs.map +1 -1
- package/dist/cjs/components/Chip/Chip.cjs +7 -7
- package/dist/cjs/components/Chip/Chip.cjs.map +1 -1
- package/dist/cjs/components/Count/Count.cjs +7 -7
- package/dist/cjs/components/Count/Count.cjs.map +1 -1
- package/dist/cjs/components/CreatorCard/CreatorCard.cjs +4 -4
- package/dist/cjs/components/CreatorCard/CreatorCard.cjs.map +1 -1
- package/dist/cjs/components/CreatorCover/CreatorCover.cjs +5 -5
- package/dist/cjs/components/CreatorCover/CreatorCover.cjs.map +1 -1
- package/dist/cjs/components/CreatorTile/CreatorTile.cjs +2 -2
- package/dist/cjs/components/CreatorTile/CreatorTile.cjs.map +1 -1
- package/dist/cjs/components/DatePicker/DatePicker.cjs +5 -5
- package/dist/cjs/components/DatePicker/DatePicker.cjs.map +1 -1
- package/dist/cjs/components/Dialog/Dialog.cjs +4 -4
- package/dist/cjs/components/Dialog/Dialog.cjs.map +1 -1
- package/dist/cjs/components/Divider/Divider.cjs +1 -1
- package/dist/cjs/components/Divider/Divider.cjs.map +1 -1
- package/dist/cjs/components/Drawer/Drawer.cjs +3 -3
- package/dist/cjs/components/Drawer/Drawer.cjs.map +1 -1
- package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs +13 -13
- package/dist/cjs/components/DropdownMenu/DropdownMenu.cjs.map +1 -1
- package/dist/cjs/components/EmptyState/EmptyState.cjs +6 -6
- package/dist/cjs/components/EmptyState/EmptyState.cjs.map +1 -1
- package/dist/cjs/components/IconButton/IconButton.cjs +6 -6
- package/dist/cjs/components/IconButton/IconButton.cjs.map +1 -1
- package/dist/cjs/components/InfoBox/InfoBox.cjs +4 -4
- package/dist/cjs/components/InfoBox/InfoBox.cjs.map +1 -1
- package/dist/cjs/components/InlineEdit/InlineEdit.cjs +1 -1
- package/dist/cjs/components/InlineEdit/InlineEdit.cjs.map +1 -1
- package/dist/cjs/components/Logo/Logo.cjs +2 -2
- package/dist/cjs/components/Logo/Logo.cjs.map +1 -1
- package/dist/cjs/components/MobileStepper/MobileStepper.cjs +1 -1
- package/dist/cjs/components/MobileStepper/MobileStepper.cjs.map +1 -1
- package/dist/cjs/components/Pagination/Pagination.cjs +1 -1
- package/dist/cjs/components/Pagination/Pagination.cjs.map +1 -1
- package/dist/cjs/components/Pill/Pill.cjs +5 -5
- package/dist/cjs/components/Pill/Pill.cjs.map +1 -1
- package/dist/cjs/components/ProgressBar/ProgressBar.cjs +5 -5
- package/dist/cjs/components/ProgressBar/ProgressBar.cjs.map +1 -1
- package/dist/cjs/components/Radio/Radio.cjs +3 -3
- package/dist/cjs/components/Radio/Radio.cjs.map +1 -1
- package/dist/cjs/components/Select/Select.cjs +11 -8
- package/dist/cjs/components/Select/Select.cjs.map +1 -1
- package/dist/cjs/components/Skeleton/Skeleton.cjs +1 -1
- package/dist/cjs/components/Skeleton/Skeleton.cjs.map +1 -1
- package/dist/cjs/components/Slider/SliderLayout.cjs +12 -5
- package/dist/cjs/components/Slider/SliderLayout.cjs.map +1 -1
- package/dist/cjs/components/Slider/SliderThumb.cjs +3 -3
- package/dist/cjs/components/Slider/SliderThumb.cjs.map +1 -1
- package/dist/cjs/components/Snackbar/Snackbar.cjs +6 -6
- package/dist/cjs/components/Snackbar/Snackbar.cjs.map +1 -1
- package/dist/cjs/components/Stepper/StepperStep.cjs +9 -9
- package/dist/cjs/components/Stepper/StepperStep.cjs.map +1 -1
- package/dist/cjs/components/Switch/Switch.cjs +1 -1
- package/dist/cjs/components/Switch/Switch.cjs.map +1 -1
- package/dist/cjs/components/SwitchField/SwitchField.cjs +2 -2
- package/dist/cjs/components/SwitchField/SwitchField.cjs.map +1 -1
- package/dist/cjs/components/SwitchToggle/SwitchToggle.cjs +1 -1
- package/dist/cjs/components/SwitchToggle/SwitchToggle.cjs.map +1 -1
- package/dist/cjs/components/Table/Table.cjs +7 -7
- package/dist/cjs/components/Table/Table.cjs.map +1 -1
- package/dist/cjs/components/Table/TablePagination.cjs +2 -2
- package/dist/cjs/components/Table/TablePagination.cjs.map +1 -1
- package/dist/cjs/components/Tabs/TabsTrigger.cjs +2 -2
- package/dist/cjs/components/Tabs/TabsTrigger.cjs.map +1 -1
- package/dist/cjs/components/TextArea/TextArea.cjs +5 -5
- package/dist/cjs/components/TextArea/TextArea.cjs.map +1 -1
- package/dist/cjs/components/TextField/TextField.cjs +5 -5
- package/dist/cjs/components/TextField/TextField.cjs.map +1 -1
- package/dist/cjs/components/Toast/Toast.cjs +2 -2
- package/dist/cjs/components/Toast/Toast.cjs.map +1 -1
- package/dist/cjs/components/Tooltip/Tooltip.cjs +1 -1
- package/dist/cjs/components/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/components/Accordion/AccordionContent.mjs +1 -1
- package/dist/components/Accordion/AccordionContent.mjs.map +1 -1
- package/dist/components/Accordion/AccordionTrigger.mjs +2 -2
- package/dist/components/Accordion/AccordionTrigger.mjs.map +1 -1
- package/dist/components/Alert/Alert.mjs +2 -2
- package/dist/components/Alert/Alert.mjs.map +1 -1
- package/dist/components/AudioUpload/AudioUpload.mjs +6 -6
- package/dist/components/AudioUpload/AudioUpload.mjs.map +1 -1
- package/dist/components/Autocomplete/Autocomplete.mjs +6 -6
- package/dist/components/Autocomplete/Autocomplete.mjs.map +1 -1
- package/dist/components/Autocomplete/AutocompleteDropdownContent.mjs +4 -4
- package/dist/components/Autocomplete/AutocompleteDropdownContent.mjs.map +1 -1
- package/dist/components/Autocomplete/AutocompleteOptionItem.mjs +1 -1
- package/dist/components/Autocomplete/AutocompleteOptionItem.mjs.map +1 -1
- package/dist/components/Autocomplete/AutocompleteTag.mjs +1 -1
- package/dist/components/Autocomplete/AutocompleteTag.mjs.map +1 -1
- package/dist/components/Badge/Badge.mjs +35 -21
- package/dist/components/Badge/Badge.mjs.map +1 -1
- package/dist/components/Banner/Banner.mjs +11 -11
- package/dist/components/Banner/Banner.mjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.mjs +2 -2
- package/dist/components/BottomNavigation/BottomNavigation.mjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigationAction.mjs +2 -2
- package/dist/components/BottomNavigation/BottomNavigationAction.mjs.map +1 -1
- package/dist/components/Breadcrumb/Breadcrumb.mjs +2 -2
- package/dist/components/Breadcrumb/Breadcrumb.mjs.map +1 -1
- package/dist/components/Button/Button.mjs +9 -9
- package/dist/components/Button/Button.mjs.map +1 -1
- package/dist/components/Card/Card.mjs +2 -2
- package/dist/components/Card/Card.mjs.map +1 -1
- package/dist/components/Chart/ChartCard.mjs +4 -4
- package/dist/components/Chart/ChartCard.mjs.map +1 -1
- package/dist/components/Chart/ChartPieLegend.mjs +2 -2
- package/dist/components/Chart/ChartPieLegend.mjs.map +1 -1
- package/dist/components/Chart/ChartSeriesToggle.mjs +1 -1
- package/dist/components/Chart/ChartSeriesToggle.mjs.map +1 -1
- package/dist/components/ChatInput/ChatInput.mjs +4 -4
- package/dist/components/ChatInput/ChatInput.mjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.mjs +3 -3
- package/dist/components/Checkbox/Checkbox.mjs.map +1 -1
- package/dist/components/Chip/Chip.mjs +7 -7
- package/dist/components/Chip/Chip.mjs.map +1 -1
- package/dist/components/Count/Count.mjs +7 -7
- package/dist/components/Count/Count.mjs.map +1 -1
- package/dist/components/CreatorCard/CreatorCard.mjs +4 -4
- package/dist/components/CreatorCard/CreatorCard.mjs.map +1 -1
- package/dist/components/CreatorCover/CreatorCover.mjs +5 -5
- package/dist/components/CreatorCover/CreatorCover.mjs.map +1 -1
- package/dist/components/CreatorTile/CreatorTile.mjs +2 -2
- package/dist/components/CreatorTile/CreatorTile.mjs.map +1 -1
- package/dist/components/DatePicker/DatePicker.mjs +5 -5
- package/dist/components/DatePicker/DatePicker.mjs.map +1 -1
- package/dist/components/Dialog/Dialog.mjs +4 -4
- package/dist/components/Dialog/Dialog.mjs.map +1 -1
- package/dist/components/Divider/Divider.mjs +1 -1
- package/dist/components/Divider/Divider.mjs.map +1 -1
- package/dist/components/Drawer/Drawer.mjs +3 -3
- package/dist/components/Drawer/Drawer.mjs.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.mjs +13 -13
- package/dist/components/DropdownMenu/DropdownMenu.mjs.map +1 -1
- package/dist/components/EmptyState/EmptyState.mjs +6 -6
- package/dist/components/EmptyState/EmptyState.mjs.map +1 -1
- package/dist/components/IconButton/IconButton.mjs +6 -6
- package/dist/components/IconButton/IconButton.mjs.map +1 -1
- package/dist/components/InfoBox/InfoBox.mjs +4 -4
- package/dist/components/InfoBox/InfoBox.mjs.map +1 -1
- package/dist/components/InlineEdit/InlineEdit.mjs +1 -1
- package/dist/components/InlineEdit/InlineEdit.mjs.map +1 -1
- package/dist/components/Logo/Logo.mjs +2 -2
- package/dist/components/Logo/Logo.mjs.map +1 -1
- package/dist/components/MobileStepper/MobileStepper.mjs +1 -1
- package/dist/components/MobileStepper/MobileStepper.mjs.map +1 -1
- package/dist/components/Pagination/Pagination.mjs +1 -1
- package/dist/components/Pagination/Pagination.mjs.map +1 -1
- package/dist/components/Pill/Pill.mjs +5 -5
- package/dist/components/Pill/Pill.mjs.map +1 -1
- package/dist/components/ProgressBar/ProgressBar.mjs +5 -5
- package/dist/components/ProgressBar/ProgressBar.mjs.map +1 -1
- package/dist/components/Radio/Radio.mjs +3 -3
- package/dist/components/Radio/Radio.mjs.map +1 -1
- package/dist/components/Select/Select.mjs +11 -8
- package/dist/components/Select/Select.mjs.map +1 -1
- package/dist/components/Skeleton/Skeleton.mjs +1 -1
- package/dist/components/Skeleton/Skeleton.mjs.map +1 -1
- package/dist/components/Slider/SliderLayout.mjs +12 -5
- package/dist/components/Slider/SliderLayout.mjs.map +1 -1
- package/dist/components/Slider/SliderThumb.mjs +3 -3
- package/dist/components/Slider/SliderThumb.mjs.map +1 -1
- package/dist/components/Snackbar/Snackbar.mjs +6 -6
- package/dist/components/Snackbar/Snackbar.mjs.map +1 -1
- package/dist/components/Stepper/StepperStep.mjs +9 -9
- package/dist/components/Stepper/StepperStep.mjs.map +1 -1
- package/dist/components/Switch/Switch.mjs +1 -1
- package/dist/components/Switch/Switch.mjs.map +1 -1
- package/dist/components/SwitchField/SwitchField.mjs +2 -2
- package/dist/components/SwitchField/SwitchField.mjs.map +1 -1
- package/dist/components/SwitchToggle/SwitchToggle.mjs +1 -1
- package/dist/components/SwitchToggle/SwitchToggle.mjs.map +1 -1
- package/dist/components/Table/Table.mjs +7 -7
- package/dist/components/Table/Table.mjs.map +1 -1
- package/dist/components/Table/TablePagination.mjs +2 -2
- package/dist/components/Table/TablePagination.mjs.map +1 -1
- package/dist/components/Tabs/TabsTrigger.mjs +2 -2
- package/dist/components/Tabs/TabsTrigger.mjs.map +1 -1
- package/dist/components/TextArea/TextArea.mjs +5 -5
- package/dist/components/TextArea/TextArea.mjs.map +1 -1
- package/dist/components/TextField/TextField.mjs +5 -5
- package/dist/components/TextField/TextField.mjs.map +1 -1
- package/dist/components/Toast/Toast.mjs +2 -2
- package/dist/components/Toast/Toast.mjs.map +1 -1
- package/dist/components/Tooltip/Tooltip.mjs +1 -1
- package/dist/components/Tooltip/Tooltip.mjs.map +1 -1
- package/dist/styles/base.css +2 -2
- package/dist/styles/theme.css +626 -195
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.mjs","sources":["../../../src/components/DatePicker/DatePicker.tsx"],"sourcesContent":["import { forwardRef, useEffect, useRef } from \"react\";\nimport {\n type ChevronProps,\n type DateRange,\n type DayButtonProps,\n DayPicker,\n type DayPickerProps,\n type DayProps,\n type Modifiers,\n type MonthGridProps,\n type WeekdayProps,\n type WeekdaysProps,\n type WeekProps,\n type WeeksProps,\n} from \"react-day-picker\";\nimport { cn } from \"../../utils/cn\";\nimport type { OmitDistributed } from \"../../utils/types\";\nimport { Button } from \"../Button/Button\";\nimport { ChevronLeftIcon } from \"../Icons/ChevronLeftIcon\";\nimport { ChevronRightIcon } from \"../Icons/ChevronRightIcon\";\n\nexport type { DateRange }; // Needed by consumers when passing props\n\n/** Layout variant — single or side-by-side month display. */\nexport type DatePickerVariant = \"single\" | \"double\";\n\n/** Props specific to the DatePicker wrapper (not inherited from react-day-picker). */\nexport interface DatePickerOwnProps {\n /** Display one month or two side-by-side. @default \"single\" */\n variant?: DatePickerVariant;\n /** Callback fired when the Apply button is clicked. */\n onApply?: () => void;\n /** Callback fired when the Cancel button is clicked. */\n onCancel?: () => void;\n /** Label for the cancel button. @default \"Cancel\" */\n cancelLabel?: string;\n /** Label for the apply button. @default \"Apply\" */\n applyLabel?: string;\n /** Whether to render the cancel / apply footer buttons. @default true */\n showFooter?: boolean;\n /** Additional CSS class name for the outer container. */\n className?: string;\n}\n\nfunction Day({ day, modifiers, className, ...divProps }: DayProps) {\n const { range_start, range_end } = modifiers;\n const isSingleDayRange = range_start && range_end;\n\n return (\n <div\n className={cn(\n className,\n (range_start || range_end) && !isSingleDayRange && \"from-50% from-transparent to-50%\",\n range_start && !isSingleDayRange && \"bg-linear-to-r to-brand-primary-muted\",\n range_end && !isSingleDayRange && \"bg-linear-to-l to-brand-primary-muted\",\n )}\n {...divProps}\n />\n );\n}\n\nfunction DayButton({ day, modifiers, className, ...buttonProps }: DayButtonProps) {\n const ref = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (modifiers.focused) ref.current?.focus();\n }, [modifiers.focused]);\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(\n \"relative z-10 inline-flex size-10 cursor-pointer items-center justify-center rounded-xs\",\n \"typography-regular-body-md\",\n \"transition-colors hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted\",\n \"focus-visible:outline-2 focus-visible:outline-brand-secondary-default focus-visible:outline-offset-[-2px]\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n modifiers.today && !modifiers.selected && \"border border-brand-primary-default\",\n modifiers.selected && !modifiers.range_middle\n ? \"bg-brand-primary-default text-content-on-brand hover:bg-brand-primary-default\"\n : \"text-content-primary\",\n modifiers.range_middle && \"rounded-none bg-transparent\",\n modifiers.outside && \"pointer-events-none opacity-50\",\n )}\n {...buttonProps}\n />\n );\n}\n\n/** Combined props — own DatePicker options plus all react-day-picker props (except `numberOfMonths`). */\nexport type DatePickerProps = DatePickerOwnProps &\n OmitDistributed<DayPickerProps, \"numberOfMonths\">;\n\n/**\n * A calendar date picker supporting single-date and date-range selection with\n * optional side-by-side month display and footer action buttons.\n *\n * Built on top of [react-day-picker](https://react-day-picker.js.org/) — all\n * `DayPickerProps` (except `numberOfMonths`) are forwarded.\n *\n * @example\n * ```tsx\n * <DatePicker\n * mode=\"range\"\n * type=\"double\"\n * selected={range}\n * onSelect={setRange}\n * onApply={save}\n * onCancel={close}\n * />\n * ```\n */\nexport const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(\n (\n {\n variant = \"single\",\n onApply,\n onCancel,\n cancelLabel = \"Cancel\",\n applyLabel = \"Apply\",\n showFooter = true,\n className,\n formatters,\n ...dayPickerProps\n },\n ref,\n ) => {\n const numberOfMonths = variant === \"double\" ? 2 : 1;\n const isMulti = numberOfMonths > 1;\n\n // Wrap onSelect for range mode: when clicking inside a complete range,\n // move the nearest boundary instead of always resetting the end date.\n const resolvedDayPickerProps = (() => {\n if (dayPickerProps.mode !== \"range\") return dayPickerProps;\n\n const { selected, onSelect } = dayPickerProps as {\n selected?: DateRange;\n onSelect?: (\n range: DateRange | undefined,\n triggerDate: Date,\n modifiers: Modifiers,\n e: React.MouseEvent | React.KeyboardEvent,\n ) => void;\n };\n\n if (!onSelect || !selected?.from || !selected?.to) return dayPickerProps;\n\n const { from, to } = selected;\n\n return {\n ...dayPickerProps,\n onSelect: (\n range: DateRange | undefined,\n triggerDate: Date,\n modifiers: Modifiers,\n e: React.MouseEvent | React.KeyboardEvent,\n ) => {\n const clickedTime = triggerDate.getTime();\n const fromTime = from.getTime();\n const toTime = to.getTime();\n\n if (clickedTime > fromTime && clickedTime < toTime) {\n if (clickedTime - fromTime <= toTime - clickedTime) {\n onSelect({ from: triggerDate, to }, triggerDate, modifiers, e);\n } else {\n onSelect({ from, to: triggerDate }, triggerDate, modifiers, e);\n }\n return;\n }\n\n onSelect(range, triggerDate, modifiers, e);\n },\n } as typeof dayPickerProps;\n })();\n\n return (\n <div\n ref={ref}\n className={cn(\n \"inline-flex flex-col rounded-md border border-neutral-alphas-200 bg-bg-primary shadow-blur-menu backdrop-blur-sm\",\n className,\n )}\n >\n <DayPicker\n showOutsideDays\n numberOfMonths={numberOfMonths}\n formatters={{\n formatCaption: (date: Date) =>\n date.toLocaleDateString(\"en-US\", { month: \"short\", year: \"numeric\" }),\n ...formatters,\n }}\n classNames={{\n root: \"w-full\",\n months: \"relative flex\",\n month: \"flex flex-1 flex-col\",\n month_caption: cn(\"flex items-center py-4\", isMulti ? \"justify-center px-2\" : \"px-5\"),\n caption_label: \"typography-semibold-body-lg text-content-primary\",\n nav: cn(\n \"absolute top-4 z-20 flex\",\n isMulti ? \"pointer-events-none inset-x-3 justify-between\" : \"right-3 gap-1\",\n ),\n button_previous:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full text-content-primary transition-colors hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-secondary-default disabled:cursor-not-allowed disabled:opacity-50\", // !TODO https://linear.app/fanvue/issue/ENG-7301/swap-out-typography-tailwind-utility-classes\n button_next:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full text-content-primary transition-colors hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-secondary-default disabled:cursor-not-allowed disabled:opacity-50\", // !TODO https://linear.app/fanvue/issue/ENG-7301/swap-out-typography-tailwind-utility-classes\n month_grid: cn(\"mb-4\", isMulti ? \"mx-2\" : \"mx-4\"),\n weekdays: \"flex\",\n weekday:\n \"flex h-[30px] w-10 flex-1 items-center justify-center typography-regular-body-md text-content-secondary\",\n week: \"flex overflow-hidden rounded-xs\",\n day: \"relative flex w-10 flex-1 items-center justify-center\",\n range_middle: \"bg-brand-primary-muted\",\n hidden: \"hidden\",\n }}\n components={{\n /**\n * !NOTE: We're unable to use semantic elements for the grid due to rdp, as such we've disabled the a11y lint rules for these elements in biome.json.\n */\n Chevron: ({ orientation }: ChevronProps) =>\n orientation === \"left\" ? <ChevronLeftIcon /> : <ChevronRightIcon />,\n MonthGrid: (props: MonthGridProps) => <div role=\"grid\" {...props} />,\n Weekdays: (props: WeekdaysProps) => <div role=\"row\" {...props} />,\n Weekday: (props: WeekdayProps) => <div role=\"columnheader\" {...props} />,\n Weeks: (props: WeeksProps) => <div role=\"rowgroup\" {...props} />,\n Week: ({ week, ...props }: WeekProps) => <div role=\"row\" {...props} />,\n Day,\n DayButton,\n }}\n {...resolvedDayPickerProps}\n />\n\n {showFooter && (\n <div className=\"flex gap-4 px-5 pb-4\">\n <Button variant=\"secondary\" size=\"40\" className=\"flex-1\" onClick={onCancel}>\n {cancelLabel}\n </Button>\n <Button variant=\"primary\" size=\"40\" className=\"flex-1\" onClick={onApply}>\n {applyLabel}\n </Button>\n </div>\n )}\n </div>\n );\n },\n);\n\nDatePicker.displayName = \"DatePicker\";\n"],"names":[],"mappings":";;;;;;;;AA4CA,SAAS,IAAI,EAAE,KAAK,WAAW,WAAW,GAAG,YAAsB;AACjE,QAAM,EAAE,aAAa,UAAA,IAAc;AACnC,QAAM,mBAAmB,eAAe;AAExC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,SACC,eAAe,cAAc,CAAC,oBAAoB;AAAA,QACnD,eAAe,CAAC,oBAAoB;AAAA,QACpC,aAAa,CAAC,oBAAoB;AAAA,MAAA;AAAA,MAEnC,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,SAAS,UAAU,EAAE,KAAK,WAAW,WAAW,GAAG,eAA+B;AAChF,QAAM,MAAM,OAA0B,IAAI;AAE1C,YAAU,MAAM;AACd,QAAI,UAAU,QAAS,KAAI,SAAS,MAAA;AAAA,EACtC,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,MAAK;AAAA,MACL,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,SAAS,CAAC,UAAU,YAAY;AAAA,QAC1C,UAAU,YAAY,CAAC,UAAU,eAC7B,kFACA;AAAA,QACJ,UAAU,gBAAgB;AAAA,QAC1B,UAAU,WAAW;AAAA,MAAA;AAAA,MAEtB,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;AAyBO,MAAM,aAAa;AAAA,EACxB,CACE;AAAA,IACE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,iBAAiB,YAAY,WAAW,IAAI;AAClD,UAAM,UAAU,iBAAiB;AAIjC,UAAM,0BAA0B,MAAM;AACpC,UAAI,eAAe,SAAS,QAAS,QAAO;AAE5C,YAAM,EAAE,UAAU,SAAA,IAAa;AAU/B,UAAI,CAAC,YAAY,CAAC,UAAU,QAAQ,CAAC,UAAU,GAAI,QAAO;AAE1D,YAAM,EAAE,MAAM,GAAA,IAAO;AAErB,aAAO;AAAA,QACL,GAAG;AAAA,QACH,UAAU,CACR,OACA,aACA,WACA,MACG;AACH,gBAAM,cAAc,YAAY,QAAA;AAChC,gBAAM,WAAW,KAAK,QAAA;AACtB,gBAAM,SAAS,GAAG,QAAA;AAElB,cAAI,cAAc,YAAY,cAAc,QAAQ;AAClD,gBAAI,cAAc,YAAY,SAAS,aAAa;AAClD,uBAAS,EAAE,MAAM,aAAa,MAAM,aAAa,WAAW,CAAC;AAAA,YAC/D,OAAO;AACL,uBAAS,EAAE,MAAM,IAAI,eAAe,aAAa,WAAW,CAAC;AAAA,YAC/D;AACA;AAAA,UACF;AAEA,mBAAS,OAAO,aAAa,WAAW,CAAC;AAAA,QAC3C;AAAA,MAAA;AAAA,IAEJ,GAAA;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAGF,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,iBAAe;AAAA,cACf;AAAA,cACA,YAAY;AAAA,gBACV,eAAe,CAAC,SACd,KAAK,mBAAmB,SAAS,EAAE,OAAO,SAAS,MAAM,WAAW;AAAA,gBACtE,GAAG;AAAA,cAAA;AAAA,cAEL,YAAY;AAAA,gBACV,MAAM;AAAA,gBACN,QAAQ;AAAA,gBACR,OAAO;AAAA,gBACP,eAAe,GAAG,0BAA0B,UAAU,wBAAwB,MAAM;AAAA,gBACpF,eAAe;AAAA,gBACf,KAAK;AAAA,kBACH;AAAA,kBACA,UAAU,kDAAkD;AAAA,gBAAA;AAAA,gBAE9D,iBACE;AAAA;AAAA,gBACF,aACE;AAAA;AAAA,gBACF,YAAY,GAAG,QAAQ,UAAU,SAAS,MAAM;AAAA,gBAChD,UAAU;AAAA,gBACV,SACE;AAAA,gBACF,MAAM;AAAA,gBACN,KAAK;AAAA,gBACL,cAAc;AAAA,gBACd,QAAQ;AAAA,cAAA;AAAA,cAEV,YAAY;AAAA;AAAA;AAAA;AAAA,gBAIV,SAAS,CAAC,EAAE,YAAA,MACV,gBAAgB,SAAS,oBAAC,iBAAA,CAAA,CAAgB,IAAK,oBAAC,kBAAA,CAAA,CAAiB;AAAA,gBACnE,WAAW,CAAC,UAA0B,oBAAC,SAAI,MAAK,QAAQ,GAAG,OAAO;AAAA,gBAClE,UAAU,CAAC,UAAyB,oBAAC,SAAI,MAAK,OAAO,GAAG,OAAO;AAAA,gBAC/D,SAAS,CAAC,UAAwB,oBAAC,SAAI,MAAK,gBAAgB,GAAG,OAAO;AAAA,gBACtE,OAAO,CAAC,UAAsB,oBAAC,SAAI,MAAK,YAAY,GAAG,OAAO;AAAA,gBAC9D,MAAM,CAAC,EAAE,MAAM,GAAG,MAAA,MAAuB,oBAAC,OAAA,EAAI,MAAK,OAAO,GAAG,MAAA,CAAO;AAAA,gBACpE;AAAA,gBACA;AAAA,cAAA;AAAA,cAED,GAAG;AAAA,YAAA;AAAA,UAAA;AAAA,UAGL,cACC,qBAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,YAAA,oBAAC,QAAA,EAAO,SAAQ,aAAY,MAAK,MAAK,WAAU,UAAS,SAAS,UAC/D,UAAA,YAAA,CACH;AAAA,YACA,oBAAC,QAAA,EAAO,SAAQ,WAAU,MAAK,MAAK,WAAU,UAAS,SAAS,SAC7D,UAAA,WAAA,CACH;AAAA,UAAA,EAAA,CACF;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,WAAW,cAAc;"}
|
|
1
|
+
{"version":3,"file":"DatePicker.mjs","sources":["../../../src/components/DatePicker/DatePicker.tsx"],"sourcesContent":["import { forwardRef, useEffect, useRef } from \"react\";\nimport {\n type ChevronProps,\n type DateRange,\n type DayButtonProps,\n DayPicker,\n type DayPickerProps,\n type DayProps,\n type Modifiers,\n type MonthGridProps,\n type WeekdayProps,\n type WeekdaysProps,\n type WeekProps,\n type WeeksProps,\n} from \"react-day-picker\";\nimport { cn } from \"../../utils/cn\";\nimport type { OmitDistributed } from \"../../utils/types\";\nimport { Button } from \"../Button/Button\";\nimport { ChevronLeftIcon } from \"../Icons/ChevronLeftIcon\";\nimport { ChevronRightIcon } from \"../Icons/ChevronRightIcon\";\n\nexport type { DateRange }; // Needed by consumers when passing props\n\n/** Layout variant — single or side-by-side month display. */\nexport type DatePickerVariant = \"single\" | \"double\";\n\n/** Props specific to the DatePicker wrapper (not inherited from react-day-picker). */\nexport interface DatePickerOwnProps {\n /** Display one month or two side-by-side. @default \"single\" */\n variant?: DatePickerVariant;\n /** Callback fired when the Apply button is clicked. */\n onApply?: () => void;\n /** Callback fired when the Cancel button is clicked. */\n onCancel?: () => void;\n /** Label for the cancel button. @default \"Cancel\" */\n cancelLabel?: string;\n /** Label for the apply button. @default \"Apply\" */\n applyLabel?: string;\n /** Whether to render the cancel / apply footer buttons. @default true */\n showFooter?: boolean;\n /** Additional CSS class name for the outer container. */\n className?: string;\n}\n\nfunction Day({ day, modifiers, className, ...divProps }: DayProps) {\n const { range_start, range_end } = modifiers;\n const isSingleDayRange = range_start && range_end;\n\n return (\n <div\n className={cn(\n className,\n (range_start || range_end) && !isSingleDayRange && \"from-50% from-transparent to-50%\",\n range_start && !isSingleDayRange && \"bg-linear-to-r to-brand-primary-muted\",\n range_end && !isSingleDayRange && \"bg-linear-to-l to-brand-primary-muted\",\n )}\n {...divProps}\n />\n );\n}\n\nfunction DayButton({ day, modifiers, className, ...buttonProps }: DayButtonProps) {\n const ref = useRef<HTMLButtonElement>(null);\n\n useEffect(() => {\n if (modifiers.focused) ref.current?.focus();\n }, [modifiers.focused]);\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(\n \"relative z-10 inline-flex size-10 cursor-pointer items-center justify-center rounded-xs\",\n \"typography-body-small-14px-regular\",\n \"transition-colors hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted\",\n \"focus-visible:outline-2 focus-visible:outline-brand-secondary-default focus-visible:outline-offset-[-2px]\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n modifiers.today && !modifiers.selected && \"border border-brand-primary-default\",\n modifiers.selected && !modifiers.range_middle\n ? \"bg-brand-primary-default text-content-always-black hover:bg-brand-primary-default\"\n : \"text-content-primary\",\n modifiers.range_middle && \"rounded-none bg-transparent\",\n modifiers.outside && \"pointer-events-none opacity-50\",\n )}\n {...buttonProps}\n />\n );\n}\n\n/** Combined props — own DatePicker options plus all react-day-picker props (except `numberOfMonths`). */\nexport type DatePickerProps = DatePickerOwnProps &\n OmitDistributed<DayPickerProps, \"numberOfMonths\">;\n\n/**\n * A calendar date picker supporting single-date and date-range selection with\n * optional side-by-side month display and footer action buttons.\n *\n * Built on top of [react-day-picker](https://react-day-picker.js.org/) — all\n * `DayPickerProps` (except `numberOfMonths`) are forwarded.\n *\n * @example\n * ```tsx\n * <DatePicker\n * mode=\"range\"\n * type=\"double\"\n * selected={range}\n * onSelect={setRange}\n * onApply={save}\n * onCancel={close}\n * />\n * ```\n */\nexport const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(\n (\n {\n variant = \"single\",\n onApply,\n onCancel,\n cancelLabel = \"Cancel\",\n applyLabel = \"Apply\",\n showFooter = true,\n className,\n formatters,\n ...dayPickerProps\n },\n ref,\n ) => {\n const numberOfMonths = variant === \"double\" ? 2 : 1;\n const isMulti = numberOfMonths > 1;\n\n // Wrap onSelect for range mode: when clicking inside a complete range,\n // move the nearest boundary instead of always resetting the end date.\n const resolvedDayPickerProps = (() => {\n if (dayPickerProps.mode !== \"range\") return dayPickerProps;\n\n const { selected, onSelect } = dayPickerProps as {\n selected?: DateRange;\n onSelect?: (\n range: DateRange | undefined,\n triggerDate: Date,\n modifiers: Modifiers,\n e: React.MouseEvent | React.KeyboardEvent,\n ) => void;\n };\n\n if (!onSelect || !selected?.from || !selected?.to) return dayPickerProps;\n\n const { from, to } = selected;\n\n return {\n ...dayPickerProps,\n onSelect: (\n range: DateRange | undefined,\n triggerDate: Date,\n modifiers: Modifiers,\n e: React.MouseEvent | React.KeyboardEvent,\n ) => {\n const clickedTime = triggerDate.getTime();\n const fromTime = from.getTime();\n const toTime = to.getTime();\n\n if (clickedTime > fromTime && clickedTime < toTime) {\n if (clickedTime - fromTime <= toTime - clickedTime) {\n onSelect({ from: triggerDate, to }, triggerDate, modifiers, e);\n } else {\n onSelect({ from, to: triggerDate }, triggerDate, modifiers, e);\n }\n return;\n }\n\n onSelect(range, triggerDate, modifiers, e);\n },\n } as typeof dayPickerProps;\n })();\n\n return (\n <div\n ref={ref}\n className={cn(\n \"inline-flex flex-col rounded-md border border-neutral-alphas-200 bg-background-primary shadow-blur-menu backdrop-blur-sm\",\n className,\n )}\n >\n <DayPicker\n showOutsideDays\n numberOfMonths={numberOfMonths}\n formatters={{\n formatCaption: (date: Date) =>\n date.toLocaleDateString(\"en-US\", { month: \"short\", year: \"numeric\" }),\n ...formatters,\n }}\n classNames={{\n root: \"w-full\",\n months: \"relative flex\",\n month: \"flex flex-1 flex-col\",\n month_caption: cn(\"flex items-center py-4\", isMulti ? \"justify-center px-2\" : \"px-5\"),\n caption_label: \"typography-body-default-16px-semibold text-content-primary\",\n nav: cn(\n \"absolute top-4 z-20 flex\",\n isMulti ? \"pointer-events-none inset-x-3 justify-between\" : \"right-3 gap-1\",\n ),\n button_previous:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full text-content-primary transition-colors hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-secondary-default disabled:cursor-not-allowed disabled:opacity-50\", // !TODO https://linear.app/fanvue/issue/ENG-7301/swap-out-typography-tailwind-utility-classes\n button_next:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full text-content-primary transition-colors hover:bg-brand-primary-muted not-disabled:active:bg-brand-primary-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-secondary-default disabled:cursor-not-allowed disabled:opacity-50\", // !TODO https://linear.app/fanvue/issue/ENG-7301/swap-out-typography-tailwind-utility-classes\n month_grid: cn(\"mb-4\", isMulti ? \"mx-2\" : \"mx-4\"),\n weekdays: \"flex\",\n weekday:\n \"flex h-[30px] w-10 flex-1 items-center justify-center typography-body-small-14px-regular text-content-secondary\",\n week: \"flex overflow-hidden rounded-xs\",\n day: \"relative flex w-10 flex-1 items-center justify-center\",\n range_middle: \"bg-brand-primary-muted\",\n hidden: \"hidden\",\n }}\n components={{\n /**\n * !NOTE: We're unable to use semantic elements for the grid due to rdp, as such we've disabled the a11y lint rules for these elements in biome.json.\n */\n Chevron: ({ orientation }: ChevronProps) =>\n orientation === \"left\" ? <ChevronLeftIcon /> : <ChevronRightIcon />,\n MonthGrid: (props: MonthGridProps) => <div role=\"grid\" {...props} />,\n Weekdays: (props: WeekdaysProps) => <div role=\"row\" {...props} />,\n Weekday: (props: WeekdayProps) => <div role=\"columnheader\" {...props} />,\n Weeks: (props: WeeksProps) => <div role=\"rowgroup\" {...props} />,\n Week: ({ week, ...props }: WeekProps) => <div role=\"row\" {...props} />,\n Day,\n DayButton,\n }}\n {...resolvedDayPickerProps}\n />\n\n {showFooter && (\n <div className=\"flex gap-4 px-5 pb-4\">\n <Button variant=\"secondary\" size=\"40\" className=\"flex-1\" onClick={onCancel}>\n {cancelLabel}\n </Button>\n <Button variant=\"primary\" size=\"40\" className=\"flex-1\" onClick={onApply}>\n {applyLabel}\n </Button>\n </div>\n )}\n </div>\n );\n },\n);\n\nDatePicker.displayName = \"DatePicker\";\n"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ const DialogOverlay = React.forwardRef(({ className, style, ...props }, ref) =>
|
|
|
16
16
|
{
|
|
17
17
|
ref,
|
|
18
18
|
className: cn(
|
|
19
|
-
"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-
|
|
19
|
+
"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-background-overlay-default data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
20
20
|
className
|
|
21
21
|
),
|
|
22
22
|
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
@@ -46,7 +46,7 @@ const DialogContent = React.forwardRef(({ className, children, size = "md", over
|
|
|
46
46
|
},
|
|
47
47
|
className: cn(
|
|
48
48
|
// Base
|
|
49
|
-
"fixed flex flex-col overflow-hidden bg-
|
|
49
|
+
"fixed flex flex-col overflow-hidden bg-background-primary shadow-lg focus:outline-none dark:bg-surface-primary",
|
|
50
50
|
// Mobile: bottom sheet
|
|
51
51
|
"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-lg",
|
|
52
52
|
// Animation (shared)
|
|
@@ -114,7 +114,7 @@ const DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
114
114
|
DialogPrimitive.Title,
|
|
115
115
|
{
|
|
116
116
|
ref,
|
|
117
|
-
className: cn("typography-
|
|
117
|
+
className: cn("typography-header-heading-xs truncate text-content-primary", className),
|
|
118
118
|
...props
|
|
119
119
|
}
|
|
120
120
|
));
|
|
@@ -123,7 +123,7 @@ const DialogDescription = React.forwardRef(({ className, ...props }, ref) => /*
|
|
|
123
123
|
DialogPrimitive.Description,
|
|
124
124
|
{
|
|
125
125
|
ref,
|
|
126
|
-
className: cn("typography-
|
|
126
|
+
className: cn("typography-body-default-16px-regular text-content-secondary", className),
|
|
127
127
|
...props
|
|
128
128
|
}
|
|
129
129
|
));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.mjs","sources":["../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ArrowLeftIcon } from \"../Icons/ArrowLeftIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Props for the {@link Dialog} root component. */\nexport interface DialogProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /** Controlled open state. When provided, you must also supply `onOpenChange`. */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the dialog when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a dialog. */\nexport const Dialog = DialogPrimitive.Root;\n\n/** Props for the {@link DialogTrigger} component. */\nexport type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the dialog when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the dialog on a scroll-drag-end.\n */\nexport const DialogTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DialogTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDialogTrigger.displayName = \"DialogTrigger\";\n\n/** Convenience alias for Radix `Dialog.Close`. Closes the dialog when clicked. */\nexport const DialogClose = DialogPrimitive.Close;\n\n/** Props for the {@link DialogClose} component. */\nexport type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\nexport interface DialogOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * Semi-transparent backdrop rendered behind the dialog content.\n * Rendered inside a portal automatically by {@link DialogContent}.\n */\nexport const DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-bg-overlay data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className,\n )}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport interface DialogContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * Width preset for the dialog.\n * - `\"sm\"` — 400px max-width (confirmations, simple forms)\n * - `\"md\"` — 440px max-width (default, standard dialogs)\n * - `\"lg\"` — 600px max-width (complex content, tables)\n *\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** When true, renders overlay automatically. @default true */\n overlay?: boolean;\n}\n\nconst SIZE_CLASSES: Record<NonNullable<DialogContentProps[\"size\"]>, string> = {\n sm: \"sm:max-w-[400px]\",\n md: \"sm:max-w-[440px]\",\n lg: \"sm:max-w-[600px]\",\n};\n\n/**\n * The dialog panel rendered inside a portal. Includes the overlay by default.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius. On larger viewports it renders centered with\n * full border radius.\n *\n * @example\n * ```tsx\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Title</DialogTitle>\n * </DialogHeader>\n * <DialogBody>Content here</DialogBody>\n * <DialogFooter>\n * <DialogClose asChild>\n * <Button variant=\"secondary\">Cancel</Button>\n * </DialogClose>\n * <Button>Accept</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n */\nexport const DialogContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(({ className, children, size = \"md\", overlay = true, style, onOpenAutoFocus, ...props }, ref) => (\n <DialogPrimitive.Portal>\n {overlay && <DialogOverlay />}\n <DialogPrimitive.Content\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n onOpenAutoFocus={(e) => {\n if (onOpenAutoFocus) {\n onOpenAutoFocus(e);\n return;\n }\n e.preventDefault();\n (e.currentTarget as HTMLElement).focus();\n }}\n className={cn(\n // Base\n \"fixed flex flex-col overflow-hidden bg-bg-primary shadow-lg focus:outline-none dark:bg-surface-primary\",\n // Mobile: bottom sheet\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-lg\",\n // Animation (shared)\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n // Mobile: slide up from bottom\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\n // Desktop: centered dialog\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg\",\n // Desktop: scale in/out (cancel mobile slide)\n \"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95\",\n \"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95\",\n // Duration\n \"duration-200\",\n // Size\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Show the close (X) button in the header. @default true */\n showClose?: boolean;\n /** Show a back arrow button on the left side. Defaults to `true` when `onBack` is provided. */\n showBack?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible label for the back button. @default \"Go back\" */\n backLabel?: string;\n /** Accessible label for the close button. @default \"Close\" */\n closeLabel?: string;\n}\n\n/**\n * Header bar for the dialog. Renders the title with an optional back arrow\n * and close button.\n *\n * @example\n * ```tsx\n * <DialogHeader>\n * <DialogTitle>Settings</DialogTitle>\n * </DialogHeader>\n *\n * <DialogHeader showBack onBack={() => setStep(0)}>\n * <DialogTitle>Step 2</DialogTitle>\n * </DialogHeader>\n * ```\n */\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n (\n {\n className,\n children,\n showClose = true,\n showBack,\n onBack,\n backLabel = \"Go back\",\n closeLabel = \"Close\",\n ...props\n },\n ref,\n ) => {\n const shouldShowBack = showBack ?? !!onBack;\n\n return (\n <div\n ref={ref}\n className={cn(\"flex h-16 shrink-0 items-center gap-2 px-6 py-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<ArrowLeftIcon />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton variant=\"tertiary\" size=\"32\" icon={<CloseIcon />} aria-label={closeLabel} />\n </DialogPrimitive.Close>\n )}\n </div>\n );\n },\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Props for the {@link DialogTitle} component. */\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\n/**\n * Accessible title for the dialog. Must be rendered inside {@link DialogHeader}\n * or directly within {@link DialogContent}.\n */\nexport const DialogTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-bold-heading-xs truncate text-content-primary\", className)}\n {...props}\n />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Props for the {@link DialogDescription} component. */\nexport type DialogDescriptionProps = React.ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/** Accessible description for the dialog. Rendered as secondary text. */\nexport const DialogDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-regular-body-lg text-content-secondary\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Scrollable content area (slot) between the header and footer.\n * Grows to fill available space and scrolls when content overflows.\n */\nexport const DialogBody = React.forwardRef<HTMLDivElement, DialogBodyProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex-1 overflow-y-auto px-6 py-4\", className)} {...props} />\n ),\n);\nDialogBody.displayName = \"DialogBody\";\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Footer bar for the dialog. Typically contains action buttons.\n * Children are laid out in a horizontal row with equal flex-basis.\n */\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex shrink-0 items-center gap-3 px-6 pt-3 pb-6\",\n \"[&>*]:min-w-0 [&>*]:flex-1\",\n className,\n )}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dialog.mjs","sources":["../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { ArrowLeftIcon } from \"../Icons/ArrowLeftIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** Props for the {@link Dialog} root component. */\nexport interface DialogProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /** Controlled open state. When provided, you must also supply `onOpenChange`. */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the dialog when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a dialog. */\nexport const Dialog = DialogPrimitive.Root;\n\n/** Props for the {@link DialogTrigger} component. */\nexport type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the dialog when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the dialog on a scroll-drag-end.\n */\nexport const DialogTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DialogTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDialogTrigger.displayName = \"DialogTrigger\";\n\n/** Convenience alias for Radix `Dialog.Close`. Closes the dialog when clicked. */\nexport const DialogClose = DialogPrimitive.Close;\n\n/** Props for the {@link DialogClose} component. */\nexport type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\nexport interface DialogOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * Semi-transparent backdrop rendered behind the dialog content.\n * Rendered inside a portal automatically by {@link DialogContent}.\n */\nexport const DialogOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DialogOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 fixed inset-0 bg-background-overlay-default data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className,\n )}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport interface DialogContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * Width preset for the dialog.\n * - `\"sm\"` — 400px max-width (confirmations, simple forms)\n * - `\"md\"` — 440px max-width (default, standard dialogs)\n * - `\"lg\"` — 600px max-width (complex content, tables)\n *\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** When true, renders overlay automatically. @default true */\n overlay?: boolean;\n}\n\nconst SIZE_CLASSES: Record<NonNullable<DialogContentProps[\"size\"]>, string> = {\n sm: \"sm:max-w-[400px]\",\n md: \"sm:max-w-[440px]\",\n lg: \"sm:max-w-[600px]\",\n};\n\n/**\n * The dialog panel rendered inside a portal. Includes the overlay by default.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius. On larger viewports it renders centered with\n * full border radius.\n *\n * @example\n * ```tsx\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button>Open</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Title</DialogTitle>\n * </DialogHeader>\n * <DialogBody>Content here</DialogBody>\n * <DialogFooter>\n * <DialogClose asChild>\n * <Button variant=\"secondary\">Cancel</Button>\n * </DialogClose>\n * <Button>Accept</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n * ```\n */\nexport const DialogContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(({ className, children, size = \"md\", overlay = true, style, onOpenAutoFocus, ...props }, ref) => (\n <DialogPrimitive.Portal>\n {overlay && <DialogOverlay />}\n <DialogPrimitive.Content\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n onOpenAutoFocus={(e) => {\n if (onOpenAutoFocus) {\n onOpenAutoFocus(e);\n return;\n }\n e.preventDefault();\n (e.currentTarget as HTMLElement).focus();\n }}\n className={cn(\n // Base\n \"fixed flex flex-col overflow-hidden bg-background-primary shadow-lg focus:outline-none dark:bg-surface-primary\",\n // Mobile: bottom sheet\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-lg\",\n // Animation (shared)\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n // Mobile: slide up from bottom\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\n // Desktop: centered dialog\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg\",\n // Desktop: scale in/out (cancel mobile slide)\n \"sm:data-[state=open]:slide-in-from-bottom-0 sm:data-[state=open]:zoom-in-95\",\n \"sm:data-[state=closed]:slide-out-to-bottom-0 sm:data-[state=closed]:zoom-out-95\",\n // Duration\n \"duration-200\",\n // Size\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Show the close (X) button in the header. @default true */\n showClose?: boolean;\n /** Show a back arrow button on the left side. Defaults to `true` when `onBack` is provided. */\n showBack?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible label for the back button. @default \"Go back\" */\n backLabel?: string;\n /** Accessible label for the close button. @default \"Close\" */\n closeLabel?: string;\n}\n\n/**\n * Header bar for the dialog. Renders the title with an optional back arrow\n * and close button.\n *\n * @example\n * ```tsx\n * <DialogHeader>\n * <DialogTitle>Settings</DialogTitle>\n * </DialogHeader>\n *\n * <DialogHeader showBack onBack={() => setStep(0)}>\n * <DialogTitle>Step 2</DialogTitle>\n * </DialogHeader>\n * ```\n */\nexport const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(\n (\n {\n className,\n children,\n showClose = true,\n showBack,\n onBack,\n backLabel = \"Go back\",\n closeLabel = \"Close\",\n ...props\n },\n ref,\n ) => {\n const shouldShowBack = showBack ?? !!onBack;\n\n return (\n <div\n ref={ref}\n className={cn(\"flex h-16 shrink-0 items-center gap-2 px-6 py-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<ArrowLeftIcon />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\n <div className=\"min-w-0 flex-1\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton variant=\"tertiary\" size=\"32\" icon={<CloseIcon />} aria-label={closeLabel} />\n </DialogPrimitive.Close>\n )}\n </div>\n );\n },\n);\nDialogHeader.displayName = \"DialogHeader\";\n\n/** Props for the {@link DialogTitle} component. */\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\n/**\n * Accessible title for the dialog. Must be rendered inside {@link DialogHeader}\n * or directly within {@link DialogContent}.\n */\nexport const DialogTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DialogTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-header-heading-xs truncate text-content-primary\", className)}\n {...props}\n />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Props for the {@link DialogDescription} component. */\nexport type DialogDescriptionProps = React.ComponentPropsWithoutRef<\n typeof DialogPrimitive.Description\n>;\n\n/** Accessible description for the dialog. Rendered as secondary text. */\nexport const DialogDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DialogDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-default-16px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Scrollable content area (slot) between the header and footer.\n * Grows to fill available space and scrolls when content overflows.\n */\nexport const DialogBody = React.forwardRef<HTMLDivElement, DialogBodyProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex-1 overflow-y-auto px-6 py-4\", className)} {...props} />\n ),\n);\nDialogBody.displayName = \"DialogBody\";\n\nexport interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/**\n * Footer bar for the dialog. Typically contains action buttons.\n * Children are laid out in a horizontal row with equal flex-basis.\n */\nexport const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex shrink-0 items-center gap-3 px-6 pt-3 pb-6\",\n \"[&>*]:min-w-0 [&>*]:flex-1\",\n className,\n )}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":[],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@ const Divider = React.forwardRef(({ label, className, ...props }, ref) => {
|
|
|
20
20
|
...props
|
|
21
21
|
}
|
|
22
22
|
),
|
|
23
|
-
/* @__PURE__ */ jsx("span", { className: "typography-
|
|
23
|
+
/* @__PURE__ */ jsx("span", { className: "typography-body-small-14px-regular shrink-0 text-content-primary", children: label }),
|
|
24
24
|
/* @__PURE__ */ jsx(
|
|
25
25
|
SeparatorPrimitive.Root,
|
|
26
26
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Divider.mjs","sources":["../../../src/components/Divider/Divider.tsx"],"sourcesContent":["import * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\n\n/** Orientation of the divider line. */\nexport type DividerOrientation = \"horizontal\" | \"vertical\";\n\nexport interface DividerProps\n extends React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> {\n /** Optional centred label text. When provided, the divider renders as two lines with the label between them. */\n label?: string;\n}\n\n/**\n * A horizontal separator used to divide content sections. Optionally displays a\n * centred text label between two lines.\n *\n * @example\n * ```tsx\n * <Divider />\n * <Divider label=\"or\" />\n * ```\n */\nexport const Divider = React.forwardRef<\n React.ElementRef<typeof SeparatorPrimitive.Root>,\n DividerProps\n>(({ label, className, ...props }, ref) => {\n if (label !== undefined) {\n return (\n <div\n ref={ref}\n className={cn(`my-2 flex w-full items-center justify-center gap-2`, className)}\n >\n <SeparatorPrimitive.Root\n decorative\n orientation=\"horizontal\"\n className=\"h-px flex-1 bg-border-primary\"\n {...props}\n />\n <span className=\"typography-
|
|
1
|
+
{"version":3,"file":"Divider.mjs","sources":["../../../src/components/Divider/Divider.tsx"],"sourcesContent":["import * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\n\n/** Orientation of the divider line. */\nexport type DividerOrientation = \"horizontal\" | \"vertical\";\n\nexport interface DividerProps\n extends React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> {\n /** Optional centred label text. When provided, the divider renders as two lines with the label between them. */\n label?: string;\n}\n\n/**\n * A horizontal separator used to divide content sections. Optionally displays a\n * centred text label between two lines.\n *\n * @example\n * ```tsx\n * <Divider />\n * <Divider label=\"or\" />\n * ```\n */\nexport const Divider = React.forwardRef<\n React.ElementRef<typeof SeparatorPrimitive.Root>,\n DividerProps\n>(({ label, className, ...props }, ref) => {\n if (label !== undefined) {\n return (\n <div\n ref={ref}\n className={cn(`my-2 flex w-full items-center justify-center gap-2`, className)}\n >\n <SeparatorPrimitive.Root\n decorative\n orientation=\"horizontal\"\n className=\"h-px flex-1 bg-border-primary\"\n {...props}\n />\n <span className=\"typography-body-small-14px-regular shrink-0 text-content-primary\">\n {label}\n </span>\n <SeparatorPrimitive.Root\n decorative\n orientation=\"horizontal\"\n className=\"h-px flex-1 bg-border-primary\"\n />\n </div>\n );\n }\n\n return (\n <SeparatorPrimitive.Root\n ref={ref}\n decorative\n orientation=\"horizontal\"\n className={cn(`mx-auto my-2 h-px w-full bg-border-primary`, className)}\n {...props}\n />\n );\n});\n\nDivider.displayName = \"Divider\";\n"],"names":[],"mappings":";;;;;AAuBO,MAAM,UAAU,MAAM,WAG3B,CAAC,EAAE,OAAO,WAAW,GAAG,MAAA,GAAS,QAAQ;AACzC,MAAI,UAAU,QAAW;AACvB,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW,GAAG,sDAAsD,SAAS;AAAA,QAE7E,UAAA;AAAA,UAAA;AAAA,YAAC,mBAAmB;AAAA,YAAnB;AAAA,cACC,YAAU;AAAA,cACV,aAAY;AAAA,cACZ,WAAU;AAAA,cACT,GAAG;AAAA,YAAA;AAAA,UAAA;AAAA,UAEN,oBAAC,QAAA,EAAK,WAAU,oEACb,UAAA,OACH;AAAA,UACA;AAAA,YAAC,mBAAmB;AAAA,YAAnB;AAAA,cACC,YAAU;AAAA,cACV,aAAY;AAAA,cACZ,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,QACZ;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AAEA,SACE;AAAA,IAAC,mBAAmB;AAAA,IAAnB;AAAA,MACC;AAAA,MACA,YAAU;AAAA,MACV,aAAY;AAAA,MACZ,WAAW,GAAG,8CAA8C,SAAS;AAAA,MACpE,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;AAED,QAAQ,cAAc;"}
|
|
@@ -24,7 +24,7 @@ const DrawerOverlay = React.forwardRef(({ className, style, ...props }, ref) =>
|
|
|
24
24
|
ref,
|
|
25
25
|
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
26
26
|
className: cn(
|
|
27
|
-
"fixed inset-0 bg-
|
|
27
|
+
"fixed inset-0 bg-background-overlay-default",
|
|
28
28
|
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
29
29
|
"data-[state=closed]:fade-out-0 data-[state=closed]:duration-150 data-[state=closed]:ease-in",
|
|
30
30
|
"data-[state=open]:fade-in-0 data-[state=open]:duration-200 data-[state=open]:ease-out",
|
|
@@ -116,7 +116,7 @@ const DrawerTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
116
116
|
DialogPrimitive.Title,
|
|
117
117
|
{
|
|
118
118
|
ref,
|
|
119
|
-
className: cn("typography-
|
|
119
|
+
className: cn("typography-body-default-16px-semibold truncate text-content-primary", className),
|
|
120
120
|
...props
|
|
121
121
|
}
|
|
122
122
|
));
|
|
@@ -125,7 +125,7 @@ const DrawerDescription = React.forwardRef(({ className, ...props }, ref) => /*
|
|
|
125
125
|
DialogPrimitive.Description,
|
|
126
126
|
{
|
|
127
127
|
ref,
|
|
128
|
-
className: cn("typography-
|
|
128
|
+
className: cn("typography-body-small-14px-regular text-content-secondary", className),
|
|
129
129
|
...props
|
|
130
130
|
}
|
|
131
131
|
));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.mjs","sources":["../../../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** The side from which the drawer slides in. */\nexport type DrawerPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/** Size presets for the drawer panel. Maps to max-width (left/right) or max-height (top/bottom). */\nexport type DrawerSize = \"sm\" | \"md\" | \"lg\" | \"full\";\n\n/**\n * Props for the {@link Drawer} root component.\n *\n * Inherits `open`, `onOpenChange`, and `defaultOpen` from Radix Dialog.Root.\n *\n * The Radix `modal` prop (default `true`) can also be passed to create a\n * non-modal drawer — useful for persistent side navigation that does not\n * block interaction with the rest of the page.\n *\n * **`overlay` behaviour:** When `overlay` is `false`, the component\n * automatically sets `modal={false}` on the underlying Radix Dialog.Root.\n * A modal dialog without a visible overlay is confusing because focus is\n * still trapped and scroll is blocked even though the page appears\n * interactive. Passing `modal={true}` explicitly will override this.\n */\nexport interface DrawerProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /**\n * Whether the default {@link DrawerOverlay} is rendered.\n * When `false`, `modal` is automatically set to `false` as well\n * (unless explicitly overridden) so focus-trap and scroll-lock are disabled.\n * @default true\n */\n overlay?: boolean;\n}\n\nconst DrawerContext = React.createContext<{ overlay: boolean }>({\n overlay: true,\n});\n\n/**\n * Root component that manages open/close state for a drawer.\n * Wraps Radix Dialog.Root.\n *\n * @example\n * ```tsx\n * <Drawer>\n * <DrawerTrigger>Open</DrawerTrigger>\n * <DrawerContent position=\"right\">\n * <DrawerHeader>\n * <DrawerTitle>Settings</DrawerTitle>\n * <DrawerDescription>Adjust your preferences.</DrawerDescription>\n * </DrawerHeader>\n * <p>Content goes here.</p>\n * <DrawerFooter>\n * <DrawerClose>Done</DrawerClose>\n * </DrawerFooter>\n * </DrawerContent>\n * </Drawer>\n * ```\n */\nexport function Drawer({ overlay = true, modal, children, ...props }: DrawerProps) {\n const resolvedModal = modal ?? (overlay ? undefined : false);\n return (\n <DrawerContext.Provider value={{ overlay }}>\n <DialogPrimitive.Root modal={resolvedModal} {...props}>\n {children}\n </DialogPrimitive.Root>\n </DrawerContext.Provider>\n );\n}\nDrawer.displayName = \"Drawer\";\n\n/** Props for the {@link DrawerTrigger} component. */\nexport type DrawerTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the drawer when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the drawer on a scroll-drag-end.\n */\nexport const DrawerTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DrawerTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDrawerTrigger.displayName = \"DrawerTrigger\";\n\n/** Props for the {@link DrawerClose} component. */\nexport type DrawerCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\n/** Closes the drawer when clicked. Can be placed anywhere inside the drawer. */\nexport const DrawerClose = DialogPrimitive.Close;\nDrawerClose.displayName = \"DrawerClose\";\n\n/** Props for the {@link DrawerOverlay} component. */\nexport interface DrawerOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * A translucent backdrop rendered behind the drawer content.\n * Clicking the overlay closes the drawer by default.\n */\nexport const DrawerOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DrawerOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"fixed inset-0 bg-bg-overlay\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:fade-in-0 data-[state=open]:duration-200 data-[state=open]:ease-out\",\n className,\n )}\n {...props}\n />\n));\nDrawerOverlay.displayName = \"DrawerOverlay\";\n\n/**\n * Slide-in animation classes keyed by position.\n * Uses Tailwind animate utilities (animate-in / animate-out).\n */\nconst SLIDE_CLASSES: Record<DrawerPosition, string> = {\n right:\n \"inset-y-0 right-0 h-full w-2/3 data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right\",\n left: \"inset-y-0 left-0 h-full w-2/3 data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left\",\n top: \"inset-x-0 top-0 w-full data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 w-full rounded-t-xs data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n};\n\n/** Props for the {@link DrawerContent} component. */\nexport interface DrawerContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * The edge from which the drawer slides in.\n *\n * Named `position` (rather than `side`) to avoid confusion with the CSS\n * `side` concept used by Radix Popover/Tooltip and to better convey the\n * spatial relationship of the drawer to the viewport.\n *\n * @default \"right\"\n */\n position?: DrawerPosition;\n /**\n * Controls the maximum extent of the drawer panel.\n * For left/right drawers this sets `max-width`; for top/bottom it sets `max-height`.\n * @default \"sm\"\n */\n size?: DrawerSize;\n /**\n * Whether to render the default {@link DrawerOverlay} behind the content.\n * Set to `false` to provide your own overlay or omit it entirely.\n *\n * Prefer setting `overlay` on the {@link Drawer} root instead so that\n * `modal` is also adjusted automatically.\n *\n * @default true\n */\n overlay?: boolean;\n /** Props forwarded to the default {@link DrawerOverlay} when `overlay` is `true`. */\n overlayProps?: DrawerOverlayProps;\n}\n\n/**\n * The panel that slides in from the chosen edge. Renders inside a portal with\n * an overlay backdrop by default.\n *\n * Includes focus-trap, `aria-describedby`, and Escape-to-close from Radix Dialog.\n */\nexport const DrawerContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DrawerContentProps\n>(\n (\n {\n className,\n position = \"right\",\n size = \"sm\",\n overlay: overlayProp,\n overlayProps,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const ctx = React.useContext(DrawerContext);\n const overlay = overlayProp ?? ctx.overlay;\n const isHorizontal = position === \"left\" || position === \"right\";\n const sizeClass = isHorizontal\n ? (\n {\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n full: \"max-w-full\",\n } as const\n )[size]\n : (\n {\n sm: \"max-h-[24rem]\",\n md: \"max-h-[28rem]\",\n lg: \"max-h-[32rem]\",\n full: \"max-h-full\",\n } as const\n )[size];\n\n return (\n <DialogPrimitive.Portal>\n {overlay && <DrawerOverlay {...overlayProps} />}\n <DialogPrimitive.Content\n ref={ref}\n style={{\n zIndex: \"calc(var(--fanvue-ui-portal-z-index, 50) + 1)\",\n ...style,\n }}\n className={cn(\n \"fixed flex flex-col bg-surface-secondary shadow-lg outline-none backdrop-blur-lg\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:duration-200 data-[state=open]:ease-out\",\n SLIDE_CLASSES[position],\n sizeClass,\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n },\n);\nDrawerContent.displayName = \"DrawerContent\";\n\n/** Props for the {@link DrawerHeader} component. */\nexport interface DrawerHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether to show a built-in close (X) button. @default true */\n showClose?: boolean;\n /** Accessible label for the close button. @default \"Close drawer\" */\n closeLabel?: string;\n}\n\n/**\n * A semantic header area for the drawer, typically containing a title and description.\n * Renders a built-in close button by default.\n */\nexport const DrawerHeader = React.forwardRef<HTMLDivElement, DrawerHeaderProps>(\n ({ className, showClose = true, closeLabel = \"Close drawer\", children, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex items-start gap-2 p-4\", className)} {...props}>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton\n icon={<CloseIcon />}\n aria-label={closeLabel}\n variant=\"tertiary\"\n size=\"24\"\n className=\"shrink-0\"\n />\n </DialogPrimitive.Close>\n )}\n </div>\n ),\n);\nDrawerHeader.displayName = \"DrawerHeader\";\n\n/** Props for the {@link DrawerFooter} component. */\nexport interface DrawerFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/** A semantic footer area for the drawer, typically containing action buttons. */\nexport const DrawerFooter = React.forwardRef<HTMLDivElement, DrawerFooterProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col gap-2 p-4\", className)} {...props} />\n ),\n);\nDrawerFooter.displayName = \"DrawerFooter\";\n\n/** Props for the {@link DrawerTitle} component. */\nexport interface DrawerTitleProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> {}\n\n/** An accessible title for the drawer. Required for screen readers. */\nexport const DrawerTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DrawerTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-semibold-body-lg truncate text-content-primary\", className)}\n {...props}\n />\n));\nDrawerTitle.displayName = \"DrawerTitle\";\n\n/** Props for the {@link DrawerDescription} component. */\nexport interface DrawerDescriptionProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> {}\n\n/** An accessible description for the drawer, providing supplementary context. */\nexport const DrawerDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DrawerDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-regular-body-md text-content-secondary\", className)}\n {...props}\n />\n));\nDrawerDescription.displayName = \"DrawerDescription\";\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Drawer.mjs","sources":["../../../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useSuppressClickAfterDrag } from \"../../utils/useSuppressClickAfterDrag\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\n\n/** The side from which the drawer slides in. */\nexport type DrawerPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/** Size presets for the drawer panel. Maps to max-width (left/right) or max-height (top/bottom). */\nexport type DrawerSize = \"sm\" | \"md\" | \"lg\" | \"full\";\n\n/**\n * Props for the {@link Drawer} root component.\n *\n * Inherits `open`, `onOpenChange`, and `defaultOpen` from Radix Dialog.Root.\n *\n * The Radix `modal` prop (default `true`) can also be passed to create a\n * non-modal drawer — useful for persistent side navigation that does not\n * block interaction with the rest of the page.\n *\n * **`overlay` behaviour:** When `overlay` is `false`, the component\n * automatically sets `modal={false}` on the underlying Radix Dialog.Root.\n * A modal dialog without a visible overlay is confusing because focus is\n * still trapped and scroll is blocked even though the page appears\n * interactive. Passing `modal={true}` explicitly will override this.\n */\nexport interface DrawerProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root> {\n /**\n * Whether the default {@link DrawerOverlay} is rendered.\n * When `false`, `modal` is automatically set to `false` as well\n * (unless explicitly overridden) so focus-trap and scroll-lock are disabled.\n * @default true\n */\n overlay?: boolean;\n}\n\nconst DrawerContext = React.createContext<{ overlay: boolean }>({\n overlay: true,\n});\n\n/**\n * Root component that manages open/close state for a drawer.\n * Wraps Radix Dialog.Root.\n *\n * @example\n * ```tsx\n * <Drawer>\n * <DrawerTrigger>Open</DrawerTrigger>\n * <DrawerContent position=\"right\">\n * <DrawerHeader>\n * <DrawerTitle>Settings</DrawerTitle>\n * <DrawerDescription>Adjust your preferences.</DrawerDescription>\n * </DrawerHeader>\n * <p>Content goes here.</p>\n * <DrawerFooter>\n * <DrawerClose>Done</DrawerClose>\n * </DrawerFooter>\n * </DrawerContent>\n * </Drawer>\n * ```\n */\nexport function Drawer({ overlay = true, modal, children, ...props }: DrawerProps) {\n const resolvedModal = modal ?? (overlay ? undefined : false);\n return (\n <DrawerContext.Provider value={{ overlay }}>\n <DialogPrimitive.Root modal={resolvedModal} {...props}>\n {children}\n </DialogPrimitive.Root>\n </DrawerContext.Provider>\n );\n}\nDrawer.displayName = \"Drawer\";\n\n/** Props for the {@link DrawerTrigger} component. */\nexport type DrawerTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;\n\n/**\n * The element that opens the drawer when clicked.\n *\n * On touch / pen, a press-and-release that crosses a small movement threshold\n * is treated as a drag and the resulting synthetic click is suppressed —\n * defends against Android Chrome opening the drawer on a scroll-drag-end.\n */\nexport const DrawerTrigger = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Trigger>,\n DrawerTriggerProps\n>((props, ref) => <DialogPrimitive.Trigger ref={ref} {...useSuppressClickAfterDrag(props)} />);\nDrawerTrigger.displayName = \"DrawerTrigger\";\n\n/** Props for the {@link DrawerClose} component. */\nexport type DrawerCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;\n\n/** Closes the drawer when clicked. Can be placed anywhere inside the drawer. */\nexport const DrawerClose = DialogPrimitive.Close;\nDrawerClose.displayName = \"DrawerClose\";\n\n/** Props for the {@link DrawerOverlay} component. */\nexport interface DrawerOverlayProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> {}\n\n/**\n * A translucent backdrop rendered behind the drawer content.\n * Clicking the overlay closes the drawer by default.\n */\nexport const DrawerOverlay = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Overlay>,\n DrawerOverlayProps\n>(({ className, style, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"fixed inset-0 bg-background-overlay-default\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:fade-in-0 data-[state=open]:duration-200 data-[state=open]:ease-out\",\n className,\n )}\n {...props}\n />\n));\nDrawerOverlay.displayName = \"DrawerOverlay\";\n\n/**\n * Slide-in animation classes keyed by position.\n * Uses Tailwind animate utilities (animate-in / animate-out).\n */\nconst SLIDE_CLASSES: Record<DrawerPosition, string> = {\n right:\n \"inset-y-0 right-0 h-full w-2/3 data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right\",\n left: \"inset-y-0 left-0 h-full w-2/3 data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left\",\n top: \"inset-x-0 top-0 w-full data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 w-full rounded-t-xs data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom\",\n};\n\n/** Props for the {@link DrawerContent} component. */\nexport interface DrawerContentProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /**\n * The edge from which the drawer slides in.\n *\n * Named `position` (rather than `side`) to avoid confusion with the CSS\n * `side` concept used by Radix Popover/Tooltip and to better convey the\n * spatial relationship of the drawer to the viewport.\n *\n * @default \"right\"\n */\n position?: DrawerPosition;\n /**\n * Controls the maximum extent of the drawer panel.\n * For left/right drawers this sets `max-width`; for top/bottom it sets `max-height`.\n * @default \"sm\"\n */\n size?: DrawerSize;\n /**\n * Whether to render the default {@link DrawerOverlay} behind the content.\n * Set to `false` to provide your own overlay or omit it entirely.\n *\n * Prefer setting `overlay` on the {@link Drawer} root instead so that\n * `modal` is also adjusted automatically.\n *\n * @default true\n */\n overlay?: boolean;\n /** Props forwarded to the default {@link DrawerOverlay} when `overlay` is `true`. */\n overlayProps?: DrawerOverlayProps;\n}\n\n/**\n * The panel that slides in from the chosen edge. Renders inside a portal with\n * an overlay backdrop by default.\n *\n * Includes focus-trap, `aria-describedby`, and Escape-to-close from Radix Dialog.\n */\nexport const DrawerContent = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Content>,\n DrawerContentProps\n>(\n (\n {\n className,\n position = \"right\",\n size = \"sm\",\n overlay: overlayProp,\n overlayProps,\n style,\n children,\n ...props\n },\n ref,\n ) => {\n const ctx = React.useContext(DrawerContext);\n const overlay = overlayProp ?? ctx.overlay;\n const isHorizontal = position === \"left\" || position === \"right\";\n const sizeClass = isHorizontal\n ? (\n {\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n full: \"max-w-full\",\n } as const\n )[size]\n : (\n {\n sm: \"max-h-[24rem]\",\n md: \"max-h-[28rem]\",\n lg: \"max-h-[32rem]\",\n full: \"max-h-full\",\n } as const\n )[size];\n\n return (\n <DialogPrimitive.Portal>\n {overlay && <DrawerOverlay {...overlayProps} />}\n <DialogPrimitive.Content\n ref={ref}\n style={{\n zIndex: \"calc(var(--fanvue-ui-portal-z-index, 50) + 1)\",\n ...style,\n }}\n className={cn(\n \"fixed flex flex-col bg-surface-secondary shadow-lg outline-none backdrop-blur-lg\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:duration-150 data-[state=closed]:ease-in\",\n \"data-[state=open]:duration-200 data-[state=open]:ease-out\",\n SLIDE_CLASSES[position],\n sizeClass,\n className,\n )}\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n },\n);\nDrawerContent.displayName = \"DrawerContent\";\n\n/** Props for the {@link DrawerHeader} component. */\nexport interface DrawerHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Whether to show a built-in close (X) button. @default true */\n showClose?: boolean;\n /** Accessible label for the close button. @default \"Close drawer\" */\n closeLabel?: string;\n}\n\n/**\n * A semantic header area for the drawer, typically containing a title and description.\n * Renders a built-in close button by default.\n */\nexport const DrawerHeader = React.forwardRef<HTMLDivElement, DrawerHeaderProps>(\n ({ className, showClose = true, closeLabel = \"Close drawer\", children, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex items-start gap-2 p-4\", className)} {...props}>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1.5\">{children}</div>\n {showClose && (\n <DialogPrimitive.Close asChild>\n <IconButton\n icon={<CloseIcon />}\n aria-label={closeLabel}\n variant=\"tertiary\"\n size=\"24\"\n className=\"shrink-0\"\n />\n </DialogPrimitive.Close>\n )}\n </div>\n ),\n);\nDrawerHeader.displayName = \"DrawerHeader\";\n\n/** Props for the {@link DrawerFooter} component. */\nexport interface DrawerFooterProps extends React.HTMLAttributes<HTMLDivElement> {}\n\n/** A semantic footer area for the drawer, typically containing action buttons. */\nexport const DrawerFooter = React.forwardRef<HTMLDivElement, DrawerFooterProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex flex-col gap-2 p-4\", className)} {...props} />\n ),\n);\nDrawerFooter.displayName = \"DrawerFooter\";\n\n/** Props for the {@link DrawerTitle} component. */\nexport interface DrawerTitleProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> {}\n\n/** An accessible title for the drawer. Required for screen readers. */\nexport const DrawerTitle = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Title>,\n DrawerTitleProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"typography-body-default-16px-semibold truncate text-content-primary\", className)}\n {...props}\n />\n));\nDrawerTitle.displayName = \"DrawerTitle\";\n\n/** Props for the {@link DrawerDescription} component. */\nexport interface DrawerDescriptionProps\n extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> {}\n\n/** An accessible description for the drawer, providing supplementary context. */\nexport const DrawerDescription = React.forwardRef<\n React.ComponentRef<typeof DialogPrimitive.Description>,\n DrawerDescriptionProps\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"typography-body-small-14px-regular text-content-secondary\", className)}\n {...props}\n />\n));\nDrawerDescription.displayName = \"DrawerDescription\";\n"],"names":[],"mappings":"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"}
|
|
@@ -127,7 +127,7 @@ const DropdownMenuLabel = React.forwardRef(({ className, position = "default", .
|
|
|
127
127
|
{
|
|
128
128
|
ref,
|
|
129
129
|
className: cn(
|
|
130
|
-
"typography-
|
|
130
|
+
"typography-description-12px-regular flex items-center px-3 text-content-secondary",
|
|
131
131
|
position === "top" ? "py-2" : "pb-2 pt-4",
|
|
132
132
|
className
|
|
133
133
|
),
|
|
@@ -142,12 +142,12 @@ const SIZE_NORMALIZED = {
|
|
|
142
142
|
sm: "32"
|
|
143
143
|
};
|
|
144
144
|
const ITEM_SIZE_CLASSES = {
|
|
145
|
-
"40": "min-h-10 py-2 typography-
|
|
146
|
-
"32": "min-h-8 py-[7px] typography-
|
|
145
|
+
"40": "min-h-10 py-2 typography-body-default-16px-regular",
|
|
146
|
+
"32": "min-h-8 py-[7px] typography-body-small-14px-regular"
|
|
147
147
|
};
|
|
148
148
|
const ITEM_SELECTED_TYPOGRAPHY = {
|
|
149
|
-
"40": "typography-
|
|
150
|
-
"32": "typography-
|
|
149
|
+
"40": "typography-body-default-16px-semibold",
|
|
150
|
+
"32": "typography-body-small-14px-semibold"
|
|
151
151
|
};
|
|
152
152
|
const DropdownMenuItem = React.forwardRef(
|
|
153
153
|
({
|
|
@@ -169,8 +169,8 @@ const DropdownMenuItem = React.forwardRef(
|
|
|
169
169
|
"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled",
|
|
170
170
|
destructive && "text-error-content",
|
|
171
171
|
selected && [
|
|
172
|
-
"bg-buttons-primary text-content-primary-inverted",
|
|
173
|
-
"data-[highlighted]:bg-buttons-primary",
|
|
172
|
+
"bg-buttons-primary-default text-content-primary-inverted",
|
|
173
|
+
"data-[highlighted]:bg-buttons-primary-default",
|
|
174
174
|
ITEM_SELECTED_TYPOGRAPHY[normalizedSize]
|
|
175
175
|
],
|
|
176
176
|
className
|
|
@@ -208,7 +208,7 @@ const DropdownMenuHeader = React.forwardRef(
|
|
|
208
208
|
children,
|
|
209
209
|
...props
|
|
210
210
|
}, ref) => {
|
|
211
|
-
const titleTypography = size === "32" ? "typography-
|
|
211
|
+
const titleTypography = size === "32" ? "typography-body-small-14px-semibold" : "typography-body-default-16px-semibold";
|
|
212
212
|
const toggleOpen = React.useContext(ToggleOpenContext);
|
|
213
213
|
const handleClose = () => {
|
|
214
214
|
onClose?.();
|
|
@@ -270,7 +270,7 @@ function SearchInput({
|
|
|
270
270
|
{
|
|
271
271
|
type: "search",
|
|
272
272
|
className: cn(
|
|
273
|
-
"typography-
|
|
273
|
+
"typography-body-default-16px-regular min-w-0 flex-1 bg-transparent outline-none",
|
|
274
274
|
"placeholder:text-content-tertiary"
|
|
275
275
|
),
|
|
276
276
|
value,
|
|
@@ -299,8 +299,8 @@ const DropdownMenuRadioItem = React.forwardRef(({ className, children, helper, s
|
|
|
299
299
|
"group flex w-full cursor-pointer items-start gap-3 rounded-xs px-4 py-2 outline-none",
|
|
300
300
|
"data-[highlighted]:bg-neutral-alphas-50",
|
|
301
301
|
"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled",
|
|
302
|
-
"data-[state=checked]:bg-buttons-primary data-[state=checked]:text-content-primary-inverted",
|
|
303
|
-
"data-[state=checked]:data-[highlighted]:bg-buttons-primary",
|
|
302
|
+
"data-[state=checked]:bg-buttons-primary-default data-[state=checked]:text-content-primary-inverted",
|
|
303
|
+
"data-[state=checked]:data-[highlighted]:bg-buttons-primary-default",
|
|
304
304
|
className
|
|
305
305
|
),
|
|
306
306
|
...props,
|
|
@@ -318,12 +318,12 @@ const DropdownMenuRadioItem = React.forwardRef(({ className, children, helper, s
|
|
|
318
318
|
}
|
|
319
319
|
),
|
|
320
320
|
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
321
|
-
/* @__PURE__ */ jsx("span", { className: "typography-
|
|
321
|
+
/* @__PURE__ */ jsx("span", { className: "typography-body-default-16px-semibold truncate", children }),
|
|
322
322
|
helper && /* @__PURE__ */ jsx(
|
|
323
323
|
"span",
|
|
324
324
|
{
|
|
325
325
|
className: cn(
|
|
326
|
-
"typography-
|
|
326
|
+
"typography-description-12px-regular text-content-secondary",
|
|
327
327
|
"group-data-[state=checked]:text-content-primary-inverted",
|
|
328
328
|
"group-data-[disabled]:text-content-disabled"
|
|
329
329
|
),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.mjs","sources":["../../../src/components/DropdownMenu/DropdownMenu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { FLOATING_CONTENT_COLLISION_PADDING } from \"../../utils/floatingContentCollisionPadding\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SearchIcon } from \"../Icons/SearchIcon\";\n\n// Movement, in CSS px, above which a touch press-and-release counts as a drag.\nconst TAP_MOVEMENT_THRESHOLD_PX = 10;\n\n// Keys that the menu must keep handling even when focus is inside a child\n// input — arrows move the highlight into the list, Tab leaves the menu, and\n// Enter / Escape close it.\nconst NAVIGATION_KEYS = new Set([\n \"ArrowDown\",\n \"ArrowUp\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"Escape\",\n \"Tab\",\n \"Enter\",\n]);\n\ntype ActiveTap = {\n pointerId: number;\n x: number;\n y: number;\n movedPastThreshold: boolean;\n};\n\n// Lets DropdownMenuTrigger toggle the menu directly so it can gate on touch\n// movement — see radix-ui/primitives#1912.\nconst ToggleOpenContext = React.createContext<\n ((updater: (prev: boolean) => boolean) => void) | null\n>(null);\n\n/** Props for the {@link DropdownMenu} root component. */\nexport interface DropdownMenuProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root> {}\n\n/** Root component that manages open/close state for a dropdown menu. */\nexport function DropdownMenu({\n open: openProp,\n defaultOpen,\n onOpenChange,\n children,\n ...props\n}: DropdownMenuProps) {\n const [open = false, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n return (\n <ToggleOpenContext.Provider value={setOpen}>\n <DropdownMenuPrimitive.Root open={open} onOpenChange={setOpen} {...props}>\n {children}\n </DropdownMenuPrimitive.Root>\n </ToggleOpenContext.Provider>\n );\n}\n\n/** Props for the {@link DropdownMenuTrigger} component. */\nexport type DropdownMenuTriggerProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Trigger\n>;\n\n/**\n * The element that toggles the dropdown menu when clicked.\n *\n * On touch devices, the menu only opens if the press-and-release stays within\n * a small movement threshold. A drag that incidentally ends over the trigger\n * (common when scrolling a feed on Android Chrome) is ignored. Mouse and\n * keyboard interactions are unchanged.\n */\nexport const DropdownMenuTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Trigger>,\n DropdownMenuTriggerProps\n>((props, ref) => {\n const toggleOpen = React.useContext(ToggleOpenContext);\n const tapRef = React.useRef<ActiveTap | null>(null);\n\n // Used outside our DropdownMenu wrapper — fall through to Radix defaults.\n if (toggleOpen === null) {\n return <DropdownMenuPrimitive.Trigger {...props} ref={ref} />;\n }\n\n return (\n <DropdownMenuPrimitive.Trigger\n {...props}\n ref={ref}\n onPointerDown={(event) => {\n props.onPointerDown?.(event);\n if (event.pointerType === \"mouse\" || props.disabled) return;\n // Keep pointerup / pointercancel on this element if the finger drifts off.\n // Optional because jsdom (used in tests) doesn't implement it.\n event.currentTarget.setPointerCapture?.(event.pointerId);\n tapRef.current = {\n pointerId: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n movedPastThreshold: false,\n };\n // preventDefault stops Radix's pointerdown open path via composeEventHandlers.\n event.preventDefault();\n }}\n onPointerMove={(event) => {\n props.onPointerMove?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId || tap.movedPastThreshold) {\n return;\n }\n const dx = event.clientX - tap.x;\n const dy = event.clientY - tap.y;\n if (Math.hypot(dx, dy) > TAP_MOVEMENT_THRESHOLD_PX) {\n tap.movedPastThreshold = true;\n }\n }}\n onPointerUp={(event) => {\n props.onPointerUp?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId) return;\n const wasDrag = tap.movedPastThreshold;\n tapRef.current = null;\n if (!wasDrag && !props.disabled) {\n toggleOpen((prev) => !prev);\n }\n }}\n onPointerCancel={(event) => {\n props.onPointerCancel?.(event);\n const tap = tapRef.current;\n if (tap !== null && event.pointerId === tap.pointerId) {\n tapRef.current = null;\n }\n }}\n />\n );\n});\nDropdownMenuTrigger.displayName = \"DropdownMenuTrigger\";\n\n/** Props for the {@link DropdownMenuContent} component. */\nexport interface DropdownMenuContentProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> {}\n\n/**\n * The positioned content panel rendered inside a portal.\n *\n * Override the portal z-index per-instance via `style={{ zIndex: 1500 }}` or\n * globally with the `--fanvue-ui-portal-z-index` CSS custom property.\n *\n * @example\n * ```tsx\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button>Open</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem>Option 1</DropdownMenuItem>\n * <DropdownMenuItem>Option 2</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n */\nexport const DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n DropdownMenuContentProps\n>(\n (\n {\n className,\n style,\n sideOffset = 4,\n collisionPadding = FLOATING_CONTENT_COLLISION_PADDING,\n ...props\n },\n ref,\n ) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(\n \"w-max min-w-(--radix-dropdown-menu-trigger-width) max-w-(--radix-dropdown-menu-content-available-width) overflow-y-auto rounded-sm border border-neutral-alphas-200 bg-surface-primary p-1 text-content-primary shadow-lg\",\n \"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n \"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95\",\n \"data-[side=top]:slide-in-from-bottom-2 data-[side=bottom]:slide-in-from-top-2\",\n \"data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2\",\n className,\n )}\n style={{\n zIndex: \"var(--fanvue-ui-portal-z-index, 50)\",\n maxHeight: \"var(--radix-dropdown-menu-content-available-height)\",\n ...style,\n }}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n ),\n);\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** Props for the {@link DropdownMenuGroup} component. */\nexport type DropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Group\n>;\n\n/** Groups related menu items. Accepts an optional `DropdownMenuLabel`. */\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nDropdownMenuGroup.displayName = \"DropdownMenuGroup\";\n\n/** Vertical placement of a {@link DropdownMenuLabel} within its group. */\nexport type DropdownMenuLabelPosition = \"default\" | \"top\";\n\n/** Props for the {@link DropdownMenuLabel} component. */\nexport interface DropdownMenuLabelProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> {\n /**\n * Vertical placement within the surrounding group. `\"top\"` is used for the\n * first label directly under a header; `\"default\"` adds extra top padding to\n * separate it from preceding items. @default \"default\"\n */\n position?: DropdownMenuLabelPosition;\n}\n\n/** A non-interactive label that groups related items within a menu. */\nexport const DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n DropdownMenuLabelProps\n>(({ className, position = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"typography-regular-body-sm flex items-center px-3 text-content-secondary\",\n position === \"top\" ? \"py-2\" : \"pb-2 pt-4\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/**\n * Height preset for a dropdown menu item.\n *\n * `\"40\"` (default) and `\"32\"` are the v2 numeric tokens that mirror the Figma\n * design system. `\"sm\"` and `\"md\"` are deprecated aliases retained for\n * backwards compatibility — `\"sm\"` maps to `\"32\"`, `\"md\"` maps to `\"40\"`.\n */\nexport type DropdownMenuItemSize =\n | \"40\"\n | \"32\"\n /** @deprecated Use `\"32\"` instead. */\n | \"sm\"\n /** @deprecated Use `\"40\"` instead. */\n | \"md\";\n\nconst SIZE_NORMALIZED: Record<DropdownMenuItemSize, \"40\" | \"32\"> = {\n \"40\": \"40\",\n md: \"40\",\n \"32\": \"32\",\n sm: \"32\",\n};\n\nconst ITEM_SIZE_CLASSES: Record<\"40\" | \"32\", string> = {\n \"40\": \"min-h-10 py-2 typography-regular-body-lg\",\n \"32\": \"min-h-8 py-[7px] typography-regular-body-md\",\n};\n\nconst ITEM_SELECTED_TYPOGRAPHY: Record<\"40\" | \"32\", string> = {\n \"40\": \"typography-semibold-body-lg\",\n \"32\": \"typography-semibold-body-md\",\n};\n\nexport interface DropdownMenuItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> {\n /** Height of the menu item row. @default \"40\" */\n size?: DropdownMenuItemSize;\n /** Applies the destructive (error) treatment. Use for irreversible actions. @default false */\n destructive?: boolean;\n /** Icon (or other node) rendered before the label. */\n leadingIcon?: React.ReactNode;\n /** Icon (or other node) rendered after the label. */\n trailingIcon?: React.ReactNode;\n /** Marks the item as the current selection in a single-select menu. @default false */\n selected?: boolean;\n}\n\n/**\n * An individual item within a {@link DropdownMenuContent}.\n *\n * @example\n * ```tsx\n * <DropdownMenuItem>Edit profile</DropdownMenuItem>\n * <DropdownMenuItem destructive>Delete</DropdownMenuItem>\n * <DropdownMenuItem leadingIcon={<EditIcon />}>Edit</DropdownMenuItem>\n *\n * // As a link\n * <DropdownMenuItem asChild>\n * <a href=\"/settings\">Settings</a>\n * </DropdownMenuItem>\n * ```\n */\nexport const DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n DropdownMenuItemProps\n>(\n (\n {\n size = \"40\",\n destructive,\n leadingIcon,\n trailingIcon,\n selected,\n className,\n children,\n asChild,\n ...props\n },\n ref,\n ) => {\n const normalizedSize = SIZE_NORMALIZED[size];\n const itemClassName = cn(\n \"flex w-full cursor-pointer items-center gap-2 rounded-xs px-3 outline-none\",\n ITEM_SIZE_CLASSES[normalizedSize],\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n destructive && \"text-error-content\",\n selected && [\n \"bg-buttons-primary text-content-primary-inverted\",\n \"data-[highlighted]:bg-buttons-primary\",\n ITEM_SELECTED_TYPOGRAPHY[normalizedSize],\n ],\n className,\n );\n\n if (asChild) {\n return (\n <DropdownMenuPrimitive.Item ref={ref} asChild className={itemClassName} {...props}>\n {children}\n </DropdownMenuPrimitive.Item>\n );\n }\n\n return (\n <DropdownMenuPrimitive.Item ref={ref} className={itemClassName} {...props}>\n {leadingIcon}\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n {trailingIcon}\n </DropdownMenuPrimitive.Item>\n );\n },\n);\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** Props for the {@link DropdownMenuSeparator} component. */\nexport interface DropdownMenuSeparatorProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> {}\n\n/** Visual separator between groups of items. */\nexport const DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n DropdownMenuSeparatorProps\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"my-1 h-px bg-neutral-alphas-200\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\n/** Header type. `\"default\"` shows a title; `\"search\"` shows a search input. */\nexport type DropdownMenuHeaderType = \"default\" | \"search\";\n\n/** Header height preset. Matches the menu item sizing scale. */\nexport type DropdownMenuHeaderSize = \"40\" | \"32\";\n\n/** Search-input configuration for {@link DropdownMenuHeader} when `type=\"search\"`. */\nexport interface DropdownMenuHeaderSearchProps {\n /** Controlled value of the search input. */\n value?: string;\n /** Uncontrolled default value. */\n defaultValue?: string;\n /** Fires when the input value changes. */\n onChange?: (value: string) => void;\n /** Placeholder text shown when the input is empty. @default \"Search…\" */\n placeholder?: string;\n /** Accessible label for the search input. @default \"Search\" */\n \"aria-label\"?: string;\n}\n\nexport interface DropdownMenuHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Visual type. `\"default\"` shows a title; `\"search\"` shows a search input. @default \"default\" */\n type?: DropdownMenuHeaderType;\n /** Height preset for the header row. @default \"40\" */\n size?: DropdownMenuHeaderSize;\n /** Title text shown when `type=\"default\"`. Ignored if `children` is provided. */\n title?: string;\n /** Configuration for the embedded search input when `type=\"search\"`. */\n searchProps?: DropdownMenuHeaderSearchProps;\n /** Whether to render the close icon button on the right. @default true */\n showClose?: boolean;\n /** Fires when the close icon button is activated. */\n onClose?: () => void;\n /** Accessible label for the close button. @default \"Close menu\" */\n closeLabel?: string;\n}\n\n/**\n * Optional header rendered at the top of a {@link DropdownMenuContent}. Use\n * `type=\"default\"` to title the menu, or `type=\"search\"` to embed a search\n * input for filtering long lists.\n *\n * Renders an inset separator beneath the row so it slots cleanly above the\n * first group of items.\n *\n * @example\n * ```tsx\n * <DropdownMenuContent>\n * <DropdownMenuHeader title=\"Sort by\" onClose={() => setOpen(false)} />\n * <DropdownMenuItem>Newest</DropdownMenuItem>\n * <DropdownMenuItem>Oldest</DropdownMenuItem>\n * </DropdownMenuContent>\n * ```\n */\nexport const DropdownMenuHeader = React.forwardRef<HTMLDivElement, DropdownMenuHeaderProps>(\n (\n {\n type = \"default\",\n size = \"40\",\n title,\n searchProps,\n showClose = true,\n onClose,\n closeLabel = \"Close menu\",\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const titleTypography =\n size === \"32\" ? \"typography-semibold-body-md\" : \"typography-semibold-body-lg\";\n const toggleOpen = React.useContext(ToggleOpenContext);\n\n const handleClose = () => {\n onClose?.();\n // Also dismiss the Radix menu when used in uncontrolled mode — otherwise\n // the close button would look broken to consumers that don't wire up\n // `open` / `onOpenChange` themselves.\n toggleOpen?.(() => false);\n };\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col px-1 pt-1 mb-1\",\n // Search needs an 8px gap between the input and the divider; the\n // default (title) variant uses 4px because the title baseline sits\n // closer to the divider naturally.\n type === \"search\" ? \"gap-2\" : \"gap-1\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-4 pl-2\">\n {type === \"default\" ? (\n <div className={cn(\"min-w-0 flex-1 truncate text-content-primary\", titleTypography)}>\n {children ?? title}\n </div>\n ) : (\n <SearchInput {...searchProps} />\n )}\n {showClose && (\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<CloseIcon />}\n onClick={handleClose}\n aria-label={closeLabel}\n />\n )}\n </div>\n <DropdownMenuSeparator className=\"my-0\" />\n </div>\n );\n },\n);\nDropdownMenuHeader.displayName = \"DropdownMenuHeader\";\n\nfunction SearchInput({\n value,\n defaultValue,\n onChange,\n placeholder = \"Search\\u2026\",\n \"aria-label\": ariaLabel = \"Search\",\n}: DropdownMenuHeaderSearchProps = {}) {\n return (\n <label\n className={cn(\n \"flex min-w-0 flex-1 items-center gap-2 rounded-xs border border-border-primary\",\n \"bg-neutral-alphas-50 px-3 py-1 text-content-primary\",\n \"focus-within:shadow-focus-ring focus-within:outline-none\",\n )}\n >\n <SearchIcon className=\"size-4 shrink-0 text-content-tertiary\" aria-hidden=\"true\" />\n <input\n type=\"search\"\n className={cn(\n \"typography-regular-body-lg min-w-0 flex-1 bg-transparent outline-none\",\n \"placeholder:text-content-tertiary\",\n )}\n value={value}\n defaultValue={defaultValue}\n placeholder={placeholder}\n aria-label={ariaLabel}\n onChange={(event) => onChange?.(event.target.value)}\n // Radix DropdownMenu listens for keystrokes on Content for its\n // typeahead (typing letters jumps focus to a matching item). That\n // listener steals focus from the input after the first letter, so we\n // stop character keys from bubbling. Navigation keys (arrows / Tab /\n // Escape / Enter) are still allowed through so the user can leave the\n // input for the list or close the menu. Pointer events are stopped so\n // clicking back into the input doesn't fight the menu's focus\n // management either.\n onKeyDown={(event) => {\n if (!NAVIGATION_KEYS.has(event.key)) event.stopPropagation();\n }}\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n />\n </label>\n );\n}\n\n/** Props for the {@link DropdownMenuRadioGroup} component. */\nexport interface DropdownMenuRadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioGroup> {}\n\n/**\n * Groups {@link DropdownMenuRadioItem} children so they behave as a\n * single-select set. Controlled via `value`/`onValueChange`.\n *\n * @example\n * ```tsx\n * <DropdownMenuRadioGroup value={sort} onValueChange={setSort}>\n * <DropdownMenuRadioItem value=\"newest\">Newest first</DropdownMenuRadioItem>\n * <DropdownMenuRadioItem value=\"oldest\">Oldest first</DropdownMenuRadioItem>\n * </DropdownMenuRadioGroup>\n * ```\n */\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/** Height preset for a {@link DropdownMenuRadioItem}. */\nexport type DropdownMenuRadioItemSize = \"40\";\n\nexport interface DropdownMenuRadioItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> {\n /** Optional secondary text shown below the title. */\n helper?: string;\n /** Height of the item row. @default \"40\" */\n size?: DropdownMenuRadioItemSize;\n}\n\n/**\n * A single radio-style choice within a {@link DropdownMenuRadioGroup}. Shows\n * a circular indicator that fills when selected, plus an optional helper line\n * underneath the title.\n */\nexport const DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n DropdownMenuRadioItemProps\n>(({ className, children, helper, size: _size = \"40\", ...props }, ref) => {\n return (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"group flex w-full cursor-pointer items-start gap-3 rounded-xs px-4 py-2 outline-none\",\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n \"data-[state=checked]:bg-buttons-primary data-[state=checked]:text-content-primary-inverted\",\n \"data-[state=checked]:data-[highlighted]:bg-buttons-primary\",\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n \"mt-1 flex size-4 shrink-0 items-center justify-center rounded-full border border-icons-primary\",\n \"group-data-[disabled]:border-content-disabled\",\n \"group-data-[state=checked]:border-icons-primary-inverted\",\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator asChild>\n <span className=\"size-2 rounded-full bg-content-primary-inverted\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span className=\"typography-semibold-body-lg truncate\">{children}</span>\n {helper && (\n <span\n className={cn(\n \"typography-regular-body-sm text-content-secondary\",\n \"group-data-[state=checked]:text-content-primary-inverted\",\n \"group-data-[disabled]:text-content-disabled\",\n )}\n >\n {helper}\n </span>\n )}\n </span>\n </DropdownMenuPrimitive.RadioItem>\n );\n});\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DropdownMenu.mjs","sources":["../../../src/components/DropdownMenu/DropdownMenu.tsx"],"sourcesContent":["import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { FLOATING_CONTENT_COLLISION_PADDING } from \"../../utils/floatingContentCollisionPadding\";\nimport { IconButton } from \"../IconButton/IconButton\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SearchIcon } from \"../Icons/SearchIcon\";\n\n// Movement, in CSS px, above which a touch press-and-release counts as a drag.\nconst TAP_MOVEMENT_THRESHOLD_PX = 10;\n\n// Keys that the menu must keep handling even when focus is inside a child\n// input — arrows move the highlight into the list, Tab leaves the menu, and\n// Enter / Escape close it.\nconst NAVIGATION_KEYS = new Set([\n \"ArrowDown\",\n \"ArrowUp\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"Escape\",\n \"Tab\",\n \"Enter\",\n]);\n\ntype ActiveTap = {\n pointerId: number;\n x: number;\n y: number;\n movedPastThreshold: boolean;\n};\n\n// Lets DropdownMenuTrigger toggle the menu directly so it can gate on touch\n// movement — see radix-ui/primitives#1912.\nconst ToggleOpenContext = React.createContext<\n ((updater: (prev: boolean) => boolean) => void) | null\n>(null);\n\n/** Props for the {@link DropdownMenu} root component. */\nexport interface DropdownMenuProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root> {}\n\n/** Root component that manages open/close state for a dropdown menu. */\nexport function DropdownMenu({\n open: openProp,\n defaultOpen,\n onOpenChange,\n children,\n ...props\n}: DropdownMenuProps) {\n const [open = false, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen ?? false,\n onChange: onOpenChange,\n });\n\n return (\n <ToggleOpenContext.Provider value={setOpen}>\n <DropdownMenuPrimitive.Root open={open} onOpenChange={setOpen} {...props}>\n {children}\n </DropdownMenuPrimitive.Root>\n </ToggleOpenContext.Provider>\n );\n}\n\n/** Props for the {@link DropdownMenuTrigger} component. */\nexport type DropdownMenuTriggerProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Trigger\n>;\n\n/**\n * The element that toggles the dropdown menu when clicked.\n *\n * On touch devices, the menu only opens if the press-and-release stays within\n * a small movement threshold. A drag that incidentally ends over the trigger\n * (common when scrolling a feed on Android Chrome) is ignored. Mouse and\n * keyboard interactions are unchanged.\n */\nexport const DropdownMenuTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Trigger>,\n DropdownMenuTriggerProps\n>((props, ref) => {\n const toggleOpen = React.useContext(ToggleOpenContext);\n const tapRef = React.useRef<ActiveTap | null>(null);\n\n // Used outside our DropdownMenu wrapper — fall through to Radix defaults.\n if (toggleOpen === null) {\n return <DropdownMenuPrimitive.Trigger {...props} ref={ref} />;\n }\n\n return (\n <DropdownMenuPrimitive.Trigger\n {...props}\n ref={ref}\n onPointerDown={(event) => {\n props.onPointerDown?.(event);\n if (event.pointerType === \"mouse\" || props.disabled) return;\n // Keep pointerup / pointercancel on this element if the finger drifts off.\n // Optional because jsdom (used in tests) doesn't implement it.\n event.currentTarget.setPointerCapture?.(event.pointerId);\n tapRef.current = {\n pointerId: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n movedPastThreshold: false,\n };\n // preventDefault stops Radix's pointerdown open path via composeEventHandlers.\n event.preventDefault();\n }}\n onPointerMove={(event) => {\n props.onPointerMove?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId || tap.movedPastThreshold) {\n return;\n }\n const dx = event.clientX - tap.x;\n const dy = event.clientY - tap.y;\n if (Math.hypot(dx, dy) > TAP_MOVEMENT_THRESHOLD_PX) {\n tap.movedPastThreshold = true;\n }\n }}\n onPointerUp={(event) => {\n props.onPointerUp?.(event);\n const tap = tapRef.current;\n if (tap === null || event.pointerId !== tap.pointerId) return;\n const wasDrag = tap.movedPastThreshold;\n tapRef.current = null;\n if (!wasDrag && !props.disabled) {\n toggleOpen((prev) => !prev);\n }\n }}\n onPointerCancel={(event) => {\n props.onPointerCancel?.(event);\n const tap = tapRef.current;\n if (tap !== null && event.pointerId === tap.pointerId) {\n tapRef.current = null;\n }\n }}\n />\n );\n});\nDropdownMenuTrigger.displayName = \"DropdownMenuTrigger\";\n\n/** Props for the {@link DropdownMenuContent} component. */\nexport interface DropdownMenuContentProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> {}\n\n/**\n * The positioned content panel rendered inside a portal.\n *\n * Override the portal z-index per-instance via `style={{ zIndex: 1500 }}` or\n * globally with the `--fanvue-ui-portal-z-index` CSS custom property.\n *\n * @example\n * ```tsx\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild>\n * <Button>Open</Button>\n * </DropdownMenuTrigger>\n * <DropdownMenuContent>\n * <DropdownMenuItem>Option 1</DropdownMenuItem>\n * <DropdownMenuItem>Option 2</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n * ```\n */\nexport const DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n DropdownMenuContentProps\n>(\n (\n {\n className,\n style,\n sideOffset = 4,\n collisionPadding = FLOATING_CONTENT_COLLISION_PADDING,\n ...props\n },\n ref,\n ) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(\n \"w-max min-w-(--radix-dropdown-menu-trigger-width) max-w-(--radix-dropdown-menu-content-available-width) overflow-y-auto rounded-sm border border-neutral-alphas-200 bg-surface-primary p-1 text-content-primary shadow-lg\",\n \"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n \"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95\",\n \"data-[side=top]:slide-in-from-bottom-2 data-[side=bottom]:slide-in-from-top-2\",\n \"data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2\",\n className,\n )}\n style={{\n zIndex: \"var(--fanvue-ui-portal-z-index, 50)\",\n maxHeight: \"var(--radix-dropdown-menu-content-available-height)\",\n ...style,\n }}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n ),\n);\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\n/** Props for the {@link DropdownMenuGroup} component. */\nexport type DropdownMenuGroupProps = React.ComponentPropsWithoutRef<\n typeof DropdownMenuPrimitive.Group\n>;\n\n/** Groups related menu items. Accepts an optional `DropdownMenuLabel`. */\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nDropdownMenuGroup.displayName = \"DropdownMenuGroup\";\n\n/** Vertical placement of a {@link DropdownMenuLabel} within its group. */\nexport type DropdownMenuLabelPosition = \"default\" | \"top\";\n\n/** Props for the {@link DropdownMenuLabel} component. */\nexport interface DropdownMenuLabelProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> {\n /**\n * Vertical placement within the surrounding group. `\"top\"` is used for the\n * first label directly under a header; `\"default\"` adds extra top padding to\n * separate it from preceding items. @default \"default\"\n */\n position?: DropdownMenuLabelPosition;\n}\n\n/** A non-interactive label that groups related items within a menu. */\nexport const DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n DropdownMenuLabelProps\n>(({ className, position = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"typography-description-12px-regular flex items-center px-3 text-content-secondary\",\n position === \"top\" ? \"py-2\" : \"pb-2 pt-4\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\n/**\n * Height preset for a dropdown menu item.\n *\n * `\"40\"` (default) and `\"32\"` are the v2 numeric tokens that mirror the Figma\n * design system. `\"sm\"` and `\"md\"` are deprecated aliases retained for\n * backwards compatibility — `\"sm\"` maps to `\"32\"`, `\"md\"` maps to `\"40\"`.\n */\nexport type DropdownMenuItemSize =\n | \"40\"\n | \"32\"\n /** @deprecated Use `\"32\"` instead. */\n | \"sm\"\n /** @deprecated Use `\"40\"` instead. */\n | \"md\";\n\nconst SIZE_NORMALIZED: Record<DropdownMenuItemSize, \"40\" | \"32\"> = {\n \"40\": \"40\",\n md: \"40\",\n \"32\": \"32\",\n sm: \"32\",\n};\n\nconst ITEM_SIZE_CLASSES: Record<\"40\" | \"32\", string> = {\n \"40\": \"min-h-10 py-2 typography-body-default-16px-regular\",\n \"32\": \"min-h-8 py-[7px] typography-body-small-14px-regular\",\n};\n\nconst ITEM_SELECTED_TYPOGRAPHY: Record<\"40\" | \"32\", string> = {\n \"40\": \"typography-body-default-16px-semibold\",\n \"32\": \"typography-body-small-14px-semibold\",\n};\n\nexport interface DropdownMenuItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> {\n /** Height of the menu item row. @default \"40\" */\n size?: DropdownMenuItemSize;\n /** Applies the destructive (error) treatment. Use for irreversible actions. @default false */\n destructive?: boolean;\n /** Icon (or other node) rendered before the label. */\n leadingIcon?: React.ReactNode;\n /** Icon (or other node) rendered after the label. */\n trailingIcon?: React.ReactNode;\n /** Marks the item as the current selection in a single-select menu. @default false */\n selected?: boolean;\n}\n\n/**\n * An individual item within a {@link DropdownMenuContent}.\n *\n * @example\n * ```tsx\n * <DropdownMenuItem>Edit profile</DropdownMenuItem>\n * <DropdownMenuItem destructive>Delete</DropdownMenuItem>\n * <DropdownMenuItem leadingIcon={<EditIcon />}>Edit</DropdownMenuItem>\n *\n * // As a link\n * <DropdownMenuItem asChild>\n * <a href=\"/settings\">Settings</a>\n * </DropdownMenuItem>\n * ```\n */\nexport const DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n DropdownMenuItemProps\n>(\n (\n {\n size = \"40\",\n destructive,\n leadingIcon,\n trailingIcon,\n selected,\n className,\n children,\n asChild,\n ...props\n },\n ref,\n ) => {\n const normalizedSize = SIZE_NORMALIZED[size];\n const itemClassName = cn(\n \"flex w-full cursor-pointer items-center gap-2 rounded-xs px-3 outline-none\",\n ITEM_SIZE_CLASSES[normalizedSize],\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n destructive && \"text-error-content\",\n selected && [\n \"bg-buttons-primary-default text-content-primary-inverted\",\n \"data-[highlighted]:bg-buttons-primary-default\",\n ITEM_SELECTED_TYPOGRAPHY[normalizedSize],\n ],\n className,\n );\n\n if (asChild) {\n return (\n <DropdownMenuPrimitive.Item ref={ref} asChild className={itemClassName} {...props}>\n {children}\n </DropdownMenuPrimitive.Item>\n );\n }\n\n return (\n <DropdownMenuPrimitive.Item ref={ref} className={itemClassName} {...props}>\n {leadingIcon}\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n {trailingIcon}\n </DropdownMenuPrimitive.Item>\n );\n },\n);\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\n/** Props for the {@link DropdownMenuSeparator} component. */\nexport interface DropdownMenuSeparatorProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> {}\n\n/** Visual separator between groups of items. */\nexport const DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n DropdownMenuSeparatorProps\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"my-1 h-px bg-neutral-alphas-200\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\n/** Header type. `\"default\"` shows a title; `\"search\"` shows a search input. */\nexport type DropdownMenuHeaderType = \"default\" | \"search\";\n\n/** Header height preset. Matches the menu item sizing scale. */\nexport type DropdownMenuHeaderSize = \"40\" | \"32\";\n\n/** Search-input configuration for {@link DropdownMenuHeader} when `type=\"search\"`. */\nexport interface DropdownMenuHeaderSearchProps {\n /** Controlled value of the search input. */\n value?: string;\n /** Uncontrolled default value. */\n defaultValue?: string;\n /** Fires when the input value changes. */\n onChange?: (value: string) => void;\n /** Placeholder text shown when the input is empty. @default \"Search…\" */\n placeholder?: string;\n /** Accessible label for the search input. @default \"Search\" */\n \"aria-label\"?: string;\n}\n\nexport interface DropdownMenuHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Visual type. `\"default\"` shows a title; `\"search\"` shows a search input. @default \"default\" */\n type?: DropdownMenuHeaderType;\n /** Height preset for the header row. @default \"40\" */\n size?: DropdownMenuHeaderSize;\n /** Title text shown when `type=\"default\"`. Ignored if `children` is provided. */\n title?: string;\n /** Configuration for the embedded search input when `type=\"search\"`. */\n searchProps?: DropdownMenuHeaderSearchProps;\n /** Whether to render the close icon button on the right. @default true */\n showClose?: boolean;\n /** Fires when the close icon button is activated. */\n onClose?: () => void;\n /** Accessible label for the close button. @default \"Close menu\" */\n closeLabel?: string;\n}\n\n/**\n * Optional header rendered at the top of a {@link DropdownMenuContent}. Use\n * `type=\"default\"` to title the menu, or `type=\"search\"` to embed a search\n * input for filtering long lists.\n *\n * Renders an inset separator beneath the row so it slots cleanly above the\n * first group of items.\n *\n * @example\n * ```tsx\n * <DropdownMenuContent>\n * <DropdownMenuHeader title=\"Sort by\" onClose={() => setOpen(false)} />\n * <DropdownMenuItem>Newest</DropdownMenuItem>\n * <DropdownMenuItem>Oldest</DropdownMenuItem>\n * </DropdownMenuContent>\n * ```\n */\nexport const DropdownMenuHeader = React.forwardRef<HTMLDivElement, DropdownMenuHeaderProps>(\n (\n {\n type = \"default\",\n size = \"40\",\n title,\n searchProps,\n showClose = true,\n onClose,\n closeLabel = \"Close menu\",\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const titleTypography =\n size === \"32\"\n ? \"typography-body-small-14px-semibold\"\n : \"typography-body-default-16px-semibold\";\n const toggleOpen = React.useContext(ToggleOpenContext);\n\n const handleClose = () => {\n onClose?.();\n // Also dismiss the Radix menu when used in uncontrolled mode — otherwise\n // the close button would look broken to consumers that don't wire up\n // `open` / `onOpenChange` themselves.\n toggleOpen?.(() => false);\n };\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col px-1 pt-1 mb-1\",\n // Search needs an 8px gap between the input and the divider; the\n // default (title) variant uses 4px because the title baseline sits\n // closer to the divider naturally.\n type === \"search\" ? \"gap-2\" : \"gap-1\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-4 pl-2\">\n {type === \"default\" ? (\n <div className={cn(\"min-w-0 flex-1 truncate text-content-primary\", titleTypography)}>\n {children ?? title}\n </div>\n ) : (\n <SearchInput {...searchProps} />\n )}\n {showClose && (\n <IconButton\n variant=\"tertiary\"\n size=\"32\"\n icon={<CloseIcon />}\n onClick={handleClose}\n aria-label={closeLabel}\n />\n )}\n </div>\n <DropdownMenuSeparator className=\"my-0\" />\n </div>\n );\n },\n);\nDropdownMenuHeader.displayName = \"DropdownMenuHeader\";\n\nfunction SearchInput({\n value,\n defaultValue,\n onChange,\n placeholder = \"Search\\u2026\",\n \"aria-label\": ariaLabel = \"Search\",\n}: DropdownMenuHeaderSearchProps = {}) {\n return (\n <label\n className={cn(\n \"flex min-w-0 flex-1 items-center gap-2 rounded-xs border border-border-primary\",\n \"bg-neutral-alphas-50 px-3 py-1 text-content-primary\",\n \"focus-within:shadow-focus-ring focus-within:outline-none\",\n )}\n >\n <SearchIcon className=\"size-4 shrink-0 text-content-tertiary\" aria-hidden=\"true\" />\n <input\n type=\"search\"\n className={cn(\n \"typography-body-default-16px-regular min-w-0 flex-1 bg-transparent outline-none\",\n \"placeholder:text-content-tertiary\",\n )}\n value={value}\n defaultValue={defaultValue}\n placeholder={placeholder}\n aria-label={ariaLabel}\n onChange={(event) => onChange?.(event.target.value)}\n // Radix DropdownMenu listens for keystrokes on Content for its\n // typeahead (typing letters jumps focus to a matching item). That\n // listener steals focus from the input after the first letter, so we\n // stop character keys from bubbling. Navigation keys (arrows / Tab /\n // Escape / Enter) are still allowed through so the user can leave the\n // input for the list or close the menu. Pointer events are stopped so\n // clicking back into the input doesn't fight the menu's focus\n // management either.\n onKeyDown={(event) => {\n if (!NAVIGATION_KEYS.has(event.key)) event.stopPropagation();\n }}\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n />\n </label>\n );\n}\n\n/** Props for the {@link DropdownMenuRadioGroup} component. */\nexport interface DropdownMenuRadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioGroup> {}\n\n/**\n * Groups {@link DropdownMenuRadioItem} children so they behave as a\n * single-select set. Controlled via `value`/`onValueChange`.\n *\n * @example\n * ```tsx\n * <DropdownMenuRadioGroup value={sort} onValueChange={setSort}>\n * <DropdownMenuRadioItem value=\"newest\">Newest first</DropdownMenuRadioItem>\n * <DropdownMenuRadioItem value=\"oldest\">Oldest first</DropdownMenuRadioItem>\n * </DropdownMenuRadioGroup>\n * ```\n */\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\n/** Height preset for a {@link DropdownMenuRadioItem}. */\nexport type DropdownMenuRadioItemSize = \"40\";\n\nexport interface DropdownMenuRadioItemProps\n extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> {\n /** Optional secondary text shown below the title. */\n helper?: string;\n /** Height of the item row. @default \"40\" */\n size?: DropdownMenuRadioItemSize;\n}\n\n/**\n * A single radio-style choice within a {@link DropdownMenuRadioGroup}. Shows\n * a circular indicator that fills when selected, plus an optional helper line\n * underneath the title.\n */\nexport const DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n DropdownMenuRadioItemProps\n>(({ className, children, helper, size: _size = \"40\", ...props }, ref) => {\n return (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"group flex w-full cursor-pointer items-start gap-3 rounded-xs px-4 py-2 outline-none\",\n \"data-[highlighted]:bg-neutral-alphas-50\",\n \"data-[disabled]:cursor-not-allowed data-[disabled]:text-content-disabled\",\n \"data-[state=checked]:bg-buttons-primary-default data-[state=checked]:text-content-primary-inverted\",\n \"data-[state=checked]:data-[highlighted]:bg-buttons-primary-default\",\n className,\n )}\n {...props}\n >\n <span\n className={cn(\n \"mt-1 flex size-4 shrink-0 items-center justify-center rounded-full border border-icons-primary\",\n \"group-data-[disabled]:border-content-disabled\",\n \"group-data-[state=checked]:border-icons-primary-inverted\",\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator asChild>\n <span className=\"size-2 rounded-full bg-content-primary-inverted\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <span className=\"typography-body-default-16px-semibold truncate\">{children}</span>\n {helper && (\n <span\n className={cn(\n \"typography-description-12px-regular text-content-secondary\",\n \"group-data-[state=checked]:text-content-primary-inverted\",\n \"group-data-[disabled]:text-content-disabled\",\n )}\n >\n {helper}\n </span>\n )}\n </span>\n </DropdownMenuPrimitive.RadioItem>\n );\n});\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n"],"names":[],"mappings":"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"}
|
|
@@ -4,11 +4,11 @@ import * as React from "react";
|
|
|
4
4
|
import { cn } from "../../utils/cn.mjs";
|
|
5
5
|
import { Button } from "../Button/Button.mjs";
|
|
6
6
|
const titleSizeClass = {
|
|
7
|
-
xs: "typography-
|
|
8
|
-
sm: "typography-
|
|
9
|
-
md: "typography-
|
|
10
|
-
lg: "typography-
|
|
11
|
-
xl: "typography-
|
|
7
|
+
xs: "typography-header-heading-xs",
|
|
8
|
+
sm: "typography-header-heading-sm",
|
|
9
|
+
md: "typography-header-heading-md",
|
|
10
|
+
lg: "typography-header-heading-lg",
|
|
11
|
+
xl: "typography-header-heading-xl"
|
|
12
12
|
};
|
|
13
13
|
const mediaSizeClass = {
|
|
14
14
|
xs: "h-[80px]",
|
|
@@ -55,7 +55,7 @@ const EmptyState = React.forwardRef(
|
|
|
55
55
|
children: title
|
|
56
56
|
}
|
|
57
57
|
);
|
|
58
|
-
const renderedDescription = description === void 0 || description === null || description === false || description === "" ? null : isNonEmptyString(description) ? /* @__PURE__ */ jsx("p", { className: "m-0 typography-
|
|
58
|
+
const renderedDescription = description === void 0 || description === null || description === false || description === "" ? null : isNonEmptyString(description) ? /* @__PURE__ */ jsx("p", { className: "m-0 typography-body-default-16px-regular text-content-secondary", children: description }) : /* @__PURE__ */ jsx("div", { className: "typography-body-default-16px-regular text-content-secondary min-w-0 w-full", children: description });
|
|
59
59
|
const renderedMedia = media === void 0 || media === null || media === false || media === "" ? null : isNonEmptyString(media) ? /* @__PURE__ */ jsx(
|
|
60
60
|
"img",
|
|
61
61
|
{
|