@dynamic-field-kit/react 1.4.0 → 1.5.1

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/index.js CHANGED
@@ -30,22 +30,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ DynamicFormDevTools: () => DynamicFormDevTools,
33
34
  DynamicInput: () => DynamicInput_default,
34
35
  FieldInput: () => FieldInput_default,
35
- FieldRegistry: () => import_core5.FieldRegistry,
36
+ FieldRegistry: () => import_core6.FieldRegistry,
36
37
  FieldRegistryProvider: () => FieldRegistryProvider,
37
38
  MultiFieldInput: () => MultiFieldInput_default,
39
+ defaultRenderersMap: () => defaultRenderersMap,
38
40
  fieldRegistry: () => fieldRegistry,
41
+ getDefaultRenderer: () => getDefaultRenderer,
39
42
  layoutRegistry: () => layoutRegistry,
40
- resolveDisabled: () => import_core6.resolveDisabled,
41
- resolveOptions: () => import_core6.resolveOptions,
42
- resolveReadOnly: () => import_core6.resolveReadOnly,
43
+ resolveDisabled: () => import_core7.resolveDisabled,
44
+ resolveOptions: () => import_core7.resolveOptions,
45
+ resolveReadOnly: () => import_core7.resolveReadOnly,
46
+ useDynamicForm: () => useDynamicForm,
43
47
  useFieldRegistry: () => useFieldRegistry,
44
- validateField: () => import_core6.validateField,
45
- validateFieldAsync: () => import_core6.validateFieldAsync,
46
- validateFields: () => import_core6.validateFields,
47
- validateFieldsAsync: () => import_core6.validateFieldsAsync,
48
- validators: () => import_core6.validators
48
+ validateField: () => import_core7.validateField,
49
+ validateFieldAsync: () => import_core7.validateFieldAsync,
50
+ validateFields: () => import_core7.validateFields,
51
+ validateFieldsAsync: () => import_core7.validateFieldsAsync,
52
+ validators: () => import_core7.validators
49
53
  });
50
54
  module.exports = __toCommonJS(index_exports);
51
55
 
