From 1a4fa4d433eaa20b9ed26d46bcf6ecd4f399eed2 Mon Sep 17 00:00:00 2001 From: "Amir H. Khanjani" <72540492+ahkhanjani@users.noreply.github.com> Date: Fri, 8 Nov 2024 21:38:39 +0330 Subject: [PATCH 01/11] button --- packages/ui/src/button.tsx | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/ui/src/button.tsx b/packages/ui/src/button.tsx index 6f5c3c695..2bfffd7ca 100644 --- a/packages/ui/src/button.tsx +++ b/packages/ui/src/button.tsx @@ -38,21 +38,26 @@ const buttonVariants = cva( interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { + ref: React.Ref; asChild?: boolean; } -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button"; - return ( - - ); - }, -); -Button.displayName = "Button"; +function Button({ + ref, + className, + variant, + size, + asChild = false, + ...props +}: ButtonProps) { + const Comp = asChild ? Slot : "button"; + return ( + + ); +} export { Button, buttonVariants }; From 084c61dbb501b8dc4d67777dd4eddcbbbf3814e0 Mon Sep 17 00:00:00 2001 From: "Amir H. Khanjani" <72540492+ahkhanjani@users.noreply.github.com> Date: Sat, 9 Nov 2024 15:58:12 +0330 Subject: [PATCH 02/11] dropdown --- packages/ui/src/dropdown-menu.tsx | 306 ++++++++++++++++-------------- 1 file changed, 164 insertions(+), 142 deletions(-) diff --git a/packages/ui/src/dropdown-menu.tsx b/packages/ui/src/dropdown-menu.tsx index ecca776cc..68f399e52 100644 --- a/packages/ui/src/dropdown-menu.tsx +++ b/packages/ui/src/dropdown-menu.tsx @@ -17,169 +17,191 @@ const DropdownMenuPortal = DropdownMenuPrimitive.Portal; const DropdownMenuSub = DropdownMenuPrimitive.Sub; const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; -const DropdownMenuSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)); -DropdownMenuSubTrigger.displayName = - DropdownMenuPrimitive.SubTrigger.displayName; - -const DropdownMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DropdownMenuSubContent.displayName = - DropdownMenuPrimitive.SubContent.displayName; +function DropdownMenuSubTrigger({ + ref, + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} -const DropdownMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - - ) { + return ( + - -)); -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + ); +} -const DropdownMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; +function DropdownMenuContent({ + ref, + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} -const DropdownMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)); -DropdownMenuCheckboxItem.displayName = - DropdownMenuPrimitive.CheckboxItem.displayName; +function DropdownMenuItem({ + ref, + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} -const DropdownMenuRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)); -DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; +function DropdownMenuCheckboxItem({ + ref, + className, + children, + checked, + ...props +}: React.ComponentProps< + typeof DropdownMenuPrimitive.DropdownMenuCheckboxItem +>) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioItem({ + ref, + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} -const DropdownMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; +function DropdownMenuLabel({ + ref, + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} -const DropdownMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; +function DropdownMenuSeparator({ + ref, + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const DropdownMenuShortcut = ({ +function DropdownMenuShortcut({ className, ...props -}: React.HTMLAttributes) => { +}: React.HTMLAttributes) { return ( ); -}; -DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; +} export { DropdownMenu, From bc2c52cb749fbdb6fd8366a4659c40bad55c50f8 Mon Sep 17 00:00:00 2001 From: "Amir H. Khanjani" <72540492+ahkhanjani@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:09:24 +0330 Subject: [PATCH 03/11] form --- packages/ui/src/form.tsx | 85 +++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/packages/ui/src/form.tsx b/packages/ui/src/form.tsx index ac0c191ab..e4518a74f 100644 --- a/packages/ui/src/form.tsx +++ b/packages/ui/src/form.tsx @@ -14,7 +14,6 @@ import { Slot } from "@radix-ui/react-slot"; import { useForm as __useForm, Controller, - FormProvider, useFormContext, } from "react-hook-form"; @@ -22,7 +21,7 @@ import { cn } from "@acme/ui"; import { Label } from "./label"; -const useForm = < +function useForm< TOut extends FieldValues, TDef extends ZodTypeDef, TIn extends FieldValues, @@ -30,16 +29,14 @@ const useForm = < props: Omit, "resolver"> & { schema: ZodType; }, -) => { +) { const form = __useForm({ ...props, resolver: zodResolver(props.schema, undefined), }); return form; -}; - -const Form = FormProvider; +} interface FormFieldContextValue< TFieldValues extends FieldValues = FieldValues, @@ -52,20 +49,18 @@ const FormFieldContext = React.createContext( null, ); -const FormField = < +function FormField< TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath, ->({ - ...props -}: ControllerProps) => { +>({ ...props }: ControllerProps) { return ( ); -}; +} -const useFormField = () => { +function useFormField() { const fieldContext = React.useContext(FormFieldContext); const itemContext = React.useContext(FormItemContext); const { getFieldState, formState } = useFormContext(); @@ -85,7 +80,7 @@ const useFormField = () => { formMessageId: `${id}-form-item-message`, ...fieldState, }; -}; +} interface FormItemContextValue { id: string; @@ -95,10 +90,11 @@ const FormItemContext = React.createContext( {} as FormItemContextValue, ); -const FormItem = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => { +function FormItem({ + ref, + className, + ...props +}: React.HTMLAttributes & { ref: React.Ref }) { const id = React.useId(); return ( @@ -106,13 +102,13 @@ const FormItem = React.forwardRef<
); -}); -FormItem.displayName = "FormItem"; +} -const FormLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { +function FormLabel({ + ref, + className, + ...props +}: React.ComponentProps) { const { error, formItemId } = useFormField(); return ( @@ -123,13 +119,9 @@ const FormLabel = React.forwardRef< {...props} /> ); -}); -FormLabel.displayName = "FormLabel"; +} -const FormControl = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ ...props }, ref) => { +function FormControl({ ref, ...props }: React.ComponentProps) { const { error, formItemId, formDescriptionId, formMessageId } = useFormField(); @@ -146,13 +138,15 @@ const FormControl = React.forwardRef< {...props} /> ); -}); -FormControl.displayName = "FormControl"; +} -const FormDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => { +function FormDescription({ + ref, + className, + ...props +}: React.HTMLAttributes & { + ref: React.Ref; +}) { const { formDescriptionId } = useFormField(); return ( @@ -163,13 +157,16 @@ const FormDescription = React.forwardRef< {...props} /> ); -}); -FormDescription.displayName = "FormDescription"; +} -const FormMessage = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, children, ...props }, ref) => { +function FormMessage({ + ref, + className, + children, + ...props +}: React.HTMLAttributes & { + ref: React.Ref; +}) { const { error, formMessageId } = useFormField(); const body = error ? String(error.message) : children; @@ -187,13 +184,11 @@ const FormMessage = React.forwardRef< {body}

); -}); -FormMessage.displayName = "FormMessage"; +} export { useForm, useFormField, - Form, FormItem, FormLabel, FormControl, @@ -202,4 +197,4 @@ export { FormField, }; -export { useFieldArray } from "react-hook-form"; +export { FormProvider as Form, useFieldArray } from "react-hook-form"; From edbc6735f10bd46a844623ef3ea31457920d1b55 Mon Sep 17 00:00:00 2001 From: "Amir H. Khanjani" <72540492+ahkhanjani@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:11:38 +0330 Subject: [PATCH 04/11] input --- packages/ui/src/input.tsx | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/ui/src/input.tsx b/packages/ui/src/input.tsx index a213c918e..5839dfd27 100644 --- a/packages/ui/src/input.tsx +++ b/packages/ui/src/input.tsx @@ -4,21 +4,23 @@ import { cn } from "@acme/ui"; type InputProps = React.InputHTMLAttributes; -const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { - return ( - - ); - }, -); -Input.displayName = "Input"; +function Input({ + ref, + className, + type, + ...props +}: InputProps & { ref: React.Ref }) { + return ( + + ); +} export { Input }; From 891e1d4e05593832e69ac903a40bba7f5704d3ce Mon Sep 17 00:00:00 2001 From: "Amir H. Khanjani" <72540492+ahkhanjani@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:14:01 +0330 Subject: [PATCH 05/11] label --- packages/ui/src/label.tsx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/ui/src/label.tsx b/packages/ui/src/label.tsx index 4e0825d6b..0d2666f91 100644 --- a/packages/ui/src/label.tsx +++ b/packages/ui/src/label.tsx @@ -9,17 +9,19 @@ const labelVariants = cva( "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", ); -const Label = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps ->(({ className, ...props }, ref) => ( - -)); -Label.displayName = LabelPrimitive.Root.displayName; +function Label({ + ref, + className, + ...props +}: React.ComponentProps & + VariantProps) { + return ( + + ); +} export { Label }; From 7f616d421862feaceb5275db195c84155a7fb2fb Mon Sep 17 00:00:00 2001 From: "Amir H. Khanjani" <72540492+ahkhanjani@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:14:33 +0330 Subject: [PATCH 06/11] toast --- packages/ui/src/toast.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/toast.tsx b/packages/ui/src/toast.tsx index 2958b9ae2..5b2a2f8dd 100644 --- a/packages/ui/src/toast.tsx +++ b/packages/ui/src/toast.tsx @@ -5,7 +5,7 @@ import { Toaster as Sonner, toast } from "sonner"; type ToasterProps = React.ComponentProps; -const Toaster = ({ ...props }: ToasterProps) => { +function Toaster({ ...props }: ToasterProps) { const { theme = "system" } = useTheme(); return ( @@ -26,6 +26,6 @@ const Toaster = ({ ...props }: ToasterProps) => { {...props} /> ); -}; +} export { Toaster, toast }; From bcd32137570172647130148d667b0851804e6c47 Mon Sep 17 00:00:00 2001 From: "Amir H. Khanjani" <72540492+ahkhanjani@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:16:01 +0330 Subject: [PATCH 07/11] make refs optional --- packages/ui/src/button.tsx | 2 +- packages/ui/src/form.tsx | 6 +++--- packages/ui/src/input.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/button.tsx b/packages/ui/src/button.tsx index 2bfffd7ca..977da8e13 100644 --- a/packages/ui/src/button.tsx +++ b/packages/ui/src/button.tsx @@ -38,7 +38,7 @@ const buttonVariants = cva( interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { - ref: React.Ref; + ref?: React.Ref; asChild?: boolean; } diff --git a/packages/ui/src/form.tsx b/packages/ui/src/form.tsx index e4518a74f..52e4b2388 100644 --- a/packages/ui/src/form.tsx +++ b/packages/ui/src/form.tsx @@ -94,7 +94,7 @@ function FormItem({ ref, className, ...props -}: React.HTMLAttributes & { ref: React.Ref }) { +}: React.HTMLAttributes & { ref?: React.Ref }) { const id = React.useId(); return ( @@ -145,7 +145,7 @@ function FormDescription({ className, ...props }: React.HTMLAttributes & { - ref: React.Ref; + ref?: React.Ref; }) { const { formDescriptionId } = useFormField(); @@ -165,7 +165,7 @@ function FormMessage({ children, ...props }: React.HTMLAttributes & { - ref: React.Ref; + ref?: React.Ref; }) { const { error, formMessageId } = useFormField(); const body = error ? String(error.message) : children; diff --git a/packages/ui/src/input.tsx b/packages/ui/src/input.tsx index 5839dfd27..31e55b999 100644 --- a/packages/ui/src/input.tsx +++ b/packages/ui/src/input.tsx @@ -9,7 +9,7 @@ function Input({ className, type, ...props -}: InputProps & { ref: React.Ref }) { +}: InputProps & { ref?: React.Ref }) { return ( Date: Mon, 11 Nov 2024 14:42:28 +0330 Subject: [PATCH 08/11] clean up a type --- packages/ui/src/input.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/input.tsx b/packages/ui/src/input.tsx index 31e55b999..26bd6f8c4 100644 --- a/packages/ui/src/input.tsx +++ b/packages/ui/src/input.tsx @@ -2,14 +2,11 @@ import * as React from "react"; import { cn } from "@acme/ui"; -type InputProps = React.InputHTMLAttributes; +type InputProps = React.InputHTMLAttributes & { + ref?: React.Ref; +}; -function Input({ - ref, - className, - type, - ...props -}: InputProps & { ref?: React.Ref }) { +function Input({ ref, className, type, ...props }: InputProps) { return ( Date: Fri, 15 Nov 2024 16:03:41 +0330 Subject: [PATCH 09/11] lots of cleaning up --- packages/ui/src/button.tsx | 6 +--- packages/ui/src/dropdown-menu.tsx | 55 +++++++++++----------------- packages/ui/src/form.tsx | 59 +++++++++---------------------- packages/ui/src/input.tsx | 10 ++---- packages/ui/src/label.tsx | 21 ++++------- packages/ui/src/theme.tsx | 1 - packages/ui/src/toast.tsx | 3 +- 7 files changed, 47 insertions(+), 108 deletions(-) diff --git a/packages/ui/src/button.tsx b/packages/ui/src/button.tsx index 977da8e13..3550a3b93 100644 --- a/packages/ui/src/button.tsx +++ b/packages/ui/src/button.tsx @@ -1,5 +1,4 @@ import type { VariantProps } from "class-variance-authority"; -import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { cva } from "class-variance-authority"; @@ -36,14 +35,12 @@ const buttonVariants = cva( ); interface ButtonProps - extends React.ButtonHTMLAttributes, + extends React.ComponentProps<"button">, VariantProps { - ref?: React.Ref; asChild?: boolean; } function Button({ - ref, className, variant, size, @@ -54,7 +51,6 @@ function Button({ return ( ); diff --git a/packages/ui/src/dropdown-menu.tsx b/packages/ui/src/dropdown-menu.tsx index 68f399e52..0e5bbf0ba 100644 --- a/packages/ui/src/dropdown-menu.tsx +++ b/packages/ui/src/dropdown-menu.tsx @@ -1,6 +1,14 @@ -"use client"; - -import * as React from "react"; +import type { + DropdownMenuCheckboxItemProps, + DropdownMenuContentProps, + DropdownMenuItemProps, + DropdownMenuLabelProps, + DropdownMenuRadioItemProps, + DropdownMenuSeparatorProps, + DropdownMenuSubContentProps, + DropdownMenuSubTriggerProps, +} from "@radix-ui/react-dropdown-menu"; +import type { ComponentProps } from "react"; import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; import { CheckIcon, @@ -18,17 +26,15 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub; const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; function DropdownMenuSubTrigger({ - ref, className, inset, children, ...props -}: React.ComponentProps & { +}: DropdownMenuSubTriggerProps & { inset?: boolean; }) { return ( ) { +}: DropdownMenuSubContentProps) { return ( ) { +}: DropdownMenuContentProps) { return ( & { +}: DropdownMenuItemProps & { inset?: boolean; }) { return ( ) { +}: DropdownMenuCheckboxItemProps) { return ( @@ -132,14 +126,12 @@ function DropdownMenuCheckboxItem({ } function DropdownMenuRadioItem({ - ref, className, children, ...props -}: React.ComponentProps) { +}: DropdownMenuRadioItemProps) { return ( & { +}: DropdownMenuLabelProps & { inset?: boolean; }) { return ( ) { +}: DropdownMenuSeparatorProps) { return ( ); } -function DropdownMenuShortcut({ - className, - ...props -}: React.HTMLAttributes) { +function DropdownMenuShortcut({ className, ...props }: ComponentProps<"span">) { return ( ( - null, -); +const FormFieldContext = createContext(null); function FormField< TFieldValues extends FieldValues = FieldValues, @@ -61,15 +61,15 @@ function FormField< } function useFormField() { - const fieldContext = React.useContext(FormFieldContext); - const itemContext = React.useContext(FormItemContext); const { getFieldState, formState } = useFormContext(); + const fieldContext = use(FormFieldContext); if (!fieldContext) { throw new Error("useFormField should be used within "); } const fieldState = getFieldState(fieldContext.name, formState); + const itemContext = use(FormItemContext); const { id } = itemContext; return { @@ -86,48 +86,38 @@ interface FormItemContextValue { id: string; } -const FormItemContext = React.createContext( +const FormItemContext = createContext( {} as FormItemContextValue, ); -function FormItem({ - ref, - className, - ...props -}: React.HTMLAttributes & { ref?: React.Ref }) { - const id = React.useId(); +function FormItem({ className, ...props }: ComponentProps<"div">) { + const id = useId(); return ( -
+
); } -function FormLabel({ - ref, - className, - ...props -}: React.ComponentProps) { +function FormLabel({ className, ...props }: LabelProps) { const { error, formItemId } = useFormField(); return (