Skip to content

Commit

Permalink
feat: add component previews for form integrations
Browse files Browse the repository at this point in the history
  • Loading branch information
JaleelB committed Jun 11, 2024
1 parent 0e63476 commit a2f0ace
Show file tree
Hide file tree
Showing 4 changed files with 377 additions and 2 deletions.
141 changes: 141 additions & 0 deletions website/components/form-demos.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Button } from '@/components/ui/button';
import { z } from 'zod';
import { Controller, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import React from 'react';
import { toast } from '@/components/ui/use-toast';
import { Tag, TagInput } from 'emblor';
import { uuid } from '@/lib/utils';

const FormSchema = z.object({
topics: z.array(
z.object({
id: z.string(),
text: z.string(),
}),
),
});

const defaultTags: Tag[] = [
{ id: uuid(), text: 'Sports' },
{ id: uuid(), text: 'Programming' },
{ id: uuid(), text: 'Travel' },
{ id: uuid(), text: 'Music' },
{ id: uuid(), text: 'Food' },
];

export function ShadcnFormDemo() {
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
});

const [tags, setTags] = React.useState<Tag[]>(defaultTags);
const [activeTagIndex, setActiveTagIndex] = React.useState<number | null>(null);
const { setValue } = form;

function onSubmit(data: z.infer<typeof FormSchema>) {
toast({
title: 'You submitted the following values:',
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
}

return (
<section className="z-10 w-full flex flex-col items-center text-center gap-5">
<div id="try" className="w-full py-8">
<div className="w-full relative my-4 flex flex-col space-y-2">
<div className="preview flex min-h-[350px] w-full justify-center p-10 items-center mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative rounded-md">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 flex flex-col items-start">
<FormField
control={form.control}
name="topics"
render={({ field }) => (
<FormItem className="flex flex-col items-start">
<FormLabel className="text-left">Topics</FormLabel>
<FormControl className="w-full">
<TagInput
{...field}
placeholder="Enter a topic"
tags={tags}
className="max-w-[250px]"
setTags={(newTags) => {
setTags(newTags);
setValue('topics', newTags as [Tag, ...Tag[]]);
}}
activeTagIndex={activeTagIndex}
setActiveTagIndex={setActiveTagIndex}
/>
</FormControl>
<FormDescription className="text-left">
These are the topics that you&apos;re interested in.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full">
Submit
</Button>
</form>
</Form>
</div>
</div>
</div>
</section>
);
}

export function ReactHookFormDemo() {
const [tags, setTags] = React.useState<Tag[]>(defaultTags);
const [activeTagIndex, setActiveTagIndex] = React.useState<number | null>(null);
const { control, handleSubmit, setValue } = useForm();

function onSubmit(data: any) {
toast({
title: 'You submitted the following values:',
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
}

return (
<section className="z-10 w-full flex flex-col items-center text-center gap-5">
<div id="try" className="w-full py-8">
<div className="w-full relative my-4 flex flex-col space-y-2">
<div className="preview flex min-h-[350px] w-full justify-center p-10 items-center mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative rounded-md">
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="tags"
control={control}
render={({ field }) => (
<TagInput
{...field}
placeholder="Enter a topic"
tags={tags}
className="max-w-[250px]"
setTags={(newTags) => {
setTags(newTags);
setValue('topics', newTags as [Tag, ...Tag[]]);
}}
activeTagIndex={activeTagIndex}
setActiveTagIndex={setActiveTagIndex}
/>
)}
/>
<button type="submit">Submit</button>
</form>
</div>
</div>
</div>
</section>
);
}
3 changes: 3 additions & 0 deletions website/components/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import CodeBlock from './code-block';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { ComponentPreview } from './component-preview';
import { ReactHookFormDemo, ShadcnFormDemo } from './form-demos';

const components = {
h1: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
Expand Down Expand Up @@ -138,6 +139,8 @@ const components = {
<CodeBlock value={value} {...props} />
),
ComponentPreview,
ShadcnFormDemo,
ReactHookFormDemo,
};

interface MdxProps {
Expand Down
104 changes: 104 additions & 0 deletions website/content/docs/integrations/react-hook-form.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,110 @@ description: Learn how to integrate Emblor with React Hook Form.

In this guide, we will take a look at integrating Emblor with [React Hook Form](https://react-hook-form.com/), a popular form library for React applications. React Hook Form is a lightweight and performant library that allows you to build forms with ease. By integrating Emblor with React Hook Form, you can create a fully-featured tag input component that is highly customizable and accessible.

<Tabs defaultValue="preview" className="relative mr-auto w-full">
<div className="flex items-center justify-between pb-3">
<TabsList className="w-full justify-start rounded-none border-b bg-transparent p-0">
<TabsTrigger
value="preview"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
Preview
</TabsTrigger>
<TabsTrigger
value="code"
className="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
Code
</TabsTrigger>
</TabsList>
</div>
<TabsContent value="preview" className="relative rounded-md border">
<ShadcnFormDemo />
</TabsContent>
<TabsContent value="code">
<div className="flex flex-col space-y-4">
<div className="w-full rounded-md [&_pre]:my-0 [&_pre]:max-h-[350px] [&_pre]:overflow-auto">
<CodeBlock value={`
import { z } from 'zod';
import { useForm } from 'react-hook-form';
import React from 'react';
import { toast } from '@/components/ui/use-toast';
import { Tag, TagInput } from 'emblor';
const FormSchema = z.object({
topics: z.array(
z.object({
id: z.string(),
text: z.string(),
}),
),
});
const defaultTags: Tag[] = [
{ id: uuid(), text: 'Sports' },
{ id: uuid(), text: 'Programming' },
{ id: uuid(), text: 'Travel' },
{ id: uuid(), text: 'Music' },
{ id: uuid(), text: 'Food' },
];
export function ReactHookFormDemo() {
const [tags, setTags] = React.useState<Tag[]>(defaultTags);
const [activeTagIndex, setActiveTagIndex] = React.useState<number | null>(null);
const { control, handleSubmit, setValue } = useForm();
function onSubmit(data: any) {
toast({
title: 'You submitted the following values:',
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
}
return (
<section className="z-10 w-full flex flex-col items-center text-center gap-5">
<div id="try" className="w-full py-8">
<div className="w-full relative my-4 flex flex-col space-y-2">
<div className="preview flex min-h-[350px] w-full justify-center p-10 items-center mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative rounded-md">
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="tags"
control={control}
render={({ field }) => (
<TagInput
{...field}
placeholder="Enter a topic"
tags={tags}
className="max-w-[250px]"
setTags={(newTags) => {
setTags(newTags);
setValue('topics', newTags as [Tag, ...Tag[]]);
}}
activeTagIndex={activeTagIndex}
setActiveTagIndex={setActiveTagIndex}
/>
)}
/>
<button type="submit">Submit</button>
</form>
</div>
</div>
</div>
</section>
);
}
`}/>

</div>
</div>

</TabsContent>
</Tabs>

## Installation

First, install Emblor and React Hook Form by running the following command:
Expand Down
Loading

0 comments on commit a2f0ace

Please sign in to comment.