@datenlotse/jsonjoy-builder 0.4.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +203 -0
  3. package/dist/components/SchemaEditor/AddFieldButton.js +312 -0
  4. package/dist/components/SchemaEditor/JsonSchemaEditor.js +166 -0
  5. package/dist/components/SchemaEditor/JsonSchemaVisualizer.js +96 -0
  6. package/dist/components/SchemaEditor/SchemaField.js +104 -0
  7. package/dist/components/SchemaEditor/SchemaFieldList.js +84 -0
  8. package/dist/components/SchemaEditor/SchemaPropertyEditor.js +249 -0
  9. package/dist/components/SchemaEditor/SchemaTypeSelector.js +55 -0
  10. package/dist/components/SchemaEditor/SchemaVisualEditor.js +77 -0
  11. package/dist/components/SchemaEditor/TypeDropdown.js +72 -0
  12. package/dist/components/SchemaEditor/TypeEditor.js +71 -0
  13. package/dist/components/SchemaEditor/types/ArrayEditor.js +173 -0
  14. package/dist/components/SchemaEditor/types/BooleanEditor.js +107 -0
  15. package/dist/components/SchemaEditor/types/NumberEditor.js +583 -0
  16. package/dist/components/SchemaEditor/types/ObjectEditor.js +90 -0
  17. package/dist/components/SchemaEditor/types/StringEditor.js +542 -0
  18. package/dist/components/features/JsonValidator.js +239 -0
  19. package/dist/components/features/SchemaInferencer.js +107 -0
  20. package/dist/components/ui/badge.js +25 -0
  21. package/dist/components/ui/button.js +41 -0
  22. package/dist/components/ui/dialog.js +73 -0
  23. package/dist/components/ui/input.js +11 -0
  24. package/dist/components/ui/label.js +13 -0
  25. package/dist/components/ui/select.js +90 -0
  26. package/dist/components/ui/switch.js +14 -0
  27. package/dist/components/ui/tabs.js +24 -0
  28. package/dist/components/ui/tooltip.js +15 -0
  29. package/dist/hooks/use-monaco-theme.js +197 -0
  30. package/dist/hooks/use-translation.js +14 -0
  31. package/dist/i18n/locales/de.js +143 -0
  32. package/dist/i18n/locales/en.js +143 -0
  33. package/dist/i18n/locales/es.js +143 -0
  34. package/dist/i18n/locales/fr.js +143 -0
  35. package/dist/i18n/locales/ru.js +143 -0
  36. package/dist/i18n/locales/uk.js +143 -0
  37. package/dist/i18n/locales/zh.js +143 -0
  38. package/dist/i18n/translation-context.js +4 -0
  39. package/dist/i18n/translation-keys.js +0 -0
  40. package/dist/index.css +3830 -0
  41. package/dist/index.d.ts +995 -0
  42. package/dist/index.js +10 -0
  43. package/dist/lib/schema-inference.js +266 -0
  44. package/dist/lib/schemaCompile.js +113 -0
  45. package/dist/lib/schemaEditor.js +167 -0
  46. package/dist/lib/utils.js +40 -0
  47. package/dist/types/jsonSchema.js +98 -0
  48. package/dist/types/validation.js +215 -0
  49. package/dist/utils/jsonValidator.js +162 -0
  50. package/package.json +112 -0
@@ -0,0 +1,173 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useId, useMemo, useState } from "react";
3
+ import { Input } from "../../ui/input.js";
4
+ import { Label } from "../../ui/label.js";
5
+ import { Switch } from "../../ui/switch.js";
6
+ import { useTranslation } from "../../../hooks/use-translation.js";
7
+ import { getArrayItemsSchema } from "../../../lib/schemaEditor.js";
8
+ import { cn } from "../../../lib/utils.js";
9
+ import { isBooleanSchema, withObjectSchema } from "../../../types/jsonSchema.js";
10
+ import TypeDropdown from "../TypeDropdown.js";
11
+ import TypeEditor from "../TypeEditor.js";
12
+ const ArrayEditor = ({ schema, readOnly = false, validationNode, onChange, depth = 0 })=>{
13
+ const t = useTranslation();
14
+ const [minItems, setMinItems] = useState(withObjectSchema(schema, (s)=>s.minItems, void 0));
15
+ const [maxItems, setMaxItems] = useState(withObjectSchema(schema, (s)=>s.maxItems, void 0));
16
+ const [uniqueItems, setUniqueItems] = useState(withObjectSchema(schema, (s)=>s.uniqueItems || false, false));
17
+ const minItemsId = useId();
18
+ const maxItemsId = useId();
19
+ const uniqueItemsId = useId();
20
+ const itemsSchema = getArrayItemsSchema(schema) || {
21
+ type: "string"
22
+ };
23
+ const itemType = withObjectSchema(itemsSchema, (s)=>s.type || "string", "string");
24
+ const handleValidationChange = ()=>{
25
+ const propsToKeep = buildValidationProps();
26
+ onChange(propsToKeep);
27
+ };
28
+ const buildValidationProps = ({ minItems: overrideMinItems, maxItems: overrideMaxItems, uniqueItems: overrideUniqueItems } = {})=>{
29
+ const validationProps = {
30
+ type: "array",
31
+ ...isBooleanSchema(schema) ? {} : schema,
32
+ minItems: overrideMinItems || minItems,
33
+ maxItems: overrideMaxItems || maxItems,
34
+ uniqueItems: overrideUniqueItems || void 0
35
+ };
36
+ if (void 0 === validationProps.items && itemsSchema) validationProps.items = itemsSchema;
37
+ const propsToKeep = {};
38
+ for (const [key, value] of Object.entries(validationProps))if (void 0 !== value) propsToKeep[key] = value;
39
+ return propsToKeep;
40
+ };
41
+ const handleItemSchemaChange = (updatedItemSchema)=>{
42
+ const updatedSchema = {
43
+ type: "array",
44
+ ...isBooleanSchema(schema) ? {} : schema,
45
+ items: updatedItemSchema
46
+ };
47
+ onChange(updatedSchema);
48
+ };
49
+ const minMaxError = useMemo(()=>validationNode?.validation.errors?.find((err)=>"minmax" === err.path[0])?.message, [
50
+ validationNode
51
+ ]);
52
+ const minItemsError = useMemo(()=>validationNode?.validation.errors?.find((err)=>"minItems" === err.path[0])?.message, [
53
+ validationNode
54
+ ]);
55
+ const maxItemsError = useMemo(()=>validationNode?.validation.errors?.find((err)=>"maxItems" === err.path[0])?.message, [
56
+ validationNode
57
+ ]);
58
+ return /*#__PURE__*/ jsxs("div", {
59
+ className: "space-y-6",
60
+ children: [
61
+ (!readOnly || !!maxItems || !!minItems) && /*#__PURE__*/ jsxs("div", {
62
+ className: "grid grid-cols-1 md:grid-cols-2 gap-4",
63
+ children: [
64
+ (!readOnly || !!minItems) && /*#__PURE__*/ jsxs("div", {
65
+ className: "space-y-2",
66
+ children: [
67
+ /*#__PURE__*/ jsx(Label, {
68
+ htmlFor: minItemsId,
69
+ className: (!!minMaxError || !!minItemsError) && "text-destructive",
70
+ children: t.arrayMinimumLabel
71
+ }),
72
+ /*#__PURE__*/ jsx(Input, {
73
+ id: minItemsId,
74
+ type: "number",
75
+ min: 0,
76
+ value: minItems ?? "",
77
+ onChange: (e)=>{
78
+ const value = e.target.value ? Number(e.target.value) : void 0;
79
+ setMinItems(value);
80
+ },
81
+ onBlur: handleValidationChange,
82
+ placeholder: t.arrayMinimumPlaceholder,
83
+ className: cn("h-8", !!minMaxError && "border-destructive")
84
+ })
85
+ ]
86
+ }),
87
+ (!readOnly || !!maxItems) && /*#__PURE__*/ jsxs("div", {
88
+ className: "space-y-2",
89
+ children: [
90
+ /*#__PURE__*/ jsx(Label, {
91
+ htmlFor: maxItemsId,
92
+ className: (!!minMaxError || !!maxItemsError) && "text-destructive",
93
+ children: t.arrayMaximumLabel
94
+ }),
95
+ /*#__PURE__*/ jsx(Input, {
96
+ id: maxItemsId,
97
+ type: "number",
98
+ min: 0,
99
+ value: maxItems ?? "",
100
+ onChange: (e)=>{
101
+ const value = e.target.value ? Number(e.target.value) : void 0;
102
+ setMaxItems(value);
103
+ },
104
+ onBlur: handleValidationChange,
105
+ placeholder: t.arrayMaximumPlaceholder,
106
+ className: cn("h-8", !!minMaxError && "border-destructive")
107
+ })
108
+ ]
109
+ }),
110
+ (!!minMaxError || !!minItemsError || !!maxItemsError) && /*#__PURE__*/ jsx("div", {
111
+ className: "text-xs text-destructive italic md:col-span-2 whitespace-pre-line",
112
+ children: [
113
+ minMaxError,
114
+ minItemsError ?? maxItemsError
115
+ ].filter(Boolean).join("\n")
116
+ })
117
+ ]
118
+ }),
119
+ (!readOnly || !!uniqueItems) && /*#__PURE__*/ jsxs("div", {
120
+ className: "flex items-center space-x-2",
121
+ children: [
122
+ /*#__PURE__*/ jsx(Switch, {
123
+ id: uniqueItemsId,
124
+ checked: uniqueItems,
125
+ onCheckedChange: (checked)=>{
126
+ setUniqueItems(checked);
127
+ onChange(buildValidationProps({
128
+ uniqueItems: checked
129
+ }));
130
+ }
131
+ }),
132
+ /*#__PURE__*/ jsx(Label, {
133
+ htmlFor: uniqueItemsId,
134
+ className: "cursor-pointer",
135
+ children: t.arrayForceUniqueItemsLabel
136
+ })
137
+ ]
138
+ }),
139
+ /*#__PURE__*/ jsxs("div", {
140
+ className: cn("space-y-2 pt-4 border-border/40", !readOnly || minItems || maxItems || uniqueItems ? "border-t" : null),
141
+ children: [
142
+ /*#__PURE__*/ jsxs("div", {
143
+ className: "flex items-center justify-between mb-4",
144
+ children: [
145
+ /*#__PURE__*/ jsx(Label, {
146
+ children: t.arrayItemTypeLabel
147
+ }),
148
+ /*#__PURE__*/ jsx(TypeDropdown, {
149
+ readOnly: readOnly,
150
+ value: itemType,
151
+ onChange: (newType)=>{
152
+ handleItemSchemaChange({
153
+ ...withObjectSchema(itemsSchema, (s)=>s, {}),
154
+ type: newType
155
+ });
156
+ }
157
+ })
158
+ ]
159
+ }),
160
+ /*#__PURE__*/ jsx(TypeEditor, {
161
+ readOnly: readOnly,
162
+ schema: itemsSchema,
163
+ validationNode: validationNode,
164
+ onChange: handleItemSchemaChange,
165
+ depth: depth + 1
166
+ })
167
+ ]
168
+ })
169
+ ]
170
+ });
171
+ };
172
+ const types_ArrayEditor = ArrayEditor;
173
+ export { types_ArrayEditor as default };
@@ -0,0 +1,107 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
3
+ import { Label } from "../../ui/label.js";
4
+ import { Switch } from "../../ui/switch.js";
5
+ import { useTranslation } from "../../../hooks/use-translation.js";
6
+ import { withObjectSchema } from "../../../types/jsonSchema.js";
7
+ const BooleanEditor = ({ schema, onChange, readOnly = false })=>{
8
+ const t = useTranslation();
9
+ const allowTrueId = useId();
10
+ const allowFalseId = useId();
11
+ const enumValues = withObjectSchema(schema, (s)=>s.enum, null);
12
+ const hasRestrictions = Array.isArray(enumValues);
13
+ const allowsTrue = !hasRestrictions || enumValues?.includes(true) || false;
14
+ const allowsFalse = !hasRestrictions || enumValues?.includes(false) || false;
15
+ const handleAllowedChange = (value, allowed)=>{
16
+ let newEnum;
17
+ if (allowed) {
18
+ if (!hasRestrictions) return;
19
+ if (enumValues?.includes(value)) return;
20
+ newEnum = enumValues ? [
21
+ ...enumValues,
22
+ value
23
+ ] : [
24
+ value
25
+ ];
26
+ if (newEnum.includes(true) && newEnum.includes(false)) newEnum = void 0;
27
+ } else {
28
+ if (hasRestrictions && !enumValues?.includes(value)) return;
29
+ newEnum = [
30
+ !value
31
+ ];
32
+ }
33
+ const updatedValidation = {
34
+ type: "boolean"
35
+ };
36
+ if (!newEnum) return void onChange({
37
+ type: "boolean"
38
+ });
39
+ updatedValidation.enum = newEnum;
40
+ onChange(updatedValidation);
41
+ };
42
+ const hasEnum = enumValues && enumValues.length > 0;
43
+ return /*#__PURE__*/ jsxs("div", {
44
+ className: "space-y-4",
45
+ children: [
46
+ readOnly && !hasEnum && /*#__PURE__*/ jsx("p", {
47
+ className: "text-sm text-muted-foreground italic",
48
+ children: t.booleanNoConstraint
49
+ }),
50
+ (!readOnly || !allowsTrue || !allowsFalse) && /*#__PURE__*/ jsxs("div", {
51
+ className: "space-y-2 pt-2",
52
+ children: [
53
+ (!readOnly || hasEnum) && /*#__PURE__*/ jsxs(Fragment, {
54
+ children: [
55
+ /*#__PURE__*/ jsx(Label, {
56
+ children: t.booleanAllowedValuesLabel
57
+ }),
58
+ /*#__PURE__*/ jsxs("div", {
59
+ className: "space-y-3",
60
+ children: [
61
+ /*#__PURE__*/ jsxs("div", {
62
+ className: "flex items-center space-x-2",
63
+ children: [
64
+ /*#__PURE__*/ jsx(Switch, {
65
+ id: allowTrueId,
66
+ checked: allowsTrue,
67
+ disabled: readOnly,
68
+ onCheckedChange: (checked)=>handleAllowedChange(true, checked)
69
+ }),
70
+ /*#__PURE__*/ jsx(Label, {
71
+ htmlFor: allowTrueId,
72
+ className: "cursor-pointer",
73
+ children: t.booleanAllowTrueLabel
74
+ })
75
+ ]
76
+ }),
77
+ /*#__PURE__*/ jsxs("div", {
78
+ className: "flex items-center space-x-2",
79
+ children: [
80
+ /*#__PURE__*/ jsx(Switch, {
81
+ id: allowFalseId,
82
+ checked: allowsFalse,
83
+ disabled: readOnly,
84
+ onCheckedChange: (checked)=>handleAllowedChange(false, checked)
85
+ }),
86
+ /*#__PURE__*/ jsx(Label, {
87
+ htmlFor: allowFalseId,
88
+ className: "cursor-pointer",
89
+ children: t.booleanAllowFalseLabel
90
+ })
91
+ ]
92
+ })
93
+ ]
94
+ })
95
+ ]
96
+ }),
97
+ !allowsTrue && !allowsFalse && /*#__PURE__*/ jsx("p", {
98
+ className: "text-xs text-amber-600 mt-2",
99
+ children: t.booleanNeitherWarning
100
+ })
101
+ ]
102
+ })
103
+ ]
104
+ });
105
+ };
106
+ const types_BooleanEditor = BooleanEditor;
107
+ export { types_BooleanEditor as default };