@fanvue/ui 3.11.0 → 3.12.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.
@@ -120,7 +120,7 @@ const DatePicker = React.forwardRef(
120
120
  weekdays: "flex",
121
121
  weekday: "flex h-[30px] w-10 flex-1 items-center justify-center typography-body-small-14px-regular text-content-secondary",
122
122
  week: "flex",
123
- day: "relative flex w-10 flex-1 items-center justify-center",
123
+ day: "relative flex flex-1 items-center justify-center p-0.5",
124
124
  hidden: "hidden"
125
125
  },
126
126
  components: {
@@ -1 +1 @@
1
- {"version":3,"file":"DatePicker.cjs","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, range_middle } = modifiers;\n const isSingleDayRange = range_start && range_end;\n const inRange = (range_start || range_end || range_middle) && !isSingleDayRange;\n\n return (\n <div\n className={cn(\n className,\n inRange && \"bg-inputs-calendar-range\",\n inRange && range_start && \"rounded-l-sm\",\n inRange && range_end && \"rounded-r-sm\",\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 const isSelected = modifiers.selected && !modifiers.range_middle;\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-sm text-content-primary\",\n \"transition-colors hover:bg-inputs-calendar-range not-disabled:active:bg-inputs-calendar-range\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n \"disabled:cursor-not-allowed\",\n isSelected ? \"typography-body-small-14px-semibold\" : \"typography-body-small-14px-regular\",\n modifiers.today &&\n !isSelected &&\n \"bg-inputs-calendar-today text-content-always-white hover:bg-inputs-calendar-today\",\n isSelected &&\n \"bg-inputs-calendar-selected text-content-primary-inverted hover:bg-inputs-calendar-selected\",\n modifiers.range_middle && \"bg-transparent hover:bg-transparent\",\n modifiers.disabled &&\n \"bg-inputs-calendar-disabled text-content-disabled hover:bg-inputs-calendar-disabled\",\n modifiers.outside && \"pointer-events-none text-content-disabled\",\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 * variant=\"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-xl border border-modal-stroke bg-modal-background p-6 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: \"long\", year: \"numeric\" }),\n ...formatters,\n }}\n classNames={{\n root: \"w-full\",\n months: cn(\"relative flex\", isMulti && \"gap-6\"),\n month: \"flex flex-1 flex-col\",\n month_caption: \"mb-4 flex h-8 items-center justify-center\",\n caption_label: \"typography-body-default-16px-regular text-content-primary\",\n nav: \"absolute inset-x-0 top-0 z-20 flex justify-between\",\n button_previous:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n button_next:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n month_grid: \"w-full\",\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\",\n day: \"relative flex w-10 flex-1 items-center justify-center\",\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-2 pt-6\">\n <Button variant=\"outline\" 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":["jsx","cn","useRef","useEffect","forwardRef","jsxs","DayPicker","ChevronLeftIcon","ChevronRightIcon","Button"],"mappings":"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"}
1
+ {"version":3,"file":"DatePicker.cjs","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, range_middle } = modifiers;\n const isSingleDayRange = range_start && range_end;\n const inRange = (range_start || range_end || range_middle) && !isSingleDayRange;\n\n return (\n <div\n className={cn(\n className,\n inRange && \"bg-inputs-calendar-range\",\n inRange && range_start && \"rounded-l-sm\",\n inRange && range_end && \"rounded-r-sm\",\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 const isSelected = modifiers.selected && !modifiers.range_middle;\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-sm text-content-primary\",\n \"transition-colors hover:bg-inputs-calendar-range not-disabled:active:bg-inputs-calendar-range\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n \"disabled:cursor-not-allowed\",\n isSelected ? \"typography-body-small-14px-semibold\" : \"typography-body-small-14px-regular\",\n modifiers.today &&\n !isSelected &&\n \"bg-inputs-calendar-today text-content-always-white hover:bg-inputs-calendar-today\",\n isSelected &&\n \"bg-inputs-calendar-selected text-content-primary-inverted hover:bg-inputs-calendar-selected\",\n modifiers.range_middle && \"bg-transparent hover:bg-transparent\",\n modifiers.disabled &&\n \"bg-inputs-calendar-disabled text-content-disabled hover:bg-inputs-calendar-disabled\",\n modifiers.outside && \"pointer-events-none text-content-disabled\",\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 * variant=\"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-xl border border-modal-stroke bg-modal-background p-6 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: \"long\", year: \"numeric\" }),\n ...formatters,\n }}\n classNames={{\n root: \"w-full\",\n months: cn(\"relative flex\", isMulti && \"gap-6\"),\n month: \"flex flex-1 flex-col\",\n month_caption: \"mb-4 flex h-8 items-center justify-center\",\n caption_label: \"typography-body-default-16px-regular text-content-primary\",\n nav: \"absolute inset-x-0 top-0 z-20 flex justify-between\",\n button_previous:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n button_next:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n month_grid: \"w-full\",\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\",\n day: \"relative flex flex-1 items-center justify-center p-0.5\",\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-2 pt-6\">\n <Button variant=\"outline\" 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":["jsx","cn","useRef","useEffect","forwardRef","jsxs","DayPicker","ChevronLeftIcon","ChevronRightIcon","Button"],"mappings":"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"}
@@ -151,7 +151,7 @@ const DialogHeader = React__namespace.forwardRef(
151
151
  "aria-label": backLabel
152
152
  }
153
153
  ),
154
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children }),
154
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children }),
155
155
  showClose && /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
156
156
  IconButton.IconButton,