@@ -164,6 +168,307 @@ layoutRegistry.register("responsive", ({ children, config }) => {
164
168
  // src/components/DynamicInput.tsx
165
169
  var import_react3 = __toESM(require("react"));
166
170
 
171
+ // src/defaultRenderers.tsx
172
+ var import_jsx_runtime3 = require("react/jsx-runtime");
173
+ var DefaultTextRenderer = ({
174
+ value,
175
+ onValueChange,
176
+ onBlur,
177
+ disabled,
178
+ readOnly,
179
+ required,
180
+ placeholder,
181
+ id,
182
+ className,
183
+ ariaInvalid,
184
+ ariaDescribedBy,
185
+ ariaRequired,
186
+ inputType = "text"
187
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
188
+ "input",
189
+ {
190
+ type: inputType,
191
+ id,
192
+ className,
193
+ value: value ?? "",
194
+ onChange: (e) => onValueChange?.(e.target.value),
195
+ onBlur,
196
+ disabled,
197
+ readOnly,
198
+ required,
199
+ placeholder,
200
+ "aria-invalid": ariaInvalid,
201
+ "aria-describedby": ariaDescribedBy,
202
+ "aria-required": ariaRequired
203
+ }
204
+ );
205
+ var DefaultNumberRenderer = ({
206
+ value,
207
+ onValueChange,
208
+ onBlur,
209
+ disabled,
210
+ readOnly,
211
+ required,
212
+ placeholder,
213
+ id,
214
+ className,
215
+ ariaInvalid,
216
+ ariaDescribedBy,
217
+ ariaRequired
218
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
219
+ "input",
220
+ {
221
+ type: "number",
222
+ id,
223
+ className,
224
+ value: value ?? "",
225
+ onChange: (e) => onValueChange?.(
226
+ e.target.value === "" ? void 0 : Number(e.target.value)
227
+ ),
228
+ onBlur,
229
+ disabled,
230
+ readOnly,
231
+ required,
232
+ placeholder,
233
+ "aria-invalid": ariaInvalid,
234
+ "aria-describedby": ariaDescribedBy,
235
+ "aria-required": ariaRequired
236
+ }
237
+ );
238
+ var DefaultPasswordRenderer = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultTextRenderer, { ...props, inputType: "password" });
239
+ var DefaultEmailRenderer = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultTextRenderer, { ...props, inputType: "email" });
240
+ var DefaultTextareaRenderer = ({
241
+ value,
242
+ onValueChange,
243
+ onBlur,
244
+ disabled,
245
+ readOnly,
246
+ required,
247
+ placeholder,
248
+ id,
249
+ className,
250
+ ariaInvalid,
251
+ ariaDescribedBy,
252
+ ariaRequired
253
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
254
+ "textarea",
255
+ {
256
+ id,
257
+ className,
258
+ value: value ?? "",
259
+ onChange: (e) => onValueChange?.(e.target.value),
260
+ onBlur,
261
+ disabled,
262
+ readOnly,
263
+ required,
264
+ placeholder,
265
+ "aria-invalid": ariaInvalid,
266
+ "aria-describedby": ariaDescribedBy,
267
+ "aria-required": ariaRequired
268
+ }
269
+ );
270
+ var DefaultCheckboxRenderer = ({
271
+ value,
272
+ onValueChange,
273
+ onBlur,
274
+ disabled,
275
+ readOnly,
276
+ required,
277
+ id,
278
+ className,
279
+ ariaInvalid,
280
+ ariaDescribedBy,
281
+ ariaRequired
282
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
283
+ "input",
284
+ {
285
+ type: "checkbox",
286
+ id,
287
+ className,
288
+ checked: Boolean(value),
289
+ onChange: (e) => onValueChange?.(e.target.checked),
290
+ onBlur,
291
+ disabled: disabled || readOnly,
292
+ required,
293
+ "aria-invalid": ariaInvalid,
294
+ "aria-describedby": ariaDescribedBy,
295
+ "aria-required": ariaRequired
296
+ }
297
+ );
298
+ var DefaultSelectRenderer = ({
299
+ value,
300
+ onValueChange,
301
+ onBlur,
302
+ disabled,
303
+ readOnly,
304
+ required,
305
+ options = [],
306
+ id,
307
+ className,
308
+ ariaInvalid,
309
+ ariaDescribedBy,
310
+ ariaRequired
311
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
312
+ "select",
313
+ {
314
+ id,
315
+ className,
316
+ value: value ?? "",
317
+ onChange: (e) => onValueChange?.(e.target.value),
318
+ onBlur,
319
+ disabled: disabled || readOnly,
320
+ required,
321
+ "aria-invalid": ariaInvalid,
322
+ "aria-describedby": ariaDescribedBy,
323
+ "aria-required": ariaRequired,
324
+ children: [
325
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", disabled: true, children: "-- Select --" }),
326
+ options.map((opt, i) => {
327
+ const optVal = opt.value ?? opt.id ?? opt;
328
+ const optLabel = opt.label ?? opt.name ?? String(optVal);
329
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: String(optVal), children: String(optLabel) }, String(optVal) + i);
330
+ })
331
+ ]
332
+ }
333
+ );
334
+ var DefaultRadioRenderer = ({
335
+ value,
336
+ onValueChange,
337
+ onBlur,
338
+ disabled,
339
+ readOnly,
340
+ required,
341
+ options = [],
342
+ id,
343
+ className,
344
+ ariaInvalid,
345
+ ariaDescribedBy
346
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `dfk-radio-group ${className || ""}`, id, onBlur, children: options.map((opt, i) => {
347
+ const optVal = opt.value ?? opt.id ?? opt;
348
+ const optLabel = opt.label ?? opt.name ?? String(optVal);
349
+ const isChecked = String(value) === String(optVal);
350
+ const radioId = `${id || "radio"}-${i}`;
351
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
352
+ "label",
353
+ {
354
+ htmlFor: radioId,
355
+ style: {
356
+ marginRight: "12px",
357
+ display: "inline-flex",
358
+ alignItems: "center"
359
+ },
360
+ children: [
361
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
362
+ "input",
363
+ {
364
+ type: "radio",
365
+ id: radioId,
366
+ name: id,
367
+ value: String(optVal),
368
+ checked: isChecked,
369
+ onChange: () => onValueChange?.(optVal),
370
+ disabled: disabled || readOnly,
371
+ required,
372
+ "aria-invalid": ariaInvalid,
373
+ "aria-describedby": ariaDescribedBy
374
+ }
375
+ ),
376
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { marginLeft: "4px" }, children: String(optLabel) })
377
+ ]
378
+ },
379
+ String(optVal) + i
380
+ );
381
+ }) });
382
+ var DefaultRangeRenderer = ({
383
+ value,
384
+ onValueChange,
385
+ onBlur,
386
+ disabled,
387
+ readOnly,
388
+ required,
389
+ min,
390
+ max,
391
+ step,
392
+ id,
393
+ className,
394
+ ariaInvalid,
395
+ ariaDescribedBy
396
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
397
+ "input",
398
+ {
399
+ type: "range",
400
+ id,
401
+ className,
402
+ value: value ?? min ?? 0,
403
+ min,
404
+ max,
405
+ step,
406
+ onChange: (e) => onValueChange?.(Number(e.target.value)),
407
+ onBlur,
408
+ disabled: disabled || readOnly,
409
+ required,
410
+ "aria-invalid": ariaInvalid,
411
+ "aria-describedby": ariaDescribedBy
412
+ }
413
+ );
414
+ var DefaultFileRenderer = ({
415
+ onValueChange,
416
+ onBlur,
417
+ disabled,
418
+ readOnly,
419
+ required,
420
+ accept,
421
+ multiple,
422
+ id,
423
+ className,
424
+ ariaInvalid,
425
+ ariaDescribedBy
426
+ }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
427
+ "input",
428
+ {
429
+ type: "file",
430
+ id,
431
+ className,
432
+ accept,
433
+ multiple,
434
+ onChange: (e) => {
435
+ const files = e.target.files;
436
+ if (!files) {
437
+ return;
438
+ }
439
+ onValueChange?.(multiple ? Array.from(files) : files[0] || null);
440
+ },
441
+ onBlur,
442
+ disabled: disabled || readOnly,
443
+ required,
444
+ "aria-invalid": ariaInvalid,
445
+ "aria-describedby": ariaDescribedBy
446
+ }
447
+ );
448
+ var DefaultDateRenderer = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultTextRenderer, { ...props, inputType: "date" });
449
+ var DefaultTimeRenderer = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultTextRenderer, { ...props, inputType: "time" });
450
+ var DefaultDateTimeLocalRenderer = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultTextRenderer, { ...props, inputType: "datetime-local" });
451
+ var DefaultSwitchRenderer = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultCheckboxRenderer, { ...props });
452
+ var defaultRenderersMap = {
453
+ text: DefaultTextRenderer,
454
+ number: DefaultNumberRenderer,
455
+ password: DefaultPasswordRenderer,
456
+ email: DefaultEmailRenderer,
457
+ textarea: DefaultTextareaRenderer,
458
+ checkbox: DefaultCheckboxRenderer,
459
+ select: DefaultSelectRenderer,
460
+ radio: DefaultRadioRenderer,
461
+ range: DefaultRangeRenderer,
462
+ file: DefaultFileRenderer,
463
+ date: DefaultDateRenderer,
464
+ time: DefaultTimeRenderer,
465
+ "datetime-local": DefaultDateTimeLocalRenderer,
466
+ switch: DefaultSwitchRenderer
467
+ };
468
+ function getDefaultRenderer(type) {
469
+ return defaultRenderersMap[type];
470
+ }
471
+
167
472
  // src/FieldRegistryContext.tsx
