import type { ReactNode } from 'react'; type PlatformSegmentedTabsColumns = | 'one' | 'two' | 'three' | 'four' | 'threeToSix'; type PlatformSegmentedTabsGap = 'sm' | 'md'; type PlatformSegmentedTabsRadius = 'md' | 'lg' | 'xl'; type PlatformSegmentedTabsSize = 'sm' | 'md' | 'compact' | 'choice' | 'tab'; type PlatformSegmentedTabsSurface = 'default' | 'soft' | 'transparent'; type PlatformSegmentedTabsTone = 'neutral' | 'warm' | 'rose' | 'underline'; type PlatformSegmentedTabsFrame = 'panel' | 'bare'; type PlatformSegmentedTabsSemantics = 'segment' | 'tabs'; export type PlatformSegmentedTabItem = { id: TId; label: ReactNode; ariaLabel?: string; disabled?: boolean; }; type PlatformSegmentedTabsProps = { items: readonly PlatformSegmentedTabItem[]; activeId: TId; onChange: (id: TId) => void; columns?: PlatformSegmentedTabsColumns; gap?: PlatformSegmentedTabsGap; radius?: PlatformSegmentedTabsRadius; size?: PlatformSegmentedTabsSize; surface?: PlatformSegmentedTabsSurface; tone?: PlatformSegmentedTabsTone; frame?: PlatformSegmentedTabsFrame; semantics?: PlatformSegmentedTabsSemantics; ariaLabel?: string; truncateLabels?: boolean; disabled?: boolean; className?: string; itemClassName?: | string | ((item: PlatformSegmentedTabItem, active: boolean) => string | null); }; const PLATFORM_SEGMENTED_TABS_COLUMNS_CLASS: Record< PlatformSegmentedTabsColumns, string > = { one: 'grid-cols-1', two: 'grid-cols-2', three: 'grid-cols-3', four: 'grid-cols-4', threeToSix: 'grid-cols-3 sm:grid-cols-6', }; const PLATFORM_SEGMENTED_TABS_GAP_CLASS: Record< PlatformSegmentedTabsGap, string > = { sm: 'gap-1', md: 'gap-2', }; const PLATFORM_SEGMENTED_TABS_RADIUS_CLASS: Record< PlatformSegmentedTabsRadius, string > = { md: 'rounded-[1rem]', lg: 'rounded-[1.1rem]', xl: 'rounded-[1.25rem]', }; const PLATFORM_SEGMENTED_TABS_SURFACE_CLASS: Record< PlatformSegmentedTabsSurface, string > = { default: 'bg-white/62', soft: 'bg-white/58', transparent: 'bg-transparent', }; const PLATFORM_SEGMENTED_TABS_FRAME_CLASS: Record< PlatformSegmentedTabsFrame, string > = { panel: 'border border-[var(--platform-subpanel-border)] p-1', bare: 'border-0 p-0', }; const PLATFORM_SEGMENTED_TABS_ITEM_SIZE_CLASS: Record< PlatformSegmentedTabsSize, string > = { sm: 'min-h-10 rounded-[0.9rem] px-3 text-sm font-bold', md: 'min-h-10 rounded-[1rem] px-3 text-sm font-bold', compact: 'min-h-10 rounded-[0.8rem] px-2 text-xs font-black sm:text-sm', choice: 'min-h-10 rounded-[0.9rem] px-1.5 py-2 text-center', tab: 'relative h-12 rounded-none px-2 text-base font-semibold sm:text-lg', }; const PLATFORM_SEGMENTED_TABS_TONE_CLASS: Record< PlatformSegmentedTabsTone, { active: string; idle: string } > = { neutral: { active: 'bg-white text-[var(--platform-text-strong)] shadow-sm', idle: 'text-[var(--platform-text-base)] hover:bg-white/60', }, warm: { active: 'bg-[var(--platform-warm-bg)] text-[var(--platform-text-strong)] shadow-[inset_0_0_0_1px_rgba(204,117,76,0.18)]', idle: 'text-[var(--platform-text-base)] hover:bg-white/58', }, rose: { active: 'border border-[#ff7890] bg-[linear-gradient(180deg,#ff7890_0%,#ff4f6a_100%)] text-white shadow-[0_8px_18px_rgba(244,63,94,0.16)]', idle: 'border border-[var(--platform-subpanel-border)] bg-white/76 text-[var(--platform-text-strong)] hover:border-[var(--platform-surface-hover-border)] hover:bg-white', }, underline: { active: 'text-[var(--platform-text-strong)]', idle: 'text-[var(--platform-text-muted)] hover:text-[var(--platform-text-base)]', }, }; function resolveItemClassName({ active, disabled, item, itemClassName, size, tone, }: { active: boolean; disabled: boolean; item: PlatformSegmentedTabItem; itemClassName?: PlatformSegmentedTabsProps['itemClassName']; size: PlatformSegmentedTabsSize; tone: PlatformSegmentedTabsTone; }) { const extraClassName = typeof itemClassName === 'function' ? itemClassName(item, active) : itemClassName; return [ 'min-w-0 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--platform-warm-border)]', PLATFORM_SEGMENTED_TABS_ITEM_SIZE_CLASS[size], active ? PLATFORM_SEGMENTED_TABS_TONE_CLASS[tone].active : PLATFORM_SEGMENTED_TABS_TONE_CLASS[tone].idle, disabled ? 'cursor-not-allowed opacity-55 hover:bg-transparent' : null, extraClassName, ] .filter(Boolean) .join(' '); } /** * 平台白底分段选择控件。 * 统一承接结果页和轻量弹窗内重复的 tab / segment button chrome。 */ export function PlatformSegmentedTabs({ items, activeId, onChange, columns = 'two', gap = 'md', radius = 'xl', size = 'md', surface = 'default', tone = 'neutral', frame = 'panel', semantics = 'segment', ariaLabel, truncateLabels = false, disabled = false, className, itemClassName, }: PlatformSegmentedTabsProps) { return (
{items.map((item) => { const active = activeId === item.id; const itemDisabled = disabled || Boolean(item.disabled); return ( ); })}
); }