From 71ea7a369bd06d39a8724f2cebbc750ee5d8999b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:09:29 +0000 Subject: [PATCH 01/11] Initial plan From c1dcf670c4c62985989631eb3aa9bfd4f5948404 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:18:54 +0000 Subject: [PATCH 02/11] Add missing shadcn components: toast, date-picker, combobox Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/components/src/hooks/toaster.tsx | 43 +++++ packages/components/src/hooks/use-toast.ts | 197 +++++++++++++++++++++ packages/components/src/index.ts | 3 + packages/components/src/ui/combobox.tsx | 104 +++++++++++ packages/components/src/ui/date-picker.tsx | 61 +++++++ packages/components/src/ui/index.ts | 3 + packages/components/src/ui/toast.tsx | 135 ++++++++++++++ 7 files changed, 546 insertions(+) create mode 100644 packages/components/src/hooks/toaster.tsx create mode 100644 packages/components/src/hooks/use-toast.ts create mode 100644 packages/components/src/ui/combobox.tsx create mode 100644 packages/components/src/ui/date-picker.tsx create mode 100644 packages/components/src/ui/toast.tsx diff --git a/packages/components/src/hooks/toaster.tsx b/packages/components/src/hooks/toaster.tsx new file mode 100644 index 000000000..197f8e485 --- /dev/null +++ b/packages/components/src/hooks/toaster.tsx @@ -0,0 +1,43 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +"use client" + +import { + Toast, + ToastClose, + ToastDescription, + ToastProvider, + ToastTitle, + ToastViewport, +} from "../ui/toast" +import { useToast } from "./use-toast" + +export function Toaster() { + const { toasts } = useToast() + + return ( + + {toasts.map(function ({ id, title, description, action, ...props }) { + return ( + +
+ {title && {title}} + {description && ( + {description} + )} +
+ {action} + +
+ ) + })} + +
+ ) +} diff --git a/packages/components/src/hooks/use-toast.ts b/packages/components/src/hooks/use-toast.ts new file mode 100644 index 000000000..fd2ac5b20 --- /dev/null +++ b/packages/components/src/hooks/use-toast.ts @@ -0,0 +1,197 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import * as React from "react" + +import type { + ToastActionElement, + ToastProps, +} from "../ui/toast" + +const TOAST_LIMIT = 1 +const TOAST_REMOVE_DELAY = 1000000 + +type ToasterToast = ToastProps & { + id: string + title?: React.ReactNode + description?: React.ReactNode + action?: ToastActionElement +} + +const actionTypes = { + ADD_TOAST: "ADD_TOAST", + UPDATE_TOAST: "UPDATE_TOAST", + DISMISS_TOAST: "DISMISS_TOAST", + REMOVE_TOAST: "REMOVE_TOAST", +} as const + +let count = 0 + +function genId() { + count = (count + 1) % Number.MAX_SAFE_INTEGER + return count.toString() +} + +type ActionType = typeof actionTypes + +type Action = + | { + type: ActionType["ADD_TOAST"] + toast: ToasterToast + } + | { + type: ActionType["UPDATE_TOAST"] + toast: Partial + } + | { + type: ActionType["DISMISS_TOAST"] + toastId?: ToasterToast["id"] + } + | { + type: ActionType["REMOVE_TOAST"] + toastId?: ToasterToast["id"] + } + +interface State { + toasts: ToasterToast[] +} + +const toastTimeouts = new Map>() + +const addToRemoveQueue = (toastId: string) => { + if (toastTimeouts.has(toastId)) { + return + } + + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId) + dispatch({ + type: "REMOVE_TOAST", + toastId: toastId, + }) + }, TOAST_REMOVE_DELAY) + + toastTimeouts.set(toastId, timeout) +} + +export const reducer = (state: State, action: Action): State => { + switch (action.type) { + case "ADD_TOAST": + return { + ...state, + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), + } + + case "UPDATE_TOAST": + return { + ...state, + toasts: state.toasts.map((t) => + t.id === action.toast.id ? { ...t, ...action.toast } : t + ), + } + + case "DISMISS_TOAST": { + const { toastId } = action + + if (toastId) { + addToRemoveQueue(toastId) + } else { + state.toasts.forEach((toast) => { + addToRemoveQueue(toast.id) + }) + } + + return { + ...state, + toasts: state.toasts.map((t) => + t.id === toastId || toastId === undefined + ? { + ...t, + open: false, + } + : t + ), + } + } + case "REMOVE_TOAST": + if (action.toastId === undefined) { + return { + ...state, + toasts: [], + } + } + return { + ...state, + toasts: state.toasts.filter((t) => t.id !== action.toastId), + } + } +} + +const listeners: Array<(state: State) => void> = [] + +let memoryState: State = { toasts: [] } + +function dispatch(action: Action) { + memoryState = reducer(memoryState, action) + listeners.forEach((listener) => { + listener(memoryState) + }) +} + +type Toast = Omit + +function toast({ ...props }: Toast) { + const id = genId() + + const update = (props: ToasterToast) => + dispatch({ + type: "UPDATE_TOAST", + toast: { ...props, id }, + }) + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + + dispatch({ + type: "ADD_TOAST", + toast: { + ...props, + id, + open: true, + onOpenChange: (open) => { + if (!open) dismiss() + }, + }, + }) + + return { + id: id, + dismiss, + update, + } +} + +function useToast() { + const [state, setState] = React.useState(memoryState) + + React.useEffect(() => { + listeners.push(setState) + return () => { + const index = listeners.indexOf(setState) + if (index > -1) { + listeners.splice(index, 1) + } + } + }, [state]) + + return { + ...state, + toast, + dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), + } +} + +export { useToast, toast } diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index d6e396e2b..512dbdba8 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -14,6 +14,9 @@ import './renderers'; // Export utils export * from './lib/utils'; +// Export hooks +export * from './hooks/use-toast'; + // Export raw Shadcn UI components export * from './ui'; diff --git a/packages/components/src/ui/combobox.tsx b/packages/components/src/ui/combobox.tsx new file mode 100644 index 000000000..35ec3e2b4 --- /dev/null +++ b/packages/components/src/ui/combobox.tsx @@ -0,0 +1,104 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +"use client" + +import * as React from "react" +import { Check, ChevronsUpDown } from "lucide-react" + +import { cn } from "../lib/utils" +import { Button } from "./button" +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from "./command" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "./popover" + +export interface ComboboxOption { + value: string + label: string +} + +export interface ComboboxProps { + options: ComboboxOption[] + value?: string + onValueChange?: (value: string) => void + placeholder?: string + searchPlaceholder?: string + emptyText?: string + className?: string + disabled?: boolean +} + +export function Combobox({ + options, + value, + onValueChange, + placeholder = "Select option...", + searchPlaceholder = "Search...", + emptyText = "No option found.", + className, + disabled, +}: ComboboxProps) { + const [open, setOpen] = React.useState(false) + + return ( + + + + + + + + + {emptyText} + + {options.map((option) => ( + { + onValueChange?.(currentValue === value ? "" : currentValue) + setOpen(false) + }} + > + + {option.label} + + ))} + + + + + + ) +} diff --git a/packages/components/src/ui/date-picker.tsx b/packages/components/src/ui/date-picker.tsx new file mode 100644 index 000000000..ac47175ea --- /dev/null +++ b/packages/components/src/ui/date-picker.tsx @@ -0,0 +1,61 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +"use client" + +import * as React from "react" +import { CalendarIcon } from "lucide-react" +import { format } from "date-fns" + +import { cn } from "../lib/utils" +import { Button } from "./button" +import { Calendar } from "./calendar" +import { Popover, PopoverContent, PopoverTrigger } from "./popover" + +export interface DatePickerProps { + date?: Date + onDateChange?: (date: Date | undefined) => void + placeholder?: string + className?: string + disabled?: boolean +} + +export function DatePicker({ + date, + onDateChange, + placeholder = "Pick a date", + className, + disabled, +}: DatePickerProps) { + return ( + + + + + + + + + ) +} diff --git a/packages/components/src/ui/index.ts b/packages/components/src/ui/index.ts index 66e3d7b60..8b437ba03 100644 --- a/packages/components/src/ui/index.ts +++ b/packages/components/src/ui/index.ts @@ -22,8 +22,10 @@ export * from './carousel'; export * from './chatbot'; export * from './checkbox'; export * from './collapsible'; +export * from './combobox'; export * from './command'; export * from './context-menu'; +export * from './date-picker'; export * from './dialog'; export * from './drawer'; export * from './dropdown-menu'; @@ -59,6 +61,7 @@ export * from './table'; export * from './tabs'; export * from './textarea'; export * from './timeline'; +export * from './toast'; export * from './toggle-group'; export * from './toggle'; export * from './tooltip'; diff --git a/packages/components/src/ui/toast.tsx b/packages/components/src/ui/toast.tsx new file mode 100644 index 000000000..7790d0a03 --- /dev/null +++ b/packages/components/src/ui/toast.tsx @@ -0,0 +1,135 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import * as React from "react" +import * as ToastPrimitives from "@radix-ui/react-toast" +import { cva, type VariantProps } from "class-variance-authority" +import { X } from "lucide-react" + +import { cn } from "../lib/utils" + +const ToastProvider = ToastPrimitives.Provider + +const ToastViewport = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ToastViewport.displayName = ToastPrimitives.Viewport.displayName + +const toastVariants = cva( + "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", + { + variants: { + variant: { + default: "border bg-background text-foreground", + destructive: + "destructive group border-destructive bg-destructive text-destructive-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +const Toast = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, ...props }, ref) => { + return ( + + ) +}) +Toast.displayName = ToastPrimitives.Root.displayName + +const ToastAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ToastAction.displayName = ToastPrimitives.Action.displayName + +const ToastClose = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +ToastClose.displayName = ToastPrimitives.Close.displayName + +const ToastTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ToastTitle.displayName = ToastPrimitives.Title.displayName + +const ToastDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ToastDescription.displayName = ToastPrimitives.Description.displayName + +type ToastProps = React.ComponentPropsWithoutRef + +type ToastActionElement = React.ReactElement + +export { + type ToastProps, + type ToastActionElement, + ToastProvider, + ToastViewport, + Toast, + ToastTitle, + ToastDescription, + ToastClose, + ToastAction, +} From 261267b8e4a7396863a3f7209faf9973025ddc6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:29:00 +0000 Subject: [PATCH 03/11] Add comprehensive fumadocs documentation for 26+ components Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- docs/components/basic/navigation-menu.mdx | 88 +++++++++++ docs/components/basic/pagination.mdx | 50 ++++++ docs/components/data-display/breadcrumb.mdx | 54 +++++++ docs/components/data-display/calendar.mdx | 70 +++++++++ docs/components/data-display/carousel.mdx | 96 ++++++++++++ docs/components/data-display/kbd.mdx | 72 +++++++++ docs/components/data-display/timeline.mdx | 80 ++++++++++ docs/components/disclosure/toggle-group.mdx | 81 ++++++++++ docs/components/disclosure/toggle.mdx | 111 +++++++++++++ docs/components/feedback/sonner.mdx | 132 ++++++++++++++++ docs/components/feedback/spinner.mdx | 85 ++++++++++ docs/components/feedback/toast.mdx | 139 +++++++++++++++++ docs/components/form/combobox.mdx | 123 +++++++++++++++ docs/components/form/command.mdx | 87 +++++++++++ docs/components/form/date-picker.mdx | 119 ++++++++++++++ docs/components/form/input-otp.mdx | 98 ++++++++++++ docs/components/form/label.mdx | 67 ++++++++ docs/components/form/radio-group.mdx | 164 ++++++++++++++++++++ docs/components/layout/aspect-ratio.mdx | 89 +++++++++++ docs/components/layout/resizable.mdx | 78 ++++++++++ docs/components/layout/scroll-area.mdx | 59 +++++++ docs/components/overlay/alert-dialog.mdx | 123 +++++++++++++++ docs/components/overlay/context-menu.mdx | 49 ++++++ docs/components/overlay/dropdown-menu.mdx | 71 +++++++++ docs/components/overlay/hover-card.mdx | 64 ++++++++ docs/components/overlay/menubar.mdx | 76 +++++++++ docs/components/overlay/sheet.mdx | 66 ++++++++ 27 files changed, 2391 insertions(+) create mode 100644 docs/components/basic/navigation-menu.mdx create mode 100644 docs/components/basic/pagination.mdx create mode 100644 docs/components/data-display/breadcrumb.mdx create mode 100644 docs/components/data-display/calendar.mdx create mode 100644 docs/components/data-display/carousel.mdx create mode 100644 docs/components/data-display/kbd.mdx create mode 100644 docs/components/data-display/timeline.mdx create mode 100644 docs/components/disclosure/toggle-group.mdx create mode 100644 docs/components/disclosure/toggle.mdx create mode 100644 docs/components/feedback/sonner.mdx create mode 100644 docs/components/feedback/spinner.mdx create mode 100644 docs/components/feedback/toast.mdx create mode 100644 docs/components/form/combobox.mdx create mode 100644 docs/components/form/command.mdx create mode 100644 docs/components/form/date-picker.mdx create mode 100644 docs/components/form/input-otp.mdx create mode 100644 docs/components/form/label.mdx create mode 100644 docs/components/form/radio-group.mdx create mode 100644 docs/components/layout/aspect-ratio.mdx create mode 100644 docs/components/layout/resizable.mdx create mode 100644 docs/components/layout/scroll-area.mdx create mode 100644 docs/components/overlay/alert-dialog.mdx create mode 100644 docs/components/overlay/context-menu.mdx create mode 100644 docs/components/overlay/dropdown-menu.mdx create mode 100644 docs/components/overlay/hover-card.mdx create mode 100644 docs/components/overlay/menubar.mdx create mode 100644 docs/components/overlay/sheet.mdx diff --git a/docs/components/basic/navigation-menu.mdx b/docs/components/basic/navigation-menu.mdx new file mode 100644 index 000000000..c3fdb4e6d --- /dev/null +++ b/docs/components/basic/navigation-menu.mdx @@ -0,0 +1,88 @@ +--- +title: "Navigation Menu" +description: "Accessible navigation menu with dropdown support" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Navigation Menu component provides an accessible menu for site navigation. + +## Basic Usage + + + +## With Descriptions + + + +## Schema + +```typescript +interface NavigationMenuItem { + label: string; + href?: string; + description?: string; + icon?: string; + items?: NavigationMenuItem[]; // Submenu items +} + +interface NavigationMenuSchema { + type: 'navigation-menu'; + items: NavigationMenuItem[]; // Menu items + className?: string; +} +``` diff --git a/docs/components/basic/pagination.mdx b/docs/components/basic/pagination.mdx new file mode 100644 index 000000000..04a957e61 --- /dev/null +++ b/docs/components/basic/pagination.mdx @@ -0,0 +1,50 @@ +--- +title: "Pagination" +description: "Navigate through pages of content" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Pagination component allows users to navigate through pages of data. + +## Basic Usage + + + +## With Page Size + + + +## Schema + +```typescript +interface PaginationSchema { + type: 'pagination'; + currentPage: number; // Current page (1-based) + totalPages: number; // Total number of pages + pageSize?: number; // Items per page + totalItems?: number; // Total number of items + + // Events + onPageChange?: string | ActionConfig; + + // Styling + className?: string; +} +``` diff --git a/docs/components/data-display/breadcrumb.mdx b/docs/components/data-display/breadcrumb.mdx new file mode 100644 index 000000000..0290dcbfb --- /dev/null +++ b/docs/components/data-display/breadcrumb.mdx @@ -0,0 +1,54 @@ +--- +title: "Breadcrumb" +description: "Display the current location within a navigational hierarchy" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Breadcrumb component shows the current page's location within the site hierarchy. + +## Basic Usage + + + +## With Icons + + + +## Schema + +```typescript +interface BreadcrumbItem { + label: string; + href?: string; + icon?: string; +} + +interface BreadcrumbSchema { + type: 'breadcrumb'; + items: BreadcrumbItem[]; // Breadcrumb items + separator?: string; // Custom separator + className?: string; +} +``` diff --git a/docs/components/data-display/calendar.mdx b/docs/components/data-display/calendar.mdx new file mode 100644 index 000000000..bd8963913 --- /dev/null +++ b/docs/components/data-display/calendar.mdx @@ -0,0 +1,70 @@ +--- +title: "Calendar" +description: "Display and select dates in a calendar view" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Calendar component displays a calendar for date selection. + +## Basic Usage + + + +## Multiple Selection + + + +## Date Range + + + +## Schema + +```typescript +interface CalendarSchema { + type: 'calendar'; + mode?: 'single' | 'multiple' | 'range'; + selected?: Date | Date[] | { from: Date; to: Date }; + + // Events + onSelect?: string | ActionConfig; + + // States + disabled?: boolean | Date[]; // Disabled dates + + // Styling + className?: string; +} +``` + +## Examples + +### With Disabled Dates + + diff --git a/docs/components/data-display/carousel.mdx b/docs/components/data-display/carousel.mdx new file mode 100644 index 000000000..8b347b6e7 --- /dev/null +++ b/docs/components/data-display/carousel.mdx @@ -0,0 +1,96 @@ +--- +title: "Carousel" +description: "Slideshow component for cycling through content" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Carousel component displays content in a slideshow format with navigation controls. + +## Basic Usage + + + +## Auto-play + + + +## Schema + +```typescript +interface CarouselSchema { + type: 'carousel'; + items: ComponentSchema[]; // Carousel slides + autoPlay?: boolean; // Auto-advance slides + interval?: number; // Auto-play interval (ms) + loop?: boolean; // Loop back to start + showControls?: boolean; // Show prev/next buttons + showIndicators?: boolean; // Show dot indicators + className?: string; +} +``` + +## Examples + +### Image Gallery + + ({ + type: 'aspect-ratio', + ratio: 16/9, + content: { + type: 'image', + src: `https://picsum.photos/800/450?random=${i}`, + alt: `Image ${i + 1}` + } + })) + }} + title="Image Gallery" +/> diff --git a/docs/components/data-display/kbd.mdx b/docs/components/data-display/kbd.mdx new file mode 100644 index 000000000..cec48bda9 --- /dev/null +++ b/docs/components/data-display/kbd.mdx @@ -0,0 +1,72 @@ +--- +title: "Kbd" +description: "Display keyboard shortcuts and hotkeys" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Kbd component displays keyboard shortcuts in a styled format. + +## Basic Usage + + + +## Multiple Key Combinations + + + + + + + +## Schema + +```typescript +interface KbdSchema { + type: 'kbd'; + keys: string[]; // Keyboard keys + className?: string; +} +``` + +## Examples + +### In Documentation + + diff --git a/docs/components/data-display/timeline.mdx b/docs/components/data-display/timeline.mdx new file mode 100644 index 000000000..166268a4f --- /dev/null +++ b/docs/components/data-display/timeline.mdx @@ -0,0 +1,80 @@ +--- +title: "Timeline" +description: "Display events in chronological order" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Timeline component displays events in chronological order with a vertical line. + +## Basic Usage + + + +## With Icons + + + +## Schema + +```typescript +interface TimelineItem { + title: string; + description?: string; + date?: string; + icon?: string; +} + +interface TimelineSchema { + type: 'timeline'; + items: TimelineItem[]; // Timeline events + className?: string; +} +``` diff --git a/docs/components/disclosure/toggle-group.mdx b/docs/components/disclosure/toggle-group.mdx new file mode 100644 index 000000000..51df1513f --- /dev/null +++ b/docs/components/disclosure/toggle-group.mdx @@ -0,0 +1,81 @@ +--- +title: "Toggle Group" +description: "A group of toggle buttons where one or more can be selected" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Toggle Group component allows users to toggle between multiple options. + +## Basic Usage + + + +## Multiple Selection + + + +## With Labels + + + +## Schema + +```typescript +interface ToggleGroupItem { + value: string; + icon?: string; + label?: string; +} + +interface ToggleGroupSchema { + type: 'toggle-group'; + type: 'single' | 'multiple'; // Selection mode + items: ToggleGroupItem[]; // Toggle items + value?: string | string[]; // Selected value(s) + variant?: 'default' | 'outline'; + size?: 'sm' | 'default' | 'lg'; + + // Events + onValueChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` diff --git a/docs/components/disclosure/toggle.mdx b/docs/components/disclosure/toggle.mdx new file mode 100644 index 000000000..3963b7f7a --- /dev/null +++ b/docs/components/disclosure/toggle.mdx @@ -0,0 +1,111 @@ +--- +title: "Toggle" +description: "A two-state button that can be on or off" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Toggle component is a two-state button that can be toggled on or off. + +## Basic Usage + + + +## Variants + + + + + + +## Sizes + + + + + + + +## Schema + +```typescript +interface ToggleSchema { + type: 'toggle'; + label?: string; // Toggle label + icon?: string; // Lucide icon name + variant?: 'default' | 'outline'; + size?: 'sm' | 'default' | 'lg'; + pressed?: boolean; // Toggle state + + // Events + onPressedChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### Text Formatting Toolbar + + diff --git a/docs/components/feedback/sonner.mdx b/docs/components/feedback/sonner.mdx new file mode 100644 index 000000000..c800f2db8 --- /dev/null +++ b/docs/components/feedback/sonner.mdx @@ -0,0 +1,132 @@ +--- +title: "Sonner" +description: "Toast notifications using Sonner library" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Sonner component provides beautiful toast notifications with a rich API. + +## Basic Usage + + + +## Toast Types + + + + + + + + +## With Action + + + +## Schema + +```typescript +interface SonnerSchema { + action: 'sonner'; + message: string; // Toast message + description?: string; // Additional description + type?: 'default' | 'success' | 'error' | 'warning' | 'info'; + duration?: number; // Auto-close duration (ms) + + // Action + action?: { + label: string; + onClick: string | ActionConfig; + }; +} +``` + +## Examples + +### Promise Toast + + diff --git a/docs/components/feedback/spinner.mdx b/docs/components/feedback/spinner.mdx new file mode 100644 index 000000000..4a8446e90 --- /dev/null +++ b/docs/components/feedback/spinner.mdx @@ -0,0 +1,85 @@ +--- +title: "Spinner" +description: "Loading spinner indicator" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Spinner component displays a loading indicator. + +## Basic Usage + + + +## Sizes + + + + + + + +## Schema + +```typescript +interface SpinnerSchema { + type: 'spinner'; + size?: 'sm' | 'md' | 'lg'; + className?: string; +} +``` + +## Examples + +### In Button + + + +### Centered + + diff --git a/docs/components/feedback/toast.mdx b/docs/components/feedback/toast.mdx new file mode 100644 index 000000000..787ffff0c --- /dev/null +++ b/docs/components/feedback/toast.mdx @@ -0,0 +1,139 @@ +--- +title: "Toast" +description: "Brief notification messages that appear temporarily" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Toast component displays brief notifications to users that appear temporarily and then disappear. + +## Basic Usage + + + +## Variants + + + + + + +## With Action + + + +## Schema + +```typescript +interface ToastSchema { + type: 'toast'; + title?: string; // Toast title + description?: string; // Toast message + variant?: 'default' | 'destructive'; + + // Action + actionLabel?: string; // Action button label + onAction?: string | ActionConfig; + + // Timing + duration?: number; // Auto-dismiss time in ms +} +``` + +## Examples + +### Success Message + + + +### Error Message + + + +### With Undo Action + + diff --git a/docs/components/form/combobox.mdx b/docs/components/form/combobox.mdx new file mode 100644 index 000000000..65ac946c3 --- /dev/null +++ b/docs/components/form/combobox.mdx @@ -0,0 +1,123 @@ +--- +title: "Combobox" +description: "Searchable dropdown for selecting from a list of options" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Combobox component combines a text input with a dropdown list, allowing users to search and select from options. + +## Basic Usage + + + +## With Search + + + +## States + + + + + + +## Schema + +```typescript +interface ComboboxOption { + value: string; + label: string; +} + +interface ComboboxSchema { + type: 'combobox'; + options: ComboboxOption[]; // Available options + value?: string; // Selected value + + // Text + placeholder?: string; // Button placeholder + searchPlaceholder?: string; // Search input placeholder + emptyText?: string; // Text when no results + + // Events + onValueChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### Dynamic Options + + diff --git a/docs/components/form/command.mdx b/docs/components/form/command.mdx new file mode 100644 index 000000000..11b996ed5 --- /dev/null +++ b/docs/components/form/command.mdx @@ -0,0 +1,87 @@ +--- +title: "Command" +description: "Fast command menu with search and keyboard navigation" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Command component provides a fast, searchable command menu with keyboard navigation. + +## Basic Usage + + + +## Schema + +```typescript +interface CommandItem { + value: string; + label: string; + icon?: string; + shortcut?: string[]; +} + +interface CommandGroup { + heading?: string; + items: CommandItem[]; +} + +interface CommandSchema { + type: 'command'; + placeholder?: string; // Search placeholder + groups: CommandGroup[]; // Command groups + emptyText?: string; // Text when no results + + // Events + onSelect?: string | ActionConfig; + + // Styling + className?: string; +} +``` + +## Examples + +### With Shortcuts + + diff --git a/docs/components/form/date-picker.mdx b/docs/components/form/date-picker.mdx new file mode 100644 index 000000000..bcc5f745c --- /dev/null +++ b/docs/components/form/date-picker.mdx @@ -0,0 +1,119 @@ +--- +title: "Date Picker" +description: "Input for selecting dates with a calendar popup" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Date Picker component allows users to select a date from a calendar interface. + +## Basic Usage + + + +## With Default Date + + + +## States + + + + + + +## Schema + +```typescript +interface DatePickerSchema { + type: 'date-picker'; + value?: string | Date; // Selected date (ISO string or Date) + placeholder?: string; // Placeholder text + + // Events + onDateChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### In a Form + + + +### Date Range + + diff --git a/docs/components/form/input-otp.mdx b/docs/components/form/input-otp.mdx new file mode 100644 index 000000000..82d028dd0 --- /dev/null +++ b/docs/components/form/input-otp.mdx @@ -0,0 +1,98 @@ +--- +title: "Input OTP" +description: "One-time password input with auto-focus" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Input OTP component provides a secure way to enter one-time passwords or verification codes. + +## Basic Usage + + + +## With Separator + + + +## Different Lengths + + + + + + +## Schema + +```typescript +interface InputOTPSchema { + type: 'input-otp'; + length: number; // Number of digits + value?: string; // Current value + separator?: boolean; // Show visual separator + + // Events + onChange?: string | ActionConfig; + onComplete?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### In a Form + + diff --git a/docs/components/form/label.mdx b/docs/components/form/label.mdx new file mode 100644 index 000000000..910ca9a75 --- /dev/null +++ b/docs/components/form/label.mdx @@ -0,0 +1,67 @@ +--- +title: "Label" +description: "Text label for form elements" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Label component renders accessible labels for form fields. + +## Basic Usage + + + +## Required Field + + + +## Schema + +```typescript +interface LabelSchema { + type: 'label'; + text: string; // Label text + htmlFor?: string; // Associated input ID + required?: boolean; // Show required indicator + className?: string; +} +``` diff --git a/docs/components/form/radio-group.mdx b/docs/components/form/radio-group.mdx new file mode 100644 index 000000000..6d6752643 --- /dev/null +++ b/docs/components/form/radio-group.mdx @@ -0,0 +1,164 @@ +--- +title: "Radio Group" +description: "A set of checkable buttons where only one can be selected at a time" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Radio Group component allows users to select one option from a set of mutually exclusive options. + +## Basic Usage + + + +## With Default Value + + + +## Layout Options + + + + + + +## States + + + + + + +## Schema + +```typescript +interface RadioOption { + value: string; + label: string; + disabled?: boolean; +} + +interface RadioGroupSchema { + type: 'radio-group'; + options: RadioOption[]; // Available options + value?: string; // Selected value + + // Layout + direction?: 'vertical' | 'horizontal'; + + // Events + onValueChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### In a Form + + + +### With Descriptions + + diff --git a/docs/components/layout/aspect-ratio.mdx b/docs/components/layout/aspect-ratio.mdx new file mode 100644 index 000000000..c0e21eb84 --- /dev/null +++ b/docs/components/layout/aspect-ratio.mdx @@ -0,0 +1,89 @@ +--- +title: "Aspect Ratio" +description: "Maintain a consistent width to height ratio" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Aspect Ratio component maintains a consistent width to height ratio for content. + +## Basic Usage + + + +## Different Ratios + + + + + + + +## Schema + +```typescript +interface AspectRatioSchema { + type: 'aspect-ratio'; + ratio: number; // Width / Height ratio + content: ComponentSchema; // Content to display + className?: string; +} +``` + +## Examples + +### Video Container + + diff --git a/docs/components/layout/resizable.mdx b/docs/components/layout/resizable.mdx new file mode 100644 index 000000000..f2e205554 --- /dev/null +++ b/docs/components/layout/resizable.mdx @@ -0,0 +1,78 @@ +--- +title: "Resizable" +description: "Resizable panel groups with draggable handles" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Resizable component allows users to resize panels by dragging handles between them. + +## Basic Usage + + + +## Vertical Layout + + + +## Schema + +```typescript +interface ResizablePanel { + defaultSize?: number; // Default size (percentage) + minSize?: number; // Minimum size + maxSize?: number; // Maximum size + content: ComponentSchema; // Panel content +} + +interface ResizableSchema { + type: 'resizable'; + direction: 'horizontal' | 'vertical'; + panels: ResizablePanel[]; // Panels to display + className?: string; +} +``` diff --git a/docs/components/layout/scroll-area.mdx b/docs/components/layout/scroll-area.mdx new file mode 100644 index 000000000..03e527d13 --- /dev/null +++ b/docs/components/layout/scroll-area.mdx @@ -0,0 +1,59 @@ +--- +title: "Scroll Area" +description: "Styled scrollable container with custom scrollbars" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Scroll Area component provides a scrollable container with customized scrollbars. + +## Basic Usage + + ({ + type: 'text', + value: `Item ${i + 1}` + })) + } + }} + title="Vertical Scroll" +/> + +## Horizontal Scroll + + ({ + type: 'badge', + text: `Tag ${i + 1}` + })) + } + }} + title="Horizontal Scroll" +/> + +## Schema + +```typescript +interface ScrollAreaSchema { + type: 'scroll-area'; + content: ComponentSchema; // Scrollable content + height?: string; // Container height + width?: string; // Container width + orientation?: 'vertical' | 'horizontal'; + className?: string; +} +``` diff --git a/docs/components/overlay/alert-dialog.mdx b/docs/components/overlay/alert-dialog.mdx new file mode 100644 index 000000000..2eea3b3d2 --- /dev/null +++ b/docs/components/overlay/alert-dialog.mdx @@ -0,0 +1,123 @@ +--- +title: "Alert Dialog" +description: "A modal dialog that interrupts the user with important content and expects a response" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Alert Dialog component is used to interrupt the user with important content and require a confirmation before proceeding. + +## Basic Usage + + + +## Variants + + + + + + +## Schema + +```typescript +interface AlertDialogSchema { + type: 'alert-dialog'; + title: string; // Dialog title + description: string; // Dialog description + + // Trigger + trigger: ComponentSchema; // Component that triggers the dialog + + // Actions + actions?: ComponentSchema[]; // Action buttons + + // Styling + className?: string; +} +``` + +## Examples + +### With Custom Actions + + diff --git a/docs/components/overlay/context-menu.mdx b/docs/components/overlay/context-menu.mdx new file mode 100644 index 000000000..72717dbe9 --- /dev/null +++ b/docs/components/overlay/context-menu.mdx @@ -0,0 +1,49 @@ +--- +title: "Context Menu" +description: "Display a menu on right-click or long-press" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Context Menu component displays a menu when right-clicking on an element. + +## Basic Usage + + + +## Schema + +```typescript +interface ContextMenuItem { + label?: string; + value?: string; + icon?: string; + type?: 'separator'; + disabled?: boolean; +} + +interface ContextMenuSchema { + type: 'context-menu'; + trigger: ComponentSchema; // Trigger element + items: ContextMenuItem[]; // Menu items + onSelect?: string | ActionConfig; + className?: string; +} +``` diff --git a/docs/components/overlay/dropdown-menu.mdx b/docs/components/overlay/dropdown-menu.mdx new file mode 100644 index 000000000..33b7eb8e0 --- /dev/null +++ b/docs/components/overlay/dropdown-menu.mdx @@ -0,0 +1,71 @@ +--- +title: "Dropdown Menu" +description: "Display a menu of actions or options triggered by a button" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Dropdown Menu component displays a list of actions or options when triggered. + +## Basic Usage + + + +## With Icons + + + +## Schema + +```typescript +interface DropdownMenuItem { + label?: string; + value?: string; + icon?: string; + variant?: 'default' | 'destructive'; + type?: 'separator'; + disabled?: boolean; +} + +interface DropdownMenuSchema { + type: 'dropdown-menu'; + trigger: ComponentSchema; // Trigger component + items: DropdownMenuItem[]; // Menu items + + // Events + onSelect?: string | ActionConfig; + + // Styling + className?: string; +} +``` diff --git a/docs/components/overlay/hover-card.mdx b/docs/components/overlay/hover-card.mdx new file mode 100644 index 000000000..6961957a8 --- /dev/null +++ b/docs/components/overlay/hover-card.mdx @@ -0,0 +1,64 @@ +--- +title: "Hover Card" +description: "Display rich content in a popup when hovering over a trigger" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Hover Card component displays rich content when hovering over an element. + +## Basic Usage + + + +## With Rich Content + + + +## Schema + +```typescript +interface HoverCardSchema { + type: 'hover-card'; + trigger: ComponentSchema; // Trigger element + content: ComponentSchema; // Card content + side?: 'top' | 'right' | 'bottom' | 'left'; + align?: 'start' | 'center' | 'end'; + openDelay?: number; // Delay before opening (ms) + closeDelay?: number; // Delay before closing (ms) + className?: string; +} +``` diff --git a/docs/components/overlay/menubar.mdx b/docs/components/overlay/menubar.mdx new file mode 100644 index 000000000..983ed1c35 --- /dev/null +++ b/docs/components/overlay/menubar.mdx @@ -0,0 +1,76 @@ +--- +title: "Menubar" +description: "Horizontal menu bar with dropdown menus" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Menubar component provides a horizontal menu bar similar to desktop applications. + +## Basic Usage + + + +## Schema + +```typescript +interface MenubarItem { + label?: string; + value?: string; + icon?: string; + shortcut?: string[]; + type?: 'separator'; + disabled?: boolean; +} + +interface MenubarMenu { + label: string; + items: MenubarItem[]; +} + +interface MenubarSchema { + type: 'menubar'; + menus: MenubarMenu[]; // Menu definitions + + // Events + onSelect?: string | ActionConfig; + + // Styling + className?: string; +} +``` diff --git a/docs/components/overlay/sheet.mdx b/docs/components/overlay/sheet.mdx new file mode 100644 index 000000000..f1da44b2d --- /dev/null +++ b/docs/components/overlay/sheet.mdx @@ -0,0 +1,66 @@ +--- +title: "Sheet" +description: "Slide-in panel from the edge of the screen" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Sheet component displays content in a panel that slides in from the edge of the screen. + +## Basic Usage + + + +## Sides + + + + + + +## Schema + +```typescript +interface SheetSchema { + type: 'sheet'; + trigger: ComponentSchema; // Trigger component + title?: string; // Sheet title + description?: string; // Sheet description + content: ComponentSchema; // Sheet content + side?: 'left' | 'right' | 'top' | 'bottom'; + className?: string; +} +``` From 84a86242dd9a95ab28aa55d12bc50d512503ba5a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:49:03 +0000 Subject: [PATCH 04/11] Add documentation for button-group, sidebar, form, and empty components Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- docs/components/basic/button-group.mdx | 128 ++++++++++++++++++++++ docs/components/basic/sidebar.mdx | 109 +++++++++++++++++++ docs/components/feedback/empty.mdx | 98 +++++++++++++++++ docs/components/form/form.mdx | 143 +++++++++++++++++++++++++ 4 files changed, 478 insertions(+) create mode 100644 docs/components/basic/button-group.mdx create mode 100644 docs/components/basic/sidebar.mdx create mode 100644 docs/components/feedback/empty.mdx create mode 100644 docs/components/form/form.mdx diff --git a/docs/components/basic/button-group.mdx b/docs/components/basic/button-group.mdx new file mode 100644 index 000000000..04223d416 --- /dev/null +++ b/docs/components/basic/button-group.mdx @@ -0,0 +1,128 @@ +--- +title: "Button Group" +description: "Group multiple buttons together with shared styling" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Button Group component groups multiple buttons together with consistent styling. + +## Basic Usage + + + +## Variants + + + + + + +## Selection Mode + + + + + + +## Schema + +```typescript +interface ButtonGroupButton { + label?: string; + value: string; + icon?: string; + disabled?: boolean; +} + +interface ButtonGroupSchema { + type: 'button-group'; + buttons: ButtonGroupButton[]; // Button definitions + value?: string | string[]; // Selected value(s) + selectionMode?: 'single' | 'multiple' | 'none'; + variant?: 'default' | 'outline' | 'ghost'; + size?: 'sm' | 'default' | 'lg'; + + // Events + onValueChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### Toolbar Actions + + diff --git a/docs/components/basic/sidebar.mdx b/docs/components/basic/sidebar.mdx new file mode 100644 index 000000000..7f0ad83b0 --- /dev/null +++ b/docs/components/basic/sidebar.mdx @@ -0,0 +1,109 @@ +--- +title: "Sidebar" +description: "Collapsible navigation sidebar" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Sidebar component provides a collapsible navigation sidebar for applications. + +## Basic Usage + + + +## With Groups + + + +## Collapsible + + + +## Schema + +```typescript +interface SidebarItem { + label: string; + icon?: string; + href?: string; + active?: boolean; + badge?: string | number; +} + +interface SidebarGroup { + title?: string; + items: SidebarItem[]; +} + +interface SidebarSchema { + type: 'sidebar'; + items?: SidebarItem[]; // Flat list of items + groups?: SidebarGroup[]; // Grouped items + collapsible?: boolean; // Allow collapse + defaultCollapsed?: boolean; // Initial state + + // Styling + className?: string; +} +``` + +## Examples + +### With Badges + + diff --git a/docs/components/feedback/empty.mdx b/docs/components/feedback/empty.mdx new file mode 100644 index 000000000..2ea7e6b53 --- /dev/null +++ b/docs/components/feedback/empty.mdx @@ -0,0 +1,98 @@ +--- +title: "Empty" +description: "Empty state placeholder with optional action" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Empty component displays a placeholder when there's no content to show. + +## Basic Usage + + + +## With Icon + + + +## With Action + + + +## Schema + +```typescript +interface EmptySchema { + type: 'empty'; + icon?: string; // Lucide icon name + title?: string; // Main message + description?: string; // Supporting text + action?: ComponentSchema; // Call to action button + className?: string; +} +``` + +## Examples + +### Search Results + + + +### Empty List + + diff --git a/docs/components/form/form.mdx b/docs/components/form/form.mdx new file mode 100644 index 000000000..58b2365a3 --- /dev/null +++ b/docs/components/form/form.mdx @@ -0,0 +1,143 @@ +--- +title: "Form" +description: "Form container with validation and submission handling" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Form component provides a complete form solution with validation and submission handling. + +## Basic Usage + + + +## With Validation + + + +## Schema + +```typescript +interface FormField { + name: string; + label?: string; + type: 'input' | 'textarea' | 'select' | 'checkbox' | 'radio-group' | 'date-picker'; + placeholder?: string; + required?: boolean; + disabled?: boolean; + + // Validation + minLength?: number; + maxLength?: number; + min?: number; + max?: number; + pattern?: string; + + // Options (for select, radio-group) + options?: Array<{ value: string; label: string }>; + + // Default value + defaultValue?: any; +} + +interface FormSchema { + type: 'form'; + fields: FormField[]; // Form fields + submitButton?: { + label: string; + variant?: string; + }; + + // Events + onSubmit?: string | ActionConfig; + + // Layout + columns?: number; // Grid layout + + // Styling + className?: string; +} +``` + +## Examples + +### Multi-column Form + + From ba3d8bde4044f548bb3592f695bb3c1cdb0ec2fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:02:25 +0000 Subject: [PATCH 05/11] Fix code review issues: move toaster, fix toast delay, update exports Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/components/src/hooks/use-toast.ts | 2 +- packages/components/src/renderers/feedback/toaster.tsx | 4 ++-- packages/components/src/ui/index.ts | 1 + packages/components/src/ui/toast.tsx | 2 +- packages/components/src/{hooks => ui}/toaster.tsx | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) rename packages/components/src/{hooks => ui}/toaster.tsx (93%) diff --git a/packages/components/src/hooks/use-toast.ts b/packages/components/src/hooks/use-toast.ts index fd2ac5b20..5c0b364ee 100644 --- a/packages/components/src/hooks/use-toast.ts +++ b/packages/components/src/hooks/use-toast.ts @@ -14,7 +14,7 @@ import type { } from "../ui/toast" const TOAST_LIMIT = 1 -const TOAST_REMOVE_DELAY = 1000000 +const TOAST_REMOVE_DELAY = 5000 type ToasterToast = ToastProps & { id: string diff --git a/packages/components/src/renderers/feedback/toaster.tsx b/packages/components/src/renderers/feedback/toaster.tsx index 711630a9b..28fb9cfb0 100644 --- a/packages/components/src/renderers/feedback/toaster.tsx +++ b/packages/components/src/renderers/feedback/toaster.tsx @@ -8,8 +8,8 @@ import { ComponentRegistry } from '@object-ui/core'; import type { ToasterSchema } from '@object-ui/types'; -import { Toaster as SonnerToaster } from '../../ui'; -import { Toaster as DefaultToaster } from '../../ui'; +import { Toaster as SonnerToaster } from '../../ui/sonner'; +import { ToastNotifier as DefaultToaster } from '../../ui'; // Note: In shadcn/ui typical setup, Toaster is exported from 'components/ui/toaster' and 'components/ui/sonner'. // But in @object-ui/ui index.tsx, we need to check if they are exported. // Assuming they are exported as Toaster and Sonner (or similar). diff --git a/packages/components/src/ui/index.ts b/packages/components/src/ui/index.ts index 8b437ba03..7ae8593ae 100644 --- a/packages/components/src/ui/index.ts +++ b/packages/components/src/ui/index.ts @@ -62,6 +62,7 @@ export * from './tabs'; export * from './textarea'; export * from './timeline'; export * from './toast'; +export { Toaster as ToastNotifier } from './toaster'; export * from './toggle-group'; export * from './toggle'; export * from './tooltip'; diff --git a/packages/components/src/ui/toast.tsx b/packages/components/src/ui/toast.tsx index 7790d0a03..5e01d452e 100644 --- a/packages/components/src/ui/toast.tsx +++ b/packages/components/src/ui/toast.tsx @@ -86,7 +86,7 @@ const ToastClose = React.forwardRef< "absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600", className )} - toast-close="" + toast-close {...props} > diff --git a/packages/components/src/hooks/toaster.tsx b/packages/components/src/ui/toaster.tsx similarity index 93% rename from packages/components/src/hooks/toaster.tsx rename to packages/components/src/ui/toaster.tsx index 197f8e485..af8a212ed 100644 --- a/packages/components/src/hooks/toaster.tsx +++ b/packages/components/src/ui/toaster.tsx @@ -15,8 +15,8 @@ import { ToastProvider, ToastTitle, ToastViewport, -} from "../ui/toast" -import { useToast } from "./use-toast" +} from "./toast" +import { useToast } from "../hooks/use-toast" export function Toaster() { const { toasts } = useToast() From 20fcaf69ee67833ad136fc50e31bff4bc6a29883 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 14:39:19 +0000 Subject: [PATCH 06/11] Update meta.json to include all 60+ components organized by category in fumadocs sidebar Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- docs/components/meta.json | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/components/meta.json b/docs/components/meta.json index 077b80b3e..8f8b71f40 100644 --- a/docs/components/meta.json +++ b/docs/components/meta.json @@ -8,14 +8,25 @@ "basic/image", "basic/separator", "basic/html", + "basic/button-group", + "basic/pagination", + "basic/navigation-menu", + "basic/sidebar", "---Form", "form/button", "form/input", + "form/textarea", "form/select", + "form/combobox", "form/checkbox", + "form/radio-group", "form/switch", - "form/textarea", "form/slider", + "form/label", + "form/date-picker", + "form/input-otp", + "form/command", + "form/form", "---Layout", "layout/container", "layout/card", @@ -23,23 +34,43 @@ "layout/flex", "layout/stack", "layout/tabs", + "layout/aspect-ratio", + "layout/scroll-area", + "layout/resizable", "---Data Display", "data-display/badge", "data-display/avatar", "data-display/alert", "data-display/list", + "data-display/breadcrumb", + "data-display/calendar", + "data-display/carousel", + "data-display/kbd", + "data-display/timeline", "---Feedback", "feedback/loading", "feedback/progress", "feedback/skeleton", + "feedback/spinner", + "feedback/empty", + "feedback/toast", + "feedback/sonner", "---Overlay", "overlay/dialog", "overlay/drawer", "overlay/tooltip", "overlay/popover", + "overlay/alert-dialog", + "overlay/sheet", + "overlay/hover-card", + "overlay/context-menu", + "overlay/dropdown-menu", + "overlay/menubar", "---Disclosure", "disclosure/accordion", "disclosure/collapsible", + "disclosure/toggle", + "disclosure/toggle-group", "---Complex", "complex/table" ] From 9f2d76f7ba31f2bf35749cd9c4c508ec16612737 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 15:00:43 +0000 Subject: [PATCH 07/11] Fix component sidebar to show collapsible category folders Restructured docs/components/meta.json to reference folder names directly, allowing fumadocs to create proper collapsible category navigation. Recreated subdirectory meta.json files with updated component lists. Components are now organized under expandable category folders in the sidebar: Basic, Form, Layout, Data Display, Feedback, Overlay, Disclosure, and Complex. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- docs/components/basic/meta.json | 6 +- docs/components/data-display/meta.json | 7 ++- docs/components/disclosure/meta.json | 4 +- docs/components/feedback/meta.json | 6 +- docs/components/form/meta.json | 11 +++- docs/components/layout/meta.json | 5 +- docs/components/meta.json | 79 +++----------------------- docs/components/overlay/meta.json | 8 ++- 8 files changed, 47 insertions(+), 79 deletions(-) diff --git a/docs/components/basic/meta.json b/docs/components/basic/meta.json index 0a7b5fb78..a0a95cec5 100644 --- a/docs/components/basic/meta.json +++ b/docs/components/basic/meta.json @@ -5,6 +5,10 @@ "icon", "image", "separator", - "html" + "html", + "button-group", + "pagination", + "navigation-menu", + "sidebar" ] } diff --git a/docs/components/data-display/meta.json b/docs/components/data-display/meta.json index 84cd041cc..40459a02e 100644 --- a/docs/components/data-display/meta.json +++ b/docs/components/data-display/meta.json @@ -4,6 +4,11 @@ "badge", "avatar", "alert", - "list" + "list", + "breadcrumb", + "calendar", + "carousel", + "kbd", + "timeline" ] } diff --git a/docs/components/disclosure/meta.json b/docs/components/disclosure/meta.json index 019b84645..060414ee8 100644 --- a/docs/components/disclosure/meta.json +++ b/docs/components/disclosure/meta.json @@ -2,6 +2,8 @@ "title": "Disclosure", "pages": [ "accordion", - "collapsible" + "collapsible", + "toggle", + "toggle-group" ] } diff --git a/docs/components/feedback/meta.json b/docs/components/feedback/meta.json index 9353c60c4..c0f19aea7 100644 --- a/docs/components/feedback/meta.json +++ b/docs/components/feedback/meta.json @@ -3,6 +3,10 @@ "pages": [ "loading", "progress", - "skeleton" + "skeleton", + "spinner", + "empty", + "toast", + "sonner" ] } diff --git a/docs/components/form/meta.json b/docs/components/form/meta.json index 449b89971..e83fe7126 100644 --- a/docs/components/form/meta.json +++ b/docs/components/form/meta.json @@ -3,10 +3,17 @@ "pages": [ "button", "input", + "textarea", "select", + "combobox", "checkbox", + "radio-group", "switch", - "textarea", - "slider" + "slider", + "label", + "date-picker", + "input-otp", + "command", + "form" ] } diff --git a/docs/components/layout/meta.json b/docs/components/layout/meta.json index 52c471e6a..8cb6a1da0 100644 --- a/docs/components/layout/meta.json +++ b/docs/components/layout/meta.json @@ -6,6 +6,9 @@ "grid", "flex", "stack", - "tabs" + "tabs", + "aspect-ratio", + "scroll-area", + "resizable" ] } diff --git a/docs/components/meta.json b/docs/components/meta.json index 8f8b71f40..58510a9bc 100644 --- a/docs/components/meta.json +++ b/docs/components/meta.json @@ -2,76 +2,13 @@ "title": "Components", "pages": [ "index", - "---Basic", - "basic/text", - "basic/icon", - "basic/image", - "basic/separator", - "basic/html", - "basic/button-group", - "basic/pagination", - "basic/navigation-menu", - "basic/sidebar", - "---Form", - "form/button", - "form/input", - "form/textarea", - "form/select", - "form/combobox", - "form/checkbox", - "form/radio-group", - "form/switch", - "form/slider", - "form/label", - "form/date-picker", - "form/input-otp", - "form/command", - "form/form", - "---Layout", - "layout/container", - "layout/card", - "layout/grid", - "layout/flex", - "layout/stack", - "layout/tabs", - "layout/aspect-ratio", - "layout/scroll-area", - "layout/resizable", - "---Data Display", - "data-display/badge", - "data-display/avatar", - "data-display/alert", - "data-display/list", - "data-display/breadcrumb", - "data-display/calendar", - "data-display/carousel", - "data-display/kbd", - "data-display/timeline", - "---Feedback", - "feedback/loading", - "feedback/progress", - "feedback/skeleton", - "feedback/spinner", - "feedback/empty", - "feedback/toast", - "feedback/sonner", - "---Overlay", - "overlay/dialog", - "overlay/drawer", - "overlay/tooltip", - "overlay/popover", - "overlay/alert-dialog", - "overlay/sheet", - "overlay/hover-card", - "overlay/context-menu", - "overlay/dropdown-menu", - "overlay/menubar", - "---Disclosure", - "disclosure/accordion", - "disclosure/collapsible", - "disclosure/toggle", - "disclosure/toggle-group", - "---Complex", - "complex/table" + "basic", + "form", + "layout", + "data-display", + "feedback", + "overlay", + "disclosure", + "complex" ] } diff --git a/docs/components/overlay/meta.json b/docs/components/overlay/meta.json index 706a4540d..54855a1bf 100644 --- a/docs/components/overlay/meta.json +++ b/docs/components/overlay/meta.json @@ -4,6 +4,12 @@ "dialog", "drawer", "tooltip", - "popover" + "popover", + "alert-dialog", + "sheet", + "hover-card", + "context-menu", + "dropdown-menu", + "menubar" ] } From ea7ac1c56520be9b28f868c9a2cb34133f55960c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 15:49:40 +0000 Subject: [PATCH 08/11] Remove documentation for components without renderers to fix "unknown type" errors Removed docs for 14 components that don't have renderer implementations: aspect-ratio, breadcrumb, button-group, combobox, command, empty, kbd, menubar, navigation-menu, pagination, sonner, spinner, toast, toggle-group. Updated meta.json files to reflect only components with working renderers. All remaining documented components now render properly without "unknown type" errors. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- docs/components/basic/button-group.mdx | 128 ------------------ docs/components/basic/meta.json | 3 - docs/components/basic/navigation-menu.mdx | 88 ------------- docs/components/basic/pagination.mdx | 50 ------- docs/components/data-display/breadcrumb.mdx | 54 -------- docs/components/data-display/kbd.mdx | 72 ---------- docs/components/data-display/meta.json | 2 - docs/components/disclosure/meta.json | 3 +- docs/components/disclosure/toggle-group.mdx | 81 ------------ docs/components/feedback/empty.mdx | 98 -------------- docs/components/feedback/meta.json | 6 +- docs/components/feedback/sonner.mdx | 132 ------------------- docs/components/feedback/spinner.mdx | 85 ------------ docs/components/feedback/toast.mdx | 139 -------------------- docs/components/form/combobox.mdx | 123 ----------------- docs/components/form/command.mdx | 87 ------------ docs/components/form/meta.json | 5 +- docs/components/layout/aspect-ratio.mdx | 89 ------------- docs/components/layout/meta.json | 1 - docs/components/overlay/menubar.mdx | 76 ----------- docs/components/overlay/meta.json | 3 +- 21 files changed, 4 insertions(+), 1321 deletions(-) delete mode 100644 docs/components/basic/button-group.mdx delete mode 100644 docs/components/basic/navigation-menu.mdx delete mode 100644 docs/components/basic/pagination.mdx delete mode 100644 docs/components/data-display/breadcrumb.mdx delete mode 100644 docs/components/data-display/kbd.mdx delete mode 100644 docs/components/disclosure/toggle-group.mdx delete mode 100644 docs/components/feedback/empty.mdx delete mode 100644 docs/components/feedback/sonner.mdx delete mode 100644 docs/components/feedback/spinner.mdx delete mode 100644 docs/components/feedback/toast.mdx delete mode 100644 docs/components/form/combobox.mdx delete mode 100644 docs/components/form/command.mdx delete mode 100644 docs/components/layout/aspect-ratio.mdx delete mode 100644 docs/components/overlay/menubar.mdx diff --git a/docs/components/basic/button-group.mdx b/docs/components/basic/button-group.mdx deleted file mode 100644 index 04223d416..000000000 --- a/docs/components/basic/button-group.mdx +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: "Button Group" -description: "Group multiple buttons together with shared styling" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Button Group component groups multiple buttons together with consistent styling. - -## Basic Usage - - - -## Variants - - - - - - -## Selection Mode - - - - - - -## Schema - -```typescript -interface ButtonGroupButton { - label?: string; - value: string; - icon?: string; - disabled?: boolean; -} - -interface ButtonGroupSchema { - type: 'button-group'; - buttons: ButtonGroupButton[]; // Button definitions - value?: string | string[]; // Selected value(s) - selectionMode?: 'single' | 'multiple' | 'none'; - variant?: 'default' | 'outline' | 'ghost'; - size?: 'sm' | 'default' | 'lg'; - - // Events - onValueChange?: string | ActionConfig; - - // States - disabled?: boolean; - - // Styling - className?: string; -} -``` - -## Examples - -### Toolbar Actions - - diff --git a/docs/components/basic/meta.json b/docs/components/basic/meta.json index a0a95cec5..fa3e42171 100644 --- a/docs/components/basic/meta.json +++ b/docs/components/basic/meta.json @@ -6,9 +6,6 @@ "image", "separator", "html", - "button-group", - "pagination", - "navigation-menu", "sidebar" ] } diff --git a/docs/components/basic/navigation-menu.mdx b/docs/components/basic/navigation-menu.mdx deleted file mode 100644 index c3fdb4e6d..000000000 --- a/docs/components/basic/navigation-menu.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: "Navigation Menu" -description: "Accessible navigation menu with dropdown support" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Navigation Menu component provides an accessible menu for site navigation. - -## Basic Usage - - - -## With Descriptions - - - -## Schema - -```typescript -interface NavigationMenuItem { - label: string; - href?: string; - description?: string; - icon?: string; - items?: NavigationMenuItem[]; // Submenu items -} - -interface NavigationMenuSchema { - type: 'navigation-menu'; - items: NavigationMenuItem[]; // Menu items - className?: string; -} -``` diff --git a/docs/components/basic/pagination.mdx b/docs/components/basic/pagination.mdx deleted file mode 100644 index 04a957e61..000000000 --- a/docs/components/basic/pagination.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "Pagination" -description: "Navigate through pages of content" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Pagination component allows users to navigate through pages of data. - -## Basic Usage - - - -## With Page Size - - - -## Schema - -```typescript -interface PaginationSchema { - type: 'pagination'; - currentPage: number; // Current page (1-based) - totalPages: number; // Total number of pages - pageSize?: number; // Items per page - totalItems?: number; // Total number of items - - // Events - onPageChange?: string | ActionConfig; - - // Styling - className?: string; -} -``` diff --git a/docs/components/data-display/breadcrumb.mdx b/docs/components/data-display/breadcrumb.mdx deleted file mode 100644 index 0290dcbfb..000000000 --- a/docs/components/data-display/breadcrumb.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: "Breadcrumb" -description: "Display the current location within a navigational hierarchy" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Breadcrumb component shows the current page's location within the site hierarchy. - -## Basic Usage - - - -## With Icons - - - -## Schema - -```typescript -interface BreadcrumbItem { - label: string; - href?: string; - icon?: string; -} - -interface BreadcrumbSchema { - type: 'breadcrumb'; - items: BreadcrumbItem[]; // Breadcrumb items - separator?: string; // Custom separator - className?: string; -} -``` diff --git a/docs/components/data-display/kbd.mdx b/docs/components/data-display/kbd.mdx deleted file mode 100644 index cec48bda9..000000000 --- a/docs/components/data-display/kbd.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: "Kbd" -description: "Display keyboard shortcuts and hotkeys" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Kbd component displays keyboard shortcuts in a styled format. - -## Basic Usage - - - -## Multiple Key Combinations - - - - - - - -## Schema - -```typescript -interface KbdSchema { - type: 'kbd'; - keys: string[]; // Keyboard keys - className?: string; -} -``` - -## Examples - -### In Documentation - - diff --git a/docs/components/data-display/meta.json b/docs/components/data-display/meta.json index 40459a02e..16d7978ef 100644 --- a/docs/components/data-display/meta.json +++ b/docs/components/data-display/meta.json @@ -5,10 +5,8 @@ "avatar", "alert", "list", - "breadcrumb", "calendar", "carousel", - "kbd", "timeline" ] } diff --git a/docs/components/disclosure/meta.json b/docs/components/disclosure/meta.json index 060414ee8..99701c3fd 100644 --- a/docs/components/disclosure/meta.json +++ b/docs/components/disclosure/meta.json @@ -3,7 +3,6 @@ "pages": [ "accordion", "collapsible", - "toggle", - "toggle-group" + "toggle" ] } diff --git a/docs/components/disclosure/toggle-group.mdx b/docs/components/disclosure/toggle-group.mdx deleted file mode 100644 index 51df1513f..000000000 --- a/docs/components/disclosure/toggle-group.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: "Toggle Group" -description: "A group of toggle buttons where one or more can be selected" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Toggle Group component allows users to toggle between multiple options. - -## Basic Usage - - - -## Multiple Selection - - - -## With Labels - - - -## Schema - -```typescript -interface ToggleGroupItem { - value: string; - icon?: string; - label?: string; -} - -interface ToggleGroupSchema { - type: 'toggle-group'; - type: 'single' | 'multiple'; // Selection mode - items: ToggleGroupItem[]; // Toggle items - value?: string | string[]; // Selected value(s) - variant?: 'default' | 'outline'; - size?: 'sm' | 'default' | 'lg'; - - // Events - onValueChange?: string | ActionConfig; - - // States - disabled?: boolean; - - // Styling - className?: string; -} -``` diff --git a/docs/components/feedback/empty.mdx b/docs/components/feedback/empty.mdx deleted file mode 100644 index 2ea7e6b53..000000000 --- a/docs/components/feedback/empty.mdx +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: "Empty" -description: "Empty state placeholder with optional action" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Empty component displays a placeholder when there's no content to show. - -## Basic Usage - - - -## With Icon - - - -## With Action - - - -## Schema - -```typescript -interface EmptySchema { - type: 'empty'; - icon?: string; // Lucide icon name - title?: string; // Main message - description?: string; // Supporting text - action?: ComponentSchema; // Call to action button - className?: string; -} -``` - -## Examples - -### Search Results - - - -### Empty List - - diff --git a/docs/components/feedback/meta.json b/docs/components/feedback/meta.json index c0f19aea7..9353c60c4 100644 --- a/docs/components/feedback/meta.json +++ b/docs/components/feedback/meta.json @@ -3,10 +3,6 @@ "pages": [ "loading", "progress", - "skeleton", - "spinner", - "empty", - "toast", - "sonner" + "skeleton" ] } diff --git a/docs/components/feedback/sonner.mdx b/docs/components/feedback/sonner.mdx deleted file mode 100644 index c800f2db8..000000000 --- a/docs/components/feedback/sonner.mdx +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: "Sonner" -description: "Toast notifications using Sonner library" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Sonner component provides beautiful toast notifications with a rich API. - -## Basic Usage - - - -## Toast Types - - - - - - - - -## With Action - - - -## Schema - -```typescript -interface SonnerSchema { - action: 'sonner'; - message: string; // Toast message - description?: string; // Additional description - type?: 'default' | 'success' | 'error' | 'warning' | 'info'; - duration?: number; // Auto-close duration (ms) - - // Action - action?: { - label: string; - onClick: string | ActionConfig; - }; -} -``` - -## Examples - -### Promise Toast - - diff --git a/docs/components/feedback/spinner.mdx b/docs/components/feedback/spinner.mdx deleted file mode 100644 index 4a8446e90..000000000 --- a/docs/components/feedback/spinner.mdx +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: "Spinner" -description: "Loading spinner indicator" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Spinner component displays a loading indicator. - -## Basic Usage - - - -## Sizes - - - - - - - -## Schema - -```typescript -interface SpinnerSchema { - type: 'spinner'; - size?: 'sm' | 'md' | 'lg'; - className?: string; -} -``` - -## Examples - -### In Button - - - -### Centered - - diff --git a/docs/components/feedback/toast.mdx b/docs/components/feedback/toast.mdx deleted file mode 100644 index 787ffff0c..000000000 --- a/docs/components/feedback/toast.mdx +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: "Toast" -description: "Brief notification messages that appear temporarily" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Toast component displays brief notifications to users that appear temporarily and then disappear. - -## Basic Usage - - - -## Variants - - - - - - -## With Action - - - -## Schema - -```typescript -interface ToastSchema { - type: 'toast'; - title?: string; // Toast title - description?: string; // Toast message - variant?: 'default' | 'destructive'; - - // Action - actionLabel?: string; // Action button label - onAction?: string | ActionConfig; - - // Timing - duration?: number; // Auto-dismiss time in ms -} -``` - -## Examples - -### Success Message - - - -### Error Message - - - -### With Undo Action - - diff --git a/docs/components/form/combobox.mdx b/docs/components/form/combobox.mdx deleted file mode 100644 index 65ac946c3..000000000 --- a/docs/components/form/combobox.mdx +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: "Combobox" -description: "Searchable dropdown for selecting from a list of options" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Combobox component combines a text input with a dropdown list, allowing users to search and select from options. - -## Basic Usage - - - -## With Search - - - -## States - - - - - - -## Schema - -```typescript -interface ComboboxOption { - value: string; - label: string; -} - -interface ComboboxSchema { - type: 'combobox'; - options: ComboboxOption[]; // Available options - value?: string; // Selected value - - // Text - placeholder?: string; // Button placeholder - searchPlaceholder?: string; // Search input placeholder - emptyText?: string; // Text when no results - - // Events - onValueChange?: string | ActionConfig; - - // States - disabled?: boolean; - - // Styling - className?: string; -} -``` - -## Examples - -### Dynamic Options - - diff --git a/docs/components/form/command.mdx b/docs/components/form/command.mdx deleted file mode 100644 index 11b996ed5..000000000 --- a/docs/components/form/command.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: "Command" -description: "Fast command menu with search and keyboard navigation" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Command component provides a fast, searchable command menu with keyboard navigation. - -## Basic Usage - - - -## Schema - -```typescript -interface CommandItem { - value: string; - label: string; - icon?: string; - shortcut?: string[]; -} - -interface CommandGroup { - heading?: string; - items: CommandItem[]; -} - -interface CommandSchema { - type: 'command'; - placeholder?: string; // Search placeholder - groups: CommandGroup[]; // Command groups - emptyText?: string; // Text when no results - - // Events - onSelect?: string | ActionConfig; - - // Styling - className?: string; -} -``` - -## Examples - -### With Shortcuts - - diff --git a/docs/components/form/meta.json b/docs/components/form/meta.json index e83fe7126..8b65ea330 100644 --- a/docs/components/form/meta.json +++ b/docs/components/form/meta.json @@ -5,15 +5,12 @@ "input", "textarea", "select", - "combobox", "checkbox", "radio-group", "switch", "slider", "label", "date-picker", - "input-otp", - "command", - "form" + "input-otp" ] } diff --git a/docs/components/layout/aspect-ratio.mdx b/docs/components/layout/aspect-ratio.mdx deleted file mode 100644 index c0e21eb84..000000000 --- a/docs/components/layout/aspect-ratio.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "Aspect Ratio" -description: "Maintain a consistent width to height ratio" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Aspect Ratio component maintains a consistent width to height ratio for content. - -## Basic Usage - - - -## Different Ratios - - - - - - - -## Schema - -```typescript -interface AspectRatioSchema { - type: 'aspect-ratio'; - ratio: number; // Width / Height ratio - content: ComponentSchema; // Content to display - className?: string; -} -``` - -## Examples - -### Video Container - - diff --git a/docs/components/layout/meta.json b/docs/components/layout/meta.json index 8cb6a1da0..6fe466297 100644 --- a/docs/components/layout/meta.json +++ b/docs/components/layout/meta.json @@ -7,7 +7,6 @@ "flex", "stack", "tabs", - "aspect-ratio", "scroll-area", "resizable" ] diff --git a/docs/components/overlay/menubar.mdx b/docs/components/overlay/menubar.mdx deleted file mode 100644 index 983ed1c35..000000000 --- a/docs/components/overlay/menubar.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: "Menubar" -description: "Horizontal menu bar with dropdown menus" ---- - -import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; - -The Menubar component provides a horizontal menu bar similar to desktop applications. - -## Basic Usage - - - -## Schema - -```typescript -interface MenubarItem { - label?: string; - value?: string; - icon?: string; - shortcut?: string[]; - type?: 'separator'; - disabled?: boolean; -} - -interface MenubarMenu { - label: string; - items: MenubarItem[]; -} - -interface MenubarSchema { - type: 'menubar'; - menus: MenubarMenu[]; // Menu definitions - - // Events - onSelect?: string | ActionConfig; - - // Styling - className?: string; -} -``` diff --git a/docs/components/overlay/meta.json b/docs/components/overlay/meta.json index 54855a1bf..a62f2d63e 100644 --- a/docs/components/overlay/meta.json +++ b/docs/components/overlay/meta.json @@ -9,7 +9,6 @@ "sheet", "hover-card", "context-menu", - "dropdown-menu", - "menubar" + "dropdown-menu" ] } From 2d95699185fdaea65a26328bc09543ac67909bd0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:02:53 +0000 Subject: [PATCH 09/11] Add renderers for all documented components Created renderers for 14 previously undocumented components: combobox, command, toast, spinner, empty, sonner, breadcrumb, kbd, toggle-group, button-group, pagination, navigation-menu, aspect-ratio, and menubar. Restored all deleted documentation files. Updated renderer index files to export new components. All 123 static pages now build successfully and all 205 tests passing. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- docs/components/basic/button-group.mdx | 128 ++++++++++++++++ docs/components/basic/meta.json | 3 + docs/components/basic/navigation-menu.mdx | 88 +++++++++++ docs/components/basic/pagination.mdx | 50 +++++++ docs/components/data-display/breadcrumb.mdx | 54 +++++++ docs/components/data-display/kbd.mdx | 72 +++++++++ docs/components/data-display/meta.json | 2 + docs/components/disclosure/meta.json | 3 +- docs/components/disclosure/toggle-group.mdx | 81 ++++++++++ docs/components/feedback/empty.mdx | 98 ++++++++++++ docs/components/feedback/meta.json | 6 +- docs/components/feedback/sonner.mdx | 132 +++++++++++++++++ docs/components/feedback/spinner.mdx | 85 +++++++++++ docs/components/feedback/toast.mdx | 139 ++++++++++++++++++ docs/components/form/combobox.mdx | 123 ++++++++++++++++ docs/components/form/command.mdx | 87 +++++++++++ docs/components/form/meta.json | 5 +- docs/components/layout/aspect-ratio.mdx | 89 +++++++++++ docs/components/layout/meta.json | 1 + docs/components/overlay/menubar.mdx | 76 ++++++++++ docs/components/overlay/meta.json | 3 +- .../src/renderers/basic/button-group.tsx | 78 ++++++++++ .../components/src/renderers/basic/index.ts | 3 + .../src/renderers/basic/navigation-menu.tsx | 80 ++++++++++ .../src/renderers/basic/pagination.tsx | 82 +++++++++++ .../src/renderers/data-display/breadcrumb.tsx | 59 ++++++++ .../src/renderers/data-display/index.ts | 2 + .../src/renderers/data-display/kbd.tsx | 49 ++++++ .../src/renderers/disclosure/index.ts | 1 + .../src/renderers/disclosure/toggle-group.tsx | 77 ++++++++++ .../src/renderers/feedback/empty.tsx | 48 ++++++ .../src/renderers/feedback/index.ts | 4 + .../src/renderers/feedback/sonner.tsx | 55 +++++++ .../src/renderers/feedback/spinner.tsx | 54 +++++++ .../src/renderers/feedback/toast.tsx | 53 +++++++ .../src/renderers/form/combobox.tsx | 47 ++++++ .../components/src/renderers/form/command.tsx | 57 +++++++ .../components/src/renderers/form/index.ts | 2 + .../src/renderers/layout/aspect-ratio.tsx | 50 +++++++ .../components/src/renderers/layout/index.ts | 1 + .../components/src/renderers/overlay/index.ts | 1 + .../src/renderers/overlay/menubar.tsx | 75 ++++++++++ 42 files changed, 2199 insertions(+), 4 deletions(-) create mode 100644 docs/components/basic/button-group.mdx create mode 100644 docs/components/basic/navigation-menu.mdx create mode 100644 docs/components/basic/pagination.mdx create mode 100644 docs/components/data-display/breadcrumb.mdx create mode 100644 docs/components/data-display/kbd.mdx create mode 100644 docs/components/disclosure/toggle-group.mdx create mode 100644 docs/components/feedback/empty.mdx create mode 100644 docs/components/feedback/sonner.mdx create mode 100644 docs/components/feedback/spinner.mdx create mode 100644 docs/components/feedback/toast.mdx create mode 100644 docs/components/form/combobox.mdx create mode 100644 docs/components/form/command.mdx create mode 100644 docs/components/layout/aspect-ratio.mdx create mode 100644 docs/components/overlay/menubar.mdx create mode 100644 packages/components/src/renderers/basic/button-group.tsx create mode 100644 packages/components/src/renderers/basic/navigation-menu.tsx create mode 100644 packages/components/src/renderers/basic/pagination.tsx create mode 100644 packages/components/src/renderers/data-display/breadcrumb.tsx create mode 100644 packages/components/src/renderers/data-display/kbd.tsx create mode 100644 packages/components/src/renderers/disclosure/toggle-group.tsx create mode 100644 packages/components/src/renderers/feedback/empty.tsx create mode 100644 packages/components/src/renderers/feedback/sonner.tsx create mode 100644 packages/components/src/renderers/feedback/spinner.tsx create mode 100644 packages/components/src/renderers/feedback/toast.tsx create mode 100644 packages/components/src/renderers/form/combobox.tsx create mode 100644 packages/components/src/renderers/form/command.tsx create mode 100644 packages/components/src/renderers/layout/aspect-ratio.tsx create mode 100644 packages/components/src/renderers/overlay/menubar.tsx diff --git a/docs/components/basic/button-group.mdx b/docs/components/basic/button-group.mdx new file mode 100644 index 000000000..04223d416 --- /dev/null +++ b/docs/components/basic/button-group.mdx @@ -0,0 +1,128 @@ +--- +title: "Button Group" +description: "Group multiple buttons together with shared styling" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Button Group component groups multiple buttons together with consistent styling. + +## Basic Usage + + + +## Variants + + + + + + +## Selection Mode + + + + + + +## Schema + +```typescript +interface ButtonGroupButton { + label?: string; + value: string; + icon?: string; + disabled?: boolean; +} + +interface ButtonGroupSchema { + type: 'button-group'; + buttons: ButtonGroupButton[]; // Button definitions + value?: string | string[]; // Selected value(s) + selectionMode?: 'single' | 'multiple' | 'none'; + variant?: 'default' | 'outline' | 'ghost'; + size?: 'sm' | 'default' | 'lg'; + + // Events + onValueChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### Toolbar Actions + + diff --git a/docs/components/basic/meta.json b/docs/components/basic/meta.json index fa3e42171..a0a95cec5 100644 --- a/docs/components/basic/meta.json +++ b/docs/components/basic/meta.json @@ -6,6 +6,9 @@ "image", "separator", "html", + "button-group", + "pagination", + "navigation-menu", "sidebar" ] } diff --git a/docs/components/basic/navigation-menu.mdx b/docs/components/basic/navigation-menu.mdx new file mode 100644 index 000000000..c3fdb4e6d --- /dev/null +++ b/docs/components/basic/navigation-menu.mdx @@ -0,0 +1,88 @@ +--- +title: "Navigation Menu" +description: "Accessible navigation menu with dropdown support" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Navigation Menu component provides an accessible menu for site navigation. + +## Basic Usage + + + +## With Descriptions + + + +## Schema + +```typescript +interface NavigationMenuItem { + label: string; + href?: string; + description?: string; + icon?: string; + items?: NavigationMenuItem[]; // Submenu items +} + +interface NavigationMenuSchema { + type: 'navigation-menu'; + items: NavigationMenuItem[]; // Menu items + className?: string; +} +``` diff --git a/docs/components/basic/pagination.mdx b/docs/components/basic/pagination.mdx new file mode 100644 index 000000000..04a957e61 --- /dev/null +++ b/docs/components/basic/pagination.mdx @@ -0,0 +1,50 @@ +--- +title: "Pagination" +description: "Navigate through pages of content" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Pagination component allows users to navigate through pages of data. + +## Basic Usage + + + +## With Page Size + + + +## Schema + +```typescript +interface PaginationSchema { + type: 'pagination'; + currentPage: number; // Current page (1-based) + totalPages: number; // Total number of pages + pageSize?: number; // Items per page + totalItems?: number; // Total number of items + + // Events + onPageChange?: string | ActionConfig; + + // Styling + className?: string; +} +``` diff --git a/docs/components/data-display/breadcrumb.mdx b/docs/components/data-display/breadcrumb.mdx new file mode 100644 index 000000000..0290dcbfb --- /dev/null +++ b/docs/components/data-display/breadcrumb.mdx @@ -0,0 +1,54 @@ +--- +title: "Breadcrumb" +description: "Display the current location within a navigational hierarchy" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Breadcrumb component shows the current page's location within the site hierarchy. + +## Basic Usage + + + +## With Icons + + + +## Schema + +```typescript +interface BreadcrumbItem { + label: string; + href?: string; + icon?: string; +} + +interface BreadcrumbSchema { + type: 'breadcrumb'; + items: BreadcrumbItem[]; // Breadcrumb items + separator?: string; // Custom separator + className?: string; +} +``` diff --git a/docs/components/data-display/kbd.mdx b/docs/components/data-display/kbd.mdx new file mode 100644 index 000000000..cec48bda9 --- /dev/null +++ b/docs/components/data-display/kbd.mdx @@ -0,0 +1,72 @@ +--- +title: "Kbd" +description: "Display keyboard shortcuts and hotkeys" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Kbd component displays keyboard shortcuts in a styled format. + +## Basic Usage + + + +## Multiple Key Combinations + + + + + + + +## Schema + +```typescript +interface KbdSchema { + type: 'kbd'; + keys: string[]; // Keyboard keys + className?: string; +} +``` + +## Examples + +### In Documentation + + diff --git a/docs/components/data-display/meta.json b/docs/components/data-display/meta.json index 16d7978ef..40459a02e 100644 --- a/docs/components/data-display/meta.json +++ b/docs/components/data-display/meta.json @@ -5,8 +5,10 @@ "avatar", "alert", "list", + "breadcrumb", "calendar", "carousel", + "kbd", "timeline" ] } diff --git a/docs/components/disclosure/meta.json b/docs/components/disclosure/meta.json index 99701c3fd..060414ee8 100644 --- a/docs/components/disclosure/meta.json +++ b/docs/components/disclosure/meta.json @@ -3,6 +3,7 @@ "pages": [ "accordion", "collapsible", - "toggle" + "toggle", + "toggle-group" ] } diff --git a/docs/components/disclosure/toggle-group.mdx b/docs/components/disclosure/toggle-group.mdx new file mode 100644 index 000000000..51df1513f --- /dev/null +++ b/docs/components/disclosure/toggle-group.mdx @@ -0,0 +1,81 @@ +--- +title: "Toggle Group" +description: "A group of toggle buttons where one or more can be selected" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Toggle Group component allows users to toggle between multiple options. + +## Basic Usage + + + +## Multiple Selection + + + +## With Labels + + + +## Schema + +```typescript +interface ToggleGroupItem { + value: string; + icon?: string; + label?: string; +} + +interface ToggleGroupSchema { + type: 'toggle-group'; + type: 'single' | 'multiple'; // Selection mode + items: ToggleGroupItem[]; // Toggle items + value?: string | string[]; // Selected value(s) + variant?: 'default' | 'outline'; + size?: 'sm' | 'default' | 'lg'; + + // Events + onValueChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` diff --git a/docs/components/feedback/empty.mdx b/docs/components/feedback/empty.mdx new file mode 100644 index 000000000..2ea7e6b53 --- /dev/null +++ b/docs/components/feedback/empty.mdx @@ -0,0 +1,98 @@ +--- +title: "Empty" +description: "Empty state placeholder with optional action" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Empty component displays a placeholder when there's no content to show. + +## Basic Usage + + + +## With Icon + + + +## With Action + + + +## Schema + +```typescript +interface EmptySchema { + type: 'empty'; + icon?: string; // Lucide icon name + title?: string; // Main message + description?: string; // Supporting text + action?: ComponentSchema; // Call to action button + className?: string; +} +``` + +## Examples + +### Search Results + + + +### Empty List + + diff --git a/docs/components/feedback/meta.json b/docs/components/feedback/meta.json index 9353c60c4..c0f19aea7 100644 --- a/docs/components/feedback/meta.json +++ b/docs/components/feedback/meta.json @@ -3,6 +3,10 @@ "pages": [ "loading", "progress", - "skeleton" + "skeleton", + "spinner", + "empty", + "toast", + "sonner" ] } diff --git a/docs/components/feedback/sonner.mdx b/docs/components/feedback/sonner.mdx new file mode 100644 index 000000000..c800f2db8 --- /dev/null +++ b/docs/components/feedback/sonner.mdx @@ -0,0 +1,132 @@ +--- +title: "Sonner" +description: "Toast notifications using Sonner library" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Sonner component provides beautiful toast notifications with a rich API. + +## Basic Usage + + + +## Toast Types + + + + + + + + +## With Action + + + +## Schema + +```typescript +interface SonnerSchema { + action: 'sonner'; + message: string; // Toast message + description?: string; // Additional description + type?: 'default' | 'success' | 'error' | 'warning' | 'info'; + duration?: number; // Auto-close duration (ms) + + // Action + action?: { + label: string; + onClick: string | ActionConfig; + }; +} +``` + +## Examples + +### Promise Toast + + diff --git a/docs/components/feedback/spinner.mdx b/docs/components/feedback/spinner.mdx new file mode 100644 index 000000000..4a8446e90 --- /dev/null +++ b/docs/components/feedback/spinner.mdx @@ -0,0 +1,85 @@ +--- +title: "Spinner" +description: "Loading spinner indicator" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Spinner component displays a loading indicator. + +## Basic Usage + + + +## Sizes + + + + + + + +## Schema + +```typescript +interface SpinnerSchema { + type: 'spinner'; + size?: 'sm' | 'md' | 'lg'; + className?: string; +} +``` + +## Examples + +### In Button + + + +### Centered + + diff --git a/docs/components/feedback/toast.mdx b/docs/components/feedback/toast.mdx new file mode 100644 index 000000000..787ffff0c --- /dev/null +++ b/docs/components/feedback/toast.mdx @@ -0,0 +1,139 @@ +--- +title: "Toast" +description: "Brief notification messages that appear temporarily" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Toast component displays brief notifications to users that appear temporarily and then disappear. + +## Basic Usage + + + +## Variants + + + + + + +## With Action + + + +## Schema + +```typescript +interface ToastSchema { + type: 'toast'; + title?: string; // Toast title + description?: string; // Toast message + variant?: 'default' | 'destructive'; + + // Action + actionLabel?: string; // Action button label + onAction?: string | ActionConfig; + + // Timing + duration?: number; // Auto-dismiss time in ms +} +``` + +## Examples + +### Success Message + + + +### Error Message + + + +### With Undo Action + + diff --git a/docs/components/form/combobox.mdx b/docs/components/form/combobox.mdx new file mode 100644 index 000000000..65ac946c3 --- /dev/null +++ b/docs/components/form/combobox.mdx @@ -0,0 +1,123 @@ +--- +title: "Combobox" +description: "Searchable dropdown for selecting from a list of options" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Combobox component combines a text input with a dropdown list, allowing users to search and select from options. + +## Basic Usage + + + +## With Search + + + +## States + + + + + + +## Schema + +```typescript +interface ComboboxOption { + value: string; + label: string; +} + +interface ComboboxSchema { + type: 'combobox'; + options: ComboboxOption[]; // Available options + value?: string; // Selected value + + // Text + placeholder?: string; // Button placeholder + searchPlaceholder?: string; // Search input placeholder + emptyText?: string; // Text when no results + + // Events + onValueChange?: string | ActionConfig; + + // States + disabled?: boolean; + + // Styling + className?: string; +} +``` + +## Examples + +### Dynamic Options + + diff --git a/docs/components/form/command.mdx b/docs/components/form/command.mdx new file mode 100644 index 000000000..11b996ed5 --- /dev/null +++ b/docs/components/form/command.mdx @@ -0,0 +1,87 @@ +--- +title: "Command" +description: "Fast command menu with search and keyboard navigation" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Command component provides a fast, searchable command menu with keyboard navigation. + +## Basic Usage + + + +## Schema + +```typescript +interface CommandItem { + value: string; + label: string; + icon?: string; + shortcut?: string[]; +} + +interface CommandGroup { + heading?: string; + items: CommandItem[]; +} + +interface CommandSchema { + type: 'command'; + placeholder?: string; // Search placeholder + groups: CommandGroup[]; // Command groups + emptyText?: string; // Text when no results + + // Events + onSelect?: string | ActionConfig; + + // Styling + className?: string; +} +``` + +## Examples + +### With Shortcuts + + diff --git a/docs/components/form/meta.json b/docs/components/form/meta.json index 8b65ea330..e83fe7126 100644 --- a/docs/components/form/meta.json +++ b/docs/components/form/meta.json @@ -5,12 +5,15 @@ "input", "textarea", "select", + "combobox", "checkbox", "radio-group", "switch", "slider", "label", "date-picker", - "input-otp" + "input-otp", + "command", + "form" ] } diff --git a/docs/components/layout/aspect-ratio.mdx b/docs/components/layout/aspect-ratio.mdx new file mode 100644 index 000000000..c0e21eb84 --- /dev/null +++ b/docs/components/layout/aspect-ratio.mdx @@ -0,0 +1,89 @@ +--- +title: "Aspect Ratio" +description: "Maintain a consistent width to height ratio" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Aspect Ratio component maintains a consistent width to height ratio for content. + +## Basic Usage + + + +## Different Ratios + + + + + + + +## Schema + +```typescript +interface AspectRatioSchema { + type: 'aspect-ratio'; + ratio: number; // Width / Height ratio + content: ComponentSchema; // Content to display + className?: string; +} +``` + +## Examples + +### Video Container + + diff --git a/docs/components/layout/meta.json b/docs/components/layout/meta.json index 6fe466297..8cb6a1da0 100644 --- a/docs/components/layout/meta.json +++ b/docs/components/layout/meta.json @@ -7,6 +7,7 @@ "flex", "stack", "tabs", + "aspect-ratio", "scroll-area", "resizable" ] diff --git a/docs/components/overlay/menubar.mdx b/docs/components/overlay/menubar.mdx new file mode 100644 index 000000000..983ed1c35 --- /dev/null +++ b/docs/components/overlay/menubar.mdx @@ -0,0 +1,76 @@ +--- +title: "Menubar" +description: "Horizontal menu bar with dropdown menus" +--- + +import { ComponentDemo, DemoGrid } from '@/app/components/ComponentDemo'; + +The Menubar component provides a horizontal menu bar similar to desktop applications. + +## Basic Usage + + + +## Schema + +```typescript +interface MenubarItem { + label?: string; + value?: string; + icon?: string; + shortcut?: string[]; + type?: 'separator'; + disabled?: boolean; +} + +interface MenubarMenu { + label: string; + items: MenubarItem[]; +} + +interface MenubarSchema { + type: 'menubar'; + menus: MenubarMenu[]; // Menu definitions + + // Events + onSelect?: string | ActionConfig; + + // Styling + className?: string; +} +``` diff --git a/docs/components/overlay/meta.json b/docs/components/overlay/meta.json index a62f2d63e..54855a1bf 100644 --- a/docs/components/overlay/meta.json +++ b/docs/components/overlay/meta.json @@ -9,6 +9,7 @@ "sheet", "hover-card", "context-menu", - "dropdown-menu" + "dropdown-menu", + "menubar" ] } diff --git a/packages/components/src/renderers/basic/button-group.tsx b/packages/components/src/renderers/basic/button-group.tsx new file mode 100644 index 000000000..d49602b38 --- /dev/null +++ b/packages/components/src/renderers/basic/button-group.tsx @@ -0,0 +1,78 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { ButtonGroupSchema } from '@object-ui/types'; +import { Button } from '../../ui'; +import { cn } from '../../lib/utils'; + +ComponentRegistry.register('button-group', + ({ schema, ...props }: { schema: ButtonGroupSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...buttonGroupProps + } = props; + + return ( +
+ {schema.buttons?.map((button, idx) => ( + + ))} +
+ ); + }, + { + label: 'Button Group', + inputs: [ + { + name: 'variant', + type: 'enum', + enum: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'], + defaultValue: 'default', + label: 'Variant' + }, + { + name: 'size', + type: 'enum', + enum: ['default', 'sm', 'lg', 'icon'], + defaultValue: 'default', + label: 'Size' + }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + variant: 'default', + size: 'default', + buttons: [ + { label: 'Left' }, + { label: 'Middle' }, + { label: 'Right' } + ] + } + } +); diff --git a/packages/components/src/renderers/basic/index.ts b/packages/components/src/renderers/basic/index.ts index f24577171..62b8b3582 100644 --- a/packages/components/src/renderers/basic/index.ts +++ b/packages/components/src/renderers/basic/index.ts @@ -13,3 +13,6 @@ import './separator'; import './image'; import './icon'; import './html'; +import './button-group'; +import './pagination'; +import './navigation-menu'; diff --git a/packages/components/src/renderers/basic/navigation-menu.tsx b/packages/components/src/renderers/basic/navigation-menu.tsx new file mode 100644 index 000000000..eb76a97ed --- /dev/null +++ b/packages/components/src/renderers/basic/navigation-menu.tsx @@ -0,0 +1,80 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { NavigationMenuSchema } from '@object-ui/types'; +import { NavigationMenu, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink } from '../../ui/navigation-menu'; +import { cn } from '../../lib/utils'; + +ComponentRegistry.register('navigation-menu', + ({ schema, ...props }: { schema: NavigationMenuSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...navigationMenuProps + } = props; + + return ( + + + {schema.items?.map((item, idx) => ( + + {item.children ? ( + <> + {item.label} + + + + + ) : ( + {item.label} + )} + + ))} + + + ); + }, + { + label: 'Navigation Menu', + inputs: [ + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + items: [ + { label: 'Home', href: '/' }, + { label: 'About', href: '/about' } + ] + } + } +); diff --git a/packages/components/src/renderers/basic/pagination.tsx b/packages/components/src/renderers/basic/pagination.tsx new file mode 100644 index 000000000..6cab496c1 --- /dev/null +++ b/packages/components/src/renderers/basic/pagination.tsx @@ -0,0 +1,82 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { PaginationSchema } from '@object-ui/types'; +import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from '../../ui/pagination'; + +ComponentRegistry.register('pagination', + ({ schema, ...props }: { schema: PaginationSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...paginationProps + } = props; + + const currentPage = schema.currentPage || 1; + const totalPages = schema.totalPages || 1; + const showEllipsis = totalPages > 7; + + const getPageNumbers = () => { + if (totalPages <= 7) { + return Array.from({ length: totalPages }, (_, i) => i + 1); + } + + if (currentPage <= 3) { + return [1, 2, 3, 4, 5, -1, totalPages]; + } + + if (currentPage >= totalPages - 2) { + return [1, -1, totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages]; + } + + return [1, -1, currentPage - 1, currentPage, currentPage + 1, -1, totalPages]; + }; + + return ( + + + + + + {getPageNumbers().map((page, idx) => ( + + {page === -1 ? ( + + ) : ( + + {page} + + )} + + ))} + + + + + + ); + }, + { + label: 'Pagination', + inputs: [ + { name: 'currentPage', type: 'number', label: 'Current Page', defaultValue: 1 }, + { name: 'totalPages', type: 'number', label: 'Total Pages', defaultValue: 10 }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + currentPage: 1, + totalPages: 10 + } + } +); diff --git a/packages/components/src/renderers/data-display/breadcrumb.tsx b/packages/components/src/renderers/data-display/breadcrumb.tsx new file mode 100644 index 000000000..111545717 --- /dev/null +++ b/packages/components/src/renderers/data-display/breadcrumb.tsx @@ -0,0 +1,59 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { BreadcrumbSchema } from '@object-ui/types'; +import { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator } from '../../ui/breadcrumb'; +import { renderChildren } from '../../lib/utils'; + +ComponentRegistry.register('breadcrumb', + ({ schema, ...props }: { schema: BreadcrumbSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...breadcrumbProps + } = props; + + return ( + + + {schema.items?.map((item, idx) => ( +
+ + {idx === (schema.items?.length || 0) - 1 ? ( + {item.label} + ) : ( + {item.label} + )} + + {idx < (schema.items?.length || 0) - 1 && } +
+ ))} +
+
+ ); + }, + { + label: 'Breadcrumb', + inputs: [ + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + items: [ + { label: 'Home', href: '/' }, + { label: 'Products', href: '/products' }, + { label: 'Product' } + ] + } + } +); diff --git a/packages/components/src/renderers/data-display/index.ts b/packages/components/src/renderers/data-display/index.ts index e8516f6f8..1bb019675 100644 --- a/packages/components/src/renderers/data-display/index.ts +++ b/packages/components/src/renderers/data-display/index.ts @@ -12,3 +12,5 @@ import './alert'; import './list'; import './tree-view'; import './statistic'; +import './breadcrumb'; +import './kbd'; diff --git a/packages/components/src/renderers/data-display/kbd.tsx b/packages/components/src/renderers/data-display/kbd.tsx new file mode 100644 index 000000000..81c6d19ad --- /dev/null +++ b/packages/components/src/renderers/data-display/kbd.tsx @@ -0,0 +1,49 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { KbdSchema } from '@object-ui/types'; +import { cn } from '../../lib/utils'; + +ComponentRegistry.register('kbd', + ({ schema, ...props }: { schema: KbdSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...kbdProps + } = props; + + const keys = Array.isArray(schema.keys) ? schema.keys : [schema.keys || schema.label || 'K']; + + return ( +
+ {keys.map((key, idx) => ( + + {key} + + ))} +
+ ); + }, + { + label: 'Keyboard Key', + inputs: [ + { name: 'label', type: 'string', label: 'Label' }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + label: 'K' + } + } +); diff --git a/packages/components/src/renderers/disclosure/index.ts b/packages/components/src/renderers/disclosure/index.ts index 3e7cad4fe..b8e55ae64 100644 --- a/packages/components/src/renderers/disclosure/index.ts +++ b/packages/components/src/renderers/disclosure/index.ts @@ -8,3 +8,4 @@ import './accordion'; import './collapsible'; +import './toggle-group'; diff --git a/packages/components/src/renderers/disclosure/toggle-group.tsx b/packages/components/src/renderers/disclosure/toggle-group.tsx new file mode 100644 index 000000000..d52a25f20 --- /dev/null +++ b/packages/components/src/renderers/disclosure/toggle-group.tsx @@ -0,0 +1,77 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { ToggleGroupSchema } from '@object-ui/types'; +import { ToggleGroup, ToggleGroupItem } from '../../ui/toggle-group'; + +ComponentRegistry.register('toggle-group', + ({ schema, ...props }: { schema: ToggleGroupSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...toggleGroupProps + } = props; + + return ( + + {schema.items?.map((item, idx) => ( + + {item.label} + + ))} + + ); + }, + { + label: 'Toggle Group', + inputs: [ + { + name: 'type', + type: 'enum', + enum: ['single', 'multiple'], + defaultValue: 'single', + label: 'Type' + }, + { + name: 'variant', + type: 'enum', + enum: ['default', 'outline'], + defaultValue: 'default', + label: 'Variant' + }, + { + name: 'size', + type: 'enum', + enum: ['default', 'sm', 'lg'], + defaultValue: 'default', + label: 'Size' + }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + type: 'single', + variant: 'default', + size: 'default', + items: [ + { value: 'bold', label: 'Bold' }, + { value: 'italic', label: 'Italic' }, + { value: 'underline', label: 'Underline' } + ] + } + } +); diff --git a/packages/components/src/renderers/feedback/empty.tsx b/packages/components/src/renderers/feedback/empty.tsx new file mode 100644 index 000000000..f59bb6b84 --- /dev/null +++ b/packages/components/src/renderers/feedback/empty.tsx @@ -0,0 +1,48 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { EmptySchema } from '@object-ui/types'; +import { InboxIcon } from 'lucide-react'; +import { cn } from '../../lib/utils'; + +ComponentRegistry.register('empty', + ({ schema, ...props }: { schema: EmptySchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...emptyProps + } = props; + + return ( +
+ +

{schema.title || 'No data'}

+ {schema.description && ( +

{schema.description}

+ )} +
+ ); + }, + { + label: 'Empty', + inputs: [ + { name: 'title', type: 'string', label: 'Title', defaultValue: 'No data' }, + { name: 'description', type: 'string', label: 'Description' }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + title: 'No data' + } + } +); diff --git a/packages/components/src/renderers/feedback/index.ts b/packages/components/src/renderers/feedback/index.ts index 90239104b..791b9f479 100644 --- a/packages/components/src/renderers/feedback/index.ts +++ b/packages/components/src/renderers/feedback/index.ts @@ -10,3 +10,7 @@ import './progress'; import './skeleton'; import './toaster'; import './loading'; +import './toast'; +import './spinner'; +import './empty'; +import './sonner'; diff --git a/packages/components/src/renderers/feedback/sonner.tsx b/packages/components/src/renderers/feedback/sonner.tsx new file mode 100644 index 000000000..c5af9fbf1 --- /dev/null +++ b/packages/components/src/renderers/feedback/sonner.tsx @@ -0,0 +1,55 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { SonnerSchema } from '@object-ui/types'; +import { toast } from 'sonner'; +import { Button } from '../../ui'; + +ComponentRegistry.register('sonner', + ({ schema, ...props }: { schema: SonnerSchema; [key: string]: any }) => { + const showToast = () => { + const toastFn = schema.variant === 'success' ? toast.success : + schema.variant === 'error' ? toast.error : + schema.variant === 'warning' ? toast.warning : + schema.variant === 'info' ? toast.info : + toast; + + toastFn(schema.message || schema.title || 'Notification', { + description: schema.description, + }); + }; + + return ( + + ); + }, + { + label: 'Sonner Toast', + inputs: [ + { name: 'message', type: 'string', label: 'Message' }, + { name: 'description', type: 'string', label: 'Description' }, + { + name: 'variant', + type: 'enum', + enum: ['default', 'success', 'error', 'warning', 'info'], + defaultValue: 'default', + label: 'Variant' + }, + { name: 'buttonLabel', type: 'string', label: 'Button Label' }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + message: 'Notification', + buttonLabel: 'Show Toast', + variant: 'default' + } + } +); diff --git a/packages/components/src/renderers/feedback/spinner.tsx b/packages/components/src/renderers/feedback/spinner.tsx new file mode 100644 index 000000000..c2e6ac84a --- /dev/null +++ b/packages/components/src/renderers/feedback/spinner.tsx @@ -0,0 +1,54 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { SpinnerSchema } from '@object-ui/types'; +import { Loader2 } from 'lucide-react'; +import { cn } from '../../lib/utils'; + +ComponentRegistry.register('spinner', + ({ schema, ...props }: { schema: SpinnerSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...spinnerProps + } = props; + + const sizeClasses = { + sm: 'h-4 w-4', + md: 'h-6 w-6', + lg: 'h-8 w-8', + xl: 'h-12 w-12' + }; + + return ( + + ); + }, + { + label: 'Spinner', + inputs: [ + { + name: 'size', + type: 'enum', + enum: ['sm', 'md', 'lg', 'xl'], + defaultValue: 'md', + label: 'Size' + }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + size: 'md' + } + } +); diff --git a/packages/components/src/renderers/feedback/toast.tsx b/packages/components/src/renderers/feedback/toast.tsx new file mode 100644 index 000000000..58f45cc8f --- /dev/null +++ b/packages/components/src/renderers/feedback/toast.tsx @@ -0,0 +1,53 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { ToastSchema } from '@object-ui/types'; +import { useToast } from '../../hooks/use-toast'; +import { Button } from '../../ui'; + +ComponentRegistry.register('toast', + ({ schema, ...props }: { schema: ToastSchema; [key: string]: any }) => { + const { toast } = useToast(); + + const showToast = () => { + toast({ + title: schema.title, + description: schema.description, + variant: schema.variant as any, + }); + }; + + return ( + + ); + }, + { + label: 'Toast', + inputs: [ + { name: 'title', type: 'string', label: 'Title' }, + { name: 'description', type: 'string', label: 'Description' }, + { + name: 'variant', + type: 'enum', + enum: ['default', 'destructive'], + defaultValue: 'default', + label: 'Variant' + }, + { name: 'buttonLabel', type: 'string', label: 'Button Label' }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + title: 'Notification', + buttonLabel: 'Show Toast', + variant: 'default' + } + } +); diff --git a/packages/components/src/renderers/form/combobox.tsx b/packages/components/src/renderers/form/combobox.tsx new file mode 100644 index 000000000..aabd4ca47 --- /dev/null +++ b/packages/components/src/renderers/form/combobox.tsx @@ -0,0 +1,47 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { ComboboxSchema } from '@object-ui/types'; +import { Combobox } from '../../ui'; + +ComponentRegistry.register('combobox', + ({ schema, ...props }: { schema: ComboboxSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...comboboxProps + } = props; + + return ( + + ); + }, + { + label: 'Combobox', + inputs: [ + { name: 'placeholder', type: 'string', label: 'Placeholder' }, + { name: 'value', type: 'string', label: 'Value' }, + { name: 'disabled', type: 'boolean', label: 'Disabled', defaultValue: false }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + placeholder: 'Select option...', + options: [] + } + } +); diff --git a/packages/components/src/renderers/form/command.tsx b/packages/components/src/renderers/form/command.tsx new file mode 100644 index 000000000..18baf02c1 --- /dev/null +++ b/packages/components/src/renderers/form/command.tsx @@ -0,0 +1,57 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { CommandSchema } from '@object-ui/types'; +import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../../ui/command'; + +ComponentRegistry.register('command', + ({ schema, ...props }: { schema: CommandSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...commandProps + } = props; + + return ( + + + + {schema.emptyText || 'No results found.'} + {schema.groups?.map((group, idx) => ( + + {group.items?.map((item, itemIdx) => ( + + {item.label} + + ))} + + ))} + + + ); + }, + { + label: 'Command', + inputs: [ + { name: 'placeholder', type: 'string', label: 'Placeholder' }, + { name: 'emptyText', type: 'string', label: 'Empty Text' }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + placeholder: 'Type a command or search...', + emptyText: 'No results found.', + groups: [] + } + } +); diff --git a/packages/components/src/renderers/form/index.ts b/packages/components/src/renderers/form/index.ts index 54cb00a70..1230512d1 100644 --- a/packages/components/src/renderers/form/index.ts +++ b/packages/components/src/renderers/form/index.ts @@ -22,3 +22,5 @@ import './input-otp'; import './calendar'; import './date-picker'; import './file-upload'; +import './combobox'; +import './command'; diff --git a/packages/components/src/renderers/layout/aspect-ratio.tsx b/packages/components/src/renderers/layout/aspect-ratio.tsx new file mode 100644 index 000000000..d0b73953c --- /dev/null +++ b/packages/components/src/renderers/layout/aspect-ratio.tsx @@ -0,0 +1,50 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { AspectRatioSchema } from '@object-ui/types'; +import { AspectRatio } from '../../ui/aspect-ratio'; +import { renderChildren } from '../../lib/utils'; + +ComponentRegistry.register('aspect-ratio', + ({ schema, ...props }: { schema: AspectRatioSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...aspectRatioProps + } = props; + + return ( + + {schema.image ? ( + {schema.alt + ) : ( + renderChildren(schema.body) + )} + + ); + }, + { + label: 'Aspect Ratio', + inputs: [ + { name: 'ratio', type: 'number', label: 'Ratio', defaultValue: 16/9 }, + { name: 'image', type: 'string', label: 'Image URL' }, + { name: 'alt', type: 'string', label: 'Alt Text' }, + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + ratio: 16 / 9 + } + } +); diff --git a/packages/components/src/renderers/layout/index.ts b/packages/components/src/renderers/layout/index.ts index 1f36ba837..f778c720e 100644 --- a/packages/components/src/renderers/layout/index.ts +++ b/packages/components/src/renderers/layout/index.ts @@ -14,5 +14,6 @@ import './stack'; import './container'; import './page'; import './semantic'; +import './aspect-ratio'; diff --git a/packages/components/src/renderers/overlay/index.ts b/packages/components/src/renderers/overlay/index.ts index a5f328dab..f4cdc4396 100644 --- a/packages/components/src/renderers/overlay/index.ts +++ b/packages/components/src/renderers/overlay/index.ts @@ -15,3 +15,4 @@ import './drawer'; import './hover-card'; import './dropdown-menu'; import './context-menu'; +import './menubar'; diff --git a/packages/components/src/renderers/overlay/menubar.tsx b/packages/components/src/renderers/overlay/menubar.tsx new file mode 100644 index 000000000..db6f211d0 --- /dev/null +++ b/packages/components/src/renderers/overlay/menubar.tsx @@ -0,0 +1,75 @@ +/** + * ObjectUI + * Copyright (c) 2024-present ObjectStack Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { ComponentRegistry } from '@object-ui/core'; +import type { MenubarSchema } from '@object-ui/types'; +import { Menubar, MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem, MenubarSeparator, MenubarSub, MenubarSubTrigger, MenubarSubContent } from '../../ui/menubar'; + +ComponentRegistry.register('menubar', + ({ schema, ...props }: { schema: MenubarSchema; [key: string]: any }) => { + const { + 'data-obj-id': dataObjId, + 'data-obj-type': dataObjType, + style, + ...menubarProps + } = props; + + return ( + + {schema.menus?.map((menu, idx) => ( + + {menu.label} + + {menu.items?.map((item, itemIdx) => ( + item.separator ? ( + + ) : item.children ? ( + + {item.label} + + {item.children.map((child, childIdx) => ( + {child.label} + ))} + + + ) : ( + + {item.label} + + ) + ))} + + + ))} + + ); + }, + { + label: 'Menubar', + inputs: [ + { name: 'className', type: 'string', label: 'CSS Class' } + ], + defaultProps: { + menus: [ + { + label: 'File', + items: [ + { label: 'New' }, + { label: 'Open' }, + { separator: true }, + { label: 'Exit' } + ] + } + ] + } + } +); From 46b7445732627b7d2ae1929f548582d5f5b88984 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:11:11 +0000 Subject: [PATCH 10/11] Add TypeScript type definitions for all new component schemas Added complete TypeScript schema definitions for 14 new components in @object-ui/types package: ComboboxSchema, CommandSchema, ToastSchema (already existed), SpinnerSchema, EmptySchema, SonnerSchema, BreadcrumbSchema (already existed in navigation), KbdSchema, ToggleGroupSchema, ButtonGroupSchema, PaginationSchema (already existed), NavigationMenuSchema, AspectRatioSchema, and MenubarSchema. Fixed type naming conflict in ToggleGroupSchema by renaming 'type' property to 'selectionType'. All 123 static pages build successfully and all 205 tests passing. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- .../src/renderers/disclosure/toggle-group.tsx | 8 +- packages/types/src/data-display.ts | 49 ++++++- packages/types/src/disclosure.ts | 67 +++++++++- packages/types/src/feedback.ts | 68 +++++++++- packages/types/src/form.ts | 124 +++++++++++++++++- packages/types/src/layout.ts | 43 ++++-- packages/types/src/navigation.ts | 103 ++++++++++++++- packages/types/src/overlay.ts | 28 +++- 8 files changed, 465 insertions(+), 25 deletions(-) diff --git a/packages/components/src/renderers/disclosure/toggle-group.tsx b/packages/components/src/renderers/disclosure/toggle-group.tsx index d52a25f20..4e846db86 100644 --- a/packages/components/src/renderers/disclosure/toggle-group.tsx +++ b/packages/components/src/renderers/disclosure/toggle-group.tsx @@ -21,7 +21,7 @@ ComponentRegistry.register('toggle-group', return ( void; } +/** + * Toggle group item + */ +export interface ToggleGroupItem { + /** + * Item value + */ + value: string; + /** + * Item label + */ + label: string; + /** + * Item icon + */ + icon?: string; + /** + * Whether item is disabled + */ + disabled?: boolean; +} + +/** + * Toggle group component + */ +export interface ToggleGroupSchema extends BaseSchema { + type: 'toggle-group'; + /** + * Toggle group selection mode + * @default 'single' + */ + selectionType?: 'single' | 'multiple'; + /** + * Toggle group variant + * @default 'default' + */ + variant?: 'default' | 'outline'; + /** + * Toggle group size + * @default 'default' + */ + size?: 'default' | 'sm' | 'lg'; + /** + * Toggle group items + */ + items?: ToggleGroupItem[]; + /** + * Default selected value(s) + */ + defaultValue?: string | string[]; + /** + * Controlled selected value(s) + */ + value?: string | string[]; + /** + * Whether toggle group is disabled + */ + disabled?: boolean; + /** + * Change handler + */ + onValueChange?: (value: string | string[]) => void; +} + /** * Union type of all disclosure schemas */ export type DisclosureSchema = | AccordionSchema - | CollapsibleSchema; + | CollapsibleSchema + | ToggleGroupSchema; diff --git a/packages/types/src/feedback.ts b/packages/types/src/feedback.ts index 098a8bf72..720c53ae8 100644 --- a/packages/types/src/feedback.ts +++ b/packages/types/src/feedback.ts @@ -167,6 +167,69 @@ export interface ToasterSchema extends BaseSchema { limit?: number; } +/** + * Spinner component + */ +export interface SpinnerSchema extends BaseSchema { + type: 'spinner'; + /** + * Spinner size + * @default 'md' + */ + size?: 'sm' | 'md' | 'lg' | 'xl'; +} + +/** + * Empty state component + */ +export interface EmptySchema extends BaseSchema { + type: 'empty'; + /** + * Empty state title + */ + title?: string; + /** + * Empty state description + */ + description?: string; + /** + * Icon to display + */ + icon?: string; +} + +/** + * Sonner toast component (using sonner library) + */ +export interface SonnerSchema extends BaseSchema { + type: 'sonner'; + /** + * Toast message/title + */ + message?: string; + /** + * Toast title (alias for message) + */ + title?: string; + /** + * Toast description + */ + description?: string; + /** + * Toast variant + * @default 'default' + */ + variant?: 'default' | 'success' | 'error' | 'warning' | 'info'; + /** + * Button label to trigger toast + */ + buttonLabel?: string; + /** + * Button variant + */ + buttonVariant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'; +} + /** * Union type of all feedback schemas */ @@ -175,4 +238,7 @@ export type FeedbackSchema = | ProgressSchema | SkeletonSchema | ToastSchema - | ToasterSchema; + | ToasterSchema + | SpinnerSchema + | EmptySchema + | SonnerSchema; diff --git a/packages/types/src/form.ts b/packages/types/src/form.ts index 43eba573f..0883aff05 100644 --- a/packages/types/src/form.ts +++ b/packages/types/src/form.ts @@ -940,6 +940,126 @@ export interface LabelSchema extends BaseSchema { htmlFor?: string; } +/** + * Combobox option + */ +export interface ComboboxOption { + /** + * Option value + */ + value: string; + /** + * Option label (displayed to user) + */ + label: string; + /** + * Whether option is disabled + */ + disabled?: boolean; +} + +/** + * Combobox component (searchable select) + */ +export interface ComboboxSchema extends BaseSchema { + type: 'combobox'; + /** + * Field name for form submission + */ + name?: string; + /** + * Combobox label + */ + label?: string; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Combobox options + */ + options?: ComboboxOption[]; + /** + * Default selected value + */ + defaultValue?: string; + /** + * Controlled value + */ + value?: string; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (value: string) => void; +} + +/** + * Command menu item + */ +export interface CommandItem { + /** + * Item value + */ + value: string; + /** + * Item label (displayed to user) + */ + label: string; + /** + * Item icon + */ + icon?: string; +} + +/** + * Command menu group + */ +export interface CommandGroup { + /** + * Group heading + */ + heading?: string; + /** + * Group items + */ + items: CommandItem[]; +} + +/** + * Command component (command palette) + */ +export interface CommandSchema extends BaseSchema { + type: 'command'; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Empty state text + */ + emptyText?: string; + /** + * Command groups + */ + groups?: CommandGroup[]; + /** + * Change handler + */ + onChange?: (value: string) => void; +} + /** * Union type of all form schemas */ @@ -958,5 +1078,7 @@ export type FormComponentSchema = | CalendarSchema | InputOTPSchema | FormSchema - | LabelSchema; + | LabelSchema + | ComboboxSchema + | CommandSchema; diff --git a/packages/types/src/layout.ts b/packages/types/src/layout.ts index 5ac68395a..b89656555 100644 --- a/packages/types/src/layout.ts +++ b/packages/types/src/layout.ts @@ -396,6 +396,34 @@ export interface ResizablePanel { content: SchemaNode | SchemaNode[]; } +/** + * Aspect ratio component + */ +export interface AspectRatioSchema extends BaseSchema { + type: 'aspect-ratio'; + /** + * Aspect ratio (width / height) + * @default 16/9 + */ + ratio?: number; + /** + * Image URL to display + */ + image?: string; + /** + * Image alt text + */ + alt?: string; + /** + * Child components (alternative to image) + */ + body?: SchemaNode | SchemaNode[]; + /** + * Child components (alternative syntax) + */ + children?: SchemaNode | SchemaNode[]; +} + /** * Page layout component * Top-level container for a page route @@ -442,19 +470,6 @@ export type LayoutSchema = | TabsSchema | ScrollAreaSchema | ResizableSchema + | AspectRatioSchema | PageSchema; -/** - * Page container component - */ -export interface PageSchema extends BaseSchema { - type: 'page'; - /** - * Page title - */ - title?: string; - /** - * Child components - */ - children?: SchemaNode | SchemaNode[]; -} diff --git a/packages/types/src/navigation.ts b/packages/types/src/navigation.ts index 6bbb3e496..5afe3db2a 100644 --- a/packages/types/src/navigation.ts +++ b/packages/types/src/navigation.ts @@ -207,7 +207,11 @@ export interface PaginationSchema extends BaseSchema { /** * Current page (1-indexed) */ - page: number; + currentPage?: number; + /** + * Legacy page property + */ + page?: number; /** * Total number of pages */ @@ -233,6 +237,99 @@ export interface PaginationSchema extends BaseSchema { onPageChange?: (page: number) => void; } +/** + * Navigation menu item + */ +export interface NavigationMenuItem { + /** + * Item label + */ + label: string; + /** + * Item href/link + */ + href?: string; + /** + * Item description + */ + description?: string; + /** + * Item icon + */ + icon?: string; + /** + * Child items + */ + children?: NavigationMenuItem[]; +} + +/** + * Navigation menu component + */ +export interface NavigationMenuSchema extends BaseSchema { + type: 'navigation-menu'; + /** + * Navigation menu items + */ + items?: NavigationMenuItem[]; + /** + * Navigation menu orientation + * @default 'horizontal' + */ + orientation?: 'horizontal' | 'vertical'; +} + +/** + * Button group button + */ +export interface ButtonGroupButton { + /** + * Button label + */ + label: string; + /** + * Button variant + */ + variant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'; + /** + * Button size + */ + size?: 'default' | 'sm' | 'lg' | 'icon'; + /** + * Whether button is disabled + */ + disabled?: boolean; + /** + * Click handler + */ + onClick?: () => void; + /** + * Button CSS class + */ + className?: string; +} + +/** + * Button group component + */ +export interface ButtonGroupSchema extends BaseSchema { + type: 'button-group'; + /** + * Button group buttons + */ + buttons?: ButtonGroupButton[]; + /** + * Default button variant + * @default 'default' + */ + variant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'; + /** + * Default button size + * @default 'default' + */ + size?: 'default' | 'sm' | 'lg' | 'icon'; +} + /** * Union type of all navigation schemas */ @@ -240,4 +337,6 @@ export type NavigationSchema = | HeaderBarSchema | SidebarSchema | BreadcrumbSchema - | PaginationSchema; + | PaginationSchema + | NavigationMenuSchema + | ButtonGroupSchema; diff --git a/packages/types/src/overlay.ts b/packages/types/src/overlay.ts index 411c0f296..76167428b 100644 --- a/packages/types/src/overlay.ts +++ b/packages/types/src/overlay.ts @@ -411,6 +411,31 @@ export interface ContextMenuSchema extends BaseSchema { children: SchemaNode | SchemaNode[]; } +/** + * Menubar menu + */ +export interface MenubarMenu { + /** + * Menu label + */ + label: string; + /** + * Menu items + */ + items: MenuItem[]; +} + +/** + * Menubar component + */ +export interface MenubarSchema extends BaseSchema { + type: 'menubar'; + /** + * Menubar menus + */ + menus?: MenubarMenu[]; +} + /** * Union type of all overlay schemas */ @@ -423,4 +448,5 @@ export type OverlaySchema = | TooltipSchema | HoverCardSchema | DropdownMenuSchema - | ContextMenuSchema; + | ContextMenuSchema + | MenubarSchema; From af110361244fe70ff2daa4b48a04dc14b9ef5ea6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:12:27 +0000 Subject: [PATCH 11/11] Fix code review issues: backward compatibility and documentation consistency Fixed pagination renderer to handle both currentPage and legacy page properties. Fixed toggle-group documentation to use selectionType instead of type property and removed icons that weren't rendering. All 123 static pages build successfully and all 205 tests passing. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- docs/components/disclosure/toggle-group.mdx | 16 ++++++++-------- .../src/renderers/basic/pagination.tsx | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/components/disclosure/toggle-group.mdx b/docs/components/disclosure/toggle-group.mdx index 51df1513f..4425dcc01 100644 --- a/docs/components/disclosure/toggle-group.mdx +++ b/docs/components/disclosure/toggle-group.mdx @@ -12,11 +12,11 @@ The Toggle Group component allows users to toggle between multiple options. 7;