168
473
  var import_react2 = require("react");
169
474
 
@@ -172,18 +477,18 @@ var import_core = require("@dynamic-field-kit/core");
172
477
  var fieldRegistry = import_core.fieldRegistry;
173
478
 
174
479
  // src/FieldRegistryContext.tsx
175
- var import_jsx_runtime3 = require("react/jsx-runtime");
480
+ var import_jsx_runtime4 = require("react/jsx-runtime");
176
481
  var FieldRegistryContext = (0, import_react2.createContext)(fieldRegistry);
177
482
  var FieldRegistryProvider = ({
178
483
  registry,
179
484
  children
180
- }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FieldRegistryContext.Provider, { value: registry, children });
485
+ }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FieldRegistryContext.Provider, { value: registry, children });
181
486
  function useFieldRegistry() {
182
487
  return (0, import_react2.useContext)(FieldRegistryContext);
183
488
  }
184
489
 
185
490
  // src/components/DynamicInput.tsx
186
- var import_jsx_runtime4 = require("react/jsx-runtime");
491
+ var import_jsx_runtime5 = require("react/jsx-runtime");
187
492
  var DynamicInputInner = ({
188
493
  type,
189
494
  value,
@@ -207,11 +512,11 @@ var DynamicInputInner = ({
207
512
  }) => {
208
513
  const registry = useFieldRegistry();
209
514
  const Renderer = (0, import_react3.useMemo)(
210
- () => registry.get(type),
515
+ () => registry.get(type) || getDefaultRenderer(type),
211
516
  [registry, type]
212
517
  );
213
518
  if (!Renderer) {
214
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
519
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
215
520
  "Unknown field type: ",
216
521
  type
217
522
  ] });
@@ -237,7 +542,7 @@ var DynamicInputInner = ({
237
542
  ariaRequired
238
543
  });
239
544
  };
