@skygraph/react 0.0.0-placeholder.0 → 0.5.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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -12
  3. package/dist/Table-BmesoMje.d.ts +1017 -0
  4. package/dist/Table-CpKMOH2x.d.cts +1017 -0
  5. package/dist/chunk-2OCEO636.js +91 -0
  6. package/dist/chunk-2OCEO636.js.map +1 -0
  7. package/dist/chunk-BNMJSYI2.js +54 -0
  8. package/dist/chunk-BNMJSYI2.js.map +1 -0
  9. package/dist/chunk-FSV73JI4.js +58 -0
  10. package/dist/chunk-FSV73JI4.js.map +1 -0
  11. package/dist/chunk-GJDDPZH7.js +226 -0
  12. package/dist/chunk-GJDDPZH7.js.map +1 -0
  13. package/dist/chunk-MLEBVELO.js +1412 -0
  14. package/dist/chunk-MLEBVELO.js.map +1 -0
  15. package/dist/chunk-NXB3VAVF.js +3794 -0
  16. package/dist/chunk-NXB3VAVF.js.map +1 -0
  17. package/dist/chunk-SEQI65CF.js +61 -0
  18. package/dist/chunk-SEQI65CF.js.map +1 -0
  19. package/dist/chunk-UO6VJC3C.js +1667 -0
  20. package/dist/chunk-UO6VJC3C.js.map +1 -0
  21. package/dist/chunk-Z5UGF7EO.js +847 -0
  22. package/dist/chunk-Z5UGF7EO.js.map +1 -0
  23. package/dist/chunk-ZJF6SJLP.js +200 -0
  24. package/dist/chunk-ZJF6SJLP.js.map +1 -0
  25. package/dist/common-CdpocIEz.d.cts +27 -0
  26. package/dist/common-CdpocIEz.d.ts +27 -0
  27. package/dist/datagrid-B6hg5yJh.d.cts +200 -0
  28. package/dist/datagrid-B6hg5yJh.d.ts +200 -0
  29. package/dist/datagrid.cjs +1053 -0
  30. package/dist/datagrid.cjs.map +1 -0
  31. package/dist/datagrid.d.cts +2 -0
  32. package/dist/datagrid.d.ts +2 -0
  33. package/dist/datagrid.js +10 -0
  34. package/dist/datagrid.js.map +1 -0
  35. package/dist/devtools.cjs +253 -0
  36. package/dist/devtools.cjs.map +1 -0
  37. package/dist/devtools.d.cts +29 -0
  38. package/dist/devtools.d.ts +29 -0
  39. package/dist/devtools.js +9 -0
  40. package/dist/devtools.js.map +1 -0
  41. package/dist/form.cjs +1723 -0
  42. package/dist/form.cjs.map +1 -0
  43. package/dist/form.d.cts +530 -0
  44. package/dist/form.d.ts +530 -0
  45. package/dist/form.js +49 -0
  46. package/dist/form.js.map +1 -0
  47. package/dist/index.cjs +22467 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.cts +3685 -0
  50. package/dist/index.d.ts +3685 -0
  51. package/dist/index.js +14131 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/table.cjs +4134 -0
  54. package/dist/table.cjs.map +1 -0
  55. package/dist/table.d.cts +31 -0
  56. package/dist/table.d.ts +31 -0
  57. package/dist/table.js +26 -0
  58. package/dist/table.js.map +1 -0
  59. package/dist/tree.cjs +1822 -0
  60. package/dist/tree.cjs.map +1 -0
  61. package/dist/tree.d.cts +348 -0
  62. package/dist/tree.d.ts +348 -0
  63. package/dist/tree.js +13 -0
  64. package/dist/tree.js.map +1 -0
  65. package/dist/virtual.cjs +145 -0
  66. package/dist/virtual.cjs.map +1 -0
  67. package/dist/virtual.d.cts +50 -0
  68. package/dist/virtual.d.ts +50 -0
  69. package/dist/virtual.js +11 -0
  70. package/dist/virtual.js.map +1 -0
  71. package/package.json +108 -18
  72. package/index.js +0 -3
