From f65159bd00114265b112dd954a04fb0de15192a9 Mon Sep 17 00:00:00 2001 From: yyh Date: Mon, 2 Mar 2026 14:57:06 +0800 Subject: [PATCH] refactor(web): share placement parser across base ui primitives --- .../components/base/ui/dropdown-menu/index.tsx | 9 +-------- web/app/components/base/ui/placement.ts | 18 ++++++++++++++++++ web/app/components/base/ui/popover/index.tsx | 9 +-------- web/app/components/base/ui/select/index.tsx | 9 +-------- web/app/components/base/ui/tooltip/index.tsx | 9 +-------- 5 files changed, 22 insertions(+), 32 deletions(-) create mode 100644 web/app/components/base/ui/placement.ts diff --git a/web/app/components/base/ui/dropdown-menu/index.tsx b/web/app/components/base/ui/dropdown-menu/index.tsx index 6534726064..370aca7d1a 100644 --- a/web/app/components/base/ui/dropdown-menu/index.tsx +++ b/web/app/components/base/ui/dropdown-menu/index.tsx @@ -3,16 +3,9 @@ import type { Placement } from '@floating-ui/react' import { Menu } from '@base-ui/react/menu' import * as React from 'react' +import { parsePlacement } from '@/app/components/base/ui/placement' import { cn } from '@/utils/classnames' -function parsePlacement(placement: Placement) { - const [side, align] = placement.split('-') as [ - 'top' | 'bottom' | 'left' | 'right', - 'start' | 'center' | 'end' | undefined, - ] - return { side, align: align ?? 'center' as const } -} - export const DropdownMenu = Menu.Root export const DropdownMenuTrigger = Menu.Trigger export const DropdownMenuSub = Menu.SubmenuRoot diff --git a/web/app/components/base/ui/placement.ts b/web/app/components/base/ui/placement.ts new file mode 100644 index 0000000000..a40221b206 --- /dev/null +++ b/web/app/components/base/ui/placement.ts @@ -0,0 +1,18 @@ +import type { Placement } from '@floating-ui/react' + +type ParsedPlacement = { + side: 'top' | 'bottom' | 'left' | 'right' + align: 'start' | 'center' | 'end' +} + +export function parsePlacement(placement: Placement): ParsedPlacement { + const [side, align] = placement.split('-') as [ + ParsedPlacement['side'], + ParsedPlacement['align'] | undefined, + ] + + return { + side, + align: align ?? 'center', + } +} diff --git a/web/app/components/base/ui/popover/index.tsx b/web/app/components/base/ui/popover/index.tsx index 1569a63c7a..1c8fda08cf 100644 --- a/web/app/components/base/ui/popover/index.tsx +++ b/web/app/components/base/ui/popover/index.tsx @@ -3,16 +3,9 @@ import type { Placement } from '@floating-ui/react' import { Popover as BasePopover } from '@base-ui/react/popover' import * as React from 'react' +import { parsePlacement } from '@/app/components/base/ui/placement' import { cn } from '@/utils/classnames' -function parsePlacement(placement: Placement) { - const [side, align] = placement.split('-') as [ - 'top' | 'bottom' | 'left' | 'right', - 'start' | 'center' | 'end' | undefined, - ] - return { side, align: align ?? 'center' as const } -} - export const Popover = BasePopover.Root export const PopoverTrigger = BasePopover.Trigger export const PopoverClose = BasePopover.Close diff --git a/web/app/components/base/ui/select/index.tsx b/web/app/components/base/ui/select/index.tsx index f240e5729b..bb4759fe7f 100644 --- a/web/app/components/base/ui/select/index.tsx +++ b/web/app/components/base/ui/select/index.tsx @@ -3,16 +3,9 @@ import type { Placement } from '@floating-ui/react' import { Select as BaseSelect } from '@base-ui/react/select' import * as React from 'react' +import { parsePlacement } from '@/app/components/base/ui/placement' import { cn } from '@/utils/classnames' -function parsePlacement(placement: Placement) { - const [side, align] = placement.split('-') as [ - 'top' | 'bottom' | 'left' | 'right', - 'start' | 'center' | 'end' | undefined, - ] - return { side, align: align ?? 'center' as const } -} - export const Select = BaseSelect.Root export const SelectValue = BaseSelect.Value export const SelectGroup = BaseSelect.Group diff --git a/web/app/components/base/ui/tooltip/index.tsx b/web/app/components/base/ui/tooltip/index.tsx index ff277892a5..df96e61fdc 100644 --- a/web/app/components/base/ui/tooltip/index.tsx +++ b/web/app/components/base/ui/tooltip/index.tsx @@ -3,16 +3,9 @@ import type { Placement } from '@floating-ui/react' import { Tooltip as BaseTooltip } from '@base-ui/react/tooltip' import * as React from 'react' +import { parsePlacement } from '@/app/components/base/ui/placement' import { cn } from '@/utils/classnames' -function parsePlacement(placement: Placement) { - const [side, align] = placement.split('-') as [ - 'top' | 'bottom' | 'left' | 'right', - 'start' | 'center' | 'end' | undefined, - ] - return { side, align: align ?? 'center' as const } -} - export type TooltipProps = { position?: Placement disabled?: boolean