mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-17 12:56:05 +00:00
initial json schema form implementation
This commit is contained in:
@@ -1,25 +1,37 @@
|
||||
import { getBrowser } from "core/utils";
|
||||
import type { Field } from "data";
|
||||
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import {
|
||||
type ElementType,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import { TbCalendar, TbChevronDown, TbInfoCircle } from "react-icons/tb";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { IconButton } from "ui/components/buttons/IconButton";
|
||||
import { useEvent } from "ui/hooks/use-event";
|
||||
|
||||
export const Group: React.FC<React.ComponentProps<"div"> & { error?: boolean }> = ({
|
||||
export const Group = <E extends ElementType = "div">({
|
||||
error,
|
||||
as,
|
||||
...props
|
||||
}) => (
|
||||
<div
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"flex flex-col gap-1.5",
|
||||
}: React.ComponentProps<E> & { error?: boolean; as?: E }) => {
|
||||
const Tag = as || "div";
|
||||
|
||||
error && "text-red-500",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<Tag
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"flex flex-col gap-1.5",
|
||||
as === "fieldset" && "border border-primary/10 p-3 rounded-md",
|
||||
error && "text-red-500",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const formElementFactory = (element: string, props: any) => {
|
||||
switch (element) {
|
||||
@@ -34,7 +46,21 @@ export const formElementFactory = (element: string, props: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const Label: React.FC<React.ComponentProps<"label">> = (props) => <label {...props} />;
|
||||
export const Label = <E extends ElementType = "label">({
|
||||
as,
|
||||
...props
|
||||
}: React.ComponentProps<E> & { as?: E }) => {
|
||||
const Tag = as || "label";
|
||||
return <Tag {...props} />;
|
||||
};
|
||||
|
||||
export const Help: React.FC<React.ComponentProps<"div">> = ({ className, ...props }) => (
|
||||
<div {...props} className={twMerge("text-sm text-primary/50", className)} />
|
||||
);
|
||||
|
||||
export const ErrorMessage: React.FC<React.ComponentProps<"div">> = ({ className, ...props }) => (
|
||||
<div {...props} className={twMerge("text-sm text-red-500", className)} />
|
||||
);
|
||||
|
||||
export const FieldLabel: React.FC<React.ComponentProps<"label"> & { field: Field }> = ({
|
||||
field,
|
||||
@@ -145,20 +171,45 @@ export const BooleanInput = forwardRef<HTMLInputElement, React.ComponentProps<"i
|
||||
}
|
||||
);
|
||||
|
||||
export const Select = forwardRef<HTMLSelectElement, React.ComponentProps<"select">>(
|
||||
(props, ref) => (
|
||||
<div className="flex w-full relative">
|
||||
<select
|
||||
{...props}
|
||||
ref={ref}
|
||||
className={twMerge(
|
||||
"bg-muted/40 focus:bg-muted rounded-md py-2.5 px-4 outline-none focus:outline-none focus:ring-2 focus:ring-zinc-500 focus:border-transparent transition-all disabled:bg-muted/50 disabled:text-primary/50",
|
||||
"appearance-none h-11 w-full",
|
||||
"border-r-8 border-r-transparent",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
export const Select = forwardRef<
|
||||
HTMLSelectElement,
|
||||
React.ComponentProps<"select"> & {
|
||||
options?: { value: string; label: string }[] | (string | number)[];
|
||||
}
|
||||
>(({ children, options, ...props }, ref) => (
|
||||
<div className="flex w-full relative">
|
||||
<select
|
||||
{...props}
|
||||
ref={ref}
|
||||
className={twMerge(
|
||||
"bg-muted/40 focus:bg-muted rounded-md py-2.5 px-4 outline-none focus:outline-none focus:ring-2 focus:ring-zinc-500 focus:border-transparent transition-all disabled:bg-muted/50 disabled:text-primary/50",
|
||||
"appearance-none h-11 w-full",
|
||||
!props.multiple && "border-r-8 border-r-transparent",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{options ? (
|
||||
<>
|
||||
{!props.required && <option value="" />}
|
||||
{options
|
||||
.map((o, i) => {
|
||||
if (typeof o !== "object") {
|
||||
return { value: o, label: String(o) };
|
||||
}
|
||||
return o;
|
||||
})
|
||||
.map((opt) => (
|
||||
<option key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</select>
|
||||
{!props.multiple && (
|
||||
<TbChevronDown className="absolute right-3 top-0 bottom-0 h-full opacity-70" size={18} />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
)}
|
||||
</div>
|
||||
));
|
||||
|
||||
Reference in New Issue
Block a user