@cisri/json-schema-ui-editor 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 ADDED
@@ -0,0 +1,60 @@
1
+ # @cisri/json-schema-ui-editor
2
+
3
+ A visual uiSchema editor for `@cisri/json-schema-form`. Renders a live form preview and lets the user configure each field's `ui:*` properties inline (RJSF-style uiSchema). Emits the updated `uiSchema` via `onChange`; never modifies the `schema`.
4
+
5
+ > 与 `@cisri/json-schema-form`(编辑 JSON 数据)不同,本组件的输入是 schema + uiSchema,产出是 **uiSchema**。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm install @cisri/json-schema-ui-editor
11
+ ```
12
+
13
+ ## Peer Dependencies
14
+
15
+ ```bash
16
+ npm install react react-dom lucide-react @dnd-kit/core @dnd-kit/sortable @dnd-kit/modifiers @dnd-kit/utilities
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 { JsonSchemaUiEditor } from '@cisri/json-schema-ui-editor';
26
+ import { generateDefaultUiSchema } from '@cisri/json-schema-ui-core';
27
+
28
+ const schema = {
29
+ type: 'object',
30
+ properties: { name: { type: 'string', title: 'Name' }, age: { type: 'integer', title: 'Age' } },
31
+ };
32
+
33
+ export default function App() {
34
+ const [uiSchema, setUiSchema] = useState(() => generateDefaultUiSchema(schema));
35
+ return (
36
+ <JsonSchemaUiEditor
37
+ schema={schema}
38
+ uiSchema={uiSchema}
39
+ onChange={setUiSchema}
40
+ formData={{ name: '', age: 0 }}
41
+ />
42
+ );
43
+ }
44
+ ```
45
+
46
+ ## 交互
47
+
48
+ 每个字段右侧出现「配置」按钮,点击弹出面板:widget 下拉、label(含隐藏)、help、placeholder、hidden/disabled/readonly 开关、classNames。对象字段额外可拖曳调整字段顺序(`ui:order`)。改动实时反映在预览表单,并经 `onChange` 产出最新 `uiSchema`。
49
+
50
+ ## Tailwind 配置
51
+
52
+ ```ts
53
+ content: [
54
+ './node_modules/@cisri/*/dist/**/*.{js,cjs}',
55
+ ];
56
+ ```
57
+
58
+ ## CSS 变量
59
+
60
+ 使用 shadcn/ui 标准 CSS 变量,可通过覆盖 `:root` 自定义主题。
@@ -0,0 +1,9 @@
1
+ import type { JsonSchema } from '@cisri/json-schema-core';
2
+ import type { UiSchema } from '@cisri/json-schema-ui-core';
3
+ export interface FieldConfigPanelProps {
4
+ schema: JsonSchema;
5
+ uiField: UiSchema | undefined;
6
+ onPatch: (patch: Partial<UiSchema>) => void;
7
+ }
8
+ export declare function FieldConfigPanel({ schema, uiField, onPatch }: FieldConfigPanelProps): import("react").JSX.Element;
9
+ //# sourceMappingURL=field-config-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-config-panel.d.ts","sourceRoot":"","sources":["../src/field-config-panel.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,4BAA4B,CAAC;AAkErE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;CAC7C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,qBAAqB,+BAsHnF"}
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),x=require("react"),t=require("@cisri/shadcn"),j=require("lucide-react"),v=require("@cisri/core"),C=require("@cisri/json-schema-form"),N=require("@cisri/json-schema-ui-core"),d=require("@dnd-kit/core"),p=require("@dnd-kit/sortable"),w=require("@dnd-kit/modifiers"),L=require("@dnd-kit/utilities");function k(s){return s.enum?!0:s.type==="string"||s.type==="number"||s.type==="integer"||s.type==="boolean"}function q(s){if(s.enum)return["select","radio","hidden"];switch(s.type){case"string":return["text","textarea","password","color","date","hidden"];case"number":case"integer":return["updown","range","hidden"];case"boolean":return["checkbox","radio","hidden"];default:return[]}}function O(s,r,a){const l=s.indexOf(r),c=s.indexOf(a);if(l===-1||c===-1||l===c)return s;const o=[...s],[i]=o.splice(l,1);return o.splice(c,0,i),o}function V({name:s}){const{attributes:r,listeners:a,setNodeRef:l,transform:c,transition:o,isDragging:i}=p.useSortable({id:s});return e.jsxs("div",{ref:l,style:{transform:L.CSS.Transform.toString(c),transition:o},className:v.cn("flex items-center gap-2 rounded border border-border px-2 py-1",i&&"opacity-50"),children:[e.jsx("button",{type:"button",className:"flex h-6 w-6 cursor-grab items-center justify-center text-muted-foreground active:cursor-grabbing","aria-label":`拖动字段 ${s}`,...r,...a,children:e.jsx(j.GripVertical,{className:"pointer-events-none h-4 w-4"})}),e.jsx("span",{className:"text-sm",children:s})]})}function I({order:s,onReorder:r}){const a=d.useSensors(d.useSensor(d.PointerSensor,{activationConstraint:{distance:5}}),d.useSensor(d.KeyboardSensor,{coordinateGetter:p.sortableKeyboardCoordinates})),l=c=>{const{active:o,over:i}=c;!i||o.id===i.id||r(O(s,String(o.id),String(i.id)))};return e.jsx(d.DndContext,{sensors:a,collisionDetection:d.closestCenter,modifiers:[w.restrictToVerticalAxis],onDragEnd:l,children:e.jsx(p.SortableContext,{items:s,strategy:p.verticalListSortingStrategy,children:e.jsx("div",{className:"space-y-1",children:s.map(c=>e.jsx(V,{name:c},c))})})})}function D({schema:s,uiField:r,onPatch:a}){const l=k(s),c=s.type==="object"&&!!s.properties,o=q(s),i=typeof(r==null?void 0:r["ui:label"])=="string"?r["ui:label"]:"",g=(r==null?void 0:r["ui:label"])===!1;return e.jsxs("div",{className:"space-y-3",children:[o.length>0&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(t.Label,{htmlFor:"ui-cfg-widget",children:"Widget"}),e.jsxs(t.Select,{value:(r==null?void 0:r["ui:widget"])??o[0],onValueChange:n=>a({"ui:widget":n}),children:[e.jsx(t.SelectTrigger,{id:"ui-cfg-widget","aria-label":"widget",children:e.jsx(t.SelectValue,{})}),e.jsx(t.SelectContent,{children:o.map(n=>e.jsx(t.SelectItem,{value:n,children:n},n))})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(t.Label,{htmlFor:"ui-cfg-label",children:"Label"}),e.jsx(t.Input,{id:"ui-cfg-label",autoComplete:"off",value:i,onChange:n=>a({"ui:label":n.target.value||void 0})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(t.Switch,{id:"ui-cfg-hide-label","aria-label":"隐藏 label",checked:g,onCheckedChange:n=>a({"ui:label":n?!1:void 0})}),e.jsx(t.Label,{htmlFor:"ui-cfg-hide-label",children:"隐藏 label"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(t.Label,{htmlFor:"ui-cfg-help",children:"Help"}),e.jsx(t.Input,{id:"ui-cfg-help",autoComplete:"off",value:(r==null?void 0:r["ui:help"])??"",onChange:n=>a({"ui:help":n.target.value||void 0})})]}),l&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(t.Label,{htmlFor:"ui-cfg-placeholder",children:"Placeholder"}),e.jsx(t.Input,{id:"ui-cfg-placeholder",autoComplete:"off",value:(r==null?void 0:r["ui:placeholder"])??"",onChange:n=>a({"ui:placeholder":n.target.value||void 0})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(t.Switch,{id:"ui-cfg-hidden","aria-label":"隐藏字段",checked:(r==null?void 0:r["ui:hidden"])===!0,onCheckedChange:n=>a({"ui:hidden":n})}),e.jsx(t.Label,{htmlFor:"ui-cfg-hidden",children:"隐藏字段"})]}),l&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(t.Switch,{id:"ui-cfg-disabled","aria-label":"禁用",checked:(r==null?void 0:r["ui:disabled"])===!0,onCheckedChange:n=>a({"ui:disabled":n})}),e.jsx(t.Label,{htmlFor:"ui-cfg-disabled",children:"禁用"})]}),l&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(t.Switch,{id:"ui-cfg-readonly","aria-label":"只读",checked:(r==null?void 0:r["ui:readonly"])===!0,onCheckedChange:n=>a({"ui:readonly":n})}),e.jsx(t.Label,{htmlFor:"ui-cfg-readonly",children:"只读"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(t.Label,{htmlFor:"ui-cfg-classnames",children:"Class names"}),e.jsx(t.Input,{id:"ui-cfg-classnames",autoComplete:"off",value:(r==null?void 0:r["ui:classNames"])??"",onChange:n=>a({"ui:classNames":n.target.value||void 0})})]}),c&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(t.Label,{children:"字段顺序"}),e.jsx(I,{order:(r==null?void 0:r["ui:order"])??Object.keys(s.properties),onReorder:n=>a({"ui:order":n})})]})]})}function T({schema:s,uiSchema:r,onChange:a,formData:l,readOnly:c,className:o}){const[i,g]=x.useState(null),[n,y]=x.useState(l),f=x.useCallback((h,u)=>{a(N.setUiField(r,h,u))},[a,r]),S=x.useCallback(h=>{if(c)return null;const u=h.path.join(".");return e.jsxs(t.Popover,{open:i===u,onOpenChange:b=>g(b?u:m=>m===u?null:m),children:[e.jsx(t.PopoverTrigger,{asChild:!0,children:e.jsx("button",{type:"button",className:"inline-flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-muted","aria-label":`配置字段 ${u}`,children:e.jsx(j.Settings2,{className:"h-4 w-4"})})}),e.jsx(t.PopoverContent,{align:"start",children:e.jsx(D,{schema:h.schema,uiField:h.uiSchema,onPatch:b=>f(h.path,b)})})]})},[c,i,f]);return e.jsx("div",{className:v.cn("space-y-3",o),children:e.jsx(C.JsonSchemaForm,{schema:s,uiSchema:r,value:n,onChange:y,renderFieldActions:S})})}exports.JsonSchemaUiEditor=T;
@@ -0,0 +1,5 @@
1
+ export { JsonSchemaUiEditor } from './json-schema-ui-editor';
2
+ export type { JsonSchemaUiEditorProps } from './json-schema-ui-editor';
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,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,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,266 @@
1
+ import { jsxs as c, jsx as r } from "react/jsx-runtime";
2
+ import { useState as y, useCallback as C } from "react";
3
+ import { Label as d, Select as k, SelectTrigger as O, SelectValue as j, SelectContent as V, SelectItem as D, Input as p, Switch as f, Popover as L, PopoverTrigger as E, PopoverContent as K } from "@cisri/shadcn";
4
+ import { GripVertical as T, Settings2 as I } from "lucide-react";
5
+ import { cn as N } from "@cisri/core";
6
+ import { JsonSchemaForm as A } from "@cisri/json-schema-form";
7
+ import { setUiField as G } from "@cisri/json-schema-ui-core";
8
+ import { useSensors as J, useSensor as S, PointerSensor as R, KeyboardSensor as U, DndContext as $, closestCenter as H } from "@dnd-kit/core";
9
+ import { sortableKeyboardCoordinates as P, SortableContext as W, verticalListSortingStrategy as q, useSortable as z } from "@dnd-kit/sortable";
10
+ import { restrictToVerticalAxis as B } from "@dnd-kit/modifiers";
11
+ import { CSS as M } from "@dnd-kit/utilities";
12
+ function Q(t) {
13
+ return t.enum ? !0 : t.type === "string" || t.type === "number" || t.type === "integer" || t.type === "boolean";
14
+ }
15
+ function X(t) {
16
+ if (t.enum) return ["select", "radio", "hidden"];
17
+ switch (t.type) {
18
+ case "string":
19
+ return ["text", "textarea", "password", "color", "date", "hidden"];
20
+ case "number":
21
+ case "integer":
22
+ return ["updown", "range", "hidden"];
23
+ case "boolean":
24
+ return ["checkbox", "radio", "hidden"];
25
+ default:
26
+ return [];
27
+ }
28
+ }
29
+ function Y(t, e, a) {
30
+ const l = t.indexOf(e), o = t.indexOf(a);
31
+ if (l === -1 || o === -1 || l === o) return t;
32
+ const s = [...t], [i] = s.splice(l, 1);
33
+ return s.splice(o, 0, i), s;
34
+ }
35
+ function Z({ name: t }) {
36
+ const { attributes: e, listeners: a, setNodeRef: l, transform: o, transition: s, isDragging: i } = z({ id: t });
37
+ return /* @__PURE__ */ c(
38
+ "div",
39
+ {
40
+ ref: l,
41
+ style: { transform: M.Transform.toString(o), transition: s },
42
+ className: N(
43
+ "flex items-center gap-2 rounded border border-border px-2 py-1",
44
+ i && "opacity-50"
45
+ ),
46
+ children: [
47
+ /* @__PURE__ */ r(
48
+ "button",
49
+ {
50
+ type: "button",
51
+ className: "flex h-6 w-6 cursor-grab items-center justify-center text-muted-foreground active:cursor-grabbing",
52
+ "aria-label": `拖动字段 ${t}`,
53
+ ...e,
54
+ ...a,
55
+ children: /* @__PURE__ */ r(T, { className: "pointer-events-none h-4 w-4" })
56
+ }
57
+ ),
58
+ /* @__PURE__ */ r("span", { className: "text-sm", children: t })
59
+ ]
60
+ }
61
+ );
62
+ }
63
+ function _({ order: t, onReorder: e }) {
64
+ const a = J(
65
+ S(R, { activationConstraint: { distance: 5 } }),
66
+ S(U, { coordinateGetter: P })
67
+ );
68
+ return /* @__PURE__ */ r(
69
+ $,
70
+ {
71
+ sensors: a,
72
+ collisionDetection: H,
73
+ modifiers: [B],
74
+ onDragEnd: (o) => {
75
+ const { active: s, over: i } = o;
76
+ !i || s.id === i.id || e(Y(t, String(s.id), String(i.id)));
77
+ },
78
+ children: /* @__PURE__ */ r(W, { items: t, strategy: q, children: /* @__PURE__ */ r("div", { className: "space-y-1", children: t.map((o) => /* @__PURE__ */ r(Z, { name: o }, o)) }) })
79
+ }
80
+ );
81
+ }
82
+ function F({ schema: t, uiField: e, onPatch: a }) {
83
+ const l = Q(t), o = t.type === "object" && !!t.properties, s = X(t), i = typeof (e == null ? void 0 : e["ui:label"]) == "string" ? e["ui:label"] : "", g = (e == null ? void 0 : e["ui:label"]) === !1;
84
+ return /* @__PURE__ */ c("div", { className: "space-y-3", children: [
85
+ s.length > 0 && /* @__PURE__ */ c("div", { className: "space-y-1", children: [
86
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-widget", children: "Widget" }),
87
+ /* @__PURE__ */ c(
88
+ k,
89
+ {
90
+ value: (e == null ? void 0 : e["ui:widget"]) ?? s[0],
91
+ onValueChange: (n) => a({ "ui:widget": n }),
92
+ children: [
93
+ /* @__PURE__ */ r(O, { id: "ui-cfg-widget", "aria-label": "widget", children: /* @__PURE__ */ r(j, {}) }),
94
+ /* @__PURE__ */ r(V, { children: s.map((n) => /* @__PURE__ */ r(D, { value: n, children: n }, n)) })
95
+ ]
96
+ }
97
+ )
98
+ ] }),
99
+ /* @__PURE__ */ c("div", { className: "space-y-1", children: [
100
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-label", children: "Label" }),
101
+ /* @__PURE__ */ r(
102
+ p,
103
+ {
104
+ id: "ui-cfg-label",
105
+ autoComplete: "off",
106
+ value: i,
107
+ onChange: (n) => a({ "ui:label": n.target.value || void 0 })
108
+ }
109
+ )
110
+ ] }),
111
+ /* @__PURE__ */ c("div", { className: "flex items-center gap-2", children: [
112
+ /* @__PURE__ */ r(
113
+ f,
114
+ {
115
+ id: "ui-cfg-hide-label",
116
+ "aria-label": "隐藏 label",
117
+ checked: g,
118
+ onCheckedChange: (n) => a({ "ui:label": n ? !1 : void 0 })
119
+ }
120
+ ),
121
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-hide-label", children: "隐藏 label" })
122
+ ] }),
123
+ /* @__PURE__ */ c("div", { className: "space-y-1", children: [
124
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-help", children: "Help" }),
125
+ /* @__PURE__ */ r(
126
+ p,
127
+ {
128
+ id: "ui-cfg-help",
129
+ autoComplete: "off",
130
+ value: (e == null ? void 0 : e["ui:help"]) ?? "",
131
+ onChange: (n) => a({ "ui:help": n.target.value || void 0 })
132
+ }
133
+ )
134
+ ] }),
135
+ l && /* @__PURE__ */ c("div", { className: "space-y-1", children: [
136
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-placeholder", children: "Placeholder" }),
137
+ /* @__PURE__ */ r(
138
+ p,
139
+ {
140
+ id: "ui-cfg-placeholder",
141
+ autoComplete: "off",
142
+ value: (e == null ? void 0 : e["ui:placeholder"]) ?? "",
143
+ onChange: (n) => a({ "ui:placeholder": n.target.value || void 0 })
144
+ }
145
+ )
146
+ ] }),
147
+ /* @__PURE__ */ c("div", { className: "flex items-center gap-2", children: [
148
+ /* @__PURE__ */ r(
149
+ f,
150
+ {
151
+ id: "ui-cfg-hidden",
152
+ "aria-label": "隐藏字段",
153
+ checked: (e == null ? void 0 : e["ui:hidden"]) === !0,
154
+ onCheckedChange: (n) => a({ "ui:hidden": n })
155
+ }
156
+ ),
157
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-hidden", children: "隐藏字段" })
158
+ ] }),
159
+ l && /* @__PURE__ */ c("div", { className: "flex items-center gap-2", children: [
160
+ /* @__PURE__ */ r(
161
+ f,
162
+ {
163
+ id: "ui-cfg-disabled",
164
+ "aria-label": "禁用",
165
+ checked: (e == null ? void 0 : e["ui:disabled"]) === !0,
166
+ onCheckedChange: (n) => a({ "ui:disabled": n })
167
+ }
168
+ ),
169
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-disabled", children: "禁用" })
170
+ ] }),
171
+ l && /* @__PURE__ */ c("div", { className: "flex items-center gap-2", children: [
172
+ /* @__PURE__ */ r(
173
+ f,
174
+ {
175
+ id: "ui-cfg-readonly",
176
+ "aria-label": "只读",
177
+ checked: (e == null ? void 0 : e["ui:readonly"]) === !0,
178
+ onCheckedChange: (n) => a({ "ui:readonly": n })
179
+ }
180
+ ),
181
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-readonly", children: "只读" })
182
+ ] }),
183
+ /* @__PURE__ */ c("div", { className: "space-y-1", children: [
184
+ /* @__PURE__ */ r(d, { htmlFor: "ui-cfg-classnames", children: "Class names" }),
185
+ /* @__PURE__ */ r(
186
+ p,
187
+ {
188
+ id: "ui-cfg-classnames",
189
+ autoComplete: "off",
190
+ value: (e == null ? void 0 : e["ui:classNames"]) ?? "",
191
+ onChange: (n) => a({ "ui:classNames": n.target.value || void 0 })
192
+ }
193
+ )
194
+ ] }),
195
+ o && /* @__PURE__ */ c("div", { className: "space-y-1", children: [
196
+ /* @__PURE__ */ r(d, { children: "字段顺序" }),
197
+ /* @__PURE__ */ r(
198
+ _,
199
+ {
200
+ order: (e == null ? void 0 : e["ui:order"]) ?? Object.keys(t.properties),
201
+ onReorder: (n) => a({ "ui:order": n })
202
+ }
203
+ )
204
+ ] })
205
+ ] });
206
+ }
207
+ function he({
208
+ schema: t,
209
+ uiSchema: e,
210
+ onChange: a,
211
+ formData: l,
212
+ readOnly: o,
213
+ className: s
214
+ }) {
215
+ const [i, g] = y(null), [n, x] = y(l), b = C(
216
+ (h, m) => {
217
+ a(G(e, h, m));
218
+ },
219
+ [a, e]
220
+ ), w = C(
221
+ (h) => {
222
+ if (o) return null;
223
+ const m = h.path.join(".");
224
+ return /* @__PURE__ */ c(
225
+ L,
226
+ {
227
+ open: i === m,
228
+ onOpenChange: (u) => g(u ? m : (v) => v === m ? null : v),
229
+ children: [
230
+ /* @__PURE__ */ r(E, { asChild: !0, children: /* @__PURE__ */ r(
231
+ "button",
232
+ {
233
+ type: "button",
234
+ className: "inline-flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-muted",
235
+ "aria-label": `配置字段 ${m}`,
236
+ children: /* @__PURE__ */ r(I, { className: "h-4 w-4" })
237
+ }
238
+ ) }),
239
+ /* @__PURE__ */ r(K, { align: "start", children: /* @__PURE__ */ r(
240
+ F,
241
+ {
242
+ schema: h.schema,
243
+ uiField: h.uiSchema,
244
+ onPatch: (u) => b(h.path, u)
245
+ }
246
+ ) })
247
+ ]
248
+ }
249
+ );
250
+ },
251
+ [o, i, b]
252
+ );
253
+ return /* @__PURE__ */ r("div", { className: N("space-y-3", s), children: /* @__PURE__ */ r(
254
+ A,
255
+ {
256
+ schema: t,
257
+ uiSchema: e,
258
+ value: n,
259
+ onChange: x,
260
+ renderFieldActions: w
261
+ }
262
+ ) });
263
+ }
264
+ export {
265
+ he as JsonSchemaUiEditor
266
+ };
@@ -0,0 +1,12 @@
1
+ import type { JsonSchema } from '@cisri/json-schema-core';
2
+ import { type UiSchema } from '@cisri/json-schema-ui-core';
3
+ export interface JsonSchemaUiEditorProps {
4
+ schema: JsonSchema;
5
+ uiSchema: UiSchema;
6
+ onChange: (uiSchema: UiSchema) => void;
7
+ formData?: unknown;
8
+ readOnly?: boolean;
9
+ className?: string;
10
+ }
11
+ export declare function JsonSchemaUiEditor({ schema, uiSchema, onChange, formData, readOnly, className, }: JsonSchemaUiEditorProps): import("react").JSX.Element;
12
+ //# sourceMappingURL=json-schema-ui-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema-ui-editor.d.ts","sourceRoot":"","sources":["../src/json-schema-ui-editor.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAGvE,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAS,GACV,EAAE,uBAAuB,+BAuDzB"}
@@ -0,0 +1,6 @@
1
+ import type { JsonSchema } from '@cisri/json-schema-core';
2
+ import type { UiWidget } from '@cisri/json-schema-ui-core';
3
+ export declare function isPrimitiveField(schema: JsonSchema): boolean;
4
+ export declare function widgetsForSchema(schema: JsonSchema): UiWidget[];
5
+ export declare function reorderOrder(order: string[], activeId: string, overId: string): string[];
6
+ //# sourceMappingURL=ui-editor-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-editor-utils.d.ts","sourceRoot":"","sources":["../src/ui-editor-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAQ5D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,EAAE,CAa/D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAQxF"}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@cisri/json-schema-ui-editor",
3
+ "version": "1.0.0",
4
+ "description": "Visual uiSchema editor for @cisri/json-schema-form (RJSF-style per-field UI config)",
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/json-schema-form": "1.0.0",
28
+ "@cisri/shadcn": "1.0.0"
29
+ },
30
+ "peerDependencies": {
31
+ "react": "^18.0.0 || ^19.0.0",
32
+ "react-dom": "^18.0.0 || ^19.0.0",
33
+ "lucide-react": "^0.300.0",
34
+ "@dnd-kit/core": "^6.0.0",
35
+ "@dnd-kit/sortable": "^8.0.0",
36
+ "@dnd-kit/modifiers": "^7.0.0",
37
+ "@dnd-kit/utilities": "^3.2.0"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "lucide-react": {
41
+ "optional": false
42
+ },
43
+ "@dnd-kit/core": {
44
+ "optional": false
45
+ },
46
+ "@dnd-kit/sortable": {
47
+ "optional": false
48
+ },
49
+ "@dnd-kit/modifiers": {
50
+ "optional": false
51
+ },
52
+ "@dnd-kit/utilities": {
53
+ "optional": false
54
+ }
55
+ },
56
+ "devDependencies": {
57
+ "@testing-library/jest-dom": "^6.4.0",
58
+ "@testing-library/react": "^15.0.0",
59
+ "@testing-library/user-event": "^14.5.0",
60
+ "@types/react": "^18.3.0",
61
+ "@types/react-dom": "^18.3.0",
62
+ "jsdom": "^24.0.0",
63
+ "react": "^18.3.1",
64
+ "react-dom": "^18.3.1",
65
+ "typescript": "^5.4.5",
66
+ "vite": "^5.2.11",
67
+ "vitest": "^1.6.0",
68
+ "@vitejs/plugin-react": "^4.2.0"
69
+ },
70
+ "scripts": {
71
+ "build": "tsc && vite build",
72
+ "test": "vitest run",
73
+ "test:watch": "vitest"
74
+ }
75
+ }