@cisri/json-schema-form 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/dist/form-utils.d.ts +3 -0
- package/dist/form-utils.d.ts.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +255 -0
- package/dist/json-schema-form.d.ts +19 -0
- package/dist/json-schema-form.d.ts.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# @cisri/json-schema-form
|
|
2
|
+
|
|
3
|
+
A schema-driven JSON data form based on shadcn/ui (RJSF-style uiSchema). Given a `JsonSchema` (+ optional `uiSchema`), renders an editable form and emits JSON data via `onChange`.
|
|
4
|
+
|
|
5
|
+
> 与 `@cisri/json-schema-editor`(编辑 schema 结构)不同,本组件的输入是 schema,产出是 **JSON 数据**。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @cisri/json-schema-form
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Peer Dependencies
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install react react-dom lucide-react
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Radix/cva/clsx/tailwind-merge 由 `@cisri/shadcn` 与 `@cisri/core` 间接 peer(按其说明安装)。
|
|
20
|
+
|
|
21
|
+
## 使用
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { useState } from 'react';
|
|
25
|
+
import { JsonSchemaForm } from '@cisri/json-schema-form';
|
|
26
|
+
|
|
27
|
+
export default function App() {
|
|
28
|
+
const [data, setData] = useState({ name: '', age: 0 });
|
|
29
|
+
const schema = {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: { name: { type: 'string', title: 'Name' }, age: { type: 'integer', title: 'Age' } },
|
|
32
|
+
required: ['name'],
|
|
33
|
+
};
|
|
34
|
+
return <JsonSchemaForm schema={schema} value={data} onChange={setData} />;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## uiSchema
|
|
39
|
+
|
|
40
|
+
可选 `uiSchema` prop(RJSF 风格 `ui:*` 键,来自 `@cisri/json-schema-ui-core`)控制每个字段的 widget/label/help/placeholder/order/hidden/disabled/readonly/classNames 等。缺省时用 `generateDefaultUiSchema(schema)`。
|
|
41
|
+
|
|
42
|
+
## Tailwind 配置
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
content: [
|
|
46
|
+
'./node_modules/@cisri/*/dist/**/*.{js,cjs}',
|
|
47
|
+
];
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## CSS 变量
|
|
51
|
+
|
|
52
|
+
使用 shadcn/ui 标准 CSS 变量,可通过覆盖 `:root` 自定义主题。
|
|
53
|
+
|
|
54
|
+
## 自定义样式
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
<JsonSchemaForm schema={schema} value={data} onChange={setData} className="w-full max-w-2xl" />
|
|
58
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-utils.d.ts","sourceRoot":"","sources":["../src/form-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAYzE"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),O=require("react"),u=require("@cisri/shadcn"),N=require("@cisri/core"),P=require("@cisri/json-schema-ui-core");function R(s,t){const r=[];if(s.type==="object"&&s.properties){const x=new Set(s.required??[]),n=t??{};for(const d of Object.keys(s.properties))x.has(d)&&(n[d]==null||n[d]==="")&&r.push(`${d} is required`)}return r}function V(s){if(s.enum)return"select";switch(s.type){case"number":case"integer":return"updown";case"boolean":return"checkbox";case"string":default:return"text"}}function C({schema:s,uiSchema:t,path:r,value:x,onChange:n,readOnly:d,required:f,renderFieldActions:l}){const a=(t==null?void 0:t["ui:widget"])??V(s);if((t==null?void 0:t["ui:hidden"])===!0||a==="hidden")return null;const p=(t==null?void 0:t["ui:label"])===!1?null:(t==null?void 0:t["ui:label"])??s.title??r[r.length-1],o=t==null?void 0:t["ui:help"],c=t==null?void 0:t["ui:placeholder"],v=d===!0||(t==null?void 0:t["ui:disabled"])===!0,q=d===!0||(t==null?void 0:t["ui:readonly"])===!0,k=t==null?void 0:t["ui:classNames"],$=(t==null?void 0:t["ui:autofocus"])===!0,T=`jsf-${r.join(".")}`;if(s.type==="object"&&s.properties){const g=(t==null?void 0:t["ui:order"])??Object.keys(s.properties),w=new Set(s.required??[]),b=x??{},i=l==null?void 0:l({path:r,uiSchema:t,schema:s});return e.jsxs("fieldset",{className:N.cn("space-y-3",k),children:[p&&e.jsx("legend",{className:"text-sm font-medium",children:p}),i&&e.jsx("div",{className:"mt-1",children:i}),g.map(j=>e.jsx(C,{schema:s.properties[j],uiSchema:t==null?void 0:t[j],path:[...r,j],value:b[j],onChange:y=>n({...b,[j]:y}),readOnly:d,required:w.has(j),renderFieldActions:l},j))]})}if(s.type==="array"&&s.items){const g=Array.isArray(x)?x:[],w=t==null?void 0:t.items,b=l==null?void 0:l({path:r,uiSchema:t,schema:s});return e.jsxs("fieldset",{className:N.cn("space-y-2",k),children:[p&&e.jsx("legend",{className:"text-sm font-medium",children:p}),b&&e.jsx("div",{className:"mt-1",children:b}),g.map((i,j)=>e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(C,{schema:s.items,uiSchema:w,path:[...r,String(j)],value:i,onChange:y=>n(g.map((I,J)=>J===j?y:I)),readOnly:d,renderFieldActions:l}),!d&&e.jsx("button",{type:"button",onClick:()=>n(g.filter((y,I)=>I!==j)),"aria-label":`删除第 ${j+1} 项`,children:"×"})]},j)),!d&&e.jsx("button",{type:"button",onClick:()=>n([...g,void 0]),children:"添加一项"})]})}const U=l==null?void 0:l({path:r,uiSchema:t,schema:s});return e.jsxs("div",{className:N.cn("space-y-1",k),children:[p&&e.jsxs(u.Label,{htmlFor:T,children:[p,f&&e.jsx("span",{className:"text-destructive",children:" *"})]}),D(a,s,T,x,n,{placeholder:c,disabled:v,readonly:q,autoFocus:$}),o&&e.jsx("p",{className:"text-xs text-muted-foreground",children:o}),U&&e.jsx("div",{className:"mt-1",children:U})]})}function D(s,t,r,x,n,d){const{placeholder:f,disabled:l,readonly:a,autoFocus:p}=d;switch(s){case"textarea":return e.jsx(u.Textarea,{id:r,value:x??"",placeholder:f,disabled:l,readOnly:a,autoFocus:p,onChange:o=>n(o.target.value)});case"password":case"color":case"date":case"text":return e.jsx(u.Input,{id:r,type:s,value:x??"",placeholder:f,disabled:l,readOnly:a,autoFocus:p,onChange:o=>n(o.target.value)});case"updown":return e.jsx(u.Input,{id:r,type:"number",value:x??"",placeholder:f,disabled:l,readOnly:a,autoFocus:p,onChange:o=>n(o.target.value===""?void 0:Number(o.target.value))});case"range":return e.jsx(u.Input,{id:r,type:"range",value:x??0,disabled:l,readOnly:a,autoFocus:p,onChange:o=>n(Number(o.target.value))});case"checkbox":return e.jsx(u.Checkbox,{id:r,checked:x===!0,disabled:l,autoFocus:p,onCheckedChange:o=>n(o===!0)});case"radio":{const o=t.enum?t.enum:[!1,!0];return e.jsx("div",{className:"space-y-1",children:o.map(c=>e.jsxs("label",{className:"flex items-center gap-2 text-sm",children:[e.jsx("input",{type:"radio",name:r,checked:x===c,disabled:l,onChange:()=>n(c)}),t.enum?String(c):c?"true":"false"]},String(c)))})}case"select":{const o=t.enum??[];return e.jsxs(u.Select,{value:x!=null?String(x):void 0,disabled:l,onValueChange:c=>{const v=o.find(q=>String(q)===c);n(v)},children:[e.jsx(u.SelectTrigger,{id:r,children:e.jsx(u.SelectValue,{placeholder:f})}),e.jsx(u.SelectContent,{children:o.map(c=>e.jsx(u.SelectItem,{value:String(c),children:String(c)},String(c)))})]})}default:return e.jsx(u.Input,{id:r,value:x??"",placeholder:f,disabled:l,onChange:o=>n(o.target.value)})}}function L({schema:s,uiSchema:t,value:r,onChange:x,onError:n,readOnly:d,className:f,renderFieldActions:l}){const a=t??P.generateDefaultUiSchema(s);return O.useEffect(()=>{n==null||n(R(s,r))},[s,r,n]),e.jsx("div",{className:N.cn("space-y-3",f),children:e.jsx(C,{schema:s,uiSchema:a,path:[],value:r,onChange:x,readOnly:d,renderFieldActions:l})})}exports.JsonSchemaForm=L;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { JsonSchemaForm } from './json-schema-form';
|
|
2
|
+
export type { JsonSchemaFormProps } from './json-schema-form';
|
|
3
|
+
export type { UiSchema, UiWidget } from '@cisri/json-schema-ui-core';
|
|
4
|
+
export type { JsonSchema } from '@cisri/json-schema-core';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { jsx as r, jsxs as b } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect as J } from "react";
|
|
3
|
+
import { Label as L, Input as v, Select as O, SelectTrigger as P, SelectValue as R, SelectContent as W, SelectItem as z, Checkbox as B, Textarea as G } from "@cisri/shadcn";
|
|
4
|
+
import { cn as j } from "@cisri/core";
|
|
5
|
+
import { generateDefaultUiSchema as H } from "@cisri/json-schema-ui-core";
|
|
6
|
+
function K(e, t) {
|
|
7
|
+
const s = [];
|
|
8
|
+
if (e.type === "object" && e.properties) {
|
|
9
|
+
const d = new Set(e.required ?? []), n = t ?? {};
|
|
10
|
+
for (const p of Object.keys(e.properties))
|
|
11
|
+
d.has(p) && (n[p] == null || n[p] === "") && s.push(`${p} is required`);
|
|
12
|
+
}
|
|
13
|
+
return s;
|
|
14
|
+
}
|
|
15
|
+
function M(e) {
|
|
16
|
+
if (e.enum) return "select";
|
|
17
|
+
switch (e.type) {
|
|
18
|
+
case "number":
|
|
19
|
+
case "integer":
|
|
20
|
+
return "updown";
|
|
21
|
+
case "boolean":
|
|
22
|
+
return "checkbox";
|
|
23
|
+
case "string":
|
|
24
|
+
default:
|
|
25
|
+
return "text";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function T({
|
|
29
|
+
schema: e,
|
|
30
|
+
uiSchema: t,
|
|
31
|
+
path: s,
|
|
32
|
+
value: d,
|
|
33
|
+
onChange: n,
|
|
34
|
+
readOnly: p,
|
|
35
|
+
required: g,
|
|
36
|
+
renderFieldActions: l
|
|
37
|
+
}) {
|
|
38
|
+
const u = (t == null ? void 0 : t["ui:widget"]) ?? M(e);
|
|
39
|
+
if ((t == null ? void 0 : t["ui:hidden"]) === !0 || u === "hidden") return null;
|
|
40
|
+
const c = (t == null ? void 0 : t["ui:label"]) === !1 ? null : (t == null ? void 0 : t["ui:label"]) ?? e.title ?? s[s.length - 1], o = t == null ? void 0 : t["ui:help"], f = t == null ? void 0 : t["ui:placeholder"], k = p === !0 || (t == null ? void 0 : t["ui:disabled"]) === !0, w = p === !0 || (t == null ? void 0 : t["ui:readonly"]) === !0, q = t == null ? void 0 : t["ui:classNames"], V = (t == null ? void 0 : t["ui:autofocus"]) === !0, U = `jsf-${s.join(".")}`;
|
|
41
|
+
if (e.type === "object" && e.properties) {
|
|
42
|
+
const y = (t == null ? void 0 : t["ui:order"]) ?? Object.keys(e.properties), C = new Set(e.required ?? []), i = d ?? {}, x = l == null ? void 0 : l({ path: s, uiSchema: t, schema: e });
|
|
43
|
+
return /* @__PURE__ */ b("fieldset", { className: j("space-y-3", q), children: [
|
|
44
|
+
c && /* @__PURE__ */ r("legend", { className: "text-sm font-medium", children: c }),
|
|
45
|
+
x && /* @__PURE__ */ r("div", { className: "mt-1", children: x }),
|
|
46
|
+
y.map((a) => /* @__PURE__ */ r(
|
|
47
|
+
T,
|
|
48
|
+
{
|
|
49
|
+
schema: e.properties[a],
|
|
50
|
+
uiSchema: t == null ? void 0 : t[a],
|
|
51
|
+
path: [...s, a],
|
|
52
|
+
value: i[a],
|
|
53
|
+
onChange: (N) => n({ ...i, [a]: N }),
|
|
54
|
+
readOnly: p,
|
|
55
|
+
required: C.has(a),
|
|
56
|
+
renderFieldActions: l
|
|
57
|
+
},
|
|
58
|
+
a
|
|
59
|
+
))
|
|
60
|
+
] });
|
|
61
|
+
}
|
|
62
|
+
if (e.type === "array" && e.items) {
|
|
63
|
+
const y = Array.isArray(d) ? d : [], C = t == null ? void 0 : t.items, i = l == null ? void 0 : l({ path: s, uiSchema: t, schema: e });
|
|
64
|
+
return /* @__PURE__ */ b("fieldset", { className: j("space-y-2", q), children: [
|
|
65
|
+
c && /* @__PURE__ */ r("legend", { className: "text-sm font-medium", children: c }),
|
|
66
|
+
i && /* @__PURE__ */ r("div", { className: "mt-1", children: i }),
|
|
67
|
+
y.map((x, a) => /* @__PURE__ */ b("div", { className: "flex items-start gap-2", children: [
|
|
68
|
+
/* @__PURE__ */ r(
|
|
69
|
+
T,
|
|
70
|
+
{
|
|
71
|
+
schema: e.items,
|
|
72
|
+
uiSchema: C,
|
|
73
|
+
path: [...s, String(a)],
|
|
74
|
+
value: x,
|
|
75
|
+
onChange: (N) => n(y.map((I, D) => D === a ? N : I)),
|
|
76
|
+
readOnly: p,
|
|
77
|
+
renderFieldActions: l
|
|
78
|
+
}
|
|
79
|
+
),
|
|
80
|
+
!p && /* @__PURE__ */ r(
|
|
81
|
+
"button",
|
|
82
|
+
{
|
|
83
|
+
type: "button",
|
|
84
|
+
onClick: () => n(y.filter((N, I) => I !== a)),
|
|
85
|
+
"aria-label": `删除第 ${a + 1} 项`,
|
|
86
|
+
children: "×"
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
] }, a)),
|
|
90
|
+
!p && /* @__PURE__ */ r("button", { type: "button", onClick: () => n([...y, void 0]), children: "添加一项" })
|
|
91
|
+
] });
|
|
92
|
+
}
|
|
93
|
+
const $ = l == null ? void 0 : l({ path: s, uiSchema: t, schema: e });
|
|
94
|
+
return /* @__PURE__ */ b("div", { className: j("space-y-1", q), children: [
|
|
95
|
+
c && /* @__PURE__ */ b(L, { htmlFor: U, children: [
|
|
96
|
+
c,
|
|
97
|
+
g && /* @__PURE__ */ r("span", { className: "text-destructive", children: " *" })
|
|
98
|
+
] }),
|
|
99
|
+
Q(u, e, U, d, n, {
|
|
100
|
+
placeholder: f,
|
|
101
|
+
disabled: k,
|
|
102
|
+
readonly: w,
|
|
103
|
+
autoFocus: V
|
|
104
|
+
}),
|
|
105
|
+
o && /* @__PURE__ */ r("p", { className: "text-xs text-muted-foreground", children: o }),
|
|
106
|
+
$ && /* @__PURE__ */ r("div", { className: "mt-1", children: $ })
|
|
107
|
+
] });
|
|
108
|
+
}
|
|
109
|
+
function Q(e, t, s, d, n, p) {
|
|
110
|
+
const { placeholder: g, disabled: l, readonly: u, autoFocus: c } = p;
|
|
111
|
+
switch (e) {
|
|
112
|
+
case "textarea":
|
|
113
|
+
return /* @__PURE__ */ r(
|
|
114
|
+
G,
|
|
115
|
+
{
|
|
116
|
+
id: s,
|
|
117
|
+
value: d ?? "",
|
|
118
|
+
placeholder: g,
|
|
119
|
+
disabled: l,
|
|
120
|
+
readOnly: u,
|
|
121
|
+
autoFocus: c,
|
|
122
|
+
onChange: (o) => n(o.target.value)
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
case "password":
|
|
126
|
+
case "color":
|
|
127
|
+
case "date":
|
|
128
|
+
case "text":
|
|
129
|
+
return /* @__PURE__ */ r(
|
|
130
|
+
v,
|
|
131
|
+
{
|
|
132
|
+
id: s,
|
|
133
|
+
type: e,
|
|
134
|
+
value: d ?? "",
|
|
135
|
+
placeholder: g,
|
|
136
|
+
disabled: l,
|
|
137
|
+
readOnly: u,
|
|
138
|
+
autoFocus: c,
|
|
139
|
+
onChange: (o) => n(o.target.value)
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
case "updown":
|
|
143
|
+
return /* @__PURE__ */ r(
|
|
144
|
+
v,
|
|
145
|
+
{
|
|
146
|
+
id: s,
|
|
147
|
+
type: "number",
|
|
148
|
+
value: d ?? "",
|
|
149
|
+
placeholder: g,
|
|
150
|
+
disabled: l,
|
|
151
|
+
readOnly: u,
|
|
152
|
+
autoFocus: c,
|
|
153
|
+
onChange: (o) => n(o.target.value === "" ? void 0 : Number(o.target.value))
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
case "range":
|
|
157
|
+
return /* @__PURE__ */ r(
|
|
158
|
+
v,
|
|
159
|
+
{
|
|
160
|
+
id: s,
|
|
161
|
+
type: "range",
|
|
162
|
+
value: d ?? 0,
|
|
163
|
+
disabled: l,
|
|
164
|
+
readOnly: u,
|
|
165
|
+
autoFocus: c,
|
|
166
|
+
onChange: (o) => n(Number(o.target.value))
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
case "checkbox":
|
|
170
|
+
return /* @__PURE__ */ r(
|
|
171
|
+
B,
|
|
172
|
+
{
|
|
173
|
+
id: s,
|
|
174
|
+
checked: d === !0,
|
|
175
|
+
disabled: l,
|
|
176
|
+
autoFocus: c,
|
|
177
|
+
onCheckedChange: (o) => n(o === !0)
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
case "radio": {
|
|
181
|
+
const o = t.enum ? t.enum : [!1, !0];
|
|
182
|
+
return /* @__PURE__ */ r("div", { className: "space-y-1", children: o.map((f) => /* @__PURE__ */ b("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
183
|
+
/* @__PURE__ */ r(
|
|
184
|
+
"input",
|
|
185
|
+
{
|
|
186
|
+
type: "radio",
|
|
187
|
+
name: s,
|
|
188
|
+
checked: d === f,
|
|
189
|
+
disabled: l,
|
|
190
|
+
onChange: () => n(f)
|
|
191
|
+
}
|
|
192
|
+
),
|
|
193
|
+
t.enum ? String(f) : f ? "true" : "false"
|
|
194
|
+
] }, String(f))) });
|
|
195
|
+
}
|
|
196
|
+
case "select": {
|
|
197
|
+
const o = t.enum ?? [];
|
|
198
|
+
return /* @__PURE__ */ b(
|
|
199
|
+
O,
|
|
200
|
+
{
|
|
201
|
+
value: d != null ? String(d) : void 0,
|
|
202
|
+
disabled: l,
|
|
203
|
+
onValueChange: (f) => {
|
|
204
|
+
const k = o.find((w) => String(w) === f);
|
|
205
|
+
n(k);
|
|
206
|
+
},
|
|
207
|
+
children: [
|
|
208
|
+
/* @__PURE__ */ r(P, { id: s, children: /* @__PURE__ */ r(R, { placeholder: g }) }),
|
|
209
|
+
/* @__PURE__ */ r(W, { children: o.map((f) => /* @__PURE__ */ r(z, { value: String(f), children: String(f) }, String(f))) })
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
default:
|
|
215
|
+
return /* @__PURE__ */ r(
|
|
216
|
+
v,
|
|
217
|
+
{
|
|
218
|
+
id: s,
|
|
219
|
+
value: d ?? "",
|
|
220
|
+
placeholder: g,
|
|
221
|
+
disabled: l,
|
|
222
|
+
onChange: (o) => n(o.target.value)
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function F({
|
|
228
|
+
schema: e,
|
|
229
|
+
uiSchema: t,
|
|
230
|
+
value: s,
|
|
231
|
+
onChange: d,
|
|
232
|
+
onError: n,
|
|
233
|
+
readOnly: p,
|
|
234
|
+
className: g,
|
|
235
|
+
renderFieldActions: l
|
|
236
|
+
}) {
|
|
237
|
+
const u = t ?? H(e);
|
|
238
|
+
return J(() => {
|
|
239
|
+
n == null || n(K(e, s));
|
|
240
|
+
}, [e, s, n]), /* @__PURE__ */ r("div", { className: j("space-y-3", g), children: /* @__PURE__ */ r(
|
|
241
|
+
T,
|
|
242
|
+
{
|
|
243
|
+
schema: e,
|
|
244
|
+
uiSchema: u,
|
|
245
|
+
path: [],
|
|
246
|
+
value: s,
|
|
247
|
+
onChange: d,
|
|
248
|
+
readOnly: p,
|
|
249
|
+
renderFieldActions: l
|
|
250
|
+
}
|
|
251
|
+
) });
|
|
252
|
+
}
|
|
253
|
+
export {
|
|
254
|
+
F as JsonSchemaForm
|
|
255
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { JsonSchema } from '@cisri/json-schema-core';
|
|
3
|
+
import { type UiSchema } from '@cisri/json-schema-ui-core';
|
|
4
|
+
export interface JsonSchemaFormProps {
|
|
5
|
+
schema: JsonSchema;
|
|
6
|
+
uiSchema?: UiSchema;
|
|
7
|
+
value: unknown;
|
|
8
|
+
onChange: (value: unknown) => void;
|
|
9
|
+
onError?: (errors: string[]) => void;
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
renderFieldActions?: (ctx: {
|
|
13
|
+
path: string[];
|
|
14
|
+
uiSchema: UiSchema | undefined;
|
|
15
|
+
schema: JsonSchema;
|
|
16
|
+
}) => ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export declare function JsonSchemaForm({ schema, uiSchema, value, onChange, onError, readOnly, className, renderFieldActions, }: JsonSchemaFormProps): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=json-schema-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-schema-form.d.ts","sourceRoot":"","sources":["../src/json-schema-form.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAalD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,4BAA4B,CAAC;AAGpC,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE;QACzB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;QAC/B,MAAM,EAAE,UAAU,CAAC;KACpB,KAAK,SAAS,CAAC;CACjB;AAuRD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,kBAAkB,GACnB,EAAE,mBAAmB,+BAkBrB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cisri/json-schema-form",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Schema-driven JSON data form editor based on shadcn/ui (RJSF-style uiSchema)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@cisri/core": "1.0.0",
|
|
25
|
+
"@cisri/json-schema-core": "1.0.0",
|
|
26
|
+
"@cisri/json-schema-ui-core": "1.0.0",
|
|
27
|
+
"@cisri/shadcn": "1.0.0"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
31
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
32
|
+
"lucide-react": "^0.300.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"lucide-react": {
|
|
36
|
+
"optional": false
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@testing-library/jest-dom": "^6.4.0",
|
|
41
|
+
"@testing-library/react": "^15.0.0",
|
|
42
|
+
"@testing-library/user-event": "^14.5.0",
|
|
43
|
+
"@types/react": "^18.3.0",
|
|
44
|
+
"@types/react-dom": "^18.3.0",
|
|
45
|
+
"jsdom": "^24.0.0",
|
|
46
|
+
"react": "^18.3.1",
|
|
47
|
+
"react-dom": "^18.3.1",
|
|
48
|
+
"typescript": "^5.4.5",
|
|
49
|
+
"vite": "^5.2.11",
|
|
50
|
+
"vitest": "^1.6.0",
|
|
51
|
+
"@vitejs/plugin-react": "^4.2.0"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc && vite build",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"test:watch": "vitest"
|
|
57
|
+
}
|
|
58
|
+
}
|