diff --git a/packages/web/__registry__/index.tsx b/packages/web/__registry__/index.tsx index b979dcd5..4dcbdcfc 100644 --- a/packages/web/__registry__/index.tsx +++ b/packages/web/__registry__/index.tsx @@ -2275,7 +2275,7 @@ export const Index: Record = { { path: 'registry/ui/mc-alert-dialog.tsx', content: - "'use client';\n\nimport * as React from 'react';\nimport { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/button';\n\nfunction McAlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {\n return ;\n}\n\nfunction McAlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {\n return ;\n}\n\nfunction McAlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {\n return ;\n}\n\nfunction McAlertDialogOverlay({ className, ...props }: AlertDialogPrimitive.Backdrop.Props) {\n return (\n \n );\n}\n\nfunction McAlertDialogContent({\n className,\n size = 'default',\n ...props\n}: AlertDialogPrimitive.Popup.Props & {\n size?: 'default' | 'sm';\n}) {\n return (\n \n \n \n \n );\n}\n\nfunction McAlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n \n );\n}\n\nfunction McAlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n \n );\n}\n\nfunction McAlertDialogMedia({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n \n );\n}\n\nfunction McAlertDialogTitle({\n className,\n media,\n icon,\n ...props\n}: React.ComponentProps & {\n media?: boolean;\n icon?: React.ReactNode;\n}) {\n return (\n \n {media && icon && {icon}}\n \n \n );\n}\n\nfunction McAlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n );\n}\n\nfunction McAlertDialogAction({ className, ...props }: React.ComponentProps) {\n return \n }\n />\n\n \n {\n onSelect?.(next);\n if (next) setOpen(false);\n }}\n />\n \n \n \n );\n}\n\nexport { McCalendar, McCalendarDayButton, McDatePicker };\n", + "'use client';\n\nimport * as React from 'react';\nimport { CalendarIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';\nimport { format } from 'date-fns';\nimport {\n DayPicker,\n getDefaultClassNames,\n type DayButton,\n type Locale,\n type OptionProps,\n type SelectProps,\n} from 'react-day-picker';\n\nimport { cn } from '@/lib/utils';\nimport { McButton, buttonVariants } from '@/components/ui/mc-button';\nimport { McPopover, McPopoverContent, McPopoverTrigger } from '@/registry/ui/mc-popover';\n\nfunction McCalendar({\n className,\n classNames,\n showOutsideDays = true,\n captionLayout = 'label',\n buttonVariant = 'secondary',\n locale,\n formatters,\n components,\n ...props\n}: React.ComponentProps & {\n buttonVariant?: React.ComponentProps['variant'];\n}) {\n const defaultClassNames = getDefaultClassNames();\n\n return (\n svg]:rotate-180`,\n String.raw`rtl:**:[.rdp-button\\_previous>svg]:rotate-180`,\n className\n )}\n captionLayout={captionLayout}\n locale={locale}\n formatters={{\n formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: 'short' }),\n ...formatters,\n }}\n classNames={{\n root: cn('w-fit', defaultClassNames.root),\n months: cn('relative flex flex-col gap-4 md:flex-row', defaultClassNames.months),\n month: cn('flex w-full flex-col gap-4', defaultClassNames.month),\n nav: cn(\n 'absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1',\n defaultClassNames.nav\n ),\n button_previous: cn(\n buttonVariants({ variant: buttonVariant }),\n 'size-(--cell-size) p-0 select-none aria-disabled:opacity-50',\n defaultClassNames.button_previous\n ),\n button_next: cn(\n buttonVariants({ variant: buttonVariant }),\n 'size-(--cell-size) p-0 select-none aria-disabled:opacity-50',\n defaultClassNames.button_next\n ),\n month_caption: cn(\n 'flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)',\n defaultClassNames.month_caption\n ),\n dropdowns: cn(\n 'flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium',\n defaultClassNames.dropdowns\n ),\n dropdown_root: cn(\n 'cn-calendar-dropdown-root relative flex items-center h-[34.304px] gap-[6px] px-[8.58px] pr-[4.29px] rounded-(--cell-radius) border border-(--Border,#E6E9FF) [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',\n defaultClassNames.dropdown_root\n ),\n dropdown: cn(\n 'absolute inset-0 bg-popover opacity-0 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',\n defaultClassNames.dropdown\n ),\n caption_label: cn(\n 'font-medium select-none',\n captionLayout === 'label'\n ? 'cn-calendar-caption text-sm'\n : 'cn-calendar-caption-label flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground',\n defaultClassNames.caption_label\n ),\n month_grid: cn('w-full border-collapse', defaultClassNames.month_grid),\n weekdays: cn('flex', defaultClassNames.weekdays),\n weekday: cn(\n 'flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-primary select-none',\n defaultClassNames.weekday\n ),\n week: cn('mt-2 flex w-full', defaultClassNames.week),\n week_number_header: cn('w-(--cell-size) select-none', defaultClassNames.week_number_header),\n week_number: cn(\n 'text-[0.8rem] text-muted-foreground select-none',\n defaultClassNames.week_number\n ),\n day: cn(\n 'group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)',\n props.showWeekNumber\n ? '[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)'\n : '[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)',\n defaultClassNames.day\n ),\n range_start: cn(\n 'relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted',\n defaultClassNames.range_start\n ),\n range_middle: cn('rounded-none', defaultClassNames.range_middle),\n range_end: cn(\n 'relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted',\n defaultClassNames.range_end\n ),\n today: cn('rounded-full bg-secondary text-secondary-foreground ', defaultClassNames.today),\n outside: cn(\n 'text-accent-foreground aria-selected:text-muted-foreground',\n defaultClassNames.outside\n ),\n disabled: cn('text-muted-foreground opacity-50', defaultClassNames.disabled),\n hidden: cn('invisible', defaultClassNames.hidden),\n ...classNames,\n }}\n components={{\n Root: ({ className, rootRef, ...props }) => {\n return
;\n },\n Chevron: ({ className, orientation, ...props }) => {\n if (orientation === 'left') {\n return ;\n }\n\n if (orientation === 'right') {\n return ;\n }\n\n return ;\n },\n DayButton: ({ ...props }) => ,\n WeekNumber: ({ children, ...props }) => {\n return (\n \n
\n {children}\n
\n \n );\n },\n Select: ({ className, ...props }: SelectProps) => {\n return (\n \n );\n },\n Option: ({ className, ...props }: OptionProps) => {\n return (\n \n );\n },\n ...components,\n }}\n {...props}\n />\n );\n}\n\nfunction McCalendarDayButton({\n className,\n day,\n modifiers,\n locale,\n ...props\n}: React.ComponentProps & { locale?: Partial }) {\n const defaultClassNames = getDefaultClassNames();\n\n const ref = React.useRef(null);\n React.useEffect(() => {\n if (modifiers.focused) ref.current?.focus();\n }, [modifiers.focused]);\n\n return (\n span]:text-xs [&>span]:opacity-70',\n defaultClassNames.day,\n className\n )}\n {...props}\n />\n );\n}\n\nfunction McDatePicker({\n label = 'Submission date',\n placeholder = 'Pick a date',\n selected,\n onSelect,\n className,\n triggerClassName,\n ...calendarProps\n}: Omit, 'mode' | 'selected' | 'onSelect'> & {\n label?: React.ReactNode;\n placeholder?: React.ReactNode;\n selected?: Date;\n onSelect?: (date?: Date) => void;\n triggerClassName?: string;\n}) {\n const [open, setOpen] = React.useState(false);\n\n return (\n
\n {label && {label}}\n\n \n \n \n {selected ? format(selected, 'PPP') : placeholder}\n \n\n \n \n }\n />\n\n \n {\n onSelect?.(next);\n if (next) setOpen(false);\n }}\n />\n \n \n
\n );\n}\n\nexport { McCalendar, McCalendarDayButton, McDatePicker };\n", type: 'registry:component', }, ], @@ -2483,7 +2483,7 @@ export const Index: Record = { { path: 'registry/ui/mc-carousel.tsx', content: - "'use client';\n\nimport * as React from 'react';\nimport useEmblaCarousel, { type UseEmblaCarouselType } from 'embla-carousel-react';\nimport { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/button';\n\ntype McCarouselApi = UseEmblaCarouselType[1];\ntype UseCarouselParameters = Parameters;\ntype CarouselOptions = UseCarouselParameters[0];\ntype CarouselPlugin = UseCarouselParameters[1];\n\ntype CarouselProps = {\n opts?: CarouselOptions;\n plugins?: CarouselPlugin;\n orientation?: 'horizontal' | 'vertical';\n setApi?: (api: McCarouselApi) => void;\n};\n\ntype CarouselContextProps = {\n carouselRef: ReturnType[0];\n api: ReturnType[1];\n scrollPrev: () => void;\n scrollNext: () => void;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n} & CarouselProps;\n\nconst McCarouselContext = React.createContext(null);\n\nfunction useMcCarousel() {\n const context = React.useContext(McCarouselContext);\n\n if (!context) {\n throw new Error('useMcCarousel must be used within a ');\n }\n\n return context;\n}\n\nfunction McCarousel({\n orientation = 'horizontal',\n opts,\n setApi,\n plugins,\n className,\n children,\n ...props\n}: React.ComponentProps<'div'> & CarouselProps) {\n const [carouselRef, api] = useEmblaCarousel(\n {\n ...opts,\n axis: orientation === 'horizontal' ? 'x' : 'y',\n },\n plugins\n );\n const [canScrollPrev, setCanScrollPrev] = React.useState(false);\n const [canScrollNext, setCanScrollNext] = React.useState(false);\n\n const onSelect = React.useCallback((api: McCarouselApi) => {\n if (!api) return;\n setCanScrollPrev(api.canScrollPrev());\n setCanScrollNext(api.canScrollNext());\n }, []);\n\n const scrollPrev = React.useCallback(() => {\n api?.scrollPrev();\n }, [api]);\n\n const scrollNext = React.useCallback(() => {\n api?.scrollNext();\n }, [api]);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n event.preventDefault();\n scrollPrev();\n } else if (event.key === 'ArrowRight') {\n event.preventDefault();\n scrollNext();\n }\n },\n [scrollPrev, scrollNext]\n );\n\n React.useEffect(() => {\n if (!api || !setApi) return;\n setApi(api);\n }, [api, setApi]);\n\n React.useEffect(() => {\n if (!api) return;\n onSelect(api);\n api.on('reInit', onSelect);\n api.on('select', onSelect);\n\n return () => {\n api?.off('select', onSelect);\n };\n }, [api, onSelect]);\n\n return (\n \n \n {children}\n
\n \n );\n}\n\nfunction McCarouselContent({ className, ...props }: React.ComponentProps<'div'>) {\n const { carouselRef, orientation } = useMcCarousel();\n\n return (\n
\n \n
\n );\n}\n\nfunction McCarouselItem({ className, children, ...props }: React.ComponentProps<'div'>) {\n const { orientation } = useMcCarousel();\n\n return (\n \n {/* Card shell matching Figma \"Wrapper\" spec exactly */}\n \n {children}\n \n \n );\n}\n\nfunction McCarouselPrevious({\n className,\n variant = 'outline',\n size = 'icon-sm',\n ...props\n}: React.ComponentProps) {\n const { orientation, scrollPrev, canScrollPrev } = useMcCarousel();\n\n return (\n \n \n Previous slide\n \n );\n}\n\nfunction McCarouselNext({\n className,\n variant = 'outline',\n size = 'icon-sm',\n ...props\n}: React.ComponentProps) {\n const { orientation, scrollNext, canScrollNext } = useMcCarousel();\n\n return (\n \n \n Next slide\n \n );\n}\n\nexport {\n type McCarouselApi,\n McCarousel,\n McCarouselContent,\n McCarouselItem,\n McCarouselPrevious,\n McCarouselNext,\n useMcCarousel,\n};\n", + "'use client';\n\nimport * as React from 'react';\nimport useEmblaCarousel, { type UseEmblaCarouselType } from 'embla-carousel-react';\nimport { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';\n\nimport { cn } from '@/lib/utils';\nimport { McButton } from '@/components/ui/mc-button';\n\ntype McCarouselApi = UseEmblaCarouselType[1];\ntype UseCarouselParameters = Parameters;\ntype CarouselOptions = UseCarouselParameters[0];\ntype CarouselPlugin = UseCarouselParameters[1];\n\ntype CarouselProps = {\n opts?: CarouselOptions;\n plugins?: CarouselPlugin;\n orientation?: 'horizontal' | 'vertical';\n setApi?: (api: McCarouselApi) => void;\n};\n\ntype CarouselContextProps = {\n carouselRef: ReturnType[0];\n api: ReturnType[1];\n scrollPrev: () => void;\n scrollNext: () => void;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n} & CarouselProps;\n\nconst McCarouselContext = React.createContext(null);\n\nfunction useMcCarousel() {\n const context = React.useContext(McCarouselContext);\n\n if (!context) {\n throw new Error('useMcCarousel must be used within a ');\n }\n\n return context;\n}\n\nfunction McCarousel({\n orientation = 'horizontal',\n opts,\n setApi,\n plugins,\n className,\n children,\n ...props\n}: React.ComponentProps<'div'> & CarouselProps) {\n const [carouselRef, api] = useEmblaCarousel(\n {\n ...opts,\n axis: orientation === 'horizontal' ? 'x' : 'y',\n },\n plugins\n );\n const [canScrollPrev, setCanScrollPrev] = React.useState(false);\n const [canScrollNext, setCanScrollNext] = React.useState(false);\n\n const onSelect = React.useCallback((api: McCarouselApi) => {\n if (!api) return;\n setCanScrollPrev(api.canScrollPrev());\n setCanScrollNext(api.canScrollNext());\n }, []);\n\n const scrollPrev = React.useCallback(() => {\n api?.scrollPrev();\n }, [api]);\n\n const scrollNext = React.useCallback(() => {\n api?.scrollNext();\n }, [api]);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'ArrowLeft') {\n event.preventDefault();\n scrollPrev();\n } else if (event.key === 'ArrowRight') {\n event.preventDefault();\n scrollNext();\n }\n },\n [scrollPrev, scrollNext]\n );\n\n React.useEffect(() => {\n if (!api || !setApi) return;\n setApi(api);\n }, [api, setApi]);\n\n React.useEffect(() => {\n if (!api) return;\n onSelect(api);\n api.on('reInit', onSelect);\n api.on('select', onSelect);\n\n return () => {\n api?.off('select', onSelect);\n };\n }, [api, onSelect]);\n\n return (\n \n \n {children}\n \n \n );\n}\n\nfunction McCarouselContent({ className, ...props }: React.ComponentProps<'div'>) {\n const { carouselRef, orientation } = useMcCarousel();\n\n return (\n
\n \n
\n );\n}\n\nfunction McCarouselItem({ className, children, ...props }: React.ComponentProps<'div'>) {\n const { orientation } = useMcCarousel();\n\n return (\n \n {/* Card shell matching Figma \"Wrapper\" spec exactly */}\n \n {children}\n \n \n );\n}\n\nfunction McCarouselPrevious({ className, ...props }: React.ComponentProps) {\n const { orientation, scrollPrev, canScrollPrev } = useMcCarousel();\n\n return (\n }\n className={cn(\n 'absolute size-8.5 touch-manipulation rounded-full border border-border bg-card p-2.5 shadow-[0px_0.81px_2.44px_0px_rgba(0,0,0,0.1)] [&_svg]:size-4',\n orientation === 'horizontal'\n ? 'inset-y-0 -left-12 my-auto'\n : '-top-12 -right-[-140px] rotate-90',\n\n className\n )}\n disabled={!canScrollPrev}\n onClick={scrollPrev}\n {...props}\n >\n Previous slide\n \n );\n}\n\nfunction McCarouselNext({ className, ...props }: React.ComponentProps) {\n const { orientation, scrollNext, canScrollNext } = useMcCarousel();\n\n return (\n }\n className={cn(\n 'absolute size-[34px] touch-manipulation rounded-full border-[1px] border-border bg-card p-[10px] [&_svg]:size-4',\n orientation === 'horizontal'\n ? 'inset-y-0 -right-12 my-auto'\n : '-bottom-12 -right-[-140px] rotate-90',\n className\n )}\n disabled={!canScrollNext}\n onClick={scrollNext}\n {...props}\n >\n Next slide\n \n );\n}\n\nexport {\n type McCarouselApi,\n McCarousel,\n McCarouselContent,\n McCarouselItem,\n McCarouselPrevious,\n McCarouselNext,\n useMcCarousel,\n};\n", type: 'registry:component', }, ], @@ -2752,13 +2752,13 @@ export const Index: Record = { { path: 'registry/examples/mc-alert-dialog-demo.tsx', content: - "import {\n McAlertDialog,\n McAlertDialogAction,\n McAlertDialogCancel,\n McAlertDialogContent,\n McAlertDialogDescription,\n McAlertDialogFooter,\n McAlertDialogHeader,\n McAlertDialogTitle,\n McAlertDialogTrigger,\n} from '@/registry/ui/mc-alert-dialog';\nimport { Button } from '@/components/ui/button';\n\nexport default function McAlertDialogDemo() {\n return (\n \n Show Dialog} />\n \n \n Are you absolutely sure?\n \n This action cannot be undone. This will permanently delete your account from our\n servers.\n \n \n \n Cancel\n Continue\n \n \n \n );\n}\n", + "import {\n McAlertDialog,\n McAlertDialogAction,\n McAlertDialogCancel,\n McAlertDialogContent,\n McAlertDialogDescription,\n McAlertDialogFooter,\n McAlertDialogHeader,\n McAlertDialogTitle,\n McAlertDialogTrigger,\n} from '@/registry/ui/mc-alert-dialog';\nimport { McButton } from '@/components/ui/mc-button';\n\nexport default function McAlertDialogDemo() {\n return (\n \n Show Dialog} />\n \n \n Are you absolutely sure?\n \n This action cannot be undone. This will permanently delete your account from our\n servers.\n \n \n \n Cancel\n Continue\n \n \n \n );\n}\n", type: 'registry:example', }, ], component: React.lazy(() => import('@/registry/examples/mc-alert-dialog-demo.tsx')), source: - "import {\n McAlertDialog,\n McAlertDialogAction,\n McAlertDialogCancel,\n McAlertDialogContent,\n McAlertDialogDescription,\n McAlertDialogFooter,\n McAlertDialogHeader,\n McAlertDialogTitle,\n McAlertDialogTrigger,\n} from '@/registry/ui/mc-alert-dialog';\nimport { Button } from '@/components/ui/button';\n\nexport default function McAlertDialogDemo() {\n return (\n \n Show Dialog} />\n \n \n Are you absolutely sure?\n \n This action cannot be undone. This will permanently delete your account from our\n servers.\n \n \n \n Cancel\n Continue\n \n \n \n );\n}\n", + "import {\n McAlertDialog,\n McAlertDialogAction,\n McAlertDialogCancel,\n McAlertDialogContent,\n McAlertDialogDescription,\n McAlertDialogFooter,\n McAlertDialogHeader,\n McAlertDialogTitle,\n McAlertDialogTrigger,\n} from '@/registry/ui/mc-alert-dialog';\nimport { McButton } from '@/components/ui/mc-button';\n\nexport default function McAlertDialogDemo() {\n return (\n \n Show Dialog} />\n \n \n Are you absolutely sure?\n \n This action cannot be undone. This will permanently delete your account from our\n servers.\n \n \n \n Cancel\n Continue\n \n \n \n );\n}\n", }, 'mc-alert-demo': { name: 'mc-alert-demo', @@ -2800,13 +2800,13 @@ export const Index: Record = { { path: 'registry/examples/mc-tooltip-demo.tsx', content: - 'import { Button } from \'@/components/ui/button\';\nimport { McTooltip, McTooltipContent, McTooltipTrigger } from \'../ui/mc-tooltip\';\n\nexport default function McTooltipDemo() {\n return (\n \n Hover} />\n \n \n );\n}\n', + 'import { McButton } from \'@/components/ui/mc-button\';\nimport { McTooltip, McTooltipContent, McTooltipTrigger } from \'../ui/mc-tooltip\';\n\nexport default function McTooltipDemo() {\n return (\n \n Hover} />\n \n \n );\n}\n', type: 'registry:example', }, ], component: React.lazy(() => import('@/registry/examples/mc-tooltip-demo.tsx')), source: - 'import { Button } from \'@/components/ui/button\';\nimport { McTooltip, McTooltipContent, McTooltipTrigger } from \'../ui/mc-tooltip\';\n\nexport default function McTooltipDemo() {\n return (\n \n Hover} />\n \n \n );\n}\n', + 'import { McButton } from \'@/components/ui/mc-button\';\nimport { McTooltip, McTooltipContent, McTooltipTrigger } from \'../ui/mc-tooltip\';\n\nexport default function McTooltipDemo() {\n return (\n \n Hover} />\n \n \n );\n}\n', }, 'mc-popover-demo': { name: 'mc-popover-demo', @@ -2832,13 +2832,13 @@ export const Index: Record = { { path: 'registry/examples/mc-dropdown-menu-demo.tsx', content: - '\'use client\';\n\nimport { Button } from \'@/components/ui/button\';\nimport {\n McDropdownMenu,\n McDropdownMenuContent,\n McDropdownMenuGroup,\n McDropdownMenuItem,\n McDropdownMenuLabel,\n McDropdownMenuPortal,\n McDropdownMenuSeparator,\n McDropdownMenuSub,\n McDropdownMenuSubContent,\n McDropdownMenuSubTrigger,\n McDropdownMenuTrigger,\n} from \'@/registry/ui/mc-dropdown-menu\';\n\nexport default function McDropdownMenuDemo() {\n return (\n \n \n Open\n \n }\n />\n \n \n My Account\n Profile\n Settings\n \n \n \n Team\n \n Invite users\n \n \n Email\n Message\n \n More...\n \n \n \n \n \n \n Log out\n \n \n \n );\n}\n', + '\'use client\';\n\nimport { McButton } from \'@/components/ui/mc-button\';\nimport {\n McDropdownMenu,\n McDropdownMenuContent,\n McDropdownMenuGroup,\n McDropdownMenuItem,\n McDropdownMenuLabel,\n McDropdownMenuPortal,\n McDropdownMenuSeparator,\n McDropdownMenuSub,\n McDropdownMenuSubContent,\n McDropdownMenuSubTrigger,\n McDropdownMenuTrigger,\n} from \'@/registry/ui/mc-dropdown-menu\';\n\nexport default function McDropdownMenuDemo() {\n return (\n \n \n Open\n \n }\n />\n \n \n My Account\n Profile\n Settings\n \n \n \n Team\n \n Invite users\n \n \n Email\n Message\n \n More...\n \n \n \n \n \n \n Log out\n \n \n \n );\n}\n', type: 'registry:example', }, ], component: React.lazy(() => import('@/registry/examples/mc-dropdown-menu-demo.tsx')), source: - '\'use client\';\n\nimport { Button } from \'@/components/ui/button\';\nimport {\n McDropdownMenu,\n McDropdownMenuContent,\n McDropdownMenuGroup,\n McDropdownMenuItem,\n McDropdownMenuLabel,\n McDropdownMenuPortal,\n McDropdownMenuSeparator,\n McDropdownMenuSub,\n McDropdownMenuSubContent,\n McDropdownMenuSubTrigger,\n McDropdownMenuTrigger,\n} from \'@/registry/ui/mc-dropdown-menu\';\n\nexport default function McDropdownMenuDemo() {\n return (\n \n \n Open\n \n }\n />\n \n \n My Account\n Profile\n Settings\n \n \n \n Team\n \n Invite users\n \n \n Email\n Message\n \n More...\n \n \n \n \n \n \n Log out\n \n \n \n );\n}\n', + '\'use client\';\n\nimport { McButton } from \'@/components/ui/mc-button\';\nimport {\n McDropdownMenu,\n McDropdownMenuContent,\n McDropdownMenuGroup,\n McDropdownMenuItem,\n McDropdownMenuLabel,\n McDropdownMenuPortal,\n McDropdownMenuSeparator,\n McDropdownMenuSub,\n McDropdownMenuSubContent,\n McDropdownMenuSubTrigger,\n McDropdownMenuTrigger,\n} from \'@/registry/ui/mc-dropdown-menu\';\n\nexport default function McDropdownMenuDemo() {\n return (\n \n \n Open\n \n }\n />\n \n \n My Account\n Profile\n Settings\n \n \n \n Team\n \n Invite users\n \n \n Email\n Message\n \n More...\n \n \n \n \n \n \n Log out\n \n \n \n );\n}\n', }, 'mc-context-menu-demo': { name: 'mc-context-menu-demo', diff --git a/packages/web/components/ThemeSwitcher.tsx b/packages/web/components/ThemeSwitcher.tsx index ae8ab9b7..1c84c333 100644 --- a/packages/web/components/ThemeSwitcher.tsx +++ b/packages/web/components/ThemeSwitcher.tsx @@ -4,13 +4,12 @@ import * as React from 'react'; import { Check, Palette } from 'lucide-react'; import { useColorTheme, ThemePalette } from './ColorThemeProvider'; -import { Button } from '@/components/ui/button'; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; + McDropdownMenu, + McDropdownMenuContent, + McDropdownMenuItem, + McDropdownMenuTrigger, +} from '@/components/ui/mc-dropdown-menu'; import { cn } from '@/lib/utils'; const themes: { name: string; value: ThemePalette; color: string }[] = [ @@ -30,22 +29,14 @@ export function ThemeSwitcher() { }, []); return ( - - - - Toggle Color Palette - - } - /> - + + + + Toggle Color Palette + + {themes.map((t) => ( - setColorTheme(t.value)} className="flex items-center justify-between cursor-pointer rounded-lg my-0.5" @@ -65,9 +56,9 @@ export function ThemeSwitcher() { {mounted && colorTheme === t.value && } - + ))} - - + + ); } diff --git a/packages/web/components/sections/BackgroundBlur.tsx b/packages/web/components/sections/BackgroundBlur.tsx index 7208161a..7a64e58d 100644 --- a/packages/web/components/sections/BackgroundBlur.tsx +++ b/packages/web/components/sections/BackgroundBlur.tsx @@ -17,24 +17,20 @@ function BackgroundBlur() { {/* The Staging Area */} -
+
{/* Grid Pattern */} -
+
- {/* Top Left: Primary Circle */} -
- - {/* Bottom Right: Secondary Rectangle */} -
- - {/* Center Stripe: Accent */} -
+ {/* Vivid forms placed UNDER the glass cards so the blur is clearly visible */} +
+
+
{blurs.map((b) => (
{/* Inner Pill for Text Legibility */}
diff --git a/packages/web/components/sections/Blur.tsx b/packages/web/components/sections/Blur.tsx index 1fd35f31..47f0b4a7 100644 --- a/packages/web/components/sections/Blur.tsx +++ b/packages/web/components/sections/Blur.tsx @@ -20,7 +20,7 @@ function Blur() { {blurs.map((b) => (
{/* Element Container */}
diff --git a/packages/web/components/sections/Colors.tsx b/packages/web/components/sections/Colors.tsx index 33d042d8..8c3ffead 100644 --- a/packages/web/components/sections/Colors.tsx +++ b/packages/web/components/sections/Colors.tsx @@ -1,4 +1,5 @@ import { CheckCircle2, AlertTriangle, Info, XCircle } from 'lucide-react'; +import { McCard } from '@/components/ui/mc-card'; // Mapping of prefixes and steps to explicit Tailwind class names // This ensures Tailwind JIT can scan the full strings at build time. @@ -202,9 +203,9 @@ function Colors() {
{/* Core Ramps */} {colorRamps.map((ramp) => ( -

{ramp.name}

@@ -224,11 +225,11 @@ function Colors() { ); })}
-
+ ))} {/* Gradients */} -
+

Gradients

--*-gradient @@ -239,10 +240,10 @@ function Colors() { title="--it-gradient" />
-
+ {/* Neutrals */} -
+

Neutrals

--neutral-* @@ -257,10 +258,10 @@ function Colors() { title="--neutral-white" />
-
+ {/* Semantic Colors */} -
+

Semantic

@@ -285,7 +286,7 @@ function Colors() { Info
-
+
); diff --git a/packages/web/components/sections/Hero.tsx b/packages/web/components/sections/Hero.tsx index f68cd190..4f60b49b 100644 --- a/packages/web/components/sections/Hero.tsx +++ b/packages/web/components/sections/Hero.tsx @@ -2,7 +2,8 @@ import Link from 'next/link'; import { ArrowRight, Terminal, GitFork, Check, Copy } from 'lucide-react'; -import { Button } from '@/components/ui/button'; +import { McButton } from '@/components/ui/mc-button'; +import { McCard } from '@/components/ui/mc-card'; import { useState } from 'react'; function Hero() { @@ -35,35 +36,34 @@ function Hero() { {/* Call to Actions */}
-
{/* High-End Terminal CLI Snippet */} -
+
@@ -76,7 +76,7 @@ function Hero() { {copied ? : }
-
+ ); } diff --git a/packages/web/components/sections/Shadow.tsx b/packages/web/components/sections/Shadow.tsx index 6ebd89d7..0b841ed8 100644 --- a/packages/web/components/sections/Shadow.tsx +++ b/packages/web/components/sections/Shadow.tsx @@ -25,7 +25,7 @@ function Shadow() { className="flex flex-col items-center gap-4 p-6 rounded-2xl border border-border bg-surface/30" >
{s.name}
diff --git a/packages/web/components/sections/Showcase.tsx b/packages/web/components/sections/Showcase.tsx index 954eb37f..8f8d4c58 100644 --- a/packages/web/components/sections/Showcase.tsx +++ b/packages/web/components/sections/Showcase.tsx @@ -1,214 +1,362 @@ +'use client'; + +import * as React from 'react'; + +import { McButton } from '@/components/ui/mc-button'; +import { McCard } from '@/registry/ui/mc-card'; +import { McInput, McInputButton } from '@/registry/ui/mc-input'; +import { McSwitch } from '@/registry/ui/mc-switch'; import { - AlertCircle, - AlertTriangle, - BarChart3, - CheckCircle2, - ChevronRight, - Info, - LayoutTemplate, - MousePointerClick, - PanelLeftClose, - Search, - Settings, - ShieldAlert, -} from 'lucide-react'; - -export function Showcase() { + McAvatar, + McAvatarImage, + McAvatarFallback, + McAvatarGroup, + McAvatarGroupCount, + McAvatarBadge, +} from '@/registry/ui/mc-avatar'; +import { McAlert } from '@/registry/ui/mc-alert'; +import { McBadge } from '@/registry/ui/mc-badge'; +import { McTabs, McTabsList, McTabsTrigger } from '@/registry/ui/mc-tabs'; +import { + McSelect, + McSelectContent, + McSelectGroup, + McSelectItem, + McSelectTrigger, + McSelectValue, +} from '@/registry/ui/mc-select'; +import McSonner, { toast } from '@/registry/ui/mc-sonner'; + +const tabs = [ + { value: 'form', label: 'Form' }, + { value: 'feedback', label: 'Feedback' }, +] as const; + +const TEAM = [ + { value: 'olivia', name: 'Olivia Rhye', handle: '@olivia', color: '#FDE68A' }, + { value: 'phoenix', name: 'Phoenix Baker', handle: '@phoenix', color: '#BFDBFE' }, + { value: 'lana', name: 'Lana Steiner', handle: '@lana', color: '#DDD6FE' }, + { value: 'demi', name: 'Demi Wilkinson', handle: '@demi', color: '#FBCFE8' }, +]; + +function MiniAvatar({ name, color }: { name: string; color: string }) { + const initials = name + .split(' ') + .map((part) => part[0]) + .join('') + .slice(0, 2) + .toUpperCase(); + return ( -
- {/* Dashed background grid (2026 Developer Aesthetic) */} -
- -
-

The Variable Anatomy

-

- Every single semantic variable mapped. Change the theme in the navigation bar to see the - entire grid adapt instantly with perfect contrast ratios + + {initials} + + ); +} + +function DemoCard({ + token, + title, + desc, + wide, + className, + children, +}: { + token: string; + title: string; + desc?: string; + wide?: boolean; + className?: string; + children: React.ReactNode; +}) { + return ( + +

+

{title}

+ {token} +
+ {desc ?

{desc}

: null} + {children} + + ); +} + +function Showcase() { + const [tab, setTab] = React.useState('form'); + const [notify, setNotify] = React.useState(true); + const [show, setShow] = React.useState(false); + const [member, setMember] = React.useState(null); + + const selectedMember = TEAM.find((m) => m.value === member) ?? null; + + return ( +
+ {/* Section header */} +
+

Showcase

+

+ Interactive previews of some mcoli-ui primitive, themed and ready to ship.

- {/* BENTO GRID: Fully responsive, explicitly labeled UI tokens */} -
- {/* 1. Base UI Box */} -
-
-
- Base UI -
- --background & --surface -
-
-
- - -
- --input - --ring -
-
-
+ {/* Category tabs */} + setTab(String(value))}> +
+ + {tabs.map((t) => ( + + {t.label} + + ))} +
+
- {/* 2. Action Tokens */} -
-
-
- Action States -
-
-
-
-
- - - --primary - -
-
- - - --secondary - + {/* PANELS */} +
+ {tab === 'form' && ( +
+ +
+ + Subscribe + + } + /> + + setShow((s) => !s)}> + {show ? 'Hide' : 'Show'} + + } + />
-
- - - --accent - + + + +
+
+ + Primary + + + Secondary + + + Tertiary + + + Link + +
+
+ + Small + + + Large + + + Saving + +
-
- - - --muted - + + + +
+
+

Push notifications

+

Get told when a new theme drops.

+
+ setNotify(Boolean(checked))} + />
-
-
-
+ - {/* 3. Semantic Feedback */} -
-
-
- Semantic States -
-
-
-
- - Completed - --success -
-
- - Warning - --warning -
-
- - Destructive - --destructive -
-
- - Info - --info -
+ +
+ + + ) : null + } + > + + {selectedMember ? ( + {selectedMember.name} + ) : null} + + + + + {TEAM.map((m) => ( + } + supportingText={m.handle} + > + {m.name} + + ))} + + + +
+
-
+ )} - {/* 4. Elevations (Card vs Popover) */} -
-
-
- Elevation & Surfaces -
-
-
- {/* Card */} -
- - --card & --card-foreground - -

Standard Card

-

- Base elevation for standard content blocks. -

-
-
- {/* Popover */} -
- - --popover & --popover-foreground - -

- Dropdown Menu -

-

Highest elevation for floating elements.

-
-
+ {tab === 'feedback' && ( +
+ +
+ + +
-
-
-
+ - {/* 5. Data Viz & Sidebar */} -
-
-
- Data & Sidebar -
-
+ +
+ toast('Event created')}> + Simple + + toast.success('Saved', { description: 'Your changes are live.' })} + > + Success + + + toast.warning('Low storage', { description: 'You are almost out of space.' }) + } + > + Warning + + + toast.error('Upload failed', { + description: 'Please try again.', + action: { label: 'Retry', onClick: () => {} }, + }) + } + > + Error + +
+
- {/* Charts Row */} -
- - --chart-1 to --chart-5 - -
- {[ - 'var(--chart-1)', - 'var(--chart-2)', - 'var(--chart-3)', - 'var(--chart-4)', - 'var(--chart-5)', - ].map((color, i) => ( -
- ))} -
-
+ +
+ + + CN + + + + ER + + + + + + CN + + + + LR + + + + ER + + +3 + +
+
- {/* Sidebar Row */} -
-
- --sidebar (bg & text) - -
-
-
--sidebar-primary -
-
-
--sidebar-accent -
+ +
+ + Primary + + + Secondary + + + Ghost + + + Outline + + + Destructive + +
+
-
+ )}
+ +
); } + +export { Showcase }; diff --git a/packages/web/components/sections/TextStyles.tsx b/packages/web/components/sections/TextStyles.tsx index 25d6cf18..9e376dca 100644 --- a/packages/web/components/sections/TextStyles.tsx +++ b/packages/web/components/sections/TextStyles.tsx @@ -1,3 +1,5 @@ +import { McCard } from '@/components/ui/mc-card'; + function TextStyles() { return (
@@ -10,7 +12,7 @@ function TextStyles() {
{/* Headers */} -
+

Headings

header-* @@ -32,10 +34,10 @@ function TextStyles() {
Header XS
-
+ {/* Paragraphs */} -
+

Paragraphs

.paragraph-* @@ -62,7 +64,7 @@ function TextStyles() { 12px / 18px
-
+
); diff --git a/packages/web/components/ui/button.tsx b/packages/web/components/ui/button.tsx deleted file mode 100644 index d7d013cf..00000000 --- a/packages/web/components/ui/button.tsx +++ /dev/null @@ -1,60 +0,0 @@ -'use client'; - -import { Button as ButtonPrimitive } from '@base-ui/react/button'; -import { cva, type VariantProps } from 'class-variance-authority'; - -import { cn } from '@/lib/utils'; - -const buttonVariants = cva( - "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", - { - variants: { - variant: { - default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80', - outline: - 'border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50', - secondary: - 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground', - ghost: - 'hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50', - destructive: - 'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40', - link: 'text-primary underline-offset-4 hover:underline', - }, - size: { - default: - 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2', - xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3", - sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5", - lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3', - icon: 'size-8', - 'icon-xs': - "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3", - 'icon-sm': - 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg', - 'icon-lg': 'size-9', - }, - }, - defaultVariants: { - variant: 'default', - size: 'default', - }, - } -); - -function Button({ - className, - variant = 'default', - size = 'default', - ...props -}: ButtonPrimitive.Props & VariantProps) { - return ( - - ); -} - -export { Button, buttonVariants }; diff --git a/packages/web/components/ui/input-group.tsx b/packages/web/components/ui/input-group.tsx deleted file mode 100644 index b3c79c8d..00000000 --- a/packages/web/components/ui/input-group.tsx +++ /dev/null @@ -1,136 +0,0 @@ -'use client'; - -import * as React from 'react'; -import { cva, type VariantProps } from 'class-variance-authority'; - -import { cn } from '@/lib/utils'; -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Textarea } from '@/components/ui/textarea'; - -function InputGroup({ className, ...props }: React.ComponentProps<'div'>) { - return
; -} - -const inputGroupAddonVariants = cva( - "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4", - { - variants: { - align: { - 'inline-start': 'order-first pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem]', - 'inline-end': 'order-last pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem]', - 'block-start': - 'order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2', - 'block-end': - 'order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2', - }, - }, - defaultVariants: { - align: 'inline-start', - }, - } -); - -function InputGroupAddon({ - className, - align = 'inline-start', - ...props -}: React.ComponentProps<'div'> & VariantProps) { - return ( -
{ - if ((e.target as HTMLElement).closest('button')) { - return; - } - e.currentTarget.parentElement?.querySelector('input')?.focus(); - }} - {...props} - /> - ); -} - -const inputGroupButtonVariants = cva('flex items-center gap-2 text-sm shadow-none', { - variants: { - size: { - xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5", - sm: '', - 'icon-xs': 'size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0', - 'icon-sm': 'size-8 p-0 has-[>svg]:p-0', - }, - }, - defaultVariants: { - size: 'xs', - }, -}); - -function InputGroupButton({ - className, - type = 'button', - variant = 'ghost', - size = 'xs', - ...props -}: Omit, 'size' | 'type'> & - VariantProps & { - type?: 'button' | 'submit' | 'reset'; - }) { - return ( -