@@ -0,0 +1,1412 @@
1
+ import {
2
+ Button,
3
+ Input,
4
+ Transition
5
+ } from "./chunk-ZJF6SJLP.js";
6
+ import {
7
+ Spin,
8
+ useConfig
9
+ } from "./chunk-2OCEO636.js";
10
+
11
+ // src/hooks/useField.ts
12
+ import { useEffect, useState, useCallback, useRef } from "react";
13
+ function useField(core, form, name) {
14
+ const [value, setValue] = useState(() => form.getValue(name));
15
+ const [meta, setMeta] = useState(() => form.getFieldState(name));
16
+ const nameRef = useRef(name);
17
+ nameRef.current = name;
18
+ useEffect(() => {
19
+ const unsubs = [];
20
+ unsubs.push(
21
+ core.subscribe(name, (v) => {
22
+ setValue(v);
23
+ })
24
+ );
25
+ unsubs.push(
26
+ core.subscribe(`$meta.${name}.errors`, () => {
27
+ setMeta(form.getFieldState(nameRef.current));
28
+ })
29
+ );
30
+ unsubs.push(
31
+ core.subscribe(`$meta.${name}.warnings`, () => {
32
+ setMeta(form.getFieldState(nameRef.current));
33
+ })
34
+ );
35
+ unsubs.push(
36
+ core.subscribe(`$meta.${name}.touched`, () => {
37
+ setMeta(form.getFieldState(nameRef.current));
38
+ })
39
+ );
40
+ unsubs.push(
41
+ core.subscribe(`$meta.${name}.dirty`, () => {
42
+ setMeta(form.getFieldState(nameRef.current));
43
+ })
44
+ );
45
+ unsubs.push(
46
+ core.subscribe(`$meta.${name}.validating`, () => {
47
+ setMeta(form.getFieldState(nameRef.current));
48
+ })
49
+ );
50
+ return () => {
51
+ for (const u of unsubs) u();
52
+ };
53
+ }, [core, form, name]);
54
+ const onChange = useCallback(
55
+ (v) => {
56
+ form.setValue(nameRef.current, v);
57
+ },
58
+ [form]
59
+ );
60
+ const onBlur = useCallback(() => {
61
+ form.onFieldBlur(nameRef.current);
62
+ }, [form]);
63
+ return {
64
+ value,
65
+ errors: meta.errors,
66
+ warnings: meta.warnings,
67
+ error: meta.error,
68
+ touched: meta.touched,
69
+ dirty: meta.dirty,
70
+ validating: meta.validating,
71
+ status: meta.status,
72
+ onChange,
73
+ onBlur
74
+ };
75
+ }
76
+
77
+ // src/hooks/useForm.ts
78
+ import { useState as useState2, useCallback as useCallback2, useMemo, useRef as useRef2 } from "react";
79
+ import { createCore, createForm } from "@skygraph/core";
80
+ function useForm(options) {
81
+ const optionsRef = useRef2(options);
82
+ optionsRef.current = options;
83
+ const [{ core, form }] = useState2(() => {
84
+ const c = createCore();
85
+ const f = createForm(c, options);
86
+ return { core: c, form: f };
87
+ });
88
+ const [formState, setFormState] = useState2(() => form.getFormState());
89
+ const refreshState = useCallback2(() => {
90
+ setFormState(form.getFormState());
91
+ }, [form]);
92
+ const submit = useCallback2(async () => {
93
+ refreshState();
94
+ await form.submit(async (values) => {
95
+ await optionsRef.current?.onSubmit?.(values);
96
+ });
97
+ const state = form.getFormState();
98
+ setFormState(state);
99
+ if (!state.isValid && optionsRef.current?.onSubmitInvalid) {
100
+ optionsRef.current.onSubmitInvalid(
101
+ (await form.validate()).errors
102
+ );
103
+ }
104
+ }, [form, refreshState]);
105
+ const reset = useCallback2(
106
+ (values) => {
107
+ form.reset(values);
108
+ setFormState(form.getFormState());
109
+ },
110
+ [form]
111
+ );
112
+ const setFieldValue = useCallback2(
113
+ (name, value) => {
114
+ form.setValue(name, value);
115
+ },
116
+ [form]
117
+ );
118
+ const setFieldsValue = useCallback2(
119
+ (values) => {
120
+ form.setFieldsValue(values);
121
+ },
122
+ [form]
123
+ );
124
+ const getFieldValue = useCallback2((name) => form.getValue(name), [form]);
125
+ const getFieldsValue = useCallback2(() => form.getFieldsValue(), [form]);
126
+ const validateFields = useCallback2((name) => form.validate(name), [form]);
127
+ return useMemo(
128
+ () => ({
129
+ core,
130
+ form,
131
+ formState,
132
+ submit,
133
+ reset,
134
+ setFieldValue,
135
+ setFieldsValue,
136
+ getFieldValue,
137
+ getFieldsValue,
138
+ validateFields
139
+ }),
140
+ [
141
+ core,
142
+ form,
143
+ formState,
144
+ submit,
145
+ reset,
146
+ setFieldValue,
147
+ setFieldsValue,
148
+ getFieldValue,
149
+ getFieldsValue,
150
+ validateFields
151
+ ]
152
+ );
153
+ }
154
+
155
+ // src/components/complex/FormContext.ts
156
+ import { createContext, useContext } from "react";
157
+ var FormContext = createContext(null);
158
+ function useFormContext() {
159
+ const ctx = useContext(FormContext);
160
+ if (!ctx) {
161
+ throw new Error("SkyGraph: useFormContext must be used inside <Form>");
162
+ }
163
+ return ctx;
164
+ }
165
+
166
+ // src/components/complex/FormProvider.tsx
167
+ import React, { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useMemo as useMemo2, useRef as useRef3 } from "react";
168
+ import { jsx } from "react/jsx-runtime";
169
+ var FormProviderContext = createContext2(null);
170
+ function FormProvider({ onFormFinish, onFormChange, children }) {
171
+ const formsRef = useRef3({});
172
+ const registerForm = useCallback3((name, form) => {
173
+ formsRef.current[name] = form;
174
+ }, []);
175
+ const unregisterForm = useCallback3((name) => {
176
+ delete formsRef.current[name];
177
+ }, []);
178
+ const value = useMemo2(
179
+ () => ({
180
+ registerForm,
181
+ unregisterForm,
182
+ onFormFinish,
183
+ onFormChange
184
+ }),
185
+ [registerForm, unregisterForm, onFormFinish, onFormChange]
186
+ );
187
+ return /* @__PURE__ */ jsx(FormProviderContext.Provider, { value, children });
188
+ }
189
+ function useFormProvider() {
190
+ return useContext2(FormProviderContext);
191
+ }
192
+ function useFormProviderRegister(name, form) {
193
+ const provider = useContext2(FormProviderContext);
194
+ React.useEffect(() => {
195
+ if (!provider || !name) return;
196
+ provider.registerForm(name, form);
197
+ return () => provider.unregisterForm(name);
198
+ }, [provider, name, form]);
199
+ return provider;
200
+ }
201
+
202
+ // src/components/complex/Form.tsx
203
+ import { useRef as useRef4 } from "react";
204
+ import { jsx as jsx2 } from "react/jsx-runtime";
205
+ function Form({
206
+ form: externalForm,
207
+ name: formName,
208
+ layout = "vertical",
209
+ size: sizeProp,
210
+ disabled: disabledProp,
211
+ colon,
212
+ requiredMark,
213
+ labelCol,
214
+ wrapperCol,
215
+ labelAlign,
216
+ className,
217
+ style,
218
+ children,
219
+ scrollToFirstError,
220
+ preserve,
221
+ feedbackIcons,
222
+ onFinish,
223
+ initialValues,
224
+ ...formOptions
225
+ }) {
226
+ const config = useConfig();
227
+ const size = sizeProp ?? config.size ?? "middle";
228
+ const disabled = disabledProp ?? config.disabled;
229
+ const mergedFormOptions = {
230
+ ...formOptions,
231
+ defaultValues: formOptions.defaultValues ?? initialValues,
232
+ onSubmit: async (values) => {
233
+ await formOptions.onSubmit?.(values);
234
+ await onFinish?.(values);
235
+ }
236
+ };
237
+ const internalForm = useForm(externalForm ? void 0 : mergedFormOptions);
238
+ const { core, form, submit } = externalForm ?? internalForm;
239
+ const formRef = useRef4(null);
240
+ useFormProviderRegister(formName, form);
241
+ const handleSubmit = async (e) => {
242
+ e.preventDefault();
243
+ await submit();
244
+ if (scrollToFirstError) {
245
+ const result = await form.validate();
246
+ if (!result.valid) {
247
+ const firstErrorField = Object.keys(result.errors)[0];
248
+ if (firstErrorField && formRef.current) {
249
+ const el = formRef.current.querySelector(`[data-field-name="${firstErrorField}"]`) ?? formRef.current.querySelector(`[name="${firstErrorField}"]`);
250
+ if (el) {
251
+ const scrollOpts = typeof scrollToFirstError === "object" ? scrollToFirstError : { behavior: "smooth", block: "center" };
252
+ el.scrollIntoView(scrollOpts);
253
+ }
254
+ }
255
+ }
256
+ }
257
+ };
258
+ const classes = ["sg-form", `sg-form-${layout}`, `sg-form-${size}`];
259
+ if (disabled) classes.push("sg-form-disabled");
260
+ if (className) classes.push(className);
261
+ return /* @__PURE__ */ jsx2(
262
+ FormContext.Provider,
263
+ {
264
+ value: {
265
+ core,
266
+ form,
267
+ layout,
268
+ size,
269
+ disabled,
270
+ colon,
271
+ requiredMark,
272
+ labelCol,
273
+ wrapperCol,
274
+ labelAlign,
275
+ preserve,
276
+ feedbackIcons
277
+ },
278
+ children: /* @__PURE__ */ jsx2(
279
+ "form",
280
+ {
281
+ ref: formRef,
282
+ name: formName,
283
+ className: classes.join(" "),
284
+ style,
285
+ onSubmit: handleSubmit,
286
+ noValidate: true,
287
+ children
288
+ }
289
+ )
290
+ }
291
+ );
292
+ }
293
+
294
+ // src/components/ui/Textarea.tsx
295
+ import React3 from "react";
296
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
297
+ function Textarea({
298
+ value,
299
+ defaultValue,
300
+ placeholder,
301
+ rows = 4,
302
+ maxLength,
303
+ showCount,
304
+ disabled: disabledProp,
305
+ loading,
306
+ size: sizeProp,
307
+ onChange,
308
+ onBlur,
309
+ onFocus,
310
+ id,
311
+ "aria-invalid": ariaInvalid,
312
+ "aria-describedby": ariaDescribedBy,
313
+ "aria-required": ariaRequired,
314
+ className,
315
+ style,
316
+ unstyled
317
+ }) {
318
+ const config = useConfig();
319
+ const disabled = disabledProp ?? config.disabled;
320
+ const size = sizeProp ?? config.size ?? "middle";
321
+ const [internalValue, setInternalValue] = React3.useState(value ?? defaultValue ?? "");
322
+ const currentValue = value ?? internalValue;
323
+ const handleChange = (e) => {
324
+ const v = e.target.value;
325
+ if (maxLength && v.length > maxLength) return;
326
+ setInternalValue(v);
327
+ onChange?.(v);
328
+ };
329
+ const wrapperClass = unstyled ? className ?? "" : ["sg-textarea-wrapper", `sg-textarea-${size}`, loading ? "sg-textarea-wrapper-loading" : "", className].filter(Boolean).join(" ");
330
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, style, children: [
331
+ /* @__PURE__ */ jsx3(
332
+ "textarea",
333
+ {
334
+ id,
335
+ className: unstyled ? "" : "sg-input sg-textarea",
336
+ value: currentValue,
337
+ placeholder,
338
+ rows,
339
+ disabled: disabled || loading,
340
+ "aria-disabled": disabled || loading,
341
+ "aria-invalid": ariaInvalid,
342
+ "aria-describedby": ariaDescribedBy,
343
+ "aria-required": ariaRequired,
344
+ onChange: handleChange,
345
+ onBlur,
346
+ onFocus
347
+ }
348
+ ),
349
+ loading && /* @__PURE__ */ jsx3(Spin, { size: "small", unstyled }),
350
+ showCount && !unstyled && /* @__PURE__ */ jsxs("span", { className: "sg-textarea-count", children: [
351
+ currentValue.length,
352
+ maxLength ? ` / ${maxLength}` : ""
353
+ ] })
354
+ ] });
355
+ }
356
+
357
+ // src/components/ui/Tooltip.tsx
358
+ import { useState as useState3, useRef as useRef5, useId, cloneElement, isValidElement } from "react";
359
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
360
+ function Tooltip({
361
+ title,
362
+ placement = "top",
363
+ children,
364
+ className,
365
+ unstyled
366
+ }) {
367
+ const [visible, setVisible] = useState3(false);
368
+ const ref = useRef5(null);
369
+ const tooltipId = useId();
370
+ const triggerWithAria = isValidElement(children) ? cloneElement(children, {
371
+ "aria-describedby": visible ? [children.props["aria-describedby"], tooltipId].filter(Boolean).join(" ") : children.props["aria-describedby"],
372
+ onFocus: (e) => {
373
+ setVisible(true);
374
+ children.props.onFocus?.(e);
375
+ },
376
+ onBlur: (e) => {
377
+ setVisible(false);
378
+ children.props.onBlur?.(e);
379
+ }
380
+ }) : children;
381
+ if (unstyled) {
382
+ return /* @__PURE__ */ jsxs2(
383
+ "div",
384
+ {
385
+ className,
386
+ onMouseEnter: () => setVisible(true),
387
+ onMouseLeave: () => setVisible(false),
388
+ style: { position: "relative", display: "inline-block" },
389
+ children: [
390
+ triggerWithAria,
391
+ visible && /* @__PURE__ */ jsx4("div", { id: tooltipId, role: "tooltip", children: title })
392
+ ]
393
+ }
394
+ );
395
+ }
396
+ return /* @__PURE__ */ jsxs2(
397
+ "div",
398
+ {
399
+ className: ["sg-tooltip-wrapper", className].filter(Boolean).join(" "),
400
+ onMouseEnter: () => setVisible(true),
401
+ onMouseLeave: () => setVisible(false),
402
+ ref,
403
+ children: [
404
+ triggerWithAria,
405
+ /* @__PURE__ */ jsx4(Transition, { visible, name: "sg-fade", unmountOnExit: true, children: /* @__PURE__ */ jsxs2("div", { id: tooltipId, role: "tooltip", className: `sg-tooltip sg-tooltip-${placement}`, children: [
406
+ /* @__PURE__ */ jsx4("div", { className: "sg-tooltip-content", children: title }),
407
+ /* @__PURE__ */ jsx4("div", { className: "sg-tooltip-arrow" })
408
+ ] }) })
409
+ ]
410
+ }
411
+ );
412
+ }
413
+
414
+ // src/components/complex/Field.tsx
415
+ import { useEffect as useEffect2, useId as useId2, useRef as useRef6 } from "react";
416
+ import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
417
+ function FeedbackIcon({
418
+ status,
419
+ icons
420
+ }) {
421
+ if (!status) return null;
422
+ const defaults = {
423
+ validating: /* @__PURE__ */ jsx5(Spin, { size: "small" }),
424
+ error: /* @__PURE__ */ jsx5("span", { className: "sg-field-feedback-icon sg-field-feedback-error", children: "\u2715" }),
425
+ warning: /* @__PURE__ */ jsx5("span", { className: "sg-field-feedback-icon sg-field-feedback-warning", children: "!" }),
426
+ success: /* @__PURE__ */ jsx5("span", { className: "sg-field-feedback-icon sg-field-feedback-success", children: "\u2713" })
427
+ };
428
+ return /* @__PURE__ */ jsx5("span", { className: "sg-field-feedback", children: icons?.[status] ?? defaults[status] });
429
+ }
430
+ function Field({
431
+ name,
432
+ label,
433
+ required,
434
+ rules = [],
435
+ warningRules,
436
+ dependencies,
437
+ hidden,
438
+ disabled: fieldDisabled,
439
+ unstyled,
440
+ placeholder,
441
+ type = "text",
442
+ help,
443
+ extra,
444
+ tooltip,
445
+ children,
446
+ noStyle,
447
+ normalize,
448
+ getValueFromEvent: _getValueFromEvent,
449
+ validateFirst,
450
+ validateStatus: manualStatus,
451
+ hasFeedback,
452
+ preserve,
453
+ labelCol: fieldLabelCol,
454
+ wrapperCol: fieldWrapperCol,
455
+ messageVariables: _messageVariables
456
+ }) {
457
+ const ctx = useFormContext();
458
+ const { core, form } = ctx;
459
+ const disabled = fieldDisabled ?? ctx.disabled;
460
+ const formLocale = useConfig().locale?.form;
461
+ const requiredMarker = formLocale?.required ?? "*";
462
+ const optionalMarker = formLocale?.optional ?? "(optional)";
463
+ const autoId = useId2();
464
+ const fieldId = `sg-field-${autoId.replace(/:/g, "")}-${name.replace(/\./g, "-")}`;
465
+ const helpId = `${fieldId}-help`;
466
+ const field = useField(core, form, name);
467
+ const prevValueRef = useRef6(field.value);
468
+ useEffect2(() => {
469
+ const allRules = [...rules];
470
+ if (required) {
471
+ allRules.unshift({ required: true });
472
+ }
473
+ form.register(name, {
474
+ rules: allRules,
475
+ warningRules,
476
+ dependencies,
477
+ validateFirst,
478
+ label,
479
+ preserve: preserve ?? ctx.preserve
480
+ });
481
+ return () => form.unregister(name);
482
+ }, [name, form, required]);
483
+ if (hidden) return null;
484
+ const wrappedOnChange = normalize ? (v) => {
485
+ const normalized = normalize(v, prevValueRef.current);
486
+ prevValueRef.current = normalized;
487
+ field.onChange(normalized);
488
+ } : field.onChange;
489
+ const effectiveStatus = manualStatus ?? field.status;
490
+ const hasErrors = field.errors.length > 0;
491
+ const hasWarnings = field.warnings.length > 0;
492
+ const layout = ctx.layout ?? "vertical";
493
+ const lCol = fieldLabelCol ?? ctx.labelCol;
494
+ const wCol = fieldWrapperCol ?? ctx.wrapperCol;
495
+ const labelAlign = ctx.labelAlign ?? "right";
496
+ const labelNode = label ? /* @__PURE__ */ jsxs3(
497
+ "label",
498
+ {
499
+ htmlFor: fieldId,
500
+ className: "sg-field-label",
501
+ style: layout === "horizontal" && lCol?.offset ? { marginLeft: `${lCol.offset / 24 * 100}%` } : void 0,
502
+ children: [
503
+ tooltip ? /* @__PURE__ */ jsx5(Tooltip, { title: tooltip, children: /* @__PURE__ */ jsx5("span", { children: label }) }) : label,
504
+ (required || ctx.requiredMark === true) && /* @__PURE__ */ jsx5("span", { className: "sg-field-required", children: requiredMarker }),
505
+ ctx.requiredMark === "optional" && !required && /* @__PURE__ */ jsx5("span", { className: "sg-field-optional", children: optionalMarker }),
506
+ ctx.colon && ":"
507
+ ]
508
+ }
509
+ ) : null;
510
+ const errorNodes = hasErrors ? /* @__PURE__ */ jsx5("div", { id: helpId, className: "sg-field-error", role: "alert", children: field.errors.map((e, i) => /* @__PURE__ */ jsx5("div", { children: e }, i)) }) : null;
511
+ const warningNodes = hasWarnings && !hasErrors ? /* @__PURE__ */ jsx5("div", { id: helpId, className: "sg-field-warning", children: field.warnings.map((w, i) => /* @__PURE__ */ jsx5("div", { children: w }, i)) }) : null;
512
+ const helpNode = errorNodes ?? warningNodes ?? (help ? /* @__PURE__ */ jsx5("div", { id: helpId, className: "sg-field-help", children: help }) : null);
513
+ const describedBy = helpNode ? helpId : void 0;
514
+ const extraNode = extra ? /* @__PURE__ */ jsx5("div", { className: "sg-field-extra", children: extra }) : null;
515
+ const feedbackIcon = hasFeedback && field.touched ? /* @__PURE__ */ jsx5(FeedbackIcon, { status: effectiveStatus, icons: ctx.feedbackIcons }) : null;
516
+ const renderControl = () => {
517
+ if (typeof children === "function") {
518
+ return /* @__PURE__ */ jsxs3(Fragment, { children: [
519
+ children({ ...field, onChange: wrappedOnChange }),
520
+ feedbackIcon
521
+ ] });
522
+ }
523
+ if (children) {
524
+ return /* @__PURE__ */ jsxs3(Fragment, { children: [
525
+ children,
526
+ feedbackIcon
527
+ ] });
528
+ }
529
+ const inputElement = type === "textarea" ? /* @__PURE__ */ jsx5(
530
+ Textarea,
531
+ {
532
+ id: fieldId,
533
+ value: field.value ?? "",
534
+ onChange: (v) => wrappedOnChange(v),
535
+ onBlur: field.onBlur,
536
+ disabled,
537
+ placeholder,
538
+ unstyled,
539
+ "aria-invalid": hasErrors || void 0,
540
+ "aria-required": required || void 0,
541
+ "aria-describedby": describedBy
542
+ }
543
+ ) : /* @__PURE__ */ jsx5(
544
+ Input,
545
+ {
546
+ id: fieldId,
547
+ type,
548
+ value: field.value ?? "",
549
+ onChange: (v) => wrappedOnChange(type === "number" ? Number(v) : v),
550
+ onBlur: field.onBlur,
551
+ disabled,
552
+ placeholder,
553
+ unstyled,
554
+ "aria-invalid": hasErrors || void 0,
555
+ "aria-required": required || void 0,
556
+ "aria-describedby": describedBy
557
+ }
558
+ );
559
+ return /* @__PURE__ */ jsxs3(Fragment, { children: [
560
+ inputElement,
561
+ feedbackIcon
562
+ ] });
563
+ };
564
+ if (noStyle) {
565
+ return /* @__PURE__ */ jsx5(Fragment, { children: renderControl() });
566
+ }
567
+ if (unstyled) {
568
+ return /* @__PURE__ */ jsxs3(Fragment, { children: [
569
+ labelNode,
570
+ renderControl(),
571
+ helpNode,
572
+ extraNode
573
+ ] });
574
+ }
575
+ if (layout === "horizontal" && lCol) {
576
+ const labelSpan = lCol.span ?? 6;
577
+ const wrapperSpan = wCol?.span ?? 24 - labelSpan;
578
+ const labelPct = `${labelSpan / 24 * 100}%`;
579
+ const wrapperPct = `${wrapperSpan / 24 * 100}%`;
580
+ return /* @__PURE__ */ jsxs3(
581
+ "div",
582
+ {
583
+ className: [
584
+ "sg-field",
585
+ "sg-field-horizontal",
586
+ hasErrors ? "sg-field-has-error" : "",
587
+ hasWarnings && !hasErrors ? "sg-field-has-warning" : "",
588
+ effectiveStatus ? `sg-field-status-${effectiveStatus}` : ""
589
+ ].filter(Boolean).join(" "),
590
+ "data-field-name": name,
591
+ children: [
592
+ /* @__PURE__ */ jsx5(
593
+ "div",
594
+ {
595
+ className: "sg-field-label-wrap",
596
+ style: {
597
+ width: labelPct,
598
+ textAlign: labelAlign
599
+ },
600
+ children: labelNode
601
+ }
602
+ ),
603
+ /* @__PURE__ */ jsxs3("div", { className: "sg-field-control-wrap", style: { width: wrapperPct }, children: [
604
+ /* @__PURE__ */ jsx5("div", { className: "sg-field-control", children: renderControl() }),
605
+ helpNode,
606
+ extraNode
607
+ ] })
608
+ ]
609
+ }
610
+ );
611
+ }
612
+ const fieldClasses = [
613
+ "sg-field",
614
+ hasErrors ? "sg-field-has-error" : "",
615
+ hasWarnings && !hasErrors ? "sg-field-has-warning" : "",
616
+ effectiveStatus ? `sg-field-status-${effectiveStatus}` : ""
617
+ ];
618
+ return /* @__PURE__ */ jsxs3("div", { className: fieldClasses.filter(Boolean).join(" "), "data-field-name": name, children: [
619
+ labelNode,
620
+ /* @__PURE__ */ jsx5("div", { className: "sg-field-control", children: renderControl() }),
621
+ helpNode,
622
+ extraNode
623
+ ] });
624
+ }
625
+
626
+ // src/components/complex/SubmitButton.tsx
627
+ import { jsx as jsx6 } from "react/jsx-runtime";
628
+ function SubmitButton({
629
+ children = "Submit",
630
+ disabled,
631
+ loading,
632
+ className,
633
+ style,
634
+ unstyled
635
+ }) {
636
+ return /* @__PURE__ */ jsx6(
637
+ Button,
638
+ {
639
+ type: "primary",
640
+ htmlType: "submit",
641
+ disabled,
642
+ loading,
643
+ className,
644
+ style,
645
+ unstyled,
646
+ children
647
+ }
648
+ );
649
+ }
650
+
651
+ // src/hooks/useWatch.ts
652
+ import { useEffect as useEffect3, useState as useState4 } from "react";
653
+ function useWatch(core, name) {
654
+ const [value, setValue] = useState4(() => core.get(name));
655
+ useEffect3(() => {
656
+ setValue(core.get(name));
657
+ return core.subscribe(name, (v) => {
658
+ setValue(v);
659
+ });
660
+ }, [core, name]);
661
+ return value;
662
+ }
663
+
664
+ // src/components/complex/FormList.tsx
665
+ import React6, { useState as useState5, useCallback as useCallback4, useMemo as useMemo3, useRef as useRef7 } from "react";
666
+ import { Fragment as Fragment2, jsx as jsx7 } from "react/jsx-runtime";
667
+ var listUid = 0;
668
+ function genKey() {
669
+ return `fl_${++listUid}`;
670
+ }
671
+ function FormList({ name, initialValue, draggable, children }) {
672
+ const { core, form } = useFormContext();
673
+ React6.useEffect(() => {
674
+ if (initialValue && !Array.isArray(core.get(name))) {
675
+ core.set(name, initialValue);
676
+ }
677
+ }, []);
678
+ const listValue = useWatch(core, name);
679
+ const items = Array.isArray(listValue) ? listValue : [];
680
+ const [keys, setKeys] = useState5(() => items.map(() => genKey()));
681
+ React6.useEffect(() => {
682
+ setKeys((prev) => {
683
+ if (prev.length === items.length) return prev;
684
+ if (items.length > prev.length) {
685
+ return [...prev, ...Array.from({ length: items.length - prev.length }, () => genKey())];
686
+ }
687
+ return prev.slice(0, items.length);
688
+ });
689
+ }, [items.length]);
690
+ const fields = useMemo3(
691
+ () => keys.slice(0, items.length).map((key, index) => ({ key, index })),
692
+ [keys, items.length]
693
+ );
694
+ const add = useCallback4(
695
+ (defaultValue, insertIndex) => {
696
+ form.listAdd(name, defaultValue, insertIndex);
697
+ setKeys((prev) => {
698
+ const k = genKey();
699
+ if (insertIndex !== void 0 && insertIndex >= 0 && insertIndex <= prev.length) {
700
+ const next = [...prev];
701
+ next.splice(insertIndex, 0, k);
702
+ return next;
703
+ }
704
+ return [...prev, k];
705
+ });
706
+ },
707
+ [form, name]
708
+ );
709
+ const remove = useCallback4(
710
+ (index) => {
711
+ form.listRemove(name, index);
712
+ setKeys((prev) => {
713
+ if (Array.isArray(index)) {
714
+ const indices = new Set(index);
715
+ return prev.filter((_, i) => !indices.has(i));
716
+ }
717
+ return prev.filter((_, i) => i !== index);
718
+ });
719
+ },
720
+ [form, name]
721
+ );
722
+ const move = useCallback4(
723
+ (from, to) => {
724
+ form.listMove(name, from, to);
725
+ setKeys((prev) => {
726
+ const next = [...prev];
727
+ const [item] = next.splice(from, 1);
728
+ next.splice(to, 0, item);
729
+ return next;
730
+ });
731
+ },
732
+ [form, name]
733
+ );
734
+ const replace = useCallback4(
735
+ (values) => {
736
+ form.listReplace(name, values);
737
+ setKeys(values.map(() => genKey()));
738
+ },
739
+ [form, name]
740
+ );
741
+ const operation = useMemo3(
742
+ () => ({ add, remove, move, replace }),
743
+ [add, remove, move, replace]
744
+ );
745
+ const meta = useMemo3(() => ({ errors: form.getFieldErrors(name) }), [form, name]);
746
+ const dragIdx = useRef7(-1);
747
+ const dragOverIdx = useRef7(-1);
748
+ if (!draggable) {
749
+ return /* @__PURE__ */ jsx7(Fragment2, { children: children(fields, operation, meta) });
750
+ }
751
+ const dragFields = fields.map((f) => ({
752
+ ...f,
753
+ dragProps: {
754
+ draggable: true,
755
+ onDragStart: () => {
756
+ dragIdx.current = f.index;
757
+ },
758
+ onDragOver: (e) => {
759
+ e.preventDefault();
760
+ dragOverIdx.current = f.index;
761
+ },
762
+ onDrop: () => {
763
+ if (dragIdx.current !== -1 && dragOverIdx.current !== -1 && dragIdx.current !== dragOverIdx.current) {
764
+ move(dragIdx.current, dragOverIdx.current);
765
+ }
766
+ dragIdx.current = -1;
767
+ dragOverIdx.current = -1;
768
+ },
769
+ onDragEnd: () => {
770
+ dragIdx.current = -1;
771
+ dragOverIdx.current = -1;
772
+ }
773
+ }
774
+ }));
775
+ return /* @__PURE__ */ jsx7(Fragment2, { children: children(dragFields, operation, meta) });
776
+ }
777
+
778
+ // src/hooks/useFieldArray.ts
779
+ import { useState as useState6, useCallback as useCallback5, useMemo as useMemo4, useRef as useRef8 } from "react";
780
+ function useFieldArray(form, name) {
781
+ const counterRef = useRef8(0);
782
+ const genKey2 = useCallback5(() => `fa_${name}_${++counterRef.current}`, [name]);
783
+ const [keys, setKeys] = useState6(() => {
784
+ const list = form.getListValue(name);
785
+ return list.map(() => genKey2());
786
+ });
787
+ const fields = useMemo4(
788
+ () => keys.map((key, index) => ({ key, index })),
789
+ [keys]
790
+ );
791
+ const append = useCallback5(
792
+ (defaultValue) => {
793
+ form.listAdd(name, defaultValue);
794
+ setKeys((prev) => [...prev, genKey2()]);
795
+ },
796
+ [form, name, genKey2]
797
+ );
798
+ const remove = useCallback5(
799
+ (index) => {
800
+ form.listRemove(name, index);
801
+ setKeys((prev) => prev.filter((_, i) => i !== index));
802
+ },
803
+ [form, name]
804
+ );
805
+ const move = useCallback5(
806
+ (from, to) => {
807
+ form.listMove(name, from, to);
808
+ setKeys((prev) => {
809
+ const next = [...prev];
810
+ const [item] = next.splice(from, 1);
811
+ next.splice(to, 0, item);
812
+ return next;
813
+ });
814
+ },
815
+ [form, name]
816
+ );
817
+ const replace = useCallback5(
818
+ (values) => {
819
+ const currentLen = form.getListValue(name).length;
820
+ for (let i = currentLen - 1; i >= 0; i--) {
821
+ form.listRemove(name, i);
822
+ }
823
+ const newKeys = [];
824
+ for (const v of values) {
825
+ form.listAdd(name, v);
826
+ newKeys.push(genKey2());
827
+ }
828
+ setKeys(newKeys);
829
+ },
830
+ [form, name, genKey2]
831
+ );
832
+ return useMemo4(
833
+ () => ({ fields, append, remove, move, replace }),
834
+ [fields, append, remove, move, replace]
835
+ );
836
+ }
837
+
838
+ // src/components/complex/AutoField/AutoField.tsx
839
+ import { useMemo as useMemo5 } from "react";
840
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
841
+ function AutoField(props) {
842
+ const {
843
+ name,
844
+ label,
845
+ type: forcedType,
846
+ options,
847
+ placeholder,
848
+ disabled: disabledProp,
849
+ className,
850
+ style,
851
+ min,
852
+ max,
853
+ step,
854
+ accept,
855
+ multiple
856
+ } = props;
857
+ const config = useConfig();
858
+ const disabled = disabledProp ?? config.disabled;
859
+ const { form } = useFormContext();
860
+ const value = form.getValue(name);
861
+ const meta = form.getFieldState(name);
862
+ const inferredType = useMemo5(() => {
863
+ if (forcedType) return forcedType;
864
+ if (options && options.length > 0) return "select";
865
+ if (typeof value === "boolean") return "boolean";
866
+ if (typeof value === "number") return "number";
867
+ if (typeof value === "string") {
868
+ if (value.includes("@")) return "email";
869
+ if (value.startsWith("http")) return "url";
870
+ }
871
+ return "string";
872
+ }, [forcedType, options, value]);
873
+ const handleChange = (newValue) => {
874
+ form.setValue(name, newValue);
875
+ };
876
+ const errorId = `${name}-error`;
877
+ const hasErrors = meta.errors.length > 0;
878
+ const hasWarnings = meta.warnings.length > 0;
879
+ const wrapperStyle = {
880
+ display: "flex",
881
+ flexDirection: "column",
882
+ gap: 4,
883
+ ...style
884
+ };
885
+ const inputStyle = {
886
+ padding: "6px 12px",
887
+ border: `1px solid ${hasErrors ? "var(--sg-error, #ff4d4f)" : hasWarnings ? "var(--sg-warning, #faad14)" : "var(--sg-border, #d9d9d9)"}`,
888
+ borderRadius: "var(--sg-radius, 6px)",
889
+ fontSize: 14,
890
+ outline: "none",
891
+ background: disabled ? "var(--sg-bg-disabled, #f5f5f5)" : "var(--sg-bg, #fff)"
892
+ };
893
+ function renderInput() {
894
+ switch (inferredType) {
895
+ case "boolean":
896
+ case "switch":
897
+ return /* @__PURE__ */ jsxs4("label", { style: { display: "flex", alignItems: "center", gap: 8, cursor: "pointer" }, children: [
898
+ /* @__PURE__ */ jsx8(
899
+ "input",
900
+ {
901
+ type: "checkbox",
902
+ checked: !!value,
903
+ onChange: (e) => handleChange(e.target.checked),
904
+ disabled,
905
+ role: inferredType === "switch" ? "switch" : void 0
906
+ }
907
+ ),
908
+ label
909
+ ] });
910
+ case "number":
911
+ return /* @__PURE__ */ jsx8(
912
+ "input",
913
+ {
914
+ type: "number",
915
+ value: value == null ? "" : String(value),
916
+ onChange: (e) => handleChange(e.target.value === "" ? null : Number(e.target.value)),
917
+ onBlur: () => form.onFieldBlur(name),
918
+ placeholder,
919
+ disabled,
920
+ min,
921
+ max,
922
+ step,
923
+ style: inputStyle,
924
+ "aria-invalid": hasErrors,
925
+ "aria-describedby": hasErrors ? errorId : void 0
926
+ }
927
+ );
928
+ case "textarea":
929
+ return /* @__PURE__ */ jsx8(
930
+ "textarea",
931
+ {
932
+ value: value == null ? "" : String(value),
933
+ onChange: (e) => handleChange(e.target.value),
934
+ onBlur: () => form.onFieldBlur(name),
935
+ placeholder,
936
+ disabled,
937
+ style: { ...inputStyle, minHeight: 80, resize: "vertical" },
938
+ "aria-invalid": hasErrors,
939
+ "aria-describedby": hasErrors ? errorId : void 0
940
+ }
941
+ );
942
+ case "select":
943
+ return /* @__PURE__ */ jsxs4(
944
+ "select",
945
+ {
946
+ value: value == null ? "" : String(value),
947
+ onChange: (e) => handleChange(e.target.value),
948
+ disabled,
949
+ style: inputStyle,
950
+ "aria-invalid": hasErrors,
951
+ "aria-describedby": hasErrors ? errorId : void 0,
952
+ children: [
953
+ /* @__PURE__ */ jsx8("option", { value: "", children: placeholder ?? "-- Select --" }),
954
+ options?.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
955
+ ]
956
+ }
957
+ );
958
+ case "multiselect":
959
+ return /* @__PURE__ */ jsx8(
960
+ "select",
961
+ {
962
+ multiple: true,
963
+ value: Array.isArray(value) ? value.map(String) : [],
964
+ onChange: (e) => {
965
+ const selected = Array.from(e.target.selectedOptions, (o) => o.value);
966
+ handleChange(selected);
967
+ },
968
+ disabled,
969
+ style: { ...inputStyle, minHeight: 80 },
970
+ "aria-invalid": hasErrors,
971
+ "aria-describedby": hasErrors ? errorId : void 0,
972
+ children: options?.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
973
+ }
974
+ );
975
+ case "radio":
976
+ return /* @__PURE__ */ jsx8("div", { role: "radiogroup", style: { display: "flex", gap: 12, flexWrap: "wrap" }, children: options?.map((opt) => /* @__PURE__ */ jsxs4("label", { style: { display: "flex", alignItems: "center", gap: 4, cursor: "pointer" }, children: [
977
+ /* @__PURE__ */ jsx8(
978
+ "input",
979
+ {
980
+ type: "radio",
981
+ name,
982
+ value: opt.value,
983
+ checked: value === opt.value,
984
+ onChange: () => handleChange(opt.value),
985
+ disabled
986
+ }
987
+ ),
988
+ opt.label
989
+ ] }, opt.value)) });
990
+ case "date":
991
+ return /* @__PURE__ */ jsx8(
992
+ "input",
993
+ {
994
+ type: "date",
995
+ value: value == null ? "" : String(value),
996
+ onChange: (e) => handleChange(e.target.value),
997
+ disabled,
998
+ style: inputStyle,
999
+ "aria-invalid": hasErrors,
1000
+ "aria-describedby": hasErrors ? errorId : void 0
1001
+ }
1002
+ );
1003
+ case "time":
1004
+ return /* @__PURE__ */ jsx8(
1005
+ "input",
1006
+ {
1007
+ type: "time",
1008
+ value: value == null ? "" : String(value),
1009
+ onChange: (e) => handleChange(e.target.value),
1010
+ disabled,
1011
+ style: inputStyle,
1012
+ "aria-invalid": hasErrors,
1013
+ "aria-describedby": hasErrors ? errorId : void 0
1014
+ }
1015
+ );
1016
+ case "password":
1017
+ return /* @__PURE__ */ jsx8(
1018
+ "input",
1019
+ {
1020
+ type: "password",
1021
+ value: value == null ? "" : String(value),
1022
+ onChange: (e) => handleChange(e.target.value),
1023
+ onBlur: () => form.onFieldBlur(name),
1024
+ placeholder,
1025
+ disabled,
1026
+ style: inputStyle,
1027
+ "aria-invalid": hasErrors,
1028
+ "aria-describedby": hasErrors ? errorId : void 0
1029
+ }
1030
+ );
1031
+ case "color":
1032
+ return /* @__PURE__ */ jsx8(
1033
+ "input",
1034
+ {
1035
+ type: "color",
1036
+ value: value == null ? "#000000" : String(value),
1037
+ onChange: (e) => handleChange(e.target.value),
1038
+ disabled,
1039
+ style: { ...inputStyle, padding: 2, width: 48, height: 32 }
1040
+ }
1041
+ );
1042
+ case "slider":
1043
+ return /* @__PURE__ */ jsxs4("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1044
+ /* @__PURE__ */ jsx8(
1045
+ "input",
1046
+ {
1047
+ type: "range",
1048
+ value: value == null ? min ?? 0 : Number(value),
1049
+ onChange: (e) => handleChange(Number(e.target.value)),
1050
+ min: min ?? 0,
1051
+ max: max ?? 100,
1052
+ step: step ?? 1,
1053
+ disabled,
1054
+ style: { flex: 1 }
1055
+ }
1056
+ ),
1057
+ /* @__PURE__ */ jsx8("span", { style: { minWidth: 32, textAlign: "right", fontSize: 14 }, children: String(value ?? min ?? 0) })
1058
+ ] });
1059
+ case "rate": {
1060
+ const maxStars = max ?? 5;
1061
+ const currentRate = typeof value === "number" ? value : 0;
1062
+ return /* @__PURE__ */ jsx8("div", { style: { display: "flex", gap: 2 }, children: Array.from({ length: maxStars }, (_, i) => /* @__PURE__ */ jsx8(
1063
+ "button",
1064
+ {
1065
+ type: "button",
1066
+ onClick: () => !disabled && handleChange(i + 1),
1067
+ disabled,
1068
+ style: {
1069
+ background: "none",
1070
+ border: "none",
1071
+ cursor: disabled ? "default" : "pointer",
1072
+ fontSize: 20,
1073
+ color: i < currentRate ? "var(--sg-warning, #faad14)" : "var(--sg-border, #d9d9d9)",
1074
+ padding: 0
1075
+ },
1076
+ "aria-label": `${i + 1} star${i !== 0 ? "s" : ""}`,
1077
+ children: "\u2605"
1078
+ },
1079
+ i
1080
+ )) });
1081
+ }
1082
+ case "file":
1083
+ return /* @__PURE__ */ jsx8(
1084
+ "input",
1085
+ {
1086
+ type: "file",
1087
+ accept,
1088
+ multiple,
1089
+ onChange: (e) => {
1090
+ const files = e.target.files;
1091
+ if (files) handleChange(multiple ? Array.from(files) : files[0] ?? null);
1092
+ },
1093
+ disabled,
1094
+ style: inputStyle
1095
+ }
1096
+ );
1097
+ case "email":
1098
+ case "url":
1099
+ case "string":
1100
+ default:
1101
+ return /* @__PURE__ */ jsx8(
1102
+ "input",
1103
+ {
1104
+ type: inferredType === "email" ? "email" : inferredType === "url" ? "url" : "text",
1105
+ value: value == null ? "" : String(value),
1106
+ onChange: (e) => handleChange(e.target.value),
1107
+ onBlur: () => form.onFieldBlur(name),
1108
+ placeholder,
1109
+ disabled,
1110
+ style: inputStyle,
1111
+ "aria-invalid": hasErrors,
1112
+ "aria-describedby": hasErrors ? errorId : void 0
1113
+ }
1114
+ );
1115
+ }
1116
+ }
1117
+ return /* @__PURE__ */ jsxs4("div", { className: `sg-autofield ${className ?? ""}`, style: wrapperStyle, children: [
1118
+ inferredType !== "boolean" && inferredType !== "switch" && label && /* @__PURE__ */ jsx8("label", { style: { fontWeight: 500, fontSize: 14 }, children: label }),
1119
+ renderInput(),
1120
+ hasErrors && /* @__PURE__ */ jsx8("span", { id: errorId, role: "alert", style: { color: "var(--sg-error, #ff4d4f)", fontSize: 12 }, children: meta.errors.join("; ") }),
1121
+ hasWarnings && !hasErrors && /* @__PURE__ */ jsx8("span", { style: { color: "var(--sg-warning, #faad14)", fontSize: 12 }, children: meta.warnings.join("; ") })
1122
+ ] });
1123
+ }
1124
+
1125
+ // src/adapters/zodAdapter.ts
1126
+ function zodRule(schema, options) {
1127
+ const rule = (value) => {
1128
+ const result = schema.safeParse(value);
1129
+ if (result.success) return null;
1130
+ const issues = result.error?.issues ?? [];
1131
+ if (issues.length === 0) return options?.message ?? "Validation failed";
1132
+ if (options?.pick === "all") {
1133
+ return issues.map((i) => i.message).join("; ");
1134
+ }
1135
+ return options?.message ?? issues[0].message;
1136
+ };
1137
+ return rule;
1138
+ }
1139
+ function zodRules(schema, options) {
1140
+ const result = {};
1141
+ for (const [key, fieldSchema] of Object.entries(schema.shape)) {
1142
+ result[key] = [zodRule(fieldSchema, options)];
1143
+ }
1144
+ return result;
1145
+ }
1146
+ function zodDefaults(schema) {
1147
+ const defaults = {};
1148
+ for (const [key, fieldSchema] of Object.entries(schema.shape)) {
1149
+ try {
1150
+ const result = fieldSchema.safeParse(void 0);
1151
+ if (result.success && result.data !== void 0) {
1152
+ defaults[key] = result.data;
1153
+ }
1154
+ } catch {
1155
+ }
1156
+ }
1157
+ return defaults;
1158
+ }
1159
+ function zodToJsonSchema(schema) {
1160
+ const properties = {};
1161
+ const required = [];
1162
+ const shape = schema.shape ?? schema.shape;
1163
+ if (!shape) return { properties, required };
1164
+ for (const [key, field] of Object.entries(shape)) {
1165
+ const prop = { title: key };
1166
+ let def = field._def;
1167
+ if (def.typeName === "ZodOptional" || def.typeName === "ZodNullable") {
1168
+ def = def.innerType?._def ?? def;
1169
+ } else {
1170
+ required.push(key);
1171
+ }
1172
+ if (def.typeName === "ZodDefault") {
1173
+ prop.default = def.defaultValue?.();
1174
+ def = def.innerType?._def ?? def;
1175
+ }
1176
+ switch (def.typeName) {
1177
+ case "ZodString":
1178
+ prop.type = "string";
1179
+ for (const check of def.checks ?? []) {
1180
+ if (check.kind === "min") prop.minLength = check.value;
1181
+ if (check.kind === "max") prop.maxLength = check.value;
1182
+ if (check.kind === "email") prop.format = "email";
1183
+ if (check.kind === "url") prop.format = "url";
1184
+ if (check.kind === "regex" && check.regex) prop.pattern = check.regex.source;
1185
+ }
1186
+ break;
1187
+ case "ZodNumber":
1188
+ prop.type = "number";
1189
+ for (const check of def.checks ?? []) {
1190
+ if (check.kind === "min") prop.minimum = check.value;
1191
+ if (check.kind === "max") prop.maximum = check.value;
1192
+ }
1193
+ break;
1194
+ case "ZodBoolean":
1195
+ prop.type = "boolean";
1196
+ break;
1197
+ case "ZodEnum":
1198
+ prop.type = "string";
1199
+ prop.enum = def.values ?? [];
1200
+ break;
1201
+ case "ZodDate":
1202
+ prop.type = "string";
1203
+ prop.format = "date";
1204
+ break;
1205
+ default:
1206
+ prop.type = "string";
1207
+ }
1208
+ if (field.description) prop.description = field.description;
1209
+ properties[key] = prop;
1210
+ }
1211
+ return { properties, required };
1212
+ }
1213
+
1214
+ // src/adapters/jsonSchemaAdapter.ts
1215
+ function jsonTypeToFieldType(schema) {
1216
+ if (schema.enum || schema.oneOf) return "select";
1217
+ if (schema.format === "email") return "email";
1218
+ if (schema.format === "uri" || schema.format === "url") return "url";
1219
+ if (schema.format === "date") return "date";
1220
+ if (schema.format === "time") return "time";
1221
+ if (schema.format === "password") return "password";
1222
+ if (schema.format === "color") return "color";
1223
+ switch (schema.type) {
1224
+ case "number":
1225
+ case "integer":
1226
+ return "number";
1227
+ case "boolean":
1228
+ return "boolean";
1229
+ case "array":
1230
+ return "multiselect";
1231
+ default:
1232
+ if (schema.maxLength && schema.maxLength > 200) return "textarea";
1233
+ return "string";
1234
+ }
1235
+ }
1236
+ function buildOptions(schema) {
1237
+ if (schema.oneOf) {
1238
+ return schema.oneOf.map((item) => ({
1239
+ value: item.const,
1240
+ label: item.title ?? String(item.const)
1241
+ }));
1242
+ }
1243
+ if (schema.enum) {
1244
+ return schema.enum.map((val, i) => ({
1245
+ value: val,
1246
+ label: schema.enumNames?.[i] ?? String(val)
1247
+ }));
1248
+ }
1249
+ return void 0;
1250
+ }
1251
+ function jsonSchemaToFields(schema) {
1252
+ const result = [];
1253
+ const props = schema.properties ?? {};
1254
+ for (const [name, prop] of Object.entries(props)) {
1255
+ result.push({
1256
+ name,
1257
+ label: prop.title ?? name,
1258
+ type: jsonTypeToFieldType(prop),
1259
+ placeholder: prop.description,
1260
+ options: buildOptions(prop),
1261
+ min: prop.minimum,
1262
+ max: prop.maximum
1263
+ });
1264
+ }
1265
+ return result;
1266
+ }
1267
+ function jsonSchemaToRules(schema) {
1268
+ const result = {};
1269
+ const props = schema.properties ?? {};
1270
+ const requiredFields = new Set(schema.required ?? []);
1271
+ for (const [name, prop] of Object.entries(props)) {
1272
+ const rules = [];
1273
+ if (requiredFields.has(name)) {
1274
+ rules.push({ required: true, message: `${prop.title ?? name} is required` });
1275
+ }
1276
+ if (prop.type === "string") {
1277
+ if (prop.minLength !== void 0) {
1278
+ rules.push({ min: prop.minLength, message: `Minimum ${prop.minLength} characters` });
1279
+ }
1280
+ if (prop.maxLength !== void 0) {
1281
+ rules.push({ max: prop.maxLength, message: `Maximum ${prop.maxLength} characters` });
1282
+ }
1283
+ if (prop.pattern) {
1284
+ rules.push({ pattern: new RegExp(prop.pattern), message: `Invalid format` });
1285
+ }
1286
+ }
1287
+ if (prop.type === "number" || prop.type === "integer") {
1288
+ if (prop.minimum !== void 0) {
1289
+ rules.push({ min: prop.minimum, type: "number" });
1290
+ }
1291
+ if (prop.maximum !== void 0) {
1292
+ rules.push({ max: prop.maximum, type: "number" });
1293
+ }
1294
+ }
1295
+ if (prop.format === "email") {
1296
+ rules.push({ type: "email" });
1297
+ }
1298
+ if (prop.format === "uri" || prop.format === "url") {
1299
+ rules.push({ type: "url" });
1300
+ }
1301
+ if (rules.length > 0) {
1302
+ result[name] = rules;
1303
+ }
1304
+ }
1305
+ return result;
1306
+ }
1307
+ function jsonSchemaToDefaults(schema) {
1308
+ const result = {};
1309
+ const props = schema.properties ?? {};
1310
+ for (const [name, prop] of Object.entries(props)) {
1311
+ if (prop.default !== void 0) {
1312
+ result[name] = prop.default;
1313
+ }
1314
+ }
1315
+ return result;
1316
+ }
1317
+
1318
+ // src/components/complex/SchemaForm.tsx
1319
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1320
+ function isZodSchema(schema) {
1321
+ return typeof schema === "object" && schema !== null && "_def" in schema;
1322
+ }
1323
+ function SchemaForm({
1324
+ schema: rawSchema,
1325
+ onSubmit,
1326
+ layout,
1327
+ size,
1328
+ disabled,
1329
+ form: externalForm,
1330
+ labelCol,
1331
+ wrapperCol,
1332
+ className,
1333
+ style,
1334
+ submitText: submitTextProp,
1335
+ children
1336
+ }) {
1337
+ const config = useConfig();
1338
+ const submitText = submitTextProp ?? config.locale?.form?.submitText ?? "Submit";
1339
+ const jsonSchema = isZodSchema(rawSchema) ? zodToJsonSchema(rawSchema) : rawSchema;
1340
+ const fields = jsonSchemaToFields(jsonSchema);
1341
+ const rulesMap = jsonSchemaToRules(jsonSchema);
1342
+ const defaults = jsonSchemaToDefaults(jsonSchema);
1343
+ const internalForm = useForm({
1344
+ defaultValues: defaults,
1345
+ onSubmit
1346
+ });
1347
+ const formInstance = externalForm ?? internalForm;
1348
+ return /* @__PURE__ */ jsxs5(
1349
+ Form,
1350
+ {
1351
+ form: formInstance,
1352
+ layout,
1353
+ size,
1354
+ disabled,
1355
+ labelCol,
1356
+ wrapperCol,
1357
+ className,
1358
+ style,
1359
+ children: [
1360
+ fields.map((fieldConfig) => /* @__PURE__ */ jsx9(
1361
+ Field,
1362
+ {
1363
+ name: fieldConfig.name,
1364
+ label: typeof fieldConfig.label === "string" ? fieldConfig.label : void 0,
1365
+ rules: rulesMap[fieldConfig.name],
1366
+ children: (field) => /* @__PURE__ */ jsx9(
1367
+ AutoField,
1368
+ {
1369
+ name: fieldConfig.name,
1370
+ type: fieldConfig.type,
1371
+ options: fieldConfig.options,
1372
+ placeholder: fieldConfig.placeholder,
1373
+ min: fieldConfig.min,
1374
+ max: fieldConfig.max,
1375
+ disabled: disabled ?? field.validating
1376
+ }
1377
+ )
1378
+ },
1379
+ fieldConfig.name
1380
+ )),
1381
+ children ?? /* @__PURE__ */ jsx9("button", { type: "submit", className: "sg-button sg-button-primary", children: submitText })
1382
+ ]
1383
+ }
1384
+ );
1385
+ }
1386
+
1387
+ export {
1388
+ useField,
1389
+ useForm,
1390
+ FormContext,
1391
+ useFormContext,
1392
+ FormProvider,
1393
+ useFormProvider,
1394
+ Form,
1395
+ Textarea,
1396
+ Tooltip,
1397
+ Field,
1398
+ SubmitButton,
1399
+ useWatch,
1400
+ FormList,
1401
+ useFieldArray,
1402
+ AutoField,
1403
+ zodRule,
1404
+ zodRules,
1405
+ zodDefaults,
1406
+ zodToJsonSchema,
1407
+ jsonSchemaToFields,
1408
+ jsonSchemaToRules,
1409
+ jsonSchemaToDefaults,
1410
+ SchemaForm
1411
+ };
1412
+ //# sourceMappingURL=chunk-MLEBVELO.js.map