157
157
  {
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.cjs","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 by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\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 * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n /** Show the v2 mobile sheet pull handle. Only rendered when `mobilePresentation` is `\"sheet\"`. @default true */\n showMobileHandle?: boolean;\n /**\n * How the dialog presents below the `sm` breakpoint.\n * - `\"sheet\"` — bottom sheet pinned to the viewport bottom edge (default)\n * - `\"card\"` — centered floating card per the v2-modal confirmation spec:\n * 16px side margins, 24px padding, 32px radius on all corners, no pull handle\n *\n * @default \"sheet\"\n */\n mobilePresentation?: \"sheet\" | \"card\";\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. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius by default; pass `mobilePresentation=\"card\"` to\n * render a centered floating card instead (used for small confirmation dialogs).\n * On larger viewports it renders centered with 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>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n showMobileHandle = true,\n mobilePresentation = \"sheet\",\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\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 \"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none\",\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 mobilePresentation === \"card\"\n ? // Floating confirmation card (v2-modal): 16px side margins, vertically centered, 32px radius\n cn(\n \"inset-x-4 top-1/2 max-h-[85vh] -translate-y-1/2 rounded-xl p-6\",\n \"data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95\",\n \"sm:inset-x-auto\",\n )\n : // Bottom sheet pinned to the viewport bottom edge\n cn(\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\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 ),\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg sm:p-6\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {showMobileHandle && mobilePresentation === \"sheet\" && (\n <div\n aria-hidden=\"true\"\n className=\"mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden\"\n />\n )}\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\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 shrink-0 items-center justify-end gap-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<ArrowLeftIcon size={16} />}\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\n variant=\"secondary\"\n size=\"32\"\n icon={<CloseIcon size={16} />}\n aria-label={closeLabel}\n />\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 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 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(\"flex shrink-0 items-center gap-2\", \"[&>*]:min-w-0 [&>*]:flex-1\", className)}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":["DialogPrimitive","React","jsx","useSuppressClickAfterDrag","cn","jsxs","Fragment","IconButton","ArrowLeftIcon","CloseIcon"],"mappings":"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"}
1
+ {"version":3,"file":"Dialog.cjs","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 by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\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 * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n /** Show the v2 mobile sheet pull handle. Only rendered when `mobilePresentation` is `\"sheet\"`. @default true */\n showMobileHandle?: boolean;\n /**\n * How the dialog presents below the `sm` breakpoint.\n * - `\"sheet\"` — bottom sheet pinned to the viewport bottom edge (default)\n * - `\"card\"` — centered floating card per the v2-modal confirmation spec:\n * 16px side margins, 24px padding, 32px radius on all corners, no pull handle\n *\n * @default \"sheet\"\n */\n mobilePresentation?: \"sheet\" | \"card\";\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. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius by default; pass `mobilePresentation=\"card\"` to\n * render a centered floating card instead (used for small confirmation dialogs).\n * On larger viewports it renders centered with 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>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n showMobileHandle = true,\n mobilePresentation = \"sheet\",\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\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 \"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none\",\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 mobilePresentation === \"card\"\n ? // Floating confirmation card (v2-modal): 16px side margins, vertically centered, 32px radius\n cn(\n \"inset-x-4 top-1/2 max-h-[85vh] -translate-y-1/2 rounded-xl p-6\",\n \"data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95\",\n \"sm:inset-x-auto\",\n )\n : // Bottom sheet pinned to the viewport bottom edge\n cn(\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\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 ),\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg sm:p-6\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {showMobileHandle && mobilePresentation === \"sheet\" && (\n <div\n aria-hidden=\"true\"\n className=\"mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden\"\n />\n )}\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\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 shrink-0 items-center justify-end gap-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<ArrowLeftIcon size={16} />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\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 variant=\"secondary\"\n size=\"32\"\n icon={<CloseIcon size={16} />}\n aria-label={closeLabel}\n />\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 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 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(\"flex shrink-0 items-center gap-2\", \"[&>*]:min-w-0 [&>*]:flex-1\", className)}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":["DialogPrimitive","React","jsx","useSuppressClickAfterDrag","cn","jsxs","Fragment","IconButton","ArrowLeftIcon","CloseIcon"],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ "use client";
2
+ "use strict";
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
4
+ const jsxRuntime = require("react/jsx-runtime");
5
+ const React = require("react");
6
+ const cn = require("../../utils/cn.cjs");
7
+ const ChevronLeftIcon = require("../Icons/ChevronLeftIcon.cjs");
8
+ const ChevronRightIcon = require("../Icons/ChevronRightIcon.cjs");
9
+ function _interopNamespaceDefault(e) {
10
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
11
+ if (e) {
12
+ for (const k in e) {
13
+ if (k !== "default") {
14
+ const d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: () => e[k]
18
+ });
19
+ }
20
+ }
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+ const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
26
+ const arrowClasses = cn.cn(
27
+ "flex shrink-0 cursor-pointer items-center justify-center rounded-xs p-1 text-content-primary [&>svg]:size-4",
28
+ "hover:bg-brand-primary-muted disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent",
29
+ "focus-visible:shadow-focus-ring focus-visible:outline-none motion-safe:transition-colors motion-safe:duration-150"
30
+ );
31
+ const PageSelector = React__namespace.forwardRef(
32
+ ({
33
+ className,
34
+ totalPages,
35
+ currentPage,
36
+ onPageChange,
37
+ loop = false,
38
+ disabled = false,
39
+ ariaLabel = "Page selector",
40
+ previousLabel = "Previous page",
41
+ nextLabel = "Next page",
42
+ formatLabel = (current, total) => `${current} of ${total}`,
43
+ ...props
44
+ }, ref) => {
45
+ const atStart = currentPage <= 1;
46
+ const atEnd = currentPage >= totalPages;
47
+ const prevDisabled = disabled || atStart && !loop;
48
+ const nextDisabled = disabled || atEnd && !loop;
49
+ const goTo = (page) => {
50
+ const wrapped = loop ? (page - 1 + totalPages) % totalPages + 1 : page;
51
+ if (wrapped < 1 || wrapped > totalPages || wrapped === currentPage) return;
52
+ onPageChange?.(wrapped);
53
+ };
54
+ return /* @__PURE__ */ jsxRuntime.jsxs(
55
+ "nav",
56
+ {
57
+ ref,
58
+ "aria-label": ariaLabel,
59
+ className: cn.cn(
60
+ "inline-flex items-center gap-1 rounded-sm border border-border-primary bg-surface-secondary p-1",
61
+ className
62
+ ),
63
+ ...props,
64
+ children: [
65
+ /* @__PURE__ */ jsxRuntime.jsx(
66
+ "button",
67
+ {
68
+ type: "button",
69
+ "aria-label": previousLabel,
70
+ disabled: prevDisabled,
71
+ onClick: () => goTo(currentPage - 1),
72
+ className: arrowClasses,
73
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeftIcon.ChevronLeftIcon, {})
74
+ }
75
+ ),
76
+ /* @__PURE__ */ jsxRuntime.jsx(
77
+ "span",
78
+ {
79
+ "aria-live": "polite",
80
+ className: "typography-description-12px-semibold px-2 py-1 text-center text-content-primary tabular-nums",
81
+ children: formatLabel(currentPage, totalPages)
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsxRuntime.jsx(
85
+ "button",
86
+ {
87
+ type: "button",
88
+ "aria-label": nextLabel,
89
+ disabled: nextDisabled,
90
+ onClick: () => goTo(currentPage + 1),
91
+ className: arrowClasses,
92
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon.ChevronRightIcon, {})
93
+ }
94
+ )
95
+ ]
96
+ }
97
+ );
98
+ }
99
+ );
100
+ PageSelector.displayName = "PageSelector";
101
+ exports.PageSelector = PageSelector;
102
+ //# sourceMappingURL=PageSelector.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageSelector.cjs","sources":["../../../../src/components/PageSelector/PageSelector.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { ChevronLeftIcon } from \"../Icons/ChevronLeftIcon\";\nimport { ChevronRightIcon } from \"../Icons/ChevronRightIcon\";\n\nexport interface PageSelectorProps extends Omit<React.HTMLAttributes<HTMLElement>, \"onChange\"> {\n /** Total number of pages. */\n totalPages: number;\n /** Current active page (1-indexed). */\n currentPage: number;\n /** Callback fired when the active page changes. Receives the new 1-indexed page number. */\n onPageChange?: (page: number) => void;\n /** Whether reaching either end wraps around to the other. @default false */\n loop?: boolean;\n /** Whether the control is disabled. @default false */\n disabled?: boolean;\n /** Accessible label for the `<nav>` landmark. @default \"Page selector\" */\n ariaLabel?: string;\n /** Accessible label for the previous-page button. @default \"Previous page\" */\n previousLabel?: string;\n /** Accessible label for the next-page button. @default \"Next page\" */\n nextLabel?: string;\n /** Formats the indicator between the arrows. @default (current, total) => \\`${current} of ${total}\\` */\n formatLabel?: (currentPage: number, totalPages: number) => string;\n}\n\nconst arrowClasses = cn(\n \"flex shrink-0 cursor-pointer items-center justify-center rounded-xs p-1 text-content-primary [&>svg]:size-4\",\n \"hover:bg-brand-primary-muted disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none motion-safe:transition-colors motion-safe:duration-150\",\n);\n\n/**\n * A compact control for stepping through a small, known set of pages one at a\n * time, showing the position as \"current of total\" between a back and forward\n * arrow. Use when the total is small and the exact page number matters less\n * than moving between them, such as flicking through generated variants or a\n * short carousel. Reach for `Pagination` instead when consumers need to jump\n * to a specific numbered page.\n *\n * @example\n * ```tsx\n * <PageSelector totalPages={3} currentPage={page} onPageChange={setPage} />\n * ```\n */\nexport const PageSelector = React.forwardRef<HTMLElement, PageSelectorProps>(\n (\n {\n className,\n totalPages,\n currentPage,\n onPageChange,\n loop = false,\n disabled = false,\n ariaLabel = \"Page selector\",\n previousLabel = \"Previous page\",\n nextLabel = \"Next page\",\n formatLabel = (current, total) => `${current} of ${total}`,\n ...props\n },\n ref,\n ) => {\n const atStart = currentPage <= 1;\n const atEnd = currentPage >= totalPages;\n const prevDisabled = disabled || (atStart && !loop);\n const nextDisabled = disabled || (atEnd && !loop);\n\n const goTo = (page: number) => {\n const wrapped = loop ? ((page - 1 + totalPages) % totalPages) + 1 : page;\n if (wrapped < 1 || wrapped > totalPages || wrapped === currentPage) return;\n onPageChange?.(wrapped);\n };\n\n return (\n <nav\n ref={ref}\n aria-label={ariaLabel}\n className={cn(\n \"inline-flex items-center gap-1 rounded-sm border border-border-primary bg-surface-secondary p-1\",\n className,\n )}\n {...props}\n >\n <button\n type=\"button\"\n aria-label={previousLabel}\n disabled={prevDisabled}\n onClick={() => goTo(currentPage - 1)}\n className={arrowClasses}\n >\n <ChevronLeftIcon />\n </button>\n\n <span\n aria-live=\"polite\"\n className=\"typography-description-12px-semibold px-2 py-1 text-center text-content-primary tabular-nums\"\n >\n {formatLabel(currentPage, totalPages)}\n </span>\n\n <button\n type=\"button\"\n aria-label={nextLabel}\n disabled={nextDisabled}\n onClick={() => goTo(currentPage + 1)}\n className={arrowClasses}\n >\n <ChevronRightIcon />\n </button>\n </nav>\n );\n },\n);\n\nPageSelector.displayName = \"PageSelector\";\n"],"names":["cn","React","jsxs","jsx","ChevronLeftIcon","ChevronRightIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,eAAeA,GAAAA;AAAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF;AAeO,MAAM,eAAeC,iBAAM;AAAA,EAChC,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,cAAc,CAAC,SAAS,UAAU,GAAG,OAAO,OAAO,KAAK;AAAA,IACxD,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,UAAU,eAAe;AAC/B,UAAM,QAAQ,eAAe;AAC7B,UAAM,eAAe,YAAa,WAAW,CAAC;AAC9C,UAAM,eAAe,YAAa,SAAS,CAAC;AAE5C,UAAM,OAAO,CAAC,SAAiB;AAC7B,YAAM,UAAU,QAAS,OAAO,IAAI,cAAc,aAAc,IAAI;AACpE,UAAI,UAAU,KAAK,UAAU,cAAc,YAAY,YAAa;AACpE,qBAAe,OAAO;AAAA,IACxB;AAEA,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,cAAY;AAAA,QACZ,WAAWF,GAAAA;AAAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAAG,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,UAAU;AAAA,cACV,SAAS,MAAM,KAAK,cAAc,CAAC;AAAA,cACnC,WAAW;AAAA,cAEX,yCAACC,gBAAAA,iBAAA,CAAA,CAAgB;AAAA,YAAA;AAAA,UAAA;AAAA,UAGnBD,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,aAAU;AAAA,cACV,WAAU;AAAA,cAET,UAAA,YAAY,aAAa,UAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAGtCA,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,UAAU;AAAA,cACV,SAAS,MAAM,KAAK,cAAc,CAAC;AAAA,cACnC,WAAW;AAAA,cAEX,yCAACE,iBAAAA,kBAAA,CAAA,CAAiB;AAAA,YAAA;AAAA,UAAA;AAAA,QACpB;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACF;AAEA,aAAa,cAAc;;"}
@@ -204,6 +204,7 @@ const Loader = require("./components/Loader/Loader.cjs");
204
204
  const Logo = require("./components/Logo/Logo.cjs");
205
205
  const MobileStepper = require("./components/MobileStepper/MobileStepper.cjs");
206
206
  const OnlineBlinkingIcon = require("./components/OnlineBlinkingIcon/OnlineBlinkingIcon.cjs");
207
+ const PageSelector = require("./components/PageSelector/PageSelector.cjs");
207
208
  const Pagination = require("./components/Pagination/Pagination.cjs");
208
209
  const PasswordField = require("./components/PasswordField/PasswordField.cjs");
209
210
  const Pill = require("./components/Pill/Pill.cjs");
@@ -492,6 +493,7 @@ exports.Loader = Loader.Loader;
492
493
  exports.Logo = Logo.Logo;
493
494
  exports.MobileStepper = MobileStepper.MobileStepper;
494
495
  exports.OnlineBlinkingIcon = OnlineBlinkingIcon.OnlineBlinkingIcon;
496
+ exports.PageSelector = PageSelector.PageSelector;
495
497
  exports.Pagination = Pagination.Pagination;
496
498
  exports.PasswordField = PasswordField.PasswordField;
497
499
  exports.Pill = Pill.Pill;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -118,7 +118,7 @@ const DatePicker = forwardRef(
118
118
  weekdays: "flex",
119
119
  weekday: "flex h-[30px] w-10 flex-1 items-center justify-center typography-body-small-14px-regular text-content-secondary",
120
120
  week: "flex",
121
- day: "relative flex w-10 flex-1 items-center justify-center",
121
+ day: "relative flex flex-1 items-center justify-center p-0.5",
122
122
  hidden: "hidden"
123
123
  },
124
124
  components: {
@@ -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, range_middle } = modifiers;\n const isSingleDayRange = range_start && range_end;\n const inRange = (range_start || range_end || range_middle) && !isSingleDayRange;\n\n return (\n <div\n className={cn(\n className,\n inRange && \"bg-inputs-calendar-range\",\n inRange && range_start && \"rounded-l-sm\",\n inRange && range_end && \"rounded-r-sm\",\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 const isSelected = modifiers.selected && !modifiers.range_middle;\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-sm text-content-primary\",\n \"transition-colors hover:bg-inputs-calendar-range not-disabled:active:bg-inputs-calendar-range\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n \"disabled:cursor-not-allowed\",\n isSelected ? \"typography-body-small-14px-semibold\" : \"typography-body-small-14px-regular\",\n modifiers.today &&\n !isSelected &&\n \"bg-inputs-calendar-today text-content-always-white hover:bg-inputs-calendar-today\",\n isSelected &&\n \"bg-inputs-calendar-selected text-content-primary-inverted hover:bg-inputs-calendar-selected\",\n modifiers.range_middle && \"bg-transparent hover:bg-transparent\",\n modifiers.disabled &&\n \"bg-inputs-calendar-disabled text-content-disabled hover:bg-inputs-calendar-disabled\",\n modifiers.outside && \"pointer-events-none text-content-disabled\",\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 * variant=\"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-xl border border-modal-stroke bg-modal-background p-6 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: \"long\", year: \"numeric\" }),\n ...formatters,\n }}\n classNames={{\n root: \"w-full\",\n months: cn(\"relative flex\", isMulti && \"gap-6\"),\n month: \"flex flex-1 flex-col\",\n month_caption: \"mb-4 flex h-8 items-center justify-center\",\n caption_label: \"typography-body-default-16px-regular text-content-primary\",\n nav: \"absolute inset-x-0 top-0 z-20 flex justify-between\",\n button_previous:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n button_next:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n month_grid: \"w-full\",\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\",\n day: \"relative flex w-10 flex-1 items-center justify-center\",\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-2 pt-6\">\n <Button variant=\"outline\" 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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"}
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, range_middle } = modifiers;\n const isSingleDayRange = range_start && range_end;\n const inRange = (range_start || range_end || range_middle) && !isSingleDayRange;\n\n return (\n <div\n className={cn(\n className,\n inRange && \"bg-inputs-calendar-range\",\n inRange && range_start && \"rounded-l-sm\",\n inRange && range_end && \"rounded-r-sm\",\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 const isSelected = modifiers.selected && !modifiers.range_middle;\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-sm text-content-primary\",\n \"transition-colors hover:bg-inputs-calendar-range not-disabled:active:bg-inputs-calendar-range\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none\",\n \"disabled:cursor-not-allowed\",\n isSelected ? \"typography-body-small-14px-semibold\" : \"typography-body-small-14px-regular\",\n modifiers.today &&\n !isSelected &&\n \"bg-inputs-calendar-today text-content-always-white hover:bg-inputs-calendar-today\",\n isSelected &&\n \"bg-inputs-calendar-selected text-content-primary-inverted hover:bg-inputs-calendar-selected\",\n modifiers.range_middle && \"bg-transparent hover:bg-transparent\",\n modifiers.disabled &&\n \"bg-inputs-calendar-disabled text-content-disabled hover:bg-inputs-calendar-disabled\",\n modifiers.outside && \"pointer-events-none text-content-disabled\",\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 * variant=\"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-xl border border-modal-stroke bg-modal-background p-6 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: \"long\", year: \"numeric\" }),\n ...formatters,\n }}\n classNames={{\n root: \"w-full\",\n months: cn(\"relative flex\", isMulti && \"gap-6\"),\n month: \"flex flex-1 flex-col\",\n month_caption: \"mb-4 flex h-8 items-center justify-center\",\n caption_label: \"typography-body-default-16px-regular text-content-primary\",\n nav: \"absolute inset-x-0 top-0 z-20 flex justify-between\",\n button_previous:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n button_next:\n \"pointer-events-auto inline-flex size-8 cursor-pointer items-center justify-center rounded-full bg-buttons-secondary-default text-content-primary transition-colors hover:bg-buttons-secondary-hover focus-visible:shadow-focus-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:bg-buttons-disabled-default disabled:text-content-disabled [&>svg]:size-4\",\n month_grid: \"w-full\",\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\",\n day: \"relative flex flex-1 items-center justify-center p-0.5\",\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-2 pt-6\">\n <Button variant=\"outline\" 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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"}
@@ -131,7 +131,7 @@ const DialogHeader = React.forwardRef(
131
131
  "aria-label": backLabel
132
132
  }
133
133
  ),
134
- /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children }),
134
+ /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children }),
135
135
  showClose && /* @__PURE__ */ jsx(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx(
136
136
  IconButton,
137
137
  {
@@ -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 by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\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 * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n /** Show the v2 mobile sheet pull handle. Only rendered when `mobilePresentation` is `\"sheet\"`. @default true */\n showMobileHandle?: boolean;\n /**\n * How the dialog presents below the `sm` breakpoint.\n * - `\"sheet\"` — bottom sheet pinned to the viewport bottom edge (default)\n * - `\"card\"` — centered floating card per the v2-modal confirmation spec:\n * 16px side margins, 24px padding, 32px radius on all corners, no pull handle\n *\n * @default \"sheet\"\n */\n mobilePresentation?: \"sheet\" | \"card\";\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. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius by default; pass `mobilePresentation=\"card\"` to\n * render a centered floating card instead (used for small confirmation dialogs).\n * On larger viewports it renders centered with 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>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n showMobileHandle = true,\n mobilePresentation = \"sheet\",\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\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 \"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none\",\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 mobilePresentation === \"card\"\n ? // Floating confirmation card (v2-modal): 16px side margins, vertically centered, 32px radius\n cn(\n \"inset-x-4 top-1/2 max-h-[85vh] -translate-y-1/2 rounded-xl p-6\",\n \"data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95\",\n \"sm:inset-x-auto\",\n )\n : // Bottom sheet pinned to the viewport bottom edge\n cn(\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\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 ),\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg sm:p-6\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {showMobileHandle && mobilePresentation === \"sheet\" && (\n <div\n aria-hidden=\"true\"\n className=\"mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden\"\n />\n )}\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\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 shrink-0 items-center justify-end gap-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<ArrowLeftIcon size={16} />}\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\n variant=\"secondary\"\n size=\"32\"\n icon={<CloseIcon size={16} />}\n aria-label={closeLabel}\n />\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 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 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(\"flex shrink-0 items-center gap-2\", \"[&>*]:min-w-0 [&>*]:flex-1\", className)}\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 by {@link DialogContent}; portaled to `document.body` when {@link DialogContent} `portal` is true.\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 * When true, teleports overlay and panel to `document.body`.\n * When false, renders inline in the React tree (useful inside theme providers or scoped containers).\n * @default true\n */\n portal?: boolean;\n /** Show the v2 mobile sheet pull handle. Only rendered when `mobilePresentation` is `\"sheet\"`. @default true */\n showMobileHandle?: boolean;\n /**\n * How the dialog presents below the `sm` breakpoint.\n * - `\"sheet\"` — bottom sheet pinned to the viewport bottom edge (default)\n * - `\"card\"` — centered floating card per the v2-modal confirmation spec:\n * 16px side margins, 24px padding, 32px radius on all corners, no pull handle\n *\n * @default \"sheet\"\n */\n mobilePresentation?: \"sheet\" | \"card\";\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. Includes the overlay by default and portals to `document.body` by default.\n *\n * Set `portal={false}` to keep overlay and content in the DOM subtree of the parent `Dialog`.\n * `fixed` positioning still applies; ancestors with `transform` or `overflow` may affect layout.\n *\n * On mobile viewports (<640px), the dialog slides up from the bottom as a sheet\n * with top-only border radius by default; pass `mobilePresentation=\"card\"` to\n * render a centered floating card instead (used for small confirmation dialogs).\n * On larger viewports it renders centered with 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>(\n (\n {\n className,\n children,\n size = \"md\",\n overlay = true,\n portal = true,\n showMobileHandle = true,\n mobilePresentation = \"sheet\",\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const content = (\n <>\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 \"fixed flex flex-col overflow-hidden border border-modal-stroke bg-modal-background shadow-blur-menu backdrop-blur-[4px] focus:outline-none\",\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 mobilePresentation === \"card\"\n ? // Floating confirmation card (v2-modal): 16px side margins, vertically centered, 32px radius\n cn(\n \"inset-x-4 top-1/2 max-h-[85vh] -translate-y-1/2 rounded-xl p-6\",\n \"data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95\",\n \"sm:inset-x-auto\",\n )\n : // Bottom sheet pinned to the viewport bottom edge\n cn(\n \"inset-x-0 bottom-0 max-h-[85vh] w-full rounded-t-xl p-4 pt-3\",\n \"data-[state=open]:slide-in-from-bottom-full\",\n \"data-[state=closed]:slide-out-to-bottom-full\",\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 ),\n \"sm:inset-auto sm:top-1/2 sm:left-1/2 sm:max-h-[85vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg sm:p-6\",\n \"duration-200\",\n SIZE_CLASSES[size],\n className,\n )}\n {...props}\n >\n {showMobileHandle && mobilePresentation === \"sheet\" && (\n <div\n aria-hidden=\"true\"\n className=\"mb-3 h-1 w-8 shrink-0 self-center rounded-full bg-icons-tertiary sm:hidden\"\n />\n )}\n {children}\n </DialogPrimitive.Content>\n </>\n );\n\n return portal ? <DialogPrimitive.Portal>{content}</DialogPrimitive.Portal> : content;\n },\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 shrink-0 items-center justify-end gap-4\", className)}\n {...props}\n >\n {shouldShowBack && (\n <IconButton\n variant=\"secondary\"\n size=\"32\"\n icon={<ArrowLeftIcon size={16} />}\n onClick={onBack}\n disabled={!onBack}\n aria-label={backLabel}\n />\n )}\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 variant=\"secondary\"\n size=\"32\"\n icon={<CloseIcon size={16} />}\n aria-label={closeLabel}\n />\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 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 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(\"flex shrink-0 items-center gap-2\", \"[&>*]:min-w-0 [&>*]:flex-1\", className)}\n {...props}\n />\n ),\n);\nDialogFooter.displayName = \"DialogFooter\";\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../../utils/cn.mjs";
5
+ import { ChevronLeftIcon } from "../Icons/ChevronLeftIcon.mjs";
6
+ import { ChevronRightIcon } from "../Icons/ChevronRightIcon.mjs";
7
+ const arrowClasses = cn(
8
+ "flex shrink-0 cursor-pointer items-center justify-center rounded-xs p-1 text-content-primary [&>svg]:size-4",
9
+ "hover:bg-brand-primary-muted disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent",
10
+ "focus-visible:shadow-focus-ring focus-visible:outline-none motion-safe:transition-colors motion-safe:duration-150"
11
+ );
12
+ const PageSelector = React.forwardRef(
13
+ ({
14
+ className,
15
+ totalPages,
16
+ currentPage,
17
+ onPageChange,
18
+ loop = false,
19
+ disabled = false,
20
+ ariaLabel = "Page selector",
21
+ previousLabel = "Previous page",
22
+ nextLabel = "Next page",
23
+ formatLabel = (current, total) => `${current} of ${total}`,
24
+ ...props
25
+ }, ref) => {
26
+ const atStart = currentPage <= 1;
27
+ const atEnd = currentPage >= totalPages;
28
+ const prevDisabled = disabled || atStart && !loop;
29
+ const nextDisabled = disabled || atEnd && !loop;
30
+ const goTo = (page) => {
31
+ const wrapped = loop ? (page - 1 + totalPages) % totalPages + 1 : page;
32
+ if (wrapped < 1 || wrapped > totalPages || wrapped === currentPage) return;
33
+ onPageChange?.(wrapped);
34
+ };
35
+ return /* @__PURE__ */ jsxs(
36
+ "nav",
37
+ {
38
+ ref,
39
+ "aria-label": ariaLabel,
40
+ className: cn(
41
+ "inline-flex items-center gap-1 rounded-sm border border-border-primary bg-surface-secondary p-1",
42
+ className
43
+ ),
44
+ ...props,
45
+ children: [
46
+ /* @__PURE__ */ jsx(
47
+ "button",
48
+ {
49
+ type: "button",
50
+ "aria-label": previousLabel,
51
+ disabled: prevDisabled,
52
+ onClick: () => goTo(currentPage - 1),
53
+ className: arrowClasses,
54
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
55
+ }
56
+ ),
57
+ /* @__PURE__ */ jsx(
58
+ "span",
59
+ {
60
+ "aria-live": "polite",
61
+ className: "typography-description-12px-semibold px-2 py-1 text-center text-content-primary tabular-nums",
62
+ children: formatLabel(currentPage, totalPages)
63
+ }
64
+ ),
65
+ /* @__PURE__ */ jsx(
66
+ "button",
67
+ {
68
+ type: "button",
69
+ "aria-label": nextLabel,
70
+ disabled: nextDisabled,
71
+ onClick: () => goTo(currentPage + 1),
72
+ className: arrowClasses,
73
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
74
+ }
75
+ )
76
+ ]
77
+ }
78
+ );
79
+ }
80
+ );
81
+ PageSelector.displayName = "PageSelector";
82
+ export {
83
+ PageSelector
84
+ };
85
+ //# sourceMappingURL=PageSelector.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageSelector.mjs","sources":["../../../src/components/PageSelector/PageSelector.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { ChevronLeftIcon } from \"../Icons/ChevronLeftIcon\";\nimport { ChevronRightIcon } from \"../Icons/ChevronRightIcon\";\n\nexport interface PageSelectorProps extends Omit<React.HTMLAttributes<HTMLElement>, \"onChange\"> {\n /** Total number of pages. */\n totalPages: number;\n /** Current active page (1-indexed). */\n currentPage: number;\n /** Callback fired when the active page changes. Receives the new 1-indexed page number. */\n onPageChange?: (page: number) => void;\n /** Whether reaching either end wraps around to the other. @default false */\n loop?: boolean;\n /** Whether the control is disabled. @default false */\n disabled?: boolean;\n /** Accessible label for the `<nav>` landmark. @default \"Page selector\" */\n ariaLabel?: string;\n /** Accessible label for the previous-page button. @default \"Previous page\" */\n previousLabel?: string;\n /** Accessible label for the next-page button. @default \"Next page\" */\n nextLabel?: string;\n /** Formats the indicator between the arrows. @default (current, total) => \\`${current} of ${total}\\` */\n formatLabel?: (currentPage: number, totalPages: number) => string;\n}\n\nconst arrowClasses = cn(\n \"flex shrink-0 cursor-pointer items-center justify-center rounded-xs p-1 text-content-primary [&>svg]:size-4\",\n \"hover:bg-brand-primary-muted disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent\",\n \"focus-visible:shadow-focus-ring focus-visible:outline-none motion-safe:transition-colors motion-safe:duration-150\",\n);\n\n/**\n * A compact control for stepping through a small, known set of pages one at a\n * time, showing the position as \"current of total\" between a back and forward\n * arrow. Use when the total is small and the exact page number matters less\n * than moving between them, such as flicking through generated variants or a\n * short carousel. Reach for `Pagination` instead when consumers need to jump\n * to a specific numbered page.\n *\n * @example\n * ```tsx\n * <PageSelector totalPages={3} currentPage={page} onPageChange={setPage} />\n * ```\n */\nexport const PageSelector = React.forwardRef<HTMLElement, PageSelectorProps>(\n (\n {\n className,\n totalPages,\n currentPage,\n onPageChange,\n loop = false,\n disabled = false,\n ariaLabel = \"Page selector\",\n previousLabel = \"Previous page\",\n nextLabel = \"Next page\",\n formatLabel = (current, total) => `${current} of ${total}`,\n ...props\n },\n ref,\n ) => {\n const atStart = currentPage <= 1;\n const atEnd = currentPage >= totalPages;\n const prevDisabled = disabled || (atStart && !loop);\n const nextDisabled = disabled || (atEnd && !loop);\n\n const goTo = (page: number) => {\n const wrapped = loop ? ((page - 1 + totalPages) % totalPages) + 1 : page;\n if (wrapped < 1 || wrapped > totalPages || wrapped === currentPage) return;\n onPageChange?.(wrapped);\n };\n\n return (\n <nav\n ref={ref}\n aria-label={ariaLabel}\n className={cn(\n \"inline-flex items-center gap-1 rounded-sm border border-border-primary bg-surface-secondary p-1\",\n className,\n )}\n {...props}\n >\n <button\n type=\"button\"\n aria-label={previousLabel}\n disabled={prevDisabled}\n onClick={() => goTo(currentPage - 1)}\n className={arrowClasses}\n >\n <ChevronLeftIcon />\n </button>\n\n <span\n aria-live=\"polite\"\n className=\"typography-description-12px-semibold px-2 py-1 text-center text-content-primary tabular-nums\"\n >\n {formatLabel(currentPage, totalPages)}\n </span>\n\n <button\n type=\"button\"\n aria-label={nextLabel}\n disabled={nextDisabled}\n onClick={() => goTo(currentPage + 1)}\n className={arrowClasses}\n >\n <ChevronRightIcon />\n </button>\n </nav>\n );\n },\n);\n\nPageSelector.displayName = \"PageSelector\";\n"],"names":[],"mappings":";;;;;;AA0BA,MAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF;AAeO,MAAM,eAAe,MAAM;AAAA,EAChC,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,cAAc,CAAC,SAAS,UAAU,GAAG,OAAO,OAAO,KAAK;AAAA,IACxD,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,UAAU,eAAe;AAC/B,UAAM,QAAQ,eAAe;AAC7B,UAAM,eAAe,YAAa,WAAW,CAAC;AAC9C,UAAM,eAAe,YAAa,SAAS,CAAC;AAE5C,UAAM,OAAO,CAAC,SAAiB;AAC7B,YAAM,UAAU,QAAS,OAAO,IAAI,cAAc,aAAc,IAAI;AACpE,UAAI,UAAU,KAAK,UAAU,cAAc,YAAY,YAAa;AACpE,qBAAe,OAAO;AAAA,IACxB;AAEA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,cAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,UAAU;AAAA,cACV,SAAS,MAAM,KAAK,cAAc,CAAC;AAAA,cACnC,WAAW;AAAA,cAEX,8BAAC,iBAAA,CAAA,CAAgB;AAAA,YAAA;AAAA,UAAA;AAAA,UAGnB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,aAAU;AAAA,cACV,WAAU;AAAA,cAET,UAAA,YAAY,aAAa,UAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAGtC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAY;AAAA,cACZ,UAAU;AAAA,cACV,SAAS,MAAM,KAAK,cAAc,CAAC;AAAA,cACnC,WAAW;AAAA,cAEX,8BAAC,kBAAA,CAAA,CAAiB;AAAA,YAAA;AAAA,UAAA;AAAA,QACpB;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACF;AAEA,aAAa,cAAc;"}
package/dist/index.d.ts CHANGED
@@ -3419,6 +3419,42 @@ export declare const OpenIcon: React_2.ForwardRefExoticComponent<React_2.SVGAttr
3419
3419
  className?: string;
3420
3420
  } & React_2.RefAttributes<SVGSVGElement>>;
3421
3421
 
3422
+ /**
3423
+ * A compact control for stepping through a small, known set of pages one at a
3424
+ * time, showing the position as "current of total" between a back and forward
3425
+ * arrow. Use when the total is small and the exact page number matters less
3426
+ * than moving between them, such as flicking through generated variants or a
3427
+ * short carousel. Reach for `Pagination` instead when consumers need to jump
3428
+ * to a specific numbered page.
3429
+ *
3430
+ * @example
3431
+ * ```tsx
3432
+ * <PageSelector totalPages={3} currentPage={page} onPageChange={setPage} />
3433
+ * ```
3434
+ */
3435
+ export declare const PageSelector: React_2.ForwardRefExoticComponent<PageSelectorProps & React_2.RefAttributes<HTMLElement>>;
3436
+
3437
+ export declare interface PageSelectorProps extends Omit<React_2.HTMLAttributes<HTMLElement>, "onChange"> {
3438
+ /** Total number of pages. */
3439
+ totalPages: number;
3440
+ /** Current active page (1-indexed). */
3441
+ currentPage: number;
3442
+ /** Callback fired when the active page changes. Receives the new 1-indexed page number. */
3443
+ onPageChange?: (page: number) => void;
3444
+ /** Whether reaching either end wraps around to the other. @default false */
3445
+ loop?: boolean;
3446
+ /** Whether the control is disabled. @default false */
3447
+ disabled?: boolean;
3448
+ /** Accessible label for the `<nav>` landmark. @default "Page selector" */
3449
+ ariaLabel?: string;
3450
+ /** Accessible label for the previous-page button. @default "Previous page" */
3451
+ previousLabel?: string;
3452
+ /** Accessible label for the next-page button. @default "Next page" */
3453
+ nextLabel?: string;
3454
+ /** Formats the indicator between the arrows. @default (current, total) => \`${current} of ${total}\` */
3455
+ formatLabel?: (currentPage: number, totalPages: number) => string;
3456
+ }
3457
+
3422
3458
  /**
3423
3459
  * Page navigation control with previous/next buttons and numbered page
3424
3460
  * indicators. Supports a numbered-buttons layout (`"default"`) and a compact
package/dist/index.mjs CHANGED
@@ -202,6 +202,7 @@ import { Loader } from "./components/Loader/Loader.mjs";
202
202
  import { Logo } from "./components/Logo/Logo.mjs";
203
203
  import { MobileStepper } from "./components/MobileStepper/MobileStepper.mjs";
204
204
  import { OnlineBlinkingIcon } from "./components/OnlineBlinkingIcon/OnlineBlinkingIcon.mjs";
205
+ import { PageSelector } from "./components/PageSelector/PageSelector.mjs";
205
206
  import { Pagination } from "./components/Pagination/Pagination.mjs";
206
207
  import { PasswordField } from "./components/PasswordField/PasswordField.mjs";
207
208
  import { Pill } from "./components/Pill/Pill.mjs";
@@ -421,6 +422,7 @@ export {
421
422
  NewMessageIcon,
422
423
  OnlineBlinkingIcon,
423
424
  OpenIcon,
425
+ PageSelector,
424
426
  Pagination,
425
427
  PasswordField,
426
428
  PauseIcon,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanvue/ui",
3
- "version": "3.11.0",
3
+ "version": "3.12.1",
4
4
  "description": "React component library built with Tailwind CSS for Fanvue ecosystem",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",