fix label

This commit is contained in:
rizrmd 2024-03-23 06:48:08 -07:00
parent cdf8c5c837
commit 1dc4da9a68
4 changed files with 163 additions and 32 deletions

View File

@ -2,16 +2,71 @@ 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 { FC, useEffect } from "react";
import type { ControllerRenderProps, FieldValues } from "react-hook-form";
import { FieldListItem, FieldOptions } from "../type";
import { FormHook } from "../utils/utils";
import { Skeleton } from "@/comps/ui/skeleton";
export const Dropdown: FC<ControllerRenderProps<FieldValues, string>> = ({
value,
}) => {
export const Dropdown: FC<
ControllerRenderProps<FieldValues, string> & {
options: FieldOptions;
form?: FormHook;
name: string;
}
> = ({ value, options, form, name }) => {
const local = useLocal({
status: "loading" as "loading" | "ready",
open: false,
ref: { input: null as null | HTMLInputElement },
list: [] as FieldListItem[],
input: "",
label: "",
filter: "",
});
useEffect(() => {
if (form) {
local.status = "loading";
local.render();
const callback = (result: any[]) => {
local.list = result.map((e) => {
if (typeof e === "string") {
return {
value: e,
label: e,
};
}
return e;
});
const found = local.list.find((e) => e.value === value);
if (found) {
local.label = found.label;
}
local.status = "ready";
local.render();
};
const res = options({ data: form.hook.getValues(), current_name: name });
if (res instanceof Promise) {
res.then(callback);
} else {
callback(res);
}
}
}, [options]);
let filtered = local.list;
if (local.filter) {
filtered = local.list.filter((e) => {
if (e.value.toLowerCase().includes(local.filter)) return true;
return false;
});
}
return (
<Popover
open={local.open}
@ -24,12 +79,51 @@ export const Dropdown: FC<ControllerRenderProps<FieldValues, string>> = ({
content={
<div
className={cx(
"c-px-3 c-py-2",
"c-text-sm",
css`
width: ${local.ref.input?.clientWidth || 100}px;
`
)}
></div>
>
{local.status === "loading" && (
<>
<div className="c-flex c-flex-col c-space-y-1 c-px-3 c-py-2">
<Skeleton className="c-h-[10px] c-w-[90px]" />
<Skeleton className="c-h-[10px] c-w-[60px]" />
</div>
</>
)}
{local.status === "ready" && (
<>
{filtered.map((item, idx) => {
return (
<div
tabIndex={0}
key={item.value + "_" + idx}
className={cx(
"c-px-3 c-py-1 cursor-pointer option-item",
item.value === value
? "c-bg-blue-600 c-text-white"
: "hover:c-bg-blue-50",
idx > 0 && "c-border-t",
idx === 0 && "c-rounded-t-sm",
idx === local.list.length - 1 && "c-rounded-b-sm"
)}
onClick={() => {
if (form) {
local.open = false;
form.hook.setValue(name, item.value);
form.render();
}
}}
>
{item.label}
</div>
);
})}
</>
)}
</div>
}
>
<div
@ -39,22 +133,41 @@ export const Dropdown: FC<ControllerRenderProps<FieldValues, string>> = ({
cursor: pointer !important;
`
)}
tabIndex={0}
onFocus={() => {
local.open = true;
local.input = local.label;
local.filter = "";
local.render();
setTimeout(() => {
local.ref.input?.focus();
});
}}
>
<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;
value={local.open ? local.input : ""}
className={cx(
local.open ? "c-cursor-pointer" : "c-pointer-events-none"
)}
onChange={(e) => {
local.input = e.currentTarget.value;
local.filter = local.input.toLowerCase();
local.render();
}}
className="cursor-pointer"
ref={(el) => {
local.ref.input = el;
}}
type="text"
/>
{!local.open && (
<div className="c-absolute c-text-sm c-inset-0 c-px-3 c-flex c-items-center">
{local.label}
</div>
)}
</div>
</Popover>
);

View File

@ -18,6 +18,7 @@ import { Radio } from "./Radio";
import { SliderOptions } from "./Slider/types";
import { FormHook, modify } from "./utils/utils";
import { Dropdown } from "./Dropdown";
import { FieldOptions } from "./type";
export const Field: FC<{
name: string;
@ -37,7 +38,7 @@ export const Field: FC<{
| "slider"
| "master-link";
required: "y" | "n";
options: () => Promise<{ value: string; label: string }[]>;
options: FieldOptions;
slider: () => Promise<SliderOptions>;
on_change: (arg: { value: any }) => void | Promise<void>;
PassProp: any;
@ -218,7 +219,14 @@ export const Field: FC<{
<Textarea {...field} ref={textAreaRef} />
)}
{type === "dropdown" && <Dropdown {...field} />}
{type === "dropdown" && (
<Dropdown
{...field}
options={options}
form={form}
name={name}
/>
)}
{type === "date" && (
<Date

View File

@ -2,14 +2,12 @@ import { useLocal } from "@/utils/use-local";
import { FC, useEffect } from "react";
import { Button } from "../../ui/button";
import { FormHook, modify } from "../utils/utils";
import { FieldOptions } from "../type";
export const Radio: FC<{
name: string;
on_select: (val: any) => void;
options: (opt: {
data: any;
current_name: string;
}) => Promise<(string | { value: string; label: string })[]>;
options: FieldOptions;
value: string | string[];
PassProp: any;
custom: "y" | "n";
@ -40,8 +38,7 @@ export const Radio: FC<{
if (!local.option_modified && form) {
local.status = "loading";
local.render();
options({ data: form.hook.getValues(), current_name: name }).then(
(result) => {
const callback = (result: any[]) => {
local.list = result.map((e) => {
if (typeof e === "string") {
return {
@ -54,8 +51,14 @@ export const Radio: FC<{
local.status = "ready";
local.render();
};
const res = options({ data: form.hook.getValues(), current_name: name });
if (res instanceof Promise) {
res.then(callback);
} else {
callback(res);
}
);
}
}, [options]);
@ -104,8 +107,8 @@ export const Radio: FC<{
local.mod(name, { value: item.value });
local.render();
} else if (selection === "multi") {
const val = []
val.push()
const val = [];
val.push();
local.mod(name, { value: item.value });
local.render();
console.log(value, "====multi", name);

7
comps/form/type.ts Executable file
View File

@ -0,0 +1,7 @@
export type FieldOptions = (opt: {
data: any;
current_name: string;
where?: { values: string[] }
}) => Promise<(string | FieldListItem)[]>
export type FieldListItem = { value: string; label: string }