Revert "Unify workspace dropdowns; Update layouts (#458)"

This reverts commit 4bc8448a1d.
This commit is contained in:
gbuomprisco
2026-03-11 14:47:47 +08:00
parent 4bc8448a1d
commit 4912e402a3
530 changed files with 11182 additions and 14382 deletions

View File

@@ -120,7 +120,9 @@ export function AlertDialogStory() {
const generateCode = () => {
let code = `<AlertDialog>\n`;
code += ` <AlertDialogTrigger render={<Button variant="${controls.triggerVariant}">${controls.triggerText}</Button>} />\n`;
code += ` <AlertDialogTrigger asChild>\n`;
code += ` <Button variant="${controls.triggerVariant}">${controls.triggerText}</Button>\n`;
code += ` </AlertDialogTrigger>\n`;
code += ` <AlertDialogContent>\n`;
code += ` <AlertDialogHeader>\n`;
@@ -177,14 +179,11 @@ export function AlertDialogStory() {
const renderPreview = () => {
return (
<AlertDialog>
<AlertDialogTrigger
render={
<Button variant={controls.triggerVariant}>
{controls.triggerText}
</Button>
}
/>
<AlertDialogTrigger asChild>
<Button variant={controls.triggerVariant}>
{controls.triggerText}
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
{controls.withIcon ? (
@@ -342,11 +341,11 @@ export function AlertDialogStory() {
<CardContent className="space-y-4">
<div className="flex flex-wrap gap-3">
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="destructive" size="sm" />}
>
<Trash2 className="mr-2 h-4 w-4" />
Delete Item
<AlertDialogTrigger asChild>
<Button variant="destructive" size="sm">
<Trash2 className="mr-2 h-4 w-4" />
Delete Item
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -371,9 +370,11 @@ export function AlertDialogStory() {
</AlertDialog>
<AlertDialog>
<AlertDialogTrigger render={<Button variant="outline" />}>
<LogOut className="mr-2 h-4 w-4" />
Sign Out
<AlertDialogTrigger asChild>
<Button variant="outline">
<LogOut className="mr-2 h-4 w-4" />
Sign Out
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -396,9 +397,11 @@ export function AlertDialogStory() {
</AlertDialog>
<AlertDialog>
<AlertDialogTrigger render={<Button variant="outline" />}>
<UserX className="mr-2 h-4 w-4" />
Remove User
<AlertDialogTrigger asChild>
<Button variant="outline">
<UserX className="mr-2 h-4 w-4" />
Remove User
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -435,9 +438,11 @@ export function AlertDialogStory() {
<CardContent className="space-y-4">
<div className="flex flex-wrap gap-3">
<AlertDialog>
<AlertDialogTrigger render={<Button variant="outline" />}>
<Archive className="mr-2 h-4 w-4" />
Archive Project
<AlertDialogTrigger asChild>
<Button variant="outline">
<Archive className="mr-2 h-4 w-4" />
Archive Project
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -460,9 +465,11 @@ export function AlertDialogStory() {
</AlertDialog>
<AlertDialog>
<AlertDialogTrigger render={<Button />}>
<Download className="mr-2 h-4 w-4" />
Export Data
<AlertDialogTrigger asChild>
<Button>
<Download className="mr-2 h-4 w-4" />
Export Data
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -486,9 +493,11 @@ export function AlertDialogStory() {
</AlertDialog>
<AlertDialog>
<AlertDialogTrigger render={<Button variant="outline" />}>
<RefreshCw className="mr-2 h-4 w-4" />
Reset Settings
<AlertDialogTrigger asChild>
<Button variant="outline">
<RefreshCw className="mr-2 h-4 w-4" />
Reset Settings
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -526,11 +535,11 @@ export function AlertDialogStory() {
<div className="space-y-3">
<h4 className="text-sm font-semibold">Error/Destructive</h4>
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="destructive" size="sm" />}
>
<Trash2 className="mr-2 h-4 w-4" />
Delete Forever
<AlertDialogTrigger asChild>
<Button variant="destructive" size="sm">
<Trash2 className="mr-2 h-4 w-4" />
Delete Forever
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -558,11 +567,11 @@ export function AlertDialogStory() {
<div className="space-y-3">
<h4 className="text-sm font-semibold">Warning</h4>
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline" size="sm" />}
>
<AlertTriangle className="mr-2 h-4 w-4" />
Unsaved Changes
<AlertDialogTrigger asChild>
<Button variant="outline" size="sm">
<AlertTriangle className="mr-2 h-4 w-4" />
Unsaved Changes
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -588,11 +597,11 @@ export function AlertDialogStory() {
<div className="space-y-3">
<h4 className="text-sm font-semibold">Info</h4>
<AlertDialog>
<AlertDialogTrigger
render={<Button variant="outline" size="sm" />}
>
<Share className="mr-2 h-4 w-4" />
Share Publicly
<AlertDialogTrigger asChild>
<Button variant="outline" size="sm">
<Share className="mr-2 h-4 w-4" />
Share Publicly
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
@@ -618,9 +627,11 @@ export function AlertDialogStory() {
<div className="space-y-3">
<h4 className="text-sm font-semibold">Success</h4>
<AlertDialog>
<AlertDialogTrigger render={<Button size="sm" />}>
<Download className="mr-2 h-4 w-4" />
Complete Setup
<AlertDialogTrigger asChild>
<Button size="sm">
<Download className="mr-2 h-4 w-4" />
Complete Setup
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>

View File

@@ -33,6 +33,7 @@ interface ButtonControls {
loading: boolean;
withIcon: boolean;
fullWidth: boolean;
asChild: boolean;
}
const variantOptions = [
@@ -67,6 +68,7 @@ export function ButtonStory() {
loading: false,
withIcon: false,
fullWidth: false,
asChild: false,
});
const generateCode = () => {
@@ -75,12 +77,14 @@ export function ButtonStory() {
variant: controls.variant,
size: controls.size,
disabled: controls.disabled,
asChild: controls.asChild,
className: controls.fullWidth ? 'w-full' : '',
},
{
variant: 'default',
size: 'default',
disabled: false,
asChild: false,
className: '',
},
);
@@ -190,6 +194,15 @@ export function ButtonStory() {
onCheckedChange={(checked) => updateControl('fullWidth', checked)}
/>
</div>
<div className="flex items-center justify-between">
<Label htmlFor="asChild">As Child</Label>
<Switch
id="asChild"
checked={controls.asChild}
onCheckedChange={(checked) => updateControl('asChild', checked)}
/>
</div>
</>
);

View File

@@ -276,11 +276,11 @@ export default function CalendarStory() {
<Card>
<CardContent className="flex justify-center pt-6">
<Popover>
<PopoverTrigger
render={<Button variant="outline" className="justify-start" />}
>
<CalendarIcon className="mr-2 h-4 w-4" />
Pick a date
<PopoverTrigger asChild>
<Button variant="outline" className="justify-start">
<CalendarIcon className="mr-2 h-4 w-4" />
Pick a date
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar

View File

@@ -320,12 +320,10 @@ export function CardButtonStory() {
</thead>
<tbody>
<tr className="border-b">
<td className="p-3 font-mono text-sm">render</td>
<td className="p-3 font-mono text-sm">
React.ReactElement
</td>
<td className="p-3 font-mono text-sm">-</td>
<td className="p-3">Compose with a custom element</td>
<td className="p-3 font-mono text-sm">asChild</td>
<td className="p-3 font-mono text-sm">boolean</td>
<td className="p-3 font-mono text-sm">false</td>
<td className="p-3">Render as child element</td>
</tr>
<tr className="border-b">
<td className="p-3 font-mono text-sm">className</td>

View File

@@ -139,8 +139,8 @@ export function DialogStory() {
});
let code = `<Dialog>\n`;
code += ` <DialogTrigger render={<Button variant="${controls.triggerVariant}" />}>\n`;
code += ` ${controls.triggerText}\n`;
code += ` <DialogTrigger asChild>\n`;
code += ` <Button variant="${controls.triggerVariant}">${controls.triggerText}</Button>\n`;
code += ` </DialogTrigger>\n`;
code += ` <DialogContent${contentPropsString}>\n`;
code += ` <DialogHeader>\n`;
@@ -182,8 +182,8 @@ export function DialogStory() {
if (controls.withFooter) {
code += ` <DialogFooter>\n`;
code += ` <DialogClose render={<Button variant="outline" />}>\n`;
code += ` Cancel\n`;
code += ` <DialogClose asChild>\n`;
code += ` <Button variant="outline">Cancel</Button>\n`;
code += ` </DialogClose>\n`;
code += ` <Button>Save Changes</Button>\n`;
code += ` </DialogFooter>\n`;
@@ -198,8 +198,10 @@ export function DialogStory() {
const renderPreview = () => {
return (
<Dialog>
<DialogTrigger render={<Button variant={controls.triggerVariant} />}>
{controls.triggerText}
<DialogTrigger asChild>
<Button variant={controls.triggerVariant}>
{controls.triggerText}
</Button>
</DialogTrigger>
<DialogContent
className={cn(
@@ -269,8 +271,8 @@ export function DialogStory() {
{controls.withFooter && (
<DialogFooter>
<DialogClose render={<Button variant="outline" />}>
Cancel
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save Changes</Button>
</DialogFooter>
@@ -389,9 +391,11 @@ export function DialogStory() {
<CardContent className="space-y-4">
<div className="flex flex-wrap gap-3">
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
<Info className="mr-2 h-4 w-4" />
Info Dialog
<DialogTrigger asChild>
<Button variant="outline">
<Info className="mr-2 h-4 w-4" />
Info Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
@@ -408,15 +412,19 @@ export function DialogStory() {
</p>
</div>
<DialogFooter>
<DialogClose render={<Button />}>Got it</DialogClose>
<DialogClose asChild>
<Button>Got it</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger render={<Button />}>
<Edit className="mr-2 h-4 w-4" />
Edit Profile
<DialogTrigger asChild>
<Button>
<Edit className="mr-2 h-4 w-4" />
Edit Profile
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
@@ -448,8 +456,8 @@ export function DialogStory() {
</div>
</div>
<DialogFooter>
<DialogClose render={<Button variant="outline" />}>
Cancel
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save Changes</Button>
</DialogFooter>
@@ -457,9 +465,11 @@ export function DialogStory() {
</Dialog>
<Dialog>
<DialogTrigger render={<Button variant="secondary" />}>
<Settings className="mr-2 h-4 w-4" />
Settings
<DialogTrigger asChild>
<Button variant="secondary">
<Settings className="mr-2 h-4 w-4" />
Settings
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
@@ -489,8 +499,8 @@ export function DialogStory() {
</div>
</div>
<DialogFooter>
<DialogClose render={<Button variant="outline" />}>
Cancel
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
@@ -508,8 +518,10 @@ export function DialogStory() {
<CardContent className="space-y-4">
<div className="flex flex-wrap gap-3">
<Dialog>
<DialogTrigger render={<Button variant="outline" size="sm" />}>
Small Dialog
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Small Dialog
</Button>
</DialogTrigger>
<DialogContent className="max-w-md">
<DialogHeader>
@@ -524,14 +536,16 @@ export function DialogStory() {
</p>
</div>
<DialogFooter>
<DialogClose render={<Button />}>Close</DialogClose>
<DialogClose asChild>
<Button>Close</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Large Dialog
<DialogTrigger asChild>
<Button variant="outline">Large Dialog</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader>
@@ -557,8 +571,8 @@ export function DialogStory() {
</div>
</div>
<DialogFooter>
<DialogClose render={<Button variant="outline" />}>
Cancel
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>Save</Button>
</DialogFooter>
@@ -576,9 +590,11 @@ export function DialogStory() {
<CardContent className="space-y-4">
<div className="flex flex-wrap gap-3">
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
<Image className="mr-2 h-4 w-4" />
Image Gallery
<DialogTrigger asChild>
<Button variant="outline">
<Image className="mr-2 h-4 w-4" />
Image Gallery
</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader>
@@ -611,9 +627,11 @@ export function DialogStory() {
</Dialog>
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
<MessageSquare className="mr-2 h-4 w-4" />
Feedback
<DialogTrigger asChild>
<Button variant="outline">
<MessageSquare className="mr-2 h-4 w-4" />
Feedback
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
@@ -650,8 +668,8 @@ export function DialogStory() {
</div>
</div>
<DialogFooter>
<DialogClose render={<Button variant="outline" />}>
Cancel
<DialogClose asChild>
<Button variant="outline">Cancel</Button>
</DialogClose>
<Button>
<MessageSquare className="mr-2 h-4 w-4" />
@@ -718,8 +736,8 @@ export function DialogStory() {
<div>
<h4 className="mb-3 text-lg font-semibold">DialogTrigger</h4>
<p className="text-muted-foreground mb-3 text-sm">
The element that opens the dialog. Use the render prop to compose
with a custom element.
The element that opens the dialog. Use asChild prop to render as
child element.
</p>
</div>

View File

@@ -2,7 +2,7 @@
import { useEffect, useRef, useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useRouter } from 'next/navigation';
import { Code2, FileText, Search } from 'lucide-react';
@@ -35,7 +35,6 @@ export function DocsSidebar({
selectedCategory,
}: DocsSidebarProps) {
const [searchQuery, setSearchQuery] = useState('');
const searchParams = useSearchParams();
const router = useRouter();
const filteredComponents = COMPONENTS_REGISTRY.filter((c) =>
@@ -51,21 +50,21 @@ export function DocsSidebar({
.sort((a, b) => a.name.localeCompare(b.name));
const onCategorySelect = (category: string | null) => {
const sp = new URLSearchParams(searchParams);
sp.set('category', category || '');
router.push(`/components?${sp.toString()}`);
const searchParams = new URLSearchParams(window.location.search);
searchParams.set('category', category || '');
router.push(`/components?${searchParams.toString()}`);
};
const onComponentSelect = (component: ComponentInfo) => {
const sp = new URLSearchParams(searchParams);
sp.set('component', component.name);
router.push(`/components?${sp.toString()}`);
const searchParams = new URLSearchParams(window.location.search);
searchParams.set('component', component.name);
router.push(`/components?${searchParams.toString()}`);
};
return (
<div className="bg-muted/30 flex h-screen w-80 flex-col overflow-hidden border-r">
{/* Header */}
<div className="shrink-0 border-b p-4">
<div className="flex-shrink-0 border-b p-4">
<div className="mb-2 flex items-center gap-2">
<Code2 className="text-primary h-6 w-6" />
@@ -78,14 +77,13 @@ export function DocsSidebar({
</div>
{/* Controls */}
<div className="shrink-0 space-y-2 border-b p-4">
<div className="flex-shrink-0 space-y-2 border-b p-4">
{/* Category Select */}
<div className="space-y-2">
<Select
defaultValue={selectedCategory || 'all'}
value={selectedCategory || 'all'}
onValueChange={(value) => {
const category = value === 'all' ? null : value;
onCategorySelect(category);
// Select first component in the filtered results
@@ -98,12 +96,8 @@ export function DocsSidebar({
}
}}
>
<SelectTrigger className="w-full">
<SelectValue>
{(category) => {
return category === 'all' ? 'All Categories' : category;
}}
</SelectValue>
<SelectTrigger>
<SelectValue placeholder={'Select a category'} />
</SelectTrigger>
<SelectContent>
@@ -160,7 +154,7 @@ export function DocsSidebar({
{/* Components List - Scrollable */}
<div className="flex flex-1 flex-col overflow-y-auto">
<div className="shrink-0 p-4 pb-2">
<div className="flex-shrink-0 p-4 pb-2">
<h3 className="flex items-center gap-2 text-sm font-semibold">
<FileText className="h-4 w-4" />
Components

View File

@@ -101,18 +101,13 @@ const examples = [
return (
<div className="flex min-h-32 items-center justify-center">
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button
variant="ghost"
className="relative h-8 w-8 rounded-full"
/>
}
>
<Avatar className="h-8 w-8">
<AvatarImage src="/avatars/01.png" alt="@username" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
<Avatar className="h-8 w-8">
<AvatarImage src="/avatars/01.png" alt="@username" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="end" forceMount>
<DropdownMenuLabel className="font-normal">
@@ -190,11 +185,11 @@ const examples = [
</div>
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant="ghost" className="h-8 w-8 p-0" />}
>
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuItem onClick={() => setSelectedAction('open')}>
@@ -280,9 +275,11 @@ const examples = [
return (
<div className="flex min-h-48 items-center justify-center">
<DropdownMenu>
<DropdownMenuTrigger render={<Button variant="outline" />}>
<Plus className="mr-2 h-4 w-4" />
Create New
<DropdownMenuTrigger asChild>
<Button variant="outline">
<Plus className="mr-2 h-4 w-4" />
Create New
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>Create Content</DropdownMenuLabel>
@@ -396,11 +393,11 @@ const examples = [
<span className="text-sm">Appearance & Layout</span>
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant="outline" size="sm" />}
>
<Settings className="mr-2 h-4 w-4" />
Configure
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm">
<Settings className="mr-2 h-4 w-4" />
Configure
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-64" align="end">
<DropdownMenuLabel>View Options</DropdownMenuLabel>
@@ -550,10 +547,10 @@ const examples = [
</div>
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant="ghost" className="h-8 w-8 p-0" />}
>
<MoreHorizontal className="h-4 w-4" />
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuItem
@@ -866,7 +863,7 @@ export default function DropdownMenuStory() {
modal: controls.modal ? true : undefined,
});
const dropdownStructure = `<DropdownMenu${rootProps}>\n <DropdownMenuTrigger render={<Button variant="outline" />}>\n Open Menu\n </DropdownMenuTrigger>\n <DropdownMenuContent${contentProps}>\n <DropdownMenuItem>\n <User className="mr-2 h-4 w-4" />\n <span>Profile</span>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Settings className="mr-2 h-4 w-4" />\n <span>Settings</span>\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n <LogOut className="mr-2 h-4 w-4" />\n <span>Log out</span>\n </DropdownMenuItem>\n </DropdownMenuContent>\n</DropdownMenu>`;
const dropdownStructure = `<DropdownMenu${rootProps}>\n <DropdownMenuTrigger asChild>\n <Button variant="outline">Open Menu</Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent${contentProps}>\n <DropdownMenuItem>\n <User className="mr-2 h-4 w-4" />\n <span>Profile</span>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Settings className="mr-2 h-4 w-4" />\n <span>Settings</span>\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n <LogOut className="mr-2 h-4 w-4" />\n <span>Log out</span>\n </DropdownMenuItem>\n </DropdownMenuContent>\n</DropdownMenu>`;
return `${importStatement}\n${buttonImport}\n${iconImport}\n\n${dropdownStructure}`;
};
@@ -974,8 +971,8 @@ export default function DropdownMenuStory() {
const previewContent = (
<div className="flex justify-center p-6">
<DropdownMenu modal={controls.modal}>
<DropdownMenuTrigger render={<Button variant="outline" />}>
Open Menu
<DropdownMenuTrigger asChild>
<Button variant="outline">Open Menu</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
side={controls.side}

View File

@@ -4,7 +4,7 @@ import { useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';
import { Badge } from '@kit/ui/badge';
import { Button } from '@kit/ui/button';
@@ -119,7 +119,7 @@ export default function FormStory() {
const formImport = generateImportStatement(formComponents, '@kit/ui/form');
const inputImport = generateImportStatement(['Input'], '@kit/ui/input');
const buttonImport = generateImportStatement(['Button'], '@kit/ui/button');
const hookFormImports = `import { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport * as z from 'zod';`;
const hookFormImports = `import { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';`;
let schemaCode = '';
let formFieldsCode = '';
@@ -130,19 +130,19 @@ export default function FormStory() {
formFieldsCode = ` <FormField\n control={form.control}\n name="username"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Username</FormLabel>\n <FormControl>\n <Input ${controls.disabled ? 'disabled ' : ''}placeholder="Enter username" {...field} />\n </FormControl>${controls.showDescriptions ? '\n <FormDescription>\n Your public display name.\n </FormDescription>' : ''}${controls.showValidation ? '\n <FormMessage />' : ''}\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name="email"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Email</FormLabel>\n <FormControl>\n <Input ${controls.disabled ? 'disabled ' : ''}type="email" placeholder="Enter email" {...field} />\n </FormControl>${controls.showDescriptions ? "\n <FormDescription>\n We'll never share your email.\n </FormDescription>" : ''}${controls.showValidation ? '\n <FormMessage />' : ''}\n </FormItem>\n )}\n />`;
onSubmitCode = ` function onSubmit(values: z.output<typeof formSchema>) {\n console.log('Form submitted:', values);\n }`;
onSubmitCode = ` function onSubmit(values: z.infer<typeof formSchema>) {\n console.log('Form submitted:', values);\n }`;
} else if (controls.formType === 'advanced') {
schemaCode = `const formSchema = z.object({\n firstName: z.string().min(1, 'First name is required.'),\n lastName: z.string().min(1, 'Last name is required.'),\n email: z.string().email('Please enter a valid email address.'),\n});`;
formFieldsCode = ` <FormField\n control={form.control}\n name="firstName"\n render={({ field }) => (\n <FormItem>\n <FormLabel>First Name</FormLabel>\n <FormControl>\n <Input ${controls.disabled ? 'disabled ' : ''}placeholder="John" {...field} />\n </FormControl>${controls.showValidation ? '\n <FormMessage />' : ''}\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name="lastName"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Last Name</FormLabel>\n <FormControl>\n <Input ${controls.disabled ? 'disabled ' : ''}placeholder="Doe" {...field} />\n </FormControl>${controls.showValidation ? '\n <FormMessage />' : ''}\n </FormItem>\n )}\n />`;
onSubmitCode = ` function onSubmit(values: z.output<typeof formSchema>) {\n console.log('Advanced form submitted:', values);\n }`;
onSubmitCode = ` function onSubmit(values: z.infer<typeof formSchema>) {\n console.log('Advanced form submitted:', values);\n }`;
} else {
schemaCode = `const formSchema = z.object({\n password: z.string().min(8, 'Password must be at least 8 characters.'),\n confirmPassword: z.string(),\n}).refine((data) => data.password === data.confirmPassword, {\n message: 'Passwords do not match.',\n path: ['confirmPassword'],\n});`;
formFieldsCode = ` <FormField\n control={form.control}\n name="password"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Password</FormLabel>\n <FormControl>\n <Input ${controls.disabled ? 'disabled ' : ''}type="password" {...field} />\n </FormControl>${controls.showValidation ? '\n <FormMessage />' : ''}\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name="confirmPassword"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Confirm Password</FormLabel>\n <FormControl>\n <Input ${controls.disabled ? 'disabled ' : ''}type="password" {...field} />\n </FormControl>${controls.showValidation ? '\n <FormMessage />' : ''}\n </FormItem>\n )}\n />`;
onSubmitCode = ` function onSubmit(values: z.output<typeof formSchema>) {\n console.log('Validation form submitted:', values);\n }`;
onSubmitCode = ` function onSubmit(values: z.infer<typeof formSchema>) {\n console.log('Validation form submitted:', values);\n }`;
}
const defaultValuesCode =
@@ -152,13 +152,13 @@ export default function FormStory() {
? ` defaultValues: {\n firstName: '',\n lastName: '',\n email: '',\n },`
: ` defaultValues: {\n password: '',\n confirmPassword: '',\n },`;
const fullFormCode = `${hookFormImports}\n${formImport}\n${inputImport}\n${buttonImport}\n\n${schemaCode}\n\nfunction MyForm() {\n const form = useForm<z.output<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n${defaultValuesCode}\n });\n\n${onSubmitCode}\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">\n${formFieldsCode}\n <Button type="submit"${controls.disabled ? ' disabled' : ''}>Submit</Button>\n </form>\n </Form>\n );\n}`;
const fullFormCode = `${hookFormImports}\n${formImport}\n${inputImport}\n${buttonImport}\n\n${schemaCode}\n\nfunction MyForm() {\n const form = useForm<z.infer<typeof formSchema>>({\n resolver: zodResolver(formSchema),\n${defaultValuesCode}\n });\n\n${onSubmitCode}\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">\n${formFieldsCode}\n <Button type="submit"${controls.disabled ? ' disabled' : ''}>Submit</Button>\n </form>\n </Form>\n );\n}`;
return fullFormCode;
};
// Basic form
const basicForm = useForm<z.output<typeof basicFormSchema>>({
const basicForm = useForm<z.infer<typeof basicFormSchema>>({
resolver: zodResolver(basicFormSchema),
defaultValues: {
username: '',
@@ -169,7 +169,7 @@ export default function FormStory() {
});
// Advanced form
const advancedForm = useForm<z.output<typeof advancedFormSchema>>({
const advancedForm = useForm<z.infer<typeof advancedFormSchema>>({
resolver: zodResolver(advancedFormSchema),
defaultValues: {
firstName: '',
@@ -183,7 +183,7 @@ export default function FormStory() {
});
// Validation form
const validationForm = useForm<z.output<typeof validationFormSchema>>({
const validationForm = useForm<z.infer<typeof validationFormSchema>>({
resolver: zodResolver(validationFormSchema),
defaultValues: {
password: '',
@@ -1056,7 +1056,7 @@ export default function FormStory() {
<pre className="overflow-x-auto text-sm">
{`import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { z } from 'zod';
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@kit/ui/form';
const formSchema = z.object({
@@ -1065,7 +1065,7 @@ const formSchema = z.object({
});
function MyForm() {
const form = useForm<z.output<typeof formSchema>>({
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
username: '',
@@ -1073,7 +1073,7 @@ function MyForm() {
},
});
function onSubmit(values: z.output<typeof formSchema>) {
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values);
}

View File

@@ -99,7 +99,7 @@ export function KbdStory() {
let snippet = groupLines.join('\n');
if (controls.showTooltip) {
snippet = `<TooltipProvider>\n <Tooltip>\n <TooltipTrigger render={<Button variant="outline" />}>\n Command palette\n </TooltipTrigger>\n <TooltipContent className="flex items-center gap-2">\n <span>Press</span>\n ${groupLines.join('\n ')}\n </TooltipContent>\n </Tooltip>\n</TooltipProvider>`;
snippet = `<TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant="outline">Command palette</Button>\n </TooltipTrigger>\n <TooltipContent className="flex items-center gap-2">\n <span>Press</span>\n ${groupLines.join('\n ')}\n </TooltipContent>\n </Tooltip>\n</TooltipProvider>`;
}
return formatCodeBlock(snippet, [
@@ -115,11 +115,11 @@ export function KbdStory() {
{controls.showTooltip ? (
<TooltipProvider delayDuration={200}>
<Tooltip>
<TooltipTrigger
render={<Button variant="outline" className="gap-2" />}
>
<Command className="h-4 w-4" />
Command palette
<TooltipTrigger asChild>
<Button variant="outline" className="gap-2">
<Command className="h-4 w-4" />
Command palette
</Button>
</TooltipTrigger>
<TooltipContent className="flex items-center gap-2">
<span>Press</span>

View File

@@ -136,13 +136,11 @@ export function SimpleDataTableStory() {
{controls.showActions && (
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button variant="ghost" className="h-8 w-8 p-0" />
}
>
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem

View File

@@ -100,7 +100,7 @@ export function SwitchStory() {
className: cn(
controls.size === 'sm' && 'h-4 w-7',
controls.size === 'lg' && 'h-6 w-11',
controls.error && 'data-checked:bg-destructive',
controls.error && 'data-[state=checked]:bg-destructive',
),
};
@@ -200,7 +200,7 @@ export function SwitchStory() {
className={cn(
controls.size === 'sm' && 'h-4 w-7',
controls.size === 'lg' && 'h-6 w-11',
controls.error && 'data-checked:bg-destructive',
controls.error && 'data-[state=checked]:bg-destructive',
)}
/>
);
@@ -616,7 +616,7 @@ export function SwitchStory() {
</Label>
<Switch
id="error-switch"
className="data-checked:bg-destructive"
className="data-[state=checked]:bg-destructive"
/>
</div>
<p className="text-destructive text-sm">
@@ -642,7 +642,7 @@ export function SwitchStory() {
<div>
<h4 className="mb-3 text-lg font-semibold">Switch</h4>
<p className="text-muted-foreground mb-3 text-sm">
A toggle switch component for boolean states. Built on Base UI
A toggle switch component for boolean states. Built on Radix UI
Switch primitive.
</p>
<div className="overflow-x-auto">

View File

@@ -62,9 +62,9 @@ interface TabsControlsProps {
const variantClasses = {
default: '',
pills:
'[&>div]:bg-background [&>div]:border [&>div]:rounded-lg [&>div]:p-1 [&_button]:rounded-md [&_button[data-active]]:bg-primary [&_button[data-active]]:text-primary-foreground',
'[&>div]:bg-background [&>div]:border [&>div]:rounded-lg [&>div]:p-1 [&_button]:rounded-md [&_button[data-state=active]]:bg-primary [&_button[data-state=active]]:text-primary-foreground',
underline:
'[&>div]:bg-transparent [&>div]:border-b [&>div]:rounded-none [&_button]:rounded-none [&_button]:border-b-2 [&_button]:border-transparent [&_button[data-active]]:border-primary [&_button[data-active]]:bg-transparent',
'[&>div]:bg-transparent [&>div]:border-b [&>div]:rounded-none [&_button]:rounded-none [&_button]:border-b-2 [&_button]:border-transparent [&_button[data-state=active]]:border-primary [&_button[data-state=active]]:bg-transparent',
};
const sizeClasses = {
@@ -683,28 +683,28 @@ function App() {
<TabsList className="h-auto rounded-none border-b bg-transparent p-0">
<TabsTrigger
value="overview"
className="data-active:border-primary rounded-none border-b-2 border-transparent data-active:bg-transparent"
className="data-[state=active]:border-primary rounded-none border-b-2 border-transparent data-[state=active]:bg-transparent"
>
<BarChart3 className="mr-2 h-4 w-4" />
Overview
</TabsTrigger>
<TabsTrigger
value="users"
className="data-active:border-primary rounded-none border-b-2 border-transparent data-active:bg-transparent"
className="data-[state=active]:border-primary rounded-none border-b-2 border-transparent data-[state=active]:bg-transparent"
>
<User className="mr-2 h-4 w-4" />
Users
</TabsTrigger>
<TabsTrigger
value="revenue"
className="data-active:border-primary rounded-none border-b-2 border-transparent data-active:bg-transparent"
className="data-[state=active]:border-primary rounded-none border-b-2 border-transparent data-[state=active]:bg-transparent"
>
<CreditCard className="mr-2 h-4 w-4" />
Revenue
</TabsTrigger>
<TabsTrigger
value="reports"
className="data-active:border-primary rounded-none border-b-2 border-transparent data-active:bg-transparent"
className="data-[state=active]:border-primary rounded-none border-b-2 border-transparent data-[state=active]:bg-transparent"
>
<FileText className="mr-2 h-4 w-4" />
Reports
@@ -905,7 +905,8 @@ const apiReference = {
{
name: '...props',
type: 'React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>',
description: 'All additional props from Base UI Tabs.Root component.',
description:
'All props from Radix UI Tabs.Root component including asChild, id, etc.',
},
],
examples: [

View File

@@ -144,23 +144,22 @@ function TooltipStory() {
let code = `<TooltipProvider${providerPropsString}>\n`;
code += ` <Tooltip>\n`;
code += ` <TooltipTrigger asChild>\n`;
if (controls.triggerType === 'button') {
code += ` <TooltipTrigger render={<Button variant="${controls.triggerVariant}" />}>\n`;
code += ` Hover me\n`;
code += ` <Button variant="${controls.triggerVariant}">Hover me</Button>\n`;
} else if (controls.triggerType === 'icon') {
code += ` <Button variant="${controls.triggerVariant}" size="icon">\n`;
const iconName = selectedIconData?.icon.name || 'Info';
code += ` <TooltipTrigger render={<Button variant="${controls.triggerVariant}" size="icon" />}>\n`;
code += ` <${iconName} className="h-4 w-4" />\n`;
code += ` <${iconName} className="h-4 w-4" />\n`;
code += ` </Button>\n`;
} else if (controls.triggerType === 'text') {
code += ` <TooltipTrigger render={<span className="cursor-help underline decoration-dotted" />}>\n`;
code += ` Hover me\n`;
code += ` <span className="cursor-help underline decoration-dotted">Hover me</span>\n`;
} else if (controls.triggerType === 'input') {
code += ` <TooltipTrigger render={<Input placeholder="Hover over this input" />} />\n`;
code += ` <Input placeholder="Hover over this input" />\n`;
}
if (controls.triggerType !== 'input') {
code += ` </TooltipTrigger>\n`;
}
code += ` </TooltipTrigger>\n`;
code += ` <TooltipContent${contentPropsString}>\n`;
code += ` <p>${controls.content}</p>\n`;
code += ` </TooltipContent>\n`;
@@ -171,50 +170,28 @@ function TooltipStory() {
};
const renderPreview = () => {
const renderTrigger = () => {
const trigger = (() => {
switch (controls.triggerType) {
case 'button':
return (
<TooltipTrigger
render={<Button variant={controls.triggerVariant} />}
>
Hover me
</TooltipTrigger>
);
return <Button variant={controls.triggerVariant}>Hover me</Button>;
case 'icon':
return (
<TooltipTrigger
render={<Button variant={controls.triggerVariant} size="icon" />}
>
<Button variant={controls.triggerVariant} size="icon">
<IconComponent className="h-4 w-4" />
</TooltipTrigger>
</Button>
);
case 'text':
return (
<TooltipTrigger
render={
<span className="cursor-help underline decoration-dotted" />
}
>
<span className="cursor-help underline decoration-dotted">
Hover me
</TooltipTrigger>
</span>
);
case 'input':
return (
<TooltipTrigger
render={<Input placeholder="Hover over this input" />}
/>
);
return <Input placeholder="Hover over this input" />;
default:
return (
<TooltipTrigger
render={<Button variant={controls.triggerVariant} />}
>
Hover me
</TooltipTrigger>
);
return <Button variant={controls.triggerVariant}>Hover me</Button>;
}
};
})();
return (
<div className="flex min-h-[200px] items-center justify-center">
@@ -224,7 +201,7 @@ function TooltipStory() {
disableHoverableContent={controls.disableHoverableContent}
>
<Tooltip>
{renderTrigger()}
<TooltipTrigger asChild>{trigger}</TooltipTrigger>
<TooltipContent
side={controls.side}
align={controls.align}
@@ -399,9 +376,11 @@ function TooltipStory() {
<TooltipProvider>
<div className="flex flex-wrap gap-4">
<Tooltip>
<TooltipTrigger render={<Button variant="outline" />}>
<Info className="mr-2 h-4 w-4" />
Info Button
<TooltipTrigger asChild>
<Button variant="outline">
<Info className="mr-2 h-4 w-4" />
Info Button
</Button>
</TooltipTrigger>
<TooltipContent>
<p>This provides additional information</p>
@@ -409,8 +388,10 @@ function TooltipStory() {
</Tooltip>
<Tooltip>
<TooltipTrigger render={<Button variant="ghost" size="icon" />}>
<HelpCircle className="h-4 w-4" />
<TooltipTrigger asChild>
<Button variant="ghost" size="icon">
<HelpCircle className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Click for help documentation</p>
@@ -418,12 +399,10 @@ function TooltipStory() {
</Tooltip>
<Tooltip>
<TooltipTrigger
render={
<span className="cursor-help underline decoration-dotted" />
}
>
Hover for explanation
<TooltipTrigger asChild>
<span className="cursor-help underline decoration-dotted">
Hover for explanation
</span>
</TooltipTrigger>
<TooltipContent>
<p>This term needs clarification for better understanding</p>
@@ -431,9 +410,9 @@ function TooltipStory() {
</Tooltip>
<Tooltip>
<TooltipTrigger
render={<Input placeholder="Hover me" className="w-48" />}
/>
<TooltipTrigger asChild>
<Input placeholder="Hover me" className="w-48" />
</TooltipTrigger>
<TooltipContent>
<p>Enter your email address here</p>
</TooltipContent>
@@ -455,10 +434,10 @@ function TooltipStory() {
{/* Top Row */}
<div></div>
<Tooltip>
<TooltipTrigger
render={<Button variant="outline" size="sm" />}
>
Top
<TooltipTrigger asChild>
<Button variant="outline" size="sm">
Top
</Button>
</TooltipTrigger>
<TooltipContent side="top">
<p>Tooltip on top</p>
@@ -468,10 +447,10 @@ function TooltipStory() {
{/* Middle Row */}
<Tooltip>
<TooltipTrigger
render={<Button variant="outline" size="sm" />}
>
Left
<TooltipTrigger asChild>
<Button variant="outline" size="sm">
Left
</Button>
</TooltipTrigger>
<TooltipContent side="left">
<p>Tooltip on left</p>
@@ -481,10 +460,10 @@ function TooltipStory() {
<span className="text-muted-foreground text-sm">Center</span>
</div>
<Tooltip>
<TooltipTrigger
render={<Button variant="outline" size="sm" />}
>
Right
<TooltipTrigger asChild>
<Button variant="outline" size="sm">
Right
</Button>
</TooltipTrigger>
<TooltipContent side="right">
<p>Tooltip on right</p>
@@ -494,10 +473,10 @@ function TooltipStory() {
{/* Bottom Row */}
<div></div>
<Tooltip>
<TooltipTrigger
render={<Button variant="outline" size="sm" />}
>
Bottom
<TooltipTrigger asChild>
<Button variant="outline" size="sm">
Bottom
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">
<p>Tooltip on bottom</p>
@@ -519,9 +498,11 @@ function TooltipStory() {
<TooltipProvider>
<div className="flex flex-wrap gap-4">
<Tooltip>
<TooltipTrigger render={<Button variant="outline" />}>
<Star className="mr-2 h-4 w-4" />
Premium Feature
<TooltipTrigger asChild>
<Button variant="outline">
<Star className="mr-2 h-4 w-4" />
Premium Feature
</Button>
</TooltipTrigger>
<TooltipContent className="max-w-xs">
<div className="space-y-1">
@@ -535,9 +516,11 @@ function TooltipStory() {
</Tooltip>
<Tooltip>
<TooltipTrigger render={<Button variant="outline" />}>
<Settings className="mr-2 h-4 w-4" />
Advanced Settings
<TooltipTrigger asChild>
<Button variant="outline">
<Settings className="mr-2 h-4 w-4" />
Advanced Settings
</Button>
</TooltipTrigger>
<TooltipContent>
<div className="space-y-1">
@@ -554,9 +537,11 @@ function TooltipStory() {
</Tooltip>
<Tooltip>
<TooltipTrigger render={<Button variant="destructive" />}>
<AlertCircle className="mr-2 h-4 w-4" />
Delete Account
<TooltipTrigger asChild>
<Button variant="destructive">
<AlertCircle className="mr-2 h-4 w-4" />
Delete Account
</Button>
</TooltipTrigger>
<TooltipContent className="border-destructive bg-destructive text-destructive-foreground max-w-xs">
<div className="space-y-1">
@@ -583,10 +568,10 @@ function TooltipStory() {
<div className="space-y-4">
<div className="flex items-center gap-4">
<Tooltip>
<TooltipTrigger
render={<Button size="icon" variant="ghost" />}
>
<Copy className="h-4 w-4" />
<TooltipTrigger asChild>
<Button size="icon" variant="ghost">
<Copy className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Copy to clipboard</p>
@@ -594,10 +579,10 @@ function TooltipStory() {
</Tooltip>
<Tooltip>
<TooltipTrigger
render={<Button size="icon" variant="ghost" />}
>
<Download className="h-4 w-4" />
<TooltipTrigger asChild>
<Button size="icon" variant="ghost">
<Download className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Download file</p>
@@ -605,10 +590,10 @@ function TooltipStory() {
</Tooltip>
<Tooltip>
<TooltipTrigger
render={<Button size="icon" variant="ghost" />}
>
<Share className="h-4 w-4" />
<TooltipTrigger asChild>
<Button size="icon" variant="ghost">
<Share className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Share with others</p>
@@ -620,11 +605,9 @@ function TooltipStory() {
<div className="space-y-2">
<Label htmlFor="username">Username</Label>
<Tooltip>
<TooltipTrigger
render={
<Input id="username" placeholder="Enter username" />
}
/>
<TooltipTrigger asChild>
<Input id="username" placeholder="Enter username" />
</TooltipTrigger>
<TooltipContent>
<p>Must be 3-20 characters, letters and numbers only</p>
</TooltipContent>
@@ -633,7 +616,9 @@ function TooltipStory() {
<div className="flex items-center space-x-2">
<Tooltip>
<TooltipTrigger render={<Checkbox id="terms" />} />
<TooltipTrigger asChild>
<Checkbox id="terms" />
</TooltipTrigger>
<TooltipContent className="max-w-xs">
<p>
By checking this, you agree to our Terms of Service and
@@ -766,7 +751,7 @@ function TooltipStory() {
</li>
<li>
<strong>TooltipTrigger:</strong> Element that triggers the
tooltip (use render prop)
tooltip (use asChild prop)
</li>
</ul>
</div>