import { IconSearch } from "@tabler/icons-react"; import { createElement, type CSSProperties, type KeyboardEvent, type MouseEvent as ReactMouseEvent, type ReactNode, type Ref, } from "react"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar.js"; import { Badge } from "../ui/badge.js"; import { ButtonBase } from "../ui/button.js"; import { Card } from "../ui/card.js"; import { Checkbox as DefaultCheckboxPrimitive } from "../ui/checkbox.js"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "../ui/dialog.js"; import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "../ui/dropdown-menu.js"; import { Input } from "../ui/input.js"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover.js"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../ui/select.js"; import { Skeleton as DefaultSkeletonPrimitive } from "../ui/skeleton.js"; import { Spinner as DefaultSpinnerPrimitive } from "../ui/spinner.js"; import { Switch as DefaultSwitchPrimitive } from "../ui/switch.js"; import { Tabs as DefaultTabsPrimitive, TabsContent, TabsList, TabsTrigger, } from "../ui/tabs.js"; import { Textarea } from "../ui/textarea.js"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "../ui/tooltip.js"; import { cn } from "../utils.js"; import type { DesignSystemComponents, MenuItem } from "./types.js"; function buttonVariant( intent: "primary" | "neutral" | "danger" = "neutral", emphasis: "solid" | "outline" | "ghost" = "solid", ) { if (emphasis === "ghost") return "ghost" as const; if (emphasis === "outline") return "outline" as const; if (intent === "primary") return "default" as const; if (intent === "danger") return "destructive" as const; return "secondary" as const; } function buttonSize(size: "compact" | "default" | "large" = "default") { if (size === "compact") return "sm" as const; if (size === "large") return "lg" as const; return "default" as const; } const DefaultActionButton: DesignSystemComponents["ActionButton"] = ({ children, intent, emphasis, size, pending, disabled, type = "button", leadingIcon, trailingIcon, onPress, elementRef, ...props }) => ( onPress?.(event)} > {pending ? : leadingIcon} {children} {trailingIcon} ); const DefaultIconButton: DesignSystemComponents["IconButton"] = ({ label, icon, intent, emphasis = "ghost", size, pending, disabled, type = "button", onPress, elementRef, className, ...props }) => ( onPress?.(event)} aria-label={label} data-size={size} > {pending ? : icon} ); function FieldShell({ label, description, errorMessage, className, style, children, }: { label?: ReactNode; description?: ReactNode; errorMessage?: ReactNode; className?: string; style?: CSSProperties; children: ReactNode; }) { return ( {label ? {label} : null} {children} {errorMessage ? ( {errorMessage} ) : description ? ( {description} ) : null} ); } const DefaultTextField: DesignSystemComponents["TextField"] = ({ value, onChange, label, description, errorMessage, invalid, inputRef, leadingContent, trailingContent, className, style, onBlur, onFocus, onKeyDown, ...props }) => ( {leadingContent} onChange(event.currentTarget.value)} onBlur={onBlur} onFocus={onFocus} onKeyDown={onKeyDown} /> {trailingContent} ); const DefaultTextArea: DesignSystemComponents["TextArea"] = ({ value, onChange, label, description, errorMessage, invalid, textAreaRef, className, style, onBlur, onFocus, onKeyDown, ...props }) => ( onChange(event.currentTarget.value)} onBlur={onBlur} onFocus={onFocus} onKeyDown={onKeyDown} /> ); const DefaultSpinner: DesignSystemComponents["Spinner"] = ({ label, size, className, ...props }) => ( ); const DefaultSkeleton: DesignSystemComponents["Skeleton"] = ({ width, height, shape = "rectangle", className, style, ...props }) => ( ); const DefaultStatus: DesignSystemComponents["Status"] = ({ children, tone = "neutral", icon, size, className, ...props }) => ( {icon} {children} ); const DefaultSurface: DesignSystemComponents["Surface"] = ({ children, as = "div", elevation = "low", padding = "default", interactive, onPress, className, ...props }) => { const onKeyDown = (event: KeyboardEvent) => { if (!interactive || (event.key !== "Enter" && event.key !== " ")) return; event.preventDefault(); onPress?.(event); }; const elementProps = { ...props, className: cn( "rounded-lg bg-card text-card-foreground", elevation === "none" && "shadow-none", elevation === "low" && "shadow-sm", elevation === "medium" && "shadow-md", padding === "compact" && "p-3", padding === "default" && "p-4", padding === "spacious" && "p-6", interactive && "cursor-pointer", className, ), onClick: (event: ReactMouseEvent) => onPress?.(event), onKeyDown, role: interactive ? "button" : undefined, tabIndex: interactive ? 0 : undefined, children, }; if (as === "div") return ; return createElement(as, elementProps); }; const DefaultAvatar: DesignSystemComponents["Avatar"] = ({ name, src, fallback, size, status, imageRef, className, ...props }) => ( {src ? : null} {fallback ?? name.slice(0, 2).toUpperCase()} {status ? ( ) : null} ); const DefaultTooltip: DesignSystemComponents["Tooltip"] = ({ trigger, content, open, defaultOpen, onOpenChange, delayMs, disabled, portalContainer, placement = "top", align = "center", collisionPadding, className, style, }) => { if (disabled) return trigger; return ( {trigger} {content} ); }; function DefaultMenuItems({ items, onAction, closeOnAction, }: { items: readonly MenuItem[]; onAction: (id: string | number) => void; closeOnAction: boolean; }) { return items.map((item) => item.children?.length ? ( {item.icon} {item.label} ) : item.selected !== undefined ? ( { if (!closeOnAction) event.preventDefault(); onAction(item.id); }} className={item.intent === "danger" ? "text-destructive" : undefined} > {item.icon} {item.label} {item.shortcut ? ( {item.shortcut} ) : null} ) : ( { if (!closeOnAction) event.preventDefault(); onAction(item.id); }} className={item.intent === "danger" ? "text-destructive" : undefined} > {item.icon} {item.label} {item.shortcut ? ( {item.shortcut} ) : null} ), ); } const DefaultMenu: DesignSystemComponents["Menu"] = ({ trigger, items, sections, open, defaultOpen, onOpenChange, onAction, portalContainer, placement = "bottom", align = "start", collisionPadding, className, style, closeOnAction = true, }) => ( {trigger} {sections ? ( sections.map((section, index) => ( {index > 0 ? : null} {section.label ? ( {section.label} ) : null} )) ) : items ? ( ) : null} ); const DefaultPopover: DesignSystemComponents["Popover"] = ({ trigger, children, open, defaultOpen, onOpenChange, modal, dismissible = true, portalContainer, placement = "bottom", align = "center", collisionPadding, className, style, }) => ( {trigger} { if (!dismissible) event.preventDefault(); }} onInteractOutside={(event) => { if (!dismissible) event.preventDefault(); }} > {children} ); const DefaultDialog: DesignSystemComponents["Dialog"] = ({ open, onOpenChange, title, description, children, footer, trigger, size = "medium", dismissible = true, closeLabel, initialFocusRef, restoreFocusRef, portalContainer, className, style, }) => ( {trigger ? {trigger} : null} { if (!initialFocusRef?.current) return; event.preventDefault(); initialFocusRef.current.focus(); }} onCloseAutoFocus={(event) => { if (!restoreFocusRef?.current) return; event.preventDefault(); restoreFocusRef.current.focus(); }} onEscapeKeyDown={(event) => { if (!dismissible) event.preventDefault(); }} onInteractOutside={(event) => { if (!dismissible) event.preventDefault(); }} > {title} {description ? ( {description} ) : null} {children} {footer ? {footer} : null} ); const DefaultPicker: DesignSystemComponents["Picker"] = ({ mode, options, value, onChange, label, description, errorMessage, placeholder, searchValue = "", onSearchChange, open, onOpenChange, emptyContent, loadingContent, loading, required, disabled, invalid, pickerRef, portalContainer, className, style, ...props }) => { const selected = options.find((option) => option.value === value); const filtered = mode === "combobox" && searchValue ? options.filter((option) => [option.textValue, option.label, ...(option.keywords ?? [])] .filter((part): part is string => typeof part === "string") .join(" ") .toLowerCase() .includes(searchValue.toLowerCase()), ) : options; if (mode === "select") { return ( { const option = options.find( (candidate) => String(candidate.value) === next, ); onChange(option?.value ?? null); }} required={required} disabled={disabled} > } aria-invalid={invalid || undefined} > {selected?.label} {loading ? loadingContent : options.length ? options.map((option) => ( {option.label} )) : emptyContent} ); } return ( } type="button" variant="outline" disabled={disabled} aria-invalid={invalid || undefined} > {selected?.label ?? placeholder} onSearchChange?.(event.currentTarget.value)} className="h-8 border-0 p-0 shadow-none focus-visible:ring-0" /> {loading ? loadingContent : filtered.length ? filtered.map((option) => ( { onChange(option.value); onOpenChange?.(false); }} > {option.icon} {option.label} )) : emptyContent} ); }; const DefaultCheckbox: DesignSystemComponents["Checkbox"] = ({ checked, onChange, label, description, indeterminate, inputRef, invalid, ...props }) => ( onChange(next === true)} /> {label || description ? ( {label ? {label} : null} {description ? ( {description} ) : null} ) : null} ); const DefaultSwitch: DesignSystemComponents["Switch"] = ({ checked, onChange, label, description, inputRef, ...props }) => ( {label || description ? ( {label ? {label} : null} {description ? ( {description} ) : null} ) : null} ); const DefaultTabs: DesignSystemComponents["Tabs"] = ({ items, value, onChange, orientation, activationMode, className, style, ...props }) => ( { const item = items.find((candidate) => String(candidate.value) === next); if (item) onChange(item.value); }} orientation={orientation} activationMode={activationMode} className={className} style={style} > {items.map((item) => ( {item.icon} {item.label} ))} {items.map((item) => ( {item.content} ))} ); export const defaultDesignSystemComponents: DesignSystemComponents = { ActionButton: DefaultActionButton, IconButton: DefaultIconButton, TextField: DefaultTextField, TextArea: DefaultTextArea, Spinner: DefaultSpinner, Skeleton: DefaultSkeleton, Status: DefaultStatus, Surface: DefaultSurface, Avatar: DefaultAvatar, Tooltip: DefaultTooltip, Menu: DefaultMenu, Popover: DefaultPopover, Dialog: DefaultDialog, Picker: DefaultPicker, Checkbox: DefaultCheckbox, Switch: DefaultSwitch, Tabs: DefaultTabs, };