240
- var DynamicInput = import_react3.default.memo(
545
+ var DynamicInput = /* @__PURE__ */ import_react3.default.memo(
241
546
  DynamicInputInner
242
547
  );
243
548
  var DynamicInput_default = DynamicInput;
@@ -253,7 +558,7 @@ var import_react5 = require("react");
253
558
  // src/components/MultiFieldInput.tsx
254
559
  var import_core2 = require("@dynamic-field-kit/core");
255
560
  var import_react4 = require("react");
256
- var import_jsx_runtime5 = require("react/jsx-runtime");
561
+ var import_jsx_runtime6 = require("react/jsx-runtime");
257
562
  function resolveLayout(layout) {
258
563
  if (!layout) {
259
564
  return { type: "column", config: {} };
@@ -269,7 +574,8 @@ var MultiFieldInput = ({
269
574
  onChange,
270
575
  layout,
271
576
  rootData,
272
- onValidityChange
577
+ onValidityChange,
578
+ onBlurField
273
579
  }) => {
274
580
  const [data, setData] = (0, import_react4.useState)({});
275
581
  const [touchedFields, setTouchedFields] = (0, import_react4.useState)(
@@ -298,6 +604,8 @@ var MultiFieldInput = ({
298
604
  rootDataRef.current = rootData;
299
605
  const onValidityChangeRef = (0, import_react4.useRef)(onValidityChange);
300
606
  onValidityChangeRef.current = onValidityChange;
607
+ const onBlurFieldRef = (0, import_react4.useRef)(onBlurField);
608
+ onBlurFieldRef.current = onBlurField;
301
609
  (0, import_react4.useEffect)(() => {
302
610
  onValidityChangeRef.current?.(
303
611
  (0, import_core2.validateFields)(fieldDescriptions, data, rootData)
@@ -316,13 +624,14 @@ var MultiFieldInput = ({
316
624
  }, []);
317
625
  const handleBlurField = (0, import_react4.useCallback)((key) => {
318
626
  setTouchedFields((prev) => prev[key] ? prev : { ...prev, [key]: true });
627
+ onBlurFieldRef.current?.(key);
319
628
  }, []);
320
629
  const { type, config } = resolveLayout(layout);
321
630
  const Layout = layoutRegistry.get(type);
322
631
  if (!Layout) {
323
632
  throw new Error(`Unknown layout: ${type}`);
324
633
  }
325
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Layout, { config, children: visibleFields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
634
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Layout, { config, children: visibleFields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
326
635
  FieldInput_default,
327
636
  {
328
637
  fieldDescription: f,
@@ -339,7 +648,7 @@ var MultiFieldInput = ({
339
648
  var MultiFieldInput_default = MultiFieldInput;
340
649
 
341
650
  // src/components/FieldGroupInput.tsx
342
- var import_jsx_runtime6 = require("react/jsx-runtime");
651
+ var import_jsx_runtime7 = require("react/jsx-runtime");
343
652
  var FieldGroupInput = ({
344
653
  fieldDescription,
345
654
  items,
@@ -380,14 +689,14 @@ var FieldGroupInput = ({
380
689
  },
381
690
  [fieldDescription, items, onChange]
382
691
  );
383
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: fieldDescription.className, children: [
384
- label && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: label }),
385
- items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
692
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: fieldDescription.className, children: [
693
+ label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: label }),
694
+ items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
386
695
  "div",
387
696
  {
388
697
  style: { display: "flex", alignItems: "flex-start", gap: 8 },
389
698
  children: [
390
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
699
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
391
700
  MultiFieldInput_default,
392
701
  {
393
702
  fieldDescriptions: fields,
@@ -396,7 +705,7 @@ var FieldGroupInput = ({
396
705
  onChange: (next) => handleItemChange(index, next)
397
706
  }
398
707
  ) }),
399
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
708
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
400
709
  "button",
401
710
  {
402
711
  type: "button",
@@ -410,7 +719,7 @@ var FieldGroupInput = ({
410
719
  },
411
720
  itemKey(item, index)
412
721
  )),
413
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
722
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
414
723
  "button",
415
724
  {
416
725
  type: "button",
@@ -425,7 +734,7 @@ var FieldGroupInput = ({
425
734
  var FieldGroupInput_default = FieldGroupInput;
426
735
 
427
736
  // src/components/FieldInput.tsx
428
- var import_jsx_runtime7 = require("react/jsx-runtime");
737
+ var import_jsx_runtime8 = require("react/jsx-runtime");
429
738
  var FieldInputInner = ({
430
739
  fieldDescription,
431
740
  renderInfos,
@@ -446,7 +755,7 @@ var FieldInputInner = ({
446
755
  );
447
756
  if (fields) {
448
757
  const items = Array.isArray(renderInfos[name]) ? renderInfos[name] : [];
449
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
758
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
450
759
  FieldGroupInput_default,
451
760
  {
452
761
  fieldDescription,
@@ -470,7 +779,7 @@ var FieldInputInner = ({
470
779
  const errors = effectiveDisabled ? [] : (0, import_core4.validateField)(fieldDescription, renderInfos[name], renderInfos, rootData);
471
780
  const error = errors.length > 0 ? errors : void 0;
472
781
  const fieldId = `dfk-field-${name}`;
473
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
782
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
474
783
  DynamicInput_default,
475
784
  {
476
785
  id: fieldId,
@@ -494,27 +803,338 @@ var FieldInputInner = ({
494
803
  }
495
804
  );
496
805
  };
497
- var FieldInput = import_react6.default.memo(FieldInputInner, (prev, next) => {
806
+ var FieldInput = /* @__PURE__ */ import_react6.default.memo(FieldInputInner, (prev, next) => {
498
807
  const name = prev.fieldDescription.name;
499
808
  return prev.fieldDescription === next.fieldDescription && prev.onValueChangeField === next.onValueChangeField && prev.onBlurField === next.onBlurField && prev.rootData === next.rootData && prev.touched === next.touched && prev.dirty === next.dirty && prev.renderInfos[name] === next.renderInfos[name];
500
809
  });
501
810
  var FieldInput_default = FieldInput;
502
811
 
503
- // src/index.ts
812
+ // src/components/DynamicFormDevTools.tsx
813
+ var import_react7 = require("react");
814
+ var import_jsx_runtime9 = require("react/jsx-runtime");
815
+ var DynamicFormDevTools = ({
816
+ data,
817
+ errors = {},
818
+ touched = {},
819
+ isDirty = false,
820
+ fields = [],
821
+ position = "bottom-right"
822
+ }) => {
823
+ const [isOpen, setIsOpen] = (0, import_react7.useState)(false);
824
+ const [activeTab, setActiveTab] = (0, import_react7.useState)("data");
825
+ const errorCount = Object.keys(errors).length;
826
+ const posStyle = position === "bottom-left" ? { left: "16px", bottom: "16px" } : { right: "16px", bottom: "16px" };
827
+ if (!isOpen) {
828
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
829
+ "button",
830
+ {
831
+ type: "button",
832
+ onClick: () => setIsOpen(true),
833
+ style: {
834
+ position: "fixed",
835
+ ...posStyle,
836
+ zIndex: 99999,
837
+ background: "#1e293b",
838
+ color: "#f8fafc",
839
+ border: "1px solid #334155",
840
+ borderRadius: "20px",
841
+ padding: "8px 14px",
842
+ fontSize: "12px",
843
+ fontWeight: 600,
844
+ cursor: "pointer",
845
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
846
+ display: "flex",
847
+ alignItems: "center",
848
+ gap: "6px"
849
+ },
850
+ children: [
851
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "\u{1F50D} DevTools" }),
852
+ errorCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
853
+ "span",
854
+ {
855
+ style: {
856
+ background: "#ef4444",
857
+ color: "#fff",
858
+ borderRadius: "10px",
859
+ padding: "2px 6px",
860
+ fontSize: "10px"
861
+ },
862
+ children: errorCount
863
+ }
864
+ )
865
+ ]
866
+ }
867
+ );
868
+ }
869
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
870
+ "div",
871
+ {
872
+ style: {
873
+ position: "fixed",
874
+ ...posStyle,
875
+ zIndex: 99999,
876
+ width: "360px",
877
+ maxHeight: "420px",
878
+ background: "#0f172a",
879
+ color: "#f8fafc",
880
+ border: "1px solid #334155",
881
+ borderRadius: "12px",
882
+ boxShadow: "0 10px 25px rgba(0,0,0,0.3)",
883
+ display: "flex",
884
+ flexDirection: "column",
885
+ fontFamily: "monospace, sans-serif",
886
+ fontSize: "12px",
887
+ overflow: "hidden"
888
+ },
889
+ children: [
890
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
891
+ "div",
892
+ {
893
+ style: {
894
+ padding: "10px 14px",
895
+ background: "#1e293b",
896
+ display: "flex",
897
+ justifyContent: "space-between",
898
+ alignItems: "center",
899
+ borderBottom: "1px solid #334155"
900
+ },
901
+ children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { fontWeight: "bold", color: "#38bdf8" }, children: "\u{1F6E0}\uFE0F Form DevTools" }),
903
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
904
+ "button",
905
+ {
906
+ type: "button",
907
+ onClick: () => setIsOpen(false),
908
+ style: {
909
+ background: "transparent",
910
+ border: "none",
911
+ color: "#94a3b8",
912
+ fontSize: "14px",
913
+ cursor: "pointer"
914
+ },
915
+ children: "\u2715"
916
+ }
917
+ )
918
+ ]
919
+ }
920
+ ),
921
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
922
+ "div",
923
+ {
924
+ style: {
925
+ display: "flex",
926
+ background: "#1e293b",
927
+ borderBottom: "1px solid #334155"
928
+ },
929
+ children: ["data", "errors", "meta", "fields"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
930
+ "button",
931
+ {
932
+ type: "button",
933
+ onClick: () => setActiveTab(tab),
934
+ style: {
935
+ flex: 1,
936
+ padding: "6px 0",
937
+ background: activeTab === tab ? "#0f172a" : "transparent",
938
+ color: activeTab === tab ? "#38bdf8" : "#94a3b8",
939
+ border: "none",
940
+ cursor: "pointer",
941
+ textTransform: "capitalize",
942
+ fontSize: "11px",
943
+ fontWeight: activeTab === tab ? "bold" : "normal"
944
+ },
945
+ children: [
946
+ tab,
947
+ " ",
948
+ tab === "errors" && errorCount > 0 ? `(${errorCount})` : ""
949
+ ]
950
+ },
951
+ tab
952
+ ))
953
+ }
954
+ ),
955
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { padding: "12px", overflowY: "auto", flex: 1 }, children: [
956
+ activeTab === "data" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
957
+ "pre",
958
+ {
959
+ style: {
960
+ margin: 0,
961
+ whiteSpace: "pre-wrap",
962
+ wordBreak: "break-all",
963
+ color: "#a7f3d0"
964
+ },
965
+ children: JSON.stringify(data, null, 2)
966
+ }
967
+ ),
968
+ activeTab === "errors" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { children: Object.keys(errors).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: "#4ade80" }, children: "\u2713 No validation errors" }) : Object.entries(errors).map(([field, msgs]) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginBottom: "8px" }, children: [
969
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: { color: "#f87171", fontWeight: "bold" }, children: [
970
+ field,
971
+ ":"
972
+ ] }),
973
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { style: { margin: "4px 0 0 16px", padding: 0 }, children: msgs.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { style: { color: "#fca5a5" }, children: m }, i)) })
974
+ ] }, field)) }),
975
+ activeTab === "meta" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
976
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginBottom: "6px" }, children: [
977
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: "#94a3b8" }, children: "isDirty: " }),
978
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: isDirty ? "#facc15" : "#4ade80" }, children: String(isDirty) })
979
+ ] }),
980
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
981
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: "#94a3b8" }, children: "Touched Fields:" }),
982
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("pre", { style: { margin: "4px 0 0 0", color: "#cbd5e1" }, children: JSON.stringify(touched, null, 2) })
983
+ ] })
984
+ ] }),
985
+ activeTab === "fields" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { children: fields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: "#94a3b8" }, children: "No field descriptions passed" }) : fields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
986
+ "div",
987
+ {
988
+ style: {
989
+ padding: "6px",
990
+ marginBottom: "6px",
991
+ background: "#1e293b",
992
+ borderRadius: "4px"
993
+ },
994
+ children: [
995
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { color: "#38bdf8", fontWeight: "bold" }, children: f.name }),
996
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { color: "#94a3b8", fontSize: "10px" }, children: [
997
+ "type: ",
998
+ f.type,
999
+ " | required: ",
1000
+ String(Boolean(f.required))
1001
+ ] })
1002
+ ]
1003
+ },
1004
+ f.name
1005
+ )) })
1006
+ ] })
1007
+ ]
1008
+ }
1009
+ );
1010
+ };
1011
+
1012
+ // src/useDynamicForm.ts
504
1013
  var import_core5 = require("@dynamic-field-kit/core");
