UNPKG

json-to-shadcn

Version:

Config-driven UI renderer using ShadCN components

2 lines (1 loc) 5.75 kB
import{useForm as j,Controller as x}from"react-hook-form";import*as B from"react";import{clsx as z}from"clsx";import{twMerge as _}from"tailwind-merge";function n(...e){return _(z(e))}import{jsx as O}from"react/jsx-runtime";var C=B.forwardRef(({className:e,type:r,...t},f)=>O("input",{type:r,className:n("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",e),ref:f,...t}));C.displayName="Input";import*as P from"react";import{Slot as X}from"@radix-ui/react-slot";import{cva as q}from"class-variance-authority";import{jsx as K}from"react/jsx-runtime";var G=q("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:"bg-primary text-primary-foreground shadow hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",outline:"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),L=P.forwardRef(({className:e,variant:r,size:t,asChild:f=!1,...N},b)=>K(f?X:"button",{className:n(G({variant:r,size:t,className:e})),ref:b,...N}));L.displayName="Button";import*as p from"react";import{jsx as u}from"react/jsx-runtime";var T=p.forwardRef(({className:e,...r},t)=>u("div",{ref:t,className:n("rounded-xl border bg-card text-card-foreground shadow",e),...r}));T.displayName="Card";var Q=p.forwardRef(({className:e,...r},t)=>u("div",{ref:t,className:n("flex flex-col space-y-1.5 p-6",e),...r}));Q.displayName="CardHeader";var U=p.forwardRef(({className:e,...r},t)=>u("div",{ref:t,className:n("font-semibold leading-none tracking-tight",e),...r}));U.displayName="CardTitle";var W=p.forwardRef(({className:e,...r},t)=>u("div",{ref:t,className:n("text-sm text-muted-foreground",e),...r}));W.displayName="CardDescription";var H=p.forwardRef(({className:e,...r},t)=>u("div",{ref:t,className:n("p-6 pt-0",e),...r}));H.displayName="CardContent";var Y=p.forwardRef(({className:e,...r},t)=>u("div",{ref:t,className:n("flex items-center p-6 pt-0",e),...r}));Y.displayName="CardFooter";import*as F from"react";import{jsx as Z}from"react/jsx-runtime";var w=F.forwardRef(({className:e,...r},t)=>Z("textarea",{className:n("flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",e),ref:t,...r}));w.displayName="Textarea";import{jsx as a,jsxs as c}from"react/jsx-runtime";var Ce=({config:e,onSubmit:r})=>{let{control:t,handleSubmit:f}=j(),N=l=>{console.log("\u2705 Form Submitted:",l),r?.(l)},b=(l,o=0)=>{let M=l.props,k=M.options||[],{wrapperClassName:v,label:i,labelClassName:g,className:d,name:y,validation:h,type:E,placeholder:D,maxLength:A,minLength:S,text:J,variant:$,content:I,title:V}=M;switch(l.type){case"input":case"date":return a(x,{name:y||`field-${o}`,control:t,defaultValue:"",rules:h,render:({field:s})=>c("div",{className:v,children:[i&&a("label",{className:g,children:i}),a(C,{...s,type:E==="date"?"date":E||"text",placeholder:D,maxLength:A,minLength:S,className:d})]})},o);case"textarea":return a(x,{name:y||`field-${o}`,control:t,defaultValue:"",rules:h,render:({field:s})=>c("div",{className:v,children:[i&&a("label",{className:g,children:i}),a(w,{...s,placeholder:D,maxLength:A,minLength:S,className:d})]})},o);case"select":return a(x,{name:y||`field-${o}`,control:t,defaultValue:"",rules:h,render:({field:s})=>c("div",{className:v,children:[i&&a("label",{className:g,children:i}),c("select",{...s,className:d,children:[a("option",{value:"",children:"Select an option"}),k?.map((m,R)=>a("option",{value:m.value,children:m.label},R))]})]})},o);case"checkbox":return a(x,{name:y||`field-${o}`,control:t,defaultValue:!1,rules:h,render:({field:s})=>c("label",{className:`${v} flex items-center gap-2`,children:[a("input",{type:"checkbox",...s,className:d}),a("span",{className:g,children:i})]})},o);case"radio":return a(x,{name:y||`field-${o}`,control:t,defaultValue:"",rules:h,render:({field:s})=>c("div",{className:v,children:[i&&a("label",{className:g,children:i}),a("div",{className:"flex gap-4",children:k?.map((m,R)=>c("label",{className:"flex items-center gap-2",children:[a("input",{type:"radio",value:m.value,checked:s.value===m.value,onChange:()=>s.onChange(m.value),className:d}),m.label]},R))})]})},o);case"button":return a(L,{type:"submit",className:d,variant:$||"default",children:J},o);case"text":return a("p",{className:d,children:I},o);case"card":return a(T,{className:d,children:c(H,{className:"space-y-4",children:[V&&a("h2",{className:"text-lg font-semibold",children:V}),Array.isArray(l.props.content)&&l.props.content.map((s,m)=>b(s,m))]})},o);default:return null}};return a("form",{onSubmit:f(N),className:"space-y-6",children:Array.isArray(e)?e.map((l,o)=>b(l,o)):b(e)})};export{Ce as JsonFormRenderer};