wip fix
This commit is contained in:
parent
bff254f467
commit
cdf8c5c837
|
|
@ -7,6 +7,7 @@ import {
|
|||
NavigationMenuTrigger,
|
||||
navigationMenuTriggerStyle,
|
||||
} from "@/comps/ui/navigation-menu";
|
||||
import { useLocal } from "@/utils/use-local";
|
||||
import get from "lodash.get";
|
||||
import { FC, forwardRef } from "react";
|
||||
|
||||
|
|
|
|||
|
|
@ -175,15 +175,13 @@ export const usePopoverContext = () => {
|
|||
export function Popover({
|
||||
children,
|
||||
content,
|
||||
className,
|
||||
modal = false,
|
||||
popoverClassName,
|
||||
className,
|
||||
arrow,
|
||||
...restOptions
|
||||
}: {
|
||||
className?: string;
|
||||
root?: HTMLElement;
|
||||
popoverClassName?: string;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
content?: React.ReactNode;
|
||||
arrow?: boolean;
|
||||
|
|
@ -196,7 +194,7 @@ export function Popover({
|
|||
return (
|
||||
<PopoverContext.Provider value={popover}>
|
||||
<PopoverTrigger
|
||||
className={className}
|
||||
asChild
|
||||
onClick={
|
||||
typeof restOptions.open !== "undefined"
|
||||
? () => {
|
||||
|
|
@ -209,11 +207,10 @@ export function Popover({
|
|||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
className={cx(
|
||||
popoverClassName
|
||||
? popoverClassName
|
||||
: css`
|
||||
className,
|
||||
css`
|
||||
background: white;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
|
||||
user-select: none;
|
||||
`
|
||||
)}
|
||||
|
|
@ -297,10 +294,7 @@ export const PopoverContent = React.forwardRef<
|
|||
return (
|
||||
<FloatingPortal root={context.root}>
|
||||
{context.backdrop ? (
|
||||
<FloatingOverlay
|
||||
className={"c-z-50"}
|
||||
lockScroll
|
||||
>
|
||||
<FloatingOverlay className={"c-z-50"} lockScroll>
|
||||
{content}
|
||||
</FloatingOverlay>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
import { Popover } from "@/comps/custom/Popover";
|
||||
import { Input } from "@/comps/ui/input";
|
||||
import { useLocal } from "@/utils/use-local";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { FC } from "react";
|
||||
import type { ControllerRenderProps, FieldValues } from "react-hook-form";
|
||||
|
||||
export const Dropdown: FC<ControllerRenderProps<FieldValues, string>> = ({
|
||||
value,
|
||||
}) => {
|
||||
const local = useLocal({
|
||||
open: false,
|
||||
ref: { input: null as null | HTMLInputElement },
|
||||
});
|
||||
return (
|
||||
<Popover
|
||||
open={local.open}
|
||||
onOpenChange={() => {
|
||||
local.open = false;
|
||||
local.render();
|
||||
}}
|
||||
arrow={false}
|
||||
className={cx("c-rounded-sm c-bg-white")}
|
||||
content={
|
||||
<div
|
||||
className={cx(
|
||||
"c-px-3 c-py-2",
|
||||
css`
|
||||
width: ${local.ref.input?.clientWidth || 100}px;
|
||||
`
|
||||
)}
|
||||
></div>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
"c-relative",
|
||||
css`
|
||||
cursor: pointer !important;
|
||||
`
|
||||
)}
|
||||
>
|
||||
<div className="c-absolute c-pointer-events-none c-inset-0 c-left-auto c-flex c-items-center c-pr-4">
|
||||
<ChevronDown size={14} />
|
||||
</div>
|
||||
<Input
|
||||
spellCheck={false}
|
||||
onFocus={() => {
|
||||
local.open = true;
|
||||
local.render();
|
||||
}}
|
||||
className="cursor-pointer"
|
||||
ref={(el) => {
|
||||
local.ref.input = el;
|
||||
}}
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
|
@ -9,16 +9,15 @@ import {
|
|||
import { useLocal } from "@/utils/use-local";
|
||||
import autosize from "autosize";
|
||||
import { FC, ReactNode, useEffect, useRef } from "react";
|
||||
import { Button } from "../ui/button";
|
||||
import { Input } from "../ui/input";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { Date } from "./Date";
|
||||
import { Datetime } from "./Datetime";
|
||||
import { InputMoney } from "./InputMoney";
|
||||
import { PopUpDropdown } from "./PopUpDropdown";
|
||||
import { Radio } from "./Radio";
|
||||
import { SliderOptions } from "./Slider/types";
|
||||
import { FormHook, modify } from "./utils/utils";
|
||||
import { Dropdown } from "./Dropdown";
|
||||
|
||||
export const Field: FC<{
|
||||
name: string;
|
||||
|
|
@ -70,9 +69,6 @@ export const Field: FC<{
|
|||
}) => {
|
||||
const value = form?.hook.getValues()[name];
|
||||
const local = useLocal({
|
||||
dropdown: {
|
||||
popup: false,
|
||||
},
|
||||
date: {
|
||||
// label: "",
|
||||
popup: false,
|
||||
|
|
@ -120,19 +116,6 @@ export const Field: FC<{
|
|||
|
||||
return (
|
||||
<>
|
||||
{local.dropdown.popup && (
|
||||
<PopUpDropdown
|
||||
on_close={() => {
|
||||
local.dropdown.popup = false;
|
||||
local.render();
|
||||
}}
|
||||
on_select={(value: any) => {
|
||||
form?.hook.setValue(name, value);
|
||||
}}
|
||||
title={label}
|
||||
options={options}
|
||||
/>
|
||||
)}
|
||||
<FormField
|
||||
control={form?.hook.control || ({} as any)}
|
||||
name={name}
|
||||
|
|
@ -235,17 +218,7 @@ export const Field: FC<{
|
|||
<Textarea {...field} ref={textAreaRef} />
|
||||
)}
|
||||
|
||||
{type === "dropdown" && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
local.dropdown.popup = true;
|
||||
local.render();
|
||||
}}
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value}
|
||||
</Button>
|
||||
)}
|
||||
{type === "dropdown" && <Dropdown {...field} />}
|
||||
|
||||
{type === "date" && (
|
||||
<Date
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
import { useLocal } from "@/utils/use-local";
|
||||
import { FC, useEffect } from "react";
|
||||
import { X } from "lucide-react";
|
||||
import { Button } from "../../ui/button";
|
||||
|
||||
export const PopUpDropdown: FC<{
|
||||
on_select: (val: any) => void;
|
||||
on_close: () => void;
|
||||
title: string;
|
||||
options: () => Promise<{ value: string; label: string }[]>;
|
||||
}> = ({ on_close, title, options, on_select }) => {
|
||||
const local = useLocal({
|
||||
list: [] as { value: string; label: string }[],
|
||||
status: "init" as "init" | "loading" | "ready",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (local.status === "init") {
|
||||
local.status = "loading";
|
||||
local.render();
|
||||
options().then((result) => {
|
||||
local.list = result;
|
||||
|
||||
local.status = "ready";
|
||||
local.render();
|
||||
});
|
||||
}
|
||||
}, [options]);
|
||||
|
||||
return (
|
||||
<div className="c-fixed c-inset-0 c-bg-white c-z-50">
|
||||
<div className="c-flex c-flex-col c-mx-3">
|
||||
<div className="c-flex c-justify-between c-items-center">
|
||||
<h1 className="c-font-bold c-text-center c-truncate c-text-ellipsis c-overflow-hidden ...">
|
||||
{title}
|
||||
</h1>
|
||||
<button
|
||||
className="c-my-5 c-mx-3 hover:c-text-black/50"
|
||||
onClick={() => {
|
||||
on_close();
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<X />
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="rounded">
|
||||
{!!local.list &&
|
||||
local.list.map((item, index) => (
|
||||
<Button
|
||||
key={index}
|
||||
onClick={() => {
|
||||
on_select(item.value);
|
||||
on_close();
|
||||
local.render();
|
||||
}}
|
||||
className="w-full px-3 py-2 mb-2 cursor-pointer rounded hover:rounded hover:c-text-white"
|
||||
>
|
||||
<p>{item.label}</p>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -10,7 +10,7 @@ export const Radio: FC<{
|
|||
data: any;
|
||||
current_name: string;
|
||||
}) => Promise<(string | { value: string; label: string })[]>;
|
||||
value: string;
|
||||
value: string | string[];
|
||||
PassProp: any;
|
||||
custom: "y" | "n";
|
||||
child: any;
|
||||
|
|
@ -99,14 +99,16 @@ export const Radio: FC<{
|
|||
option_item={item}
|
||||
current_name={name}
|
||||
item_click={() => {
|
||||
console.log(selection);
|
||||
console.log(value, "====single", name);
|
||||
if (selection === "single") {
|
||||
console.log(form.hook.get);
|
||||
|
||||
form.hook.setValue(name, [...value]);
|
||||
local.mod(name, { value: item.value });
|
||||
local.render();
|
||||
} else if (selection === "multi") {
|
||||
|
||||
form.hook
|
||||
const val = []
|
||||
val.push()
|
||||
local.mod(name, { value: item.value });
|
||||
local.render();
|
||||
console.log(value, "====multi", name);
|
||||
} else {
|
||||
null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/utils"
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"c-flex c-cursor-default c-select-none c-items-center c-rounded-sm c-px-2 c-py-1.5 c-text-sm c-outline-none focus:c-bg-accent data-[state=open]:c-bg-accent",
|
||||
inset && "c-pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="c-ml-auto c-h-4 c-w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
))
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"c-z-50 c-min-w-[8rem] c-overflow-hidden c-rounded-md c-border c-bg-popover c-p-1 c-text-popover-foreground c-shadow-lg data-[state=open]:c-animate-in data-[state=closed]:c-animate-out data-[state=closed]:c-fade-out-0 data-[state=open]:c-fade-in-0 data-[state=closed]:c-zoom-out-95 data-[state=open]:c-zoom-in-95 data-[side=bottom]:c-slide-in-from-top-2 data-[side=left]:c-slide-in-from-right-2 data-[side=right]:c-slide-in-from-left-2 data-[side=top]:c-slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"c-z-50 c-min-w-[8rem] c-overflow-hidden c-rounded-md c-border c-bg-popover c-p-1 c-text-popover-foreground c-shadow-md data-[state=open]:c-animate-in data-[state=closed]:c-animate-out data-[state=closed]:c-fade-out-0 data-[state=open]:c-fade-in-0 data-[state=closed]:c-zoom-out-95 data-[state=open]:c-zoom-in-95 data-[side=bottom]:c-slide-in-from-top-2 data-[side=left]:c-slide-in-from-right-2 data-[side=right]:c-slide-in-from-left-2 data-[side=top]:c-slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
))
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"c-relative c-flex c-cursor-default c-select-none c-items-center c-rounded-sm c-px-2 c-py-1.5 c-text-sm c-outline-none c-transition-colors focus:c-bg-accent focus:c-text-accent-foreground data-[disabled]:c-pointer-events-none data-[disabled]:c-opacity-50",
|
||||
inset && "c-pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"c-relative c-flex c-cursor-default c-select-none c-items-center c-rounded-sm c-py-1.5 c-pl-8 c-pr-2 c-text-sm c-outline-none c-transition-colors focus:c-bg-accent focus:c-text-accent-foreground data-[disabled]:c-pointer-events-none data-[disabled]:c-opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="c-absolute c-left-2 c-flex c-h-3.5 c-w-3.5 c-items-center c-justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="c-h-4 c-w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
))
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"c-relative c-flex c-cursor-default c-select-none c-items-center c-rounded-sm c-py-1.5 c-pl-8 c-pr-2 c-text-sm c-outline-none c-transition-colors focus:c-bg-accent focus:c-text-accent-foreground data-[disabled]:c-pointer-events-none data-[disabled]:c-opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="c-absolute c-left-2 c-flex c-h-3.5 c-w-3.5 c-items-center c-justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="c-h-2 c-w-2 c-fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
))
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"c-px-2 c-py-1.5 c-text-sm c-font-semibold",
|
||||
inset && "c-pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("c--mx-1 c-my-1 c-h-px c-bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn("c-ml-auto c-text-xs c-tracking-widest c-opacity-60", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import * as React from "react";
|
||||
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import {
|
||||
Controller,
|
||||
ControllerProps,
|
||||
|
|
@ -8,23 +8,23 @@ import {
|
|||
FieldValues,
|
||||
FormProvider,
|
||||
useFormContext,
|
||||
} from "react-hook-form"
|
||||
} from "react-hook-form";
|
||||
|
||||
import { cn } from "@/utils"
|
||||
import { Label } from "@/comps/ui/label"
|
||||
import { cn } from "@/utils";
|
||||
import { Label } from "@/comps/ui/label";
|
||||
|
||||
const Form = FormProvider
|
||||
const Form = FormProvider;
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
> = {
|
||||
name: TName
|
||||
}
|
||||
name: TName;
|
||||
};
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue
|
||||
)
|
||||
);
|
||||
|
||||
const FormField = <
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
|
|
@ -36,21 +36,21 @@ const FormField = <
|
|||
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||
<Controller {...props} />
|
||||
</FormFieldContext.Provider>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = React.useContext(FormFieldContext)
|
||||
const itemContext = React.useContext(FormItemContext)
|
||||
const { getFieldState, formState } = useFormContext()
|
||||
const fieldContext = React.useContext(FormFieldContext);
|
||||
const itemContext = React.useContext(FormItemContext);
|
||||
const { getFieldState, formState } = useFormContext();
|
||||
|
||||
const fieldState = getFieldState(fieldContext.name, formState)
|
||||
const fieldState = getFieldState(fieldContext.name, formState);
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error("useFormField should be used within <FormField>")
|
||||
throw new Error("useFormField should be used within <FormField>");
|
||||
}
|
||||
|
||||
const { id } = itemContext
|
||||
const { id } = itemContext;
|
||||
|
||||
return {
|
||||
id,
|
||||
|
|
@ -59,36 +59,36 @@ const useFormField = () => {
|
|||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
type FormItemContextValue = {
|
||||
id: string
|
||||
}
|
||||
id: string;
|
||||
};
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue
|
||||
)
|
||||
);
|
||||
|
||||
const FormItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const id = React.useId()
|
||||
const id = React.useId();
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn("c-space-y-2", className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
)
|
||||
})
|
||||
FormItem.displayName = "FormItem"
|
||||
);
|
||||
});
|
||||
FormItem.displayName = "FormItem";
|
||||
|
||||
const FormLabel = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { error, formItemId } = useFormField()
|
||||
const { error, formItemId } = useFormField();
|
||||
|
||||
return (
|
||||
<Label
|
||||
|
|
@ -97,15 +97,16 @@ const FormLabel = React.forwardRef<
|
|||
htmlFor={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormLabel.displayName = "FormLabel"
|
||||
);
|
||||
});
|
||||
FormLabel.displayName = "FormLabel";
|
||||
|
||||
const FormControl = React.forwardRef<
|
||||
React.ElementRef<typeof Slot>,
|
||||
React.ComponentPropsWithoutRef<typeof Slot>
|
||||
>(({ ...props }, ref) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
||||
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||
useFormField();
|
||||
|
||||
return (
|
||||
<Slot
|
||||
|
|
@ -119,15 +120,15 @@ const FormControl = React.forwardRef<
|
|||
aria-invalid={!!error}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormControl.displayName = "FormControl"
|
||||
);
|
||||
});
|
||||
FormControl.displayName = "FormControl";
|
||||
|
||||
const FormDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { formDescriptionId } = useFormField()
|
||||
const { formDescriptionId } = useFormField();
|
||||
|
||||
return (
|
||||
<p
|
||||
|
|
@ -136,19 +137,19 @@ const FormDescription = React.forwardRef<
|
|||
className={cn("c-text-sm c-text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormDescription.displayName = "FormDescription"
|
||||
);
|
||||
});
|
||||
FormDescription.displayName = "FormDescription";
|
||||
|
||||
const FormMessage = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { error, formMessageId } = useFormField()
|
||||
const body = error ? String(error?.message) : children
|
||||
const { error, formMessageId } = useFormField();
|
||||
const body = error ? String(error?.message) : children;
|
||||
|
||||
if (!body) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -160,9 +161,9 @@ const FormMessage = React.forwardRef<
|
|||
>
|
||||
{body}
|
||||
</p>
|
||||
)
|
||||
})
|
||||
FormMessage.displayName = "FormMessage"
|
||||
);
|
||||
});
|
||||
FormMessage.displayName = "FormMessage";
|
||||
|
||||
export {
|
||||
useFormField,
|
||||
|
|
@ -173,4 +174,4 @@ export {
|
|||
FormDescription,
|
||||
FormMessage,
|
||||
FormField,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ export const useLocal = <T extends object>(
|
|||
deps?: any[]
|
||||
): {
|
||||
[K in keyof T]: T[K] extends Promise<any> ? null | Awaited<T[K]> : T[K];
|
||||
} & { render: () => void } => {
|
||||
} & { render: (force?: boolean) => void } => {
|
||||
const [, _render] = useState({});
|
||||
const _ = useRef({
|
||||
data: data as unknown as T & {
|
||||
render: () => void;
|
||||
render: (force?: boolean) => void;
|
||||
},
|
||||
deps: (deps || []) as any[],
|
||||
promisedKeys: new Set<string>(),
|
||||
|
|
@ -45,8 +45,9 @@ export const useLocal = <T extends object>(
|
|||
}
|
||||
}
|
||||
|
||||
local.data.render = () => {
|
||||
if (local.ready) _render({});
|
||||
local.data.render = (force) => {
|
||||
if (force) _render({})
|
||||
else if (local.ready) _render({});
|
||||
};
|
||||
} else {
|
||||
if (local.deps.length > 0 && deps) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue