@dappworks/kit 0.4.82 → 0.4.83

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/dist/form.mjs CHANGED
@@ -2,10 +2,10 @@ import { useStore } from './chunk-DZMNL4BZ.mjs';
2
2
  import { RootStore } from './chunk-HRWHDF2F.mjs';
3
3
  import { helper } from './chunk-XAIZMT2F.mjs';
4
4
  import { _ } from './chunk-MGU3KYGC.mjs';
5
- import { cn } from './chunk-6UHBBDKI.mjs';
5
+ import { cn } from './chunk-TMFAGW4V.mjs';
6
6
  import { __objRest, __spreadValues, __spreadProps } from './chunk-6F7H4PAA.mjs';
7
- import React6, { useEffect, useMemo, useState, createRef } from 'react';
8
- import { Modal, ModalContent, ModalHeader, ModalBody, Checkbox, Input, Button, Textarea, Card, Tabs, Tab } from '@nextui-org/react';
7
+ import React6, { useEffect, useMemo, useState, useCallback, useRef, createRef } from 'react';
8
+ import { Modal, ModalContent, ModalHeader, ModalBody, Checkbox, Input, Select, SelectItem, Button, Textarea, DatePicker, Card, Tabs, Tab } from '@nextui-org/react';
9
9
  import { Check, ChevronUp, ChevronDown } from 'lucide-react';
10
10
  import MonacoEditor from '@monaco-editor/react';
11
11
  import validator from '@rjsf/validator-ajv8';
@@ -13,6 +13,7 @@ import { makeAutoObservable, makeObservable, computed, observable, action, toJS
13
13
  import Form from '@rjsf/core';
14
14
  import * as Utils from '@rjsf/utils';
15
15
  import { observer, useLocalObservable } from 'mobx-react-lite';
16
+ import { parseAbsoluteToLocal } from '@internationalized/date';
16
17
  import Draggable from 'react-draggable';
17
18
  import EventEmitter from 'events';
18
19
 
@@ -22,19 +23,18 @@ function CheckboxWidget({
22
23
  label,
23
24
  value,
24
25
  disabled,
25
- schema
26
+ uiSchema
26
27
  }) {
27
- const { size = "sm", color = "primary" } = options;
28
- const { description } = schema;
28
+ const { className, size = "sm", color = "primary", description, descriptionClassName } = options;
29
+ const { validate } = uiSchema;
30
+ const [errMsg, setErrMsg] = useState("");
31
+ const isInvalid = !!errMsg;
29
32
  return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(
30
33
  Checkbox,
31
34
  {
35
+ className: cn("w-full", className),
32
36
  classNames: {
33
- base: cn(
34
- "m-0 flex items-center justify-start w-full",
35
- "cursor-pointer rounded-lg gap-2 p-3 bg-content2 border-1 border-transparent",
36
- value ? `border-${color}` : ""
37
- )
37
+ base: cn("m-0 flex items-center justify-start w-full", "cursor-pointer rounded-lg gap-2 p-[13px] bg-content2 border-1 border-transparent", value ? `border-${color}` : "")
38
38
  },
39
39
  defaultSelected: value,
40
40
  isDisabled: disabled,
@@ -44,76 +44,152 @@ function CheckboxWidget({
44
44
  onChange: (e) => {
45
45
  const checked = e.target.checked;
46
46
  onChange(checked);
47
+ },
48
+ onBlur: () => {
49
+ if (validate) {
50
+ const errMsg2 = validate(value);
51
+ setErrMsg(errMsg2);
52
+ return;
53
+ }
54
+ setErrMsg("");
47
55
  }
48
56
  },
49
57
  label
50
- ), description && /* @__PURE__ */ React6.createElement("div", { className: "mt-1 text-xs text-[#A1A1A9] dark:text-[#717179]" }, description));
58
+ ), description && /* @__PURE__ */ React6.createElement("div", { className: cn("mt-1 text-xs text-[#A1A1A9] dark:text-[#717179]", descriptionClassName) }, description), isInvalid && /* @__PURE__ */ React6.createElement("div", { className: "mt-2 text-xs text-[#DF3562]" }, errMsg));
51
59
  }
52
60
  function InputWidget(props) {
53
- const {
54
- onChange,
55
- options,
56
- label,
57
- value,
58
- required,
59
- disabled,
60
- schema
61
- } = props;
62
- const { className, labelPlacement = "inside", size = "sm" } = options;
63
- const placeholder = props.placeholder || options.placeholder;
61
+ const { onChange, options, label, value, required, disabled, uiSchema } = props;
62
+ const { className, nextuiClassNames, labelPlacement = "inside", size = "sm", inputType = "text", placeholder, color, variant, radius, startContent, endContent, description } = options;
63
+ const { requiredErrMsg, validate } = uiSchema;
64
64
  return /* @__PURE__ */ React6.createElement(
65
65
  Input,
66
66
  {
67
67
  className: cn("w-full", className),
68
+ classNames: nextuiClassNames,
68
69
  label,
69
70
  placeholder,
70
71
  value,
71
- defaultValue: "",
72
72
  isRequired: required,
73
73
  isDisabled: disabled,
74
74
  size,
75
75
  labelPlacement,
76
- description: schema.description || "",
77
- type: schema.inputType || "text",
78
- onChange: (e) => onChange(e.target.value)
76
+ description,
77
+ type: inputType,
78
+ color,
79
+ variant,
80
+ radius,
81
+ startContent,
82
+ endContent,
83
+ onChange: (e) => onChange(e.target.value),
84
+ validate: () => {
85
+ if (value === "" && required) {
86
+ return requiredErrMsg || "This field is required";
87
+ }
88
+ if (validate) {
89
+ const errMsg = validate(value);
90
+ return errMsg;
91
+ }
92
+ return true;
93
+ }
79
94
  }
80
95
  );
81
96
  }
82
97
  function SelectWidget(props) {
83
- const { onChange, options, label, value, required, disabled, schema } = props;
84
- const { className, labelPlacement = "top", placeholder = "Select an option" } = options;
85
- const { selectOptions = [], description } = schema;
86
- const labelText = label == null ? void 0 : label.trim();
87
- const placeholderText = props.placeholder || placeholder;
88
- return /* @__PURE__ */ React6.createElement("div", { className: cn("", className) }, /* @__PURE__ */ React6.createElement(
89
- "div",
98
+ const { onChange, options, label, value, required, disabled, uiSchema } = props;
99
+ const {
100
+ className,
101
+ nextuiClassNames = {
102
+ popoverContent: "rounded-lg shadow-md border dark:border-[#3e3e3e]"
103
+ },
104
+ listboxProps = {
105
+ itemClasses: {
106
+ base: [
107
+ "rounded-lg",
108
+ "text-default-500",
109
+ "transition-opacity",
110
+ "data-[hover=true]:text-foreground",
111
+ "data-[hover=true]:bg-default-100",
112
+ "dark:data-[hover=true]:bg-default-50",
113
+ "data-[selectable=true]:focus:bg-default-50",
114
+ "data-[pressed=true]:opacity-70",
115
+ "data-[focus-visible=true]:ring-default-500"
116
+ ]
117
+ }
118
+ },
119
+ labelPlacement = "inside",
120
+ size = "sm",
121
+ placeholder = "Select an option",
122
+ color,
123
+ variant,
124
+ radius,
125
+ description
126
+ } = options;
127
+ const { selectOptions = [], requiredErrMsg, validate } = uiSchema;
128
+ const [errMsg, setErrMsg] = useState("");
129
+ const isInvalid = !!errMsg;
130
+ const checkValue = useCallback((value2) => {
131
+ if (!value2 && required) {
132
+ setErrMsg(requiredErrMsg || "This field is required");
133
+ return;
134
+ }
135
+ if (validate) {
136
+ const errMsg2 = validate(value2);
137
+ setErrMsg(errMsg2);
138
+ return;
139
+ }
140
+ setErrMsg("");
141
+ }, []);
142
+ return /* @__PURE__ */ React6.createElement(
143
+ Select,
90
144
  {
91
- className: cn("flex flex-col", {
92
- "flex-row items-center": labelPlacement === "left"
93
- })
145
+ label: label == null ? void 0 : label.trim(),
146
+ className: cn("w-full", className),
147
+ classNames: nextuiClassNames,
148
+ labelPlacement,
149
+ placeholder,
150
+ size,
151
+ isRequired: required,
152
+ isDisabled: disabled,
153
+ isInvalid,
154
+ description,
155
+ listboxProps,
156
+ variant,
157
+ radius,
158
+ color: isInvalid ? "danger" : color,
159
+ errorMessage: isInvalid && errMsg,
160
+ selectedKeys: [value],
161
+ onSelectionChange: (v) => {
162
+ const keys = Array.from(v);
163
+ const _v = keys[0];
164
+ onChange(_v);
165
+ checkValue(_v);
166
+ }
94
167
  },
95
- labelText && /* @__PURE__ */ React6.createElement(
96
- "label",
97
- {
98
- className: cn("flex items-center text-sm whitespace-nowrap", {
99
- "mb-2": labelPlacement === "top",
100
- "mr-2": labelPlacement === "left"
101
- })
102
- },
103
- labelText,
104
- required && /* @__PURE__ */ React6.createElement("span", { className: "ml-[2px] font-bold text-red-600" }, "*")
105
- ),
106
- description && labelPlacement === "top" && /* @__PURE__ */ React6.createElement("div", { className: "mb-2 text-xs text-[#A1A1A9] dark:text-[#717179]" }, description),
107
- /* @__PURE__ */ React6.createElement("select", { className: "w-full py-3.5 px-2 text-sm rounded-md bg-[#F4F4F5] dark:bg-[#27272A]", defaultValue: value, disabled, onChange: (event) => onChange(event.target.value) }, /* @__PURE__ */ React6.createElement("option", { value: "", disabled: true, selected: true }, placeholderText), selectOptions.map((item) => {
108
- return /* @__PURE__ */ React6.createElement("option", { key: item.value, value: item.value }, item.label);
109
- }))
110
- ));
168
+ selectOptions.map((item) => /* @__PURE__ */ React6.createElement(SelectItem, { key: item.value, value: item.value }, item.label))
169
+ );
111
170
  }
112
- var EditorWidget = ({ label, options = {}, value, required, schema, disabled, onChange }) => {
113
- const { editorHeight = "200px", readOnly = false, language = "json", jsonStrSpace, languageSelectorOptions = [], onChangeLanguage, onRun, onMount } = options;
171
+ var EditorWidget = ({ label, options = {}, value, required, uiSchema, disabled, onChange }) => {
172
+ const { editorHeight = "200px", readOnly = false, language = "json", jsonStrSpace, languageSelectorOptions = [], description, descriptionClassName, errMsgClassName, onChangeLanguage, onRun, onMount } = options;
173
+ const { requiredErrMsg, validate } = uiSchema;
114
174
  const [selectedLanguage, setSelectedLanguage] = useState("");
115
175
  const [runLoading, setRunLoading] = useState(false);
116
176
  const showLanguageSelector = languageSelectorOptions.length > 0;
177
+ const [errMsg, setErrMsg] = useState("");
178
+ const isInvalid = !!errMsg;
179
+ const debouncedCheckValue = useRef(
180
+ _.debounce(async (value2) => {
181
+ if (!value2 && required) {
182
+ setErrMsg(requiredErrMsg || "This field is required");
183
+ return;
184
+ }
185
+ if (validate) {
186
+ const errMsg2 = validate(value2);
187
+ setErrMsg(errMsg2);
188
+ return;
189
+ }
190
+ setErrMsg("");
191
+ }, 1e3)
192
+ ).current;
117
193
  return /* @__PURE__ */ React6.createElement("div", { className: "flex flex-col relative" }, /* @__PURE__ */ React6.createElement("div", { className: cn("flex justify-between items-center", { "mb-[10px]": label.trim() || showLanguageSelector }) }, label && /* @__PURE__ */ React6.createElement(
118
194
  "label",
119
195
  {
@@ -135,7 +211,7 @@ var EditorWidget = ({ label, options = {}, value, required, schema, disabled, on
135
211
  languageSelectorOptions.map((item) => {
136
212
  return /* @__PURE__ */ React6.createElement("option", { key: item.value, value: item.value }, item.label);
137
213
  })
138
- )), schema.description && /* @__PURE__ */ React6.createElement("div", { className: "mb-2 text-xs text-[#A1A1A9] dark:text-[#717179]" }, schema.description), /* @__PURE__ */ React6.createElement("div", { className: "rounded-lg overflow-hidden relative" }, /* @__PURE__ */ React6.createElement(
214
+ )), description && /* @__PURE__ */ React6.createElement("div", { className: cn("mb-2 text-xs text-[#A1A1A9] dark:text-[#717179]", descriptionClassName) }, description), /* @__PURE__ */ React6.createElement("div", { className: "rounded-lg overflow-hidden relative" }, /* @__PURE__ */ React6.createElement(
139
215
  MonacoEditor,
140
216
  {
141
217
  options: { readOnly: readOnly || disabled, minimap: { enabled: false } },
@@ -143,7 +219,10 @@ var EditorWidget = ({ label, options = {}, value, required, schema, disabled, on
143
219
  theme: "vs-dark",
144
220
  language: selectedLanguage ? selectedLanguage : language,
145
221
  value,
146
- onChange,
222
+ onChange: (v) => {
223
+ onChange(v);
224
+ debouncedCheckValue(v);
225
+ },
147
226
  onMount: (editor, monaco) => {
148
227
  onMount && onMount(editor, monaco);
149
228
  if (language === "json" && jsonStrSpace && value) {
@@ -152,7 +231,7 @@ var EditorWidget = ({ label, options = {}, value, required, schema, disabled, on
152
231
  }
153
232
  }
154
233
  }
155
- )), onRun && /* @__PURE__ */ React6.createElement(
234
+ )), isInvalid && /* @__PURE__ */ React6.createElement("div", { className: cn("mt-2 text-xs text-[#DF3562]", errMsgClassName) }, errMsg), onRun && /* @__PURE__ */ React6.createElement(
156
235
  Button,
157
236
  {
158
237
  className: "absolute bottom-2 right-4",
@@ -264,7 +343,7 @@ var getFormState = (props, formLayout = {}) => {
264
343
  const value = {};
265
344
  const required = [];
266
345
  const properties = Object.entries(metadata).reduce((p, c) => {
267
- var _a2, _b, _c, _d, _e;
346
+ var _a2, _b, _c;
268
347
  const [k, v] = c;
269
348
  const type = typeof v;
270
349
  p[k] = {
@@ -274,15 +353,22 @@ var getFormState = (props, formLayout = {}) => {
274
353
  if (!formConfigData[k]) {
275
354
  formConfigData[k] = {};
276
355
  }
356
+ if ((_a2 = formConfigData[k]) == null ? void 0 : _a2.title) {
357
+ p[k].title = formConfigData[k].title || k;
358
+ }
359
+ if ((_b = formConfigData[k]) == null ? void 0 : _b.required) {
360
+ required.push(k);
361
+ }
277
362
  if (type === "string" || type === "number") {
278
- if ((_a2 = formConfigData[k]) == null ? void 0 : _a2.selectOptions) {
363
+ if ((_c = formConfigData[k]) == null ? void 0 : _c.selectOptions) {
279
364
  formConfigData[k]["ui:widget"] = SelectWidget;
280
- p[k].selectOptions = formConfigData[k].selectOptions;
281
365
  } else {
282
366
  if (!formConfigData[k]["ui:widget"]) {
283
367
  formConfigData[k]["ui:widget"] = InputWidget;
284
368
  if (type === "number") {
285
- p[k].inputType = "number";
369
+ formConfigData[k]["ui:options"] = __spreadProps(__spreadValues({}, formConfigData[k]["ui:options"]), {
370
+ inputType: "number"
371
+ });
286
372
  }
287
373
  if (helper.json.isJsonString(v)) {
288
374
  formConfigData[k]["ui:widget"] = EditorWidget;
@@ -301,18 +387,6 @@ var getFormState = (props, formLayout = {}) => {
301
387
  value[k] = JSON.stringify(v, null, 2);
302
388
  formConfigData[k]["ui:widget"] = EditorWidget;
303
389
  }
304
- if ((_b = formConfigData[k]) == null ? void 0 : _b.inputType) {
305
- p[k].inputType = formConfigData[k].inputType;
306
- }
307
- if ((_c = formConfigData[k]) == null ? void 0 : _c.title) {
308
- p[k].title = formConfigData[k].title || k;
309
- }
310
- if ((_d = formConfigData[k]) == null ? void 0 : _d.description) {
311
- p[k].description = formConfigData[k].description;
312
- }
313
- if ((_e = formConfigData[k]) == null ? void 0 : _e.required) {
314
- required.push(k);
315
- }
316
390
  return p;
317
391
  }, {});
318
392
  const schema = {
@@ -373,23 +447,32 @@ var BatchSubmitButton = ({ formStates, onSubmit, buttonProps }) => {
373
447
  onClick: (e) => {
374
448
  const formData = {};
375
449
  const formKeys = Object.keys(formStates);
376
- for (const key of formKeys) {
377
- const form = formStates[key];
450
+ for (const formKey of formKeys) {
451
+ const form = formStates[formKey];
378
452
  const current = form.formRef.current;
379
453
  if (current) {
380
454
  current.submit();
381
455
  const data = current.state.formData;
382
- const required = current.state.schema.required;
383
- for (const i of required) {
384
- if (!data[i]) {
385
- return;
456
+ const uiSchema = current.state.uiSchema;
457
+ const keys = Object.keys(uiSchema);
458
+ for (const key of keys) {
459
+ const uiConfig = uiSchema[key];
460
+ if (uiConfig) {
461
+ const { required, validate } = uiConfig;
462
+ if (required) {
463
+ if (data[key] === void 0 || data[key] === null || data[key] === "") {
464
+ return;
465
+ }
466
+ }
467
+ if (validate) {
468
+ const errMsg = validate(data[key]);
469
+ if (errMsg) {
470
+ return;
471
+ }
472
+ }
386
473
  }
387
474
  }
388
- const errors = current.state.errors;
389
- if (errors.length > 0) {
390
- return;
391
- }
392
- formData[key] = data;
475
+ formData[formKey] = data;
393
476
  } else {
394
477
  console.error("formRef.current is null");
395
478
  return;
@@ -419,16 +502,25 @@ var SubmitButton = ({ formKey, formState, buttonProps }) => {
419
502
  if (current) {
420
503
  current.submit();
421
504
  formData = current.state.formData;
422
- const required = current.state.schema.required;
423
- for (const i of required) {
424
- if (!formData[i]) {
425
- return;
505
+ const uiSchema = current.state.uiSchema;
506
+ const keys = Object.keys(uiSchema);
507
+ for (const key of keys) {
508
+ const uiConfig = uiSchema[key];
509
+ if (uiConfig) {
510
+ const { required, validate } = uiConfig;
511
+ if (required) {
512
+ if (formData[key] === void 0 || formData[key] === null || formData[key] === "") {
513
+ return;
514
+ }
515
+ }
516
+ if (validate) {
517
+ const errMsg = validate(formData[key]);
518
+ if (errMsg) {
519
+ return;
520
+ }
521
+ }
426
522
  }
427
523
  }
428
- const errors = current.state.errors;
429
- if (errors.length > 0) {
430
- return;
431
- }
432
524
  }
433
525
  onAfterSubmit == null ? void 0 : onAfterSubmit(formKey, formData, setLoading);
434
526
  }
@@ -452,7 +544,7 @@ var renderLayout = (layout, fields, n = 1) => {
452
544
  return layout.map((item, index) => {
453
545
  if (Array.isArray(item)) {
454
546
  const even = (n & 1) === 0;
455
- return /* @__PURE__ */ React6.createElement("div", { key: index, className: cn("w-full flex justify-between items-center space-x-2", even ? "flex-row items-end" : "flex-col") }, renderLayout(item, fields, n));
547
+ return /* @__PURE__ */ React6.createElement("div", { key: index, className: cn("w-full flex justify-between items-center space-x-2", even ? "flex-row items-start" : "flex-col") }, renderLayout(item, fields, n));
456
548
  } else {
457
549
  return /* @__PURE__ */ React6.createElement("div", { className: "w-full", key: index }, fields[item]);
458
550
  }
@@ -796,13 +888,14 @@ var JSONForm = (props) => {
796
888
  );
797
889
  };
798
890
  function TextareaWidget(props) {
799
- const { onChange, options, label, value, required, disabled, schema } = props;
800
- const { className, labelPlacement = "inside", size = "md", minRows = 2, maxRows = 8 } = options;
801
- const placeholder = props.placeholder || options.placeholder;
891
+ const { onChange, options, label, value, required, disabled, uiSchema } = props;
892
+ const { className, nextuiClassNames, labelPlacement = "inside", size = "md", minRows = 3, maxRows = 8, placeholder, color, variant, radius, startContent, endContent, description } = options;
893
+ const { requiredErrMsg, validate } = uiSchema;
802
894
  return /* @__PURE__ */ React6.createElement(
803
895
  Textarea,
804
896
  {
805
897
  className: cn("w-full", className),
898
+ classNames: nextuiClassNames,
806
899
  label,
807
900
  placeholder,
808
901
  value,
@@ -812,8 +905,72 @@ function TextareaWidget(props) {
812
905
  maxRows,
813
906
  size,
814
907
  labelPlacement,
815
- description: schema.description || "",
816
- onChange: (e) => onChange(e.target.value)
908
+ description,
909
+ color,
910
+ variant,
911
+ radius,
912
+ startContent,
913
+ endContent,
914
+ onChange: (e) => onChange(e.target.value),
915
+ validate: () => {
916
+ if (value === "" && required) {
917
+ return requiredErrMsg || "This field is required";
918
+ }
919
+ if (validate) {
920
+ const errMsg = validate(value);
921
+ return errMsg;
922
+ }
923
+ return true;
924
+ }
925
+ }
926
+ );
927
+ }
928
+ function DatePickerWidget({ label, options, value, required, disabled, uiSchema, onChange }) {
929
+ const { className, nextuiClassNames = { calendarContent: "min-w-fit" }, labelPlacement = "inside", size = "sm", granularity = "day", color = "default", description } = options;
930
+ const [date, setDate] = useState();
931
+ const { requiredErrMsg, validate } = uiSchema;
932
+ useEffect(() => {
933
+ if (value) {
934
+ try {
935
+ const ISOStr = new Date(value).toISOString();
936
+ const v = parseAbsoluteToLocal(ISOStr);
937
+ setDate(v);
938
+ } catch (error) {
939
+ console.log("error", error.message);
940
+ }
941
+ }
942
+ }, [value]);
943
+ return /* @__PURE__ */ React6.createElement(
944
+ DatePicker,
945
+ {
946
+ showMonthAndYearPickers: true,
947
+ className: cn("w-full", className),
948
+ classNames: nextuiClassNames,
949
+ label,
950
+ size,
951
+ labelPlacement,
952
+ color,
953
+ granularity,
954
+ value: date,
955
+ isRequired: required,
956
+ description: description || "",
957
+ isDisabled: disabled,
958
+ onChange: (dateValue) => {
959
+ if (dateValue) {
960
+ const v = dateValue.toDate("GMT").toISOString();
961
+ onChange(v);
962
+ }
963
+ },
964
+ validate: () => {
965
+ if (value === "" && required) {
966
+ return requiredErrMsg || "This field is required";
967
+ }
968
+ if (validate) {
969
+ const errMsg = validate(value);
970
+ return errMsg;
971
+ }
972
+ return true;
973
+ }
817
974
  }
818
975
  );
819
976
  }
@@ -1159,6 +1316,6 @@ _JSONViewPlugin.JSONView = (props) => {
1159
1316
  };
1160
1317
  var JSONViewPlugin = _JSONViewPlugin;
1161
1318
 
1162
- export { CheckboxWidget, ComplexFormModalStore, EditorWidget, FormModalStore, InputWidget, JSONForm, JSONSchemaForm, JSONViewPlugin, SelectWidget, TextareaWidget, getComplexFormData, getFormData, getFormState2 as getFormState, getSimpleFormData };
1319
+ export { CheckboxWidget, ComplexFormModalStore, DatePickerWidget, EditorWidget, FormModalStore, InputWidget, JSONForm, JSONSchemaForm, JSONViewPlugin, SelectWidget, TextareaWidget, getComplexFormData, getFormData, getFormState2 as getFormState, getSimpleFormData };
1163
1320
  //# sourceMappingURL=out.js.map
1164
1321
  //# sourceMappingURL=form.mjs.map