1014
+ var import_react8 = require("react");
1015
+ function useDynamicForm({
1016
+ fields,
1017
+ initialValues = {},
1018
+ validateOnBlur = true,
1019
+ validateOnChange = false
1020
+ }) {
1021
+ const [data, setData] = (0, import_react8.useState)(
1022
+ () => (0, import_core5.applyComputedValues)(fields, initialValues)
1023
+ );
1024
+ const [errors, setErrors] = (0, import_react8.useState)({});
1025
+ const [isDirty, setIsDirty] = (0, import_react8.useState)(false);
1026
+ const [touched, setTouched] = (0, import_react8.useState)({});
1027
+ const [isSubmitting, setIsSubmitting] = (0, import_react8.useState)(false);
1028
+ const [isSubmitted, setIsSubmitted] = (0, import_react8.useState)(false);
1029
+ const validate = (0, import_react8.useCallback)(() => {
1030
+ const res = (0, import_core5.validateFields)(fields, data);
1031
+ setErrors(res.errors);
1032
+ return res.valid;
1033
+ }, [fields, data]);
1034
+ const handleChange = (0, import_react8.useCallback)(
1035
+ (newData) => {
1036
+ const next = (0, import_core5.applyComputedValues)(fields, newData);
1037
+ setData(next);
1038
+ setIsDirty(true);
1039
+ if (validateOnChange) {
1040
+ const res = (0, import_core5.validateFields)(fields, next);
1041
+ setErrors(res.errors);
1042
+ }
1043
+ },
1044
+ [fields, validateOnChange]
1045
+ );
1046
+ const setFieldValue = (0, import_react8.useCallback)(
1047
+ (name, value) => {
1048
+ handleChange({ ...data, [name]: value });
1049
+ },
1050
+ [data, handleChange]
1051
+ );
1052
+ const setFieldTouched = (0, import_react8.useCallback)((name, isTouched = true) => {
1053
+ setTouched((prev) => ({ ...prev, [name]: isTouched }));
1054
+ }, []);
1055
+ const handleBlur = (0, import_react8.useCallback)(
1056
+ (fieldName) => {
1057
+ setFieldTouched(fieldName, true);
1058
+ if (validateOnBlur) {
1059
+ const res = (0, import_core5.validateFields)(fields, data);
1060
+ setErrors(res.errors);
1061
+ }
1062
+ },
1063
+ [fields, data, validateOnBlur, setFieldTouched]
1064
+ );
1065
+ const reset = (0, import_react8.useCallback)(
1066
+ (newValues) => {
1067
+ const seed = newValues ?? initialValues;
1068
+ const next = (0, import_core5.applyComputedValues)(fields, seed);
1069
+ setData(next);
1070
+ setErrors({});
1071
+ setIsDirty(false);
1072
+ setTouched({});
1073
+ setIsSubmitting(false);
1074
+ setIsSubmitted(false);
1075
+ },
1076
+ [fields, initialValues]
1077
+ );
1078
+ const handleSubmit = (0, import_react8.useCallback)(
1079
+ (onValid, onInvalid) => async (e) => {
1080
+ if (e && typeof e.preventDefault === "function") {
1081
+ e.preventDefault();
1082
+ }
1083
+ setIsSubmitting(true);
1084
+ try {
1085
+ const res = (0, import_core5.validateFields)(fields, data);
1086
+ setErrors(res.errors);
1087
+ setIsSubmitted(true);
1088
+ if (res.valid) {
1089
+ await onValid(data);
1090
+ } else if (onInvalid) {
1091
+ onInvalid(res.errors);
1092
+ }
1093
+ } finally {
1094
+ setIsSubmitting(false);
1095
+ }
1096
+ },
1097
+ [fields, data]
1098
+ );
1099
+ const isValid = Object.keys(errors).length === 0;
1100
+ return {
1101
+ data,
1102
+ errors,
1103
+ isValid,
1104
+ isDirty,
1105
+ isSubmitting,
1106
+ isSubmitted,
1107
+ touched,
1108
+ setData,
1109
+ setFieldValue,
1110
+ setFieldTouched,
1111
+ handleChange,
1112
+ handleBlur,
1113
+ reset,
1114
+ validate,
1115
+ handleSubmit
1116
+ };
1117
+ }
1118
+
1119
+ // src/index.ts
505
1120
  var import_core6 = require("@dynamic-field-kit/core");
1121
+ var import_core7 = require("@dynamic-field-kit/core");
506
1122
  // Annotate the CommonJS export names for ESM import in node:
507
1123
  0 && (module.exports = {
1124
+ DynamicFormDevTools,
508
1125
  DynamicInput,
509
1126
  FieldInput,
510
1127
  FieldRegistry,
511
1128
  FieldRegistryProvider,
512
1129
  MultiFieldInput,
1130
+ defaultRenderersMap,
513
1131
  fieldRegistry,
1132
+ getDefaultRenderer,
514
1133
  layoutRegistry,
515
1134
  resolveDisabled,
516
1135
  resolveOptions,
517
1136
  resolveReadOnly,
1137
+ useDynamicForm,
518
1138
  useFieldRegistry,
519
1139
  validateField,
520
1140
  validateFieldAsync,
@@ -522,4 +1142,3 @@ var import_core6 = require("@dynamic-field-kit/core");
522
1142
  validateFieldsAsync,
523
1143
  validators
524
1144
  });
525
- //# sourceMappingURL=index.js.map