wip fix
This commit is contained in:
parent
bff254f467
commit
cdf8c5c837
|
|
@ -7,6 +7,7 @@ import {
|
||||||
NavigationMenuTrigger,
|
NavigationMenuTrigger,
|
||||||
navigationMenuTriggerStyle,
|
navigationMenuTriggerStyle,
|
||||||
} from "@/comps/ui/navigation-menu";
|
} from "@/comps/ui/navigation-menu";
|
||||||
|
import { useLocal } from "@/utils/use-local";
|
||||||
import get from "lodash.get";
|
import get from "lodash.get";
|
||||||
import { FC, forwardRef } from "react";
|
import { FC, forwardRef } from "react";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,15 +175,13 @@ export const usePopoverContext = () => {
|
||||||
export function Popover({
|
export function Popover({
|
||||||
children,
|
children,
|
||||||
content,
|
content,
|
||||||
className,
|
|
||||||
modal = false,
|
modal = false,
|
||||||
popoverClassName,
|
className,
|
||||||
arrow,
|
arrow,
|
||||||
...restOptions
|
...restOptions
|
||||||
}: {
|
}: {
|
||||||
className?: string;
|
|
||||||
root?: HTMLElement;
|
root?: HTMLElement;
|
||||||
popoverClassName?: string;
|
className?: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
content?: React.ReactNode;
|
content?: React.ReactNode;
|
||||||
arrow?: boolean;
|
arrow?: boolean;
|
||||||
|
|
@ -196,7 +194,7 @@ export function Popover({
|
||||||
return (
|
return (
|
||||||
<PopoverContext.Provider value={popover}>
|
<PopoverContext.Provider value={popover}>
|
||||||
<PopoverTrigger
|
<PopoverTrigger
|
||||||
className={className}
|
asChild
|
||||||
onClick={
|
onClick={
|
||||||
typeof restOptions.open !== "undefined"
|
typeof restOptions.open !== "undefined"
|
||||||
? () => {
|
? () => {
|
||||||
|
|
@ -209,13 +207,12 @@ export function Popover({
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
className={cx(
|
className={cx(
|
||||||
popoverClassName
|
className,
|
||||||
? popoverClassName
|
css`
|
||||||
: css`
|
background: white;
|
||||||
background: white;
|
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
|
||||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.4);
|
user-select: none;
|
||||||
user-select: none;
|
`
|
||||||
`
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{_content}
|
{_content}
|
||||||
|
|
@ -297,10 +294,7 @@ export const PopoverContent = React.forwardRef<
|
||||||
return (
|
return (
|
||||||
<FloatingPortal root={context.root}>
|
<FloatingPortal root={context.root}>
|
||||||
{context.backdrop ? (
|
{context.backdrop ? (
|
||||||
<FloatingOverlay
|
<FloatingOverlay className={"c-z-50"} lockScroll>
|
||||||
className={"c-z-50"}
|
|
||||||
lockScroll
|
|
||||||
>
|
|
||||||
{content}
|
{content}
|
||||||
</FloatingOverlay>
|
</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 { useLocal } from "@/utils/use-local";
|
||||||
import autosize from "autosize";
|
import autosize from "autosize";
|
||||||
import { FC, ReactNode, useEffect, useRef } from "react";
|
import { FC, ReactNode, useEffect, useRef } from "react";
|
||||||
import { Button } from "../ui/button";
|
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
import { Textarea } from "../ui/textarea";
|
import { Textarea } from "../ui/textarea";
|
||||||
import { Date } from "./Date";
|
import { Date } from "./Date";
|
||||||
import { Datetime } from "./Datetime";
|
import { Datetime } from "./Datetime";
|
||||||
import { InputMoney } from "./InputMoney";
|
import { InputMoney } from "./InputMoney";
|
||||||
import { PopUpDropdown } from "./PopUpDropdown";
|
|
||||||
import { Radio } from "./Radio";
|
import { Radio } from "./Radio";
|
||||||
import { SliderOptions } from "./Slider/types";
|
import { SliderOptions } from "./Slider/types";
|
||||||
import { FormHook, modify } from "./utils/utils";
|
import { FormHook, modify } from "./utils/utils";
|
||||||
|
import { Dropdown } from "./Dropdown";
|
||||||
|
|
||||||
export const Field: FC<{
|
export const Field: FC<{
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -70,9 +69,6 @@ export const Field: FC<{
|
||||||
}) => {
|
}) => {
|
||||||
const value = form?.hook.getValues()[name];
|
const value = form?.hook.getValues()[name];
|
||||||
const local = useLocal({
|
const local = useLocal({
|
||||||
dropdown: {
|
|
||||||
popup: false,
|
|
||||||
},
|
|
||||||
date: {
|
date: {
|
||||||
// label: "",
|
// label: "",
|
||||||
popup: false,
|
popup: false,
|
||||||
|
|
@ -120,19 +116,6 @@ export const Field: FC<{
|
||||||
|
|
||||||
return (
|
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
|
<FormField
|
||||||
control={form?.hook.control || ({} as any)}
|
control={form?.hook.control || ({} as any)}
|
||||||
name={name}
|
name={name}
|
||||||
|
|
@ -235,17 +218,7 @@ export const Field: FC<{
|
||||||
<Textarea {...field} ref={textAreaRef} />
|
<Textarea {...field} ref={textAreaRef} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{type === "dropdown" && (
|
{type === "dropdown" && <Dropdown {...field} />}
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
local.dropdown.popup = true;
|
|
||||||
local.render();
|
|
||||||
}}
|
|
||||||
variant={"outline"}
|
|
||||||
>
|
|
||||||
{field.value}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{type === "date" && (
|
{type === "date" && (
|
||||||
<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;
|
data: any;
|
||||||
current_name: string;
|
current_name: string;
|
||||||
}) => Promise<(string | { value: string; label: string })[]>;
|
}) => Promise<(string | { value: string; label: string })[]>;
|
||||||
value: string;
|
value: string | string[];
|
||||||
PassProp: any;
|
PassProp: any;
|
||||||
custom: "y" | "n";
|
custom: "y" | "n";
|
||||||
child: any;
|
child: any;
|
||||||
|
|
@ -99,14 +99,16 @@ export const Radio: FC<{
|
||||||
option_item={item}
|
option_item={item}
|
||||||
current_name={name}
|
current_name={name}
|
||||||
item_click={() => {
|
item_click={() => {
|
||||||
console.log(selection);
|
console.log(value, "====single", name);
|
||||||
if (selection === "single") {
|
if (selection === "single") {
|
||||||
console.log(form.hook.get);
|
local.mod(name, { value: item.value });
|
||||||
|
local.render();
|
||||||
form.hook.setValue(name, [...value]);
|
|
||||||
} else if (selection === "multi") {
|
} else if (selection === "multi") {
|
||||||
|
const val = []
|
||||||
form.hook
|
val.push()
|
||||||
|
local.mod(name, { value: item.value });
|
||||||
|
local.render();
|
||||||
|
console.log(value, "====multi", name);
|
||||||
} else {
|
} else {
|
||||||
null;
|
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 React from "react";
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
import { Slot } from "@radix-ui/react-slot"
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
ControllerProps,
|
ControllerProps,
|
||||||
|
|
@ -8,23 +8,23 @@ import {
|
||||||
FieldValues,
|
FieldValues,
|
||||||
FormProvider,
|
FormProvider,
|
||||||
useFormContext,
|
useFormContext,
|
||||||
} from "react-hook-form"
|
} from "react-hook-form";
|
||||||
|
|
||||||
import { cn } from "@/utils"
|
import { cn } from "@/utils";
|
||||||
import { Label } from "@/comps/ui/label"
|
import { Label } from "@/comps/ui/label";
|
||||||
|
|
||||||
const Form = FormProvider
|
const Form = FormProvider;
|
||||||
|
|
||||||
type FormFieldContextValue<
|
type FormFieldContextValue<
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||||
> = {
|
> = {
|
||||||
name: TName
|
name: TName;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||||
{} as FormFieldContextValue
|
{} as FormFieldContextValue
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormField = <
|
const FormField = <
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
|
|
@ -36,21 +36,21 @@ const FormField = <
|
||||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||||
<Controller {...props} />
|
<Controller {...props} />
|
||||||
</FormFieldContext.Provider>
|
</FormFieldContext.Provider>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const useFormField = () => {
|
const useFormField = () => {
|
||||||
const fieldContext = React.useContext(FormFieldContext)
|
const fieldContext = React.useContext(FormFieldContext);
|
||||||
const itemContext = React.useContext(FormItemContext)
|
const itemContext = React.useContext(FormItemContext);
|
||||||
const { getFieldState, formState } = useFormContext()
|
const { getFieldState, formState } = useFormContext();
|
||||||
|
|
||||||
const fieldState = getFieldState(fieldContext.name, formState)
|
const fieldState = getFieldState(fieldContext.name, formState);
|
||||||
|
|
||||||
if (!fieldContext) {
|
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 {
|
return {
|
||||||
id,
|
id,
|
||||||
|
|
@ -59,36 +59,36 @@ const useFormField = () => {
|
||||||
formDescriptionId: `${id}-form-item-description`,
|
formDescriptionId: `${id}-form-item-description`,
|
||||||
formMessageId: `${id}-form-item-message`,
|
formMessageId: `${id}-form-item-message`,
|
||||||
...fieldState,
|
...fieldState,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
type FormItemContextValue = {
|
type FormItemContextValue = {
|
||||||
id: string
|
id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||||
{} as FormItemContextValue
|
{} as FormItemContextValue
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormItem = React.forwardRef<
|
const FormItem = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
React.HTMLAttributes<HTMLDivElement>
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const id = React.useId()
|
const id = React.useId();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormItemContext.Provider value={{ id }}>
|
<FormItemContext.Provider value={{ id }}>
|
||||||
<div ref={ref} className={cn("c-space-y-2", className)} {...props} />
|
<div ref={ref} className={cn("c-space-y-2", className)} {...props} />
|
||||||
</FormItemContext.Provider>
|
</FormItemContext.Provider>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormItem.displayName = "FormItem"
|
FormItem.displayName = "FormItem";
|
||||||
|
|
||||||
const FormLabel = React.forwardRef<
|
const FormLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { error, formItemId } = useFormField()
|
const { error, formItemId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Label
|
<Label
|
||||||
|
|
@ -97,15 +97,16 @@ const FormLabel = React.forwardRef<
|
||||||
htmlFor={formItemId}
|
htmlFor={formItemId}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormLabel.displayName = "FormLabel"
|
FormLabel.displayName = "FormLabel";
|
||||||
|
|
||||||
const FormControl = React.forwardRef<
|
const FormControl = React.forwardRef<
|
||||||
React.ElementRef<typeof Slot>,
|
React.ElementRef<typeof Slot>,
|
||||||
React.ComponentPropsWithoutRef<typeof Slot>
|
React.ComponentPropsWithoutRef<typeof Slot>
|
||||||
>(({ ...props }, ref) => {
|
>(({ ...props }, ref) => {
|
||||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||||
|
useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slot
|
<Slot
|
||||||
|
|
@ -119,15 +120,15 @@ const FormControl = React.forwardRef<
|
||||||
aria-invalid={!!error}
|
aria-invalid={!!error}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormControl.displayName = "FormControl"
|
FormControl.displayName = "FormControl";
|
||||||
|
|
||||||
const FormDescription = React.forwardRef<
|
const FormDescription = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
React.HTMLAttributes<HTMLParagraphElement>
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { formDescriptionId } = useFormField()
|
const { formDescriptionId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
|
|
@ -136,19 +137,19 @@ const FormDescription = React.forwardRef<
|
||||||
className={cn("c-text-sm c-text-muted-foreground", className)}
|
className={cn("c-text-sm c-text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormDescription.displayName = "FormDescription"
|
FormDescription.displayName = "FormDescription";
|
||||||
|
|
||||||
const FormMessage = React.forwardRef<
|
const FormMessage = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
React.HTMLAttributes<HTMLParagraphElement>
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, children, ...props }, ref) => {
|
>(({ className, children, ...props }, ref) => {
|
||||||
const { error, formMessageId } = useFormField()
|
const { error, formMessageId } = useFormField();
|
||||||
const body = error ? String(error?.message) : children
|
const body = error ? String(error?.message) : children;
|
||||||
|
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -160,9 +161,9 @@ const FormMessage = React.forwardRef<
|
||||||
>
|
>
|
||||||
{body}
|
{body}
|
||||||
</p>
|
</p>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormMessage.displayName = "FormMessage"
|
FormMessage.displayName = "FormMessage";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useFormField,
|
useFormField,
|
||||||
|
|
@ -173,4 +174,4 @@ export {
|
||||||
FormDescription,
|
FormDescription,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
FormField,
|
FormField,
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ export const useLocal = <T extends object>(
|
||||||
deps?: any[]
|
deps?: any[]
|
||||||
): {
|
): {
|
||||||
[K in keyof T]: T[K] extends Promise<any> ? null | Awaited<T[K]> : T[K];
|
[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 [, _render] = useState({});
|
||||||
const _ = useRef({
|
const _ = useRef({
|
||||||
data: data as unknown as T & {
|
data: data as unknown as T & {
|
||||||
render: () => void;
|
render: (force?: boolean) => void;
|
||||||
},
|
},
|
||||||
deps: (deps || []) as any[],
|
deps: (deps || []) as any[],
|
||||||
promisedKeys: new Set<string>(),
|
promisedKeys: new Set<string>(),
|
||||||
|
|
@ -45,8 +45,9 @@ export const useLocal = <T extends object>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
local.data.render = () => {
|
local.data.render = (force) => {
|
||||||
if (local.ready) _render({});
|
if (force) _render({})
|
||||||
|
else if (local.ready) _render({});
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (local.deps.length > 0 && deps) {
|
if (local.deps.length > 0 && deps) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue