@pixpilot/formily-shadcn 1.4.5 → 1.6.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 (45) hide show
  1. package/dist/components/Form.d.ts +2 -2
  2. package/dist/components/FormGrid.d.ts +2 -2
  3. package/dist/components/IconPicker.d.ts +3 -3
  4. package/dist/components/IconToggle.d.cts +2 -2
  5. package/dist/components/IconToggle.d.ts +3 -3
  6. package/dist/components/Input.d.cts +3 -3
  7. package/dist/components/Input.d.ts +3 -3
  8. package/dist/components/Radio.d.ts +2 -2
  9. package/dist/components/Rating.d.ts +4 -4
  10. package/dist/components/Row.d.ts +2 -2
  11. package/dist/components/Separator.d.cts +2 -2
  12. package/dist/components/Separator.d.ts +2 -2
  13. package/dist/components/Switch.d.cts +2 -2
  14. package/dist/components/Switch.d.ts +2 -2
  15. package/dist/components/TagsInputInline.d.cts +3 -3
  16. package/dist/components/TagsInputInline.d.ts +3 -3
  17. package/dist/components/Textarea.d.cts +2 -2
  18. package/dist/components/Textarea.d.ts +2 -2
  19. package/dist/components/ToggleButton.d.cts +3 -3
  20. package/dist/components/ToggleButton.d.ts +3 -3
  21. package/dist/components/array-common/ArrayItemDraftFields.cjs +37 -25
  22. package/dist/components/array-common/ArrayItemDraftFields.js +37 -25
  23. package/dist/components/array-common/ArrayItemsList.cjs +3 -2
  24. package/dist/components/array-common/ArrayItemsList.js +3 -2
  25. package/dist/components/array-common/ItemWrapper.cjs +1 -0
  26. package/dist/components/array-common/ItemWrapper.js +1 -0
  27. package/dist/components/array-common/ListItem.cjs +21 -4
  28. package/dist/components/array-common/ListItem.js +23 -6
  29. package/dist/components/array-common/use-array-item-draft-form.cjs +31 -15
  30. package/dist/components/array-common/use-array-item-draft-form.js +31 -15
  31. package/dist/components/array-common/use-array-item-edit-state.cjs +5 -14
  32. package/dist/components/array-common/use-array-item-edit-state.js +5 -13
  33. package/dist/components/array-dialog/ArrayDialog.cjs +8 -4
  34. package/dist/components/array-dialog/ArrayDialog.js +8 -4
  35. package/dist/components/array-dialog/EditDialog.cjs +67 -9
  36. package/dist/components/array-dialog/EditDialog.js +67 -9
  37. package/dist/components/array-popover/ArrayPopover.cjs +34 -17
  38. package/dist/components/array-popover/ArrayPopover.js +35 -18
  39. package/dist/components/array-popover/Popover.cjs +100 -88
  40. package/dist/components/array-popover/Popover.js +100 -88
  41. package/dist/components/context/types.d.cts +7 -2
  42. package/dist/components/context/types.d.ts +7 -2
  43. package/dist/components/slider/Slider.d.ts +3 -3
  44. package/dist/components/slider/SliderInput.d.ts +3 -3
  45. package/package.json +4 -4
@@ -7,15 +7,15 @@ import { getHiddenItemSchema } from "./get-hidden-item-schema.js";
7
7
  import { ItemWrapper } from "./ItemWrapper.js";
8
8
  import { RecursionField, useFieldSchema } from "@formily/react";
9
9
  import React from "react";
10
- import { jsx, jsxs } from "react/jsx-runtime";
11
- import { cn } from "@pixpilot/shadcn";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ import { PopoverAnchor, cn } from "@pixpilot/shadcn";
12
12
 
13
13
  //#region src/components/array-common/ListItem.tsx
14
14
  /**
15
15
  * Individual list item component for array items
16
16
  * Displays an item with label and operation controls
17
17
  */
18
- const ListItem = React.memo(({ itemKey, index, record, isNew }) => {
18
+ const ListItem = React.memo(({ itemKey, index, record, isNew, isAnchor }) => {
19
19
  const schema = useFieldSchema();
20
20
  const hiddenItemSchema = React.useMemo(() => {
21
21
  return getHiddenItemSchema(schema.items);
@@ -24,9 +24,26 @@ const ListItem = React.memo(({ itemKey, index, record, isNew }) => {
24
24
  return /* @__PURE__ */ jsx(ArrayBase.Item, {
25
25
  index,
26
26
  record,
27
- children: /* @__PURE__ */ jsxs(SortableItem, {
27
+ children: /* @__PURE__ */ jsx(SortableItem, {
28
28
  id: itemKey,
29
- children: [hiddenItemSchema ? /* @__PURE__ */ jsx("div", {
29
+ children: isAnchor ? /* @__PURE__ */ jsx(PopoverAnchor, {
30
+ asChild: true,
31
+ children: /* @__PURE__ */ jsxs("div", { children: [hiddenItemSchema ? /* @__PURE__ */ jsx("div", {
32
+ style: { display: "none" },
33
+ children: /* @__PURE__ */ jsx(RecursionField, {
34
+ schema: hiddenItemSchema,
35
+ name: index
36
+ })
37
+ }) : null, /* @__PURE__ */ jsx(ItemWrapper, {
38
+ className: cn("px-3 pl-4 py-2", isNewItem && "hidden"),
39
+ index,
40
+ children: /* @__PURE__ */ jsx(ArrayItemHeaderRow, {
41
+ schema,
42
+ index,
43
+ slots: { content: { content: "text-foreground font-medium" } }
44
+ })
45
+ })] })
46
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [hiddenItemSchema ? /* @__PURE__ */ jsx("div", {
30
47
  style: { display: "none" },
31
48
  children: /* @__PURE__ */ jsx(RecursionField, {
32
49
  schema: hiddenItemSchema,
@@ -40,7 +57,7 @@ const ListItem = React.memo(({ itemKey, index, record, isNew }) => {
40
57
  index,
41
58
  slots: { content: { content: "text-foreground font-medium" } }
42
59
  })
43
- })]
60
+ })] })
44
61
  })
45
62
  }, itemKey);
46
63
  });
@@ -11,29 +11,45 @@ function useArrayItemDraftForm({ arrayField, index, autoSave, onDraftChange, ini
11
11
  onDraftChangeRef.current = onDraftChange;
12
12
  }, [onDraftChange]);
13
13
  return react.default.useMemo(() => {
14
+ if (autoSave) {
15
+ const basePath = index ?? "draft";
16
+ const validationPath = index != null ? `${arrayField.address.toString()}.${index}.*` : void 0;
17
+ return {
18
+ form: arrayField.form,
19
+ basePath,
20
+ validationPath,
21
+ isolatedForm: false
22
+ };
23
+ }
14
24
  const arrayValue = arrayField.value;
15
25
  const hasArray = Array.isArray(arrayValue);
16
26
  const arrayLength = hasArray ? arrayValue.length : 0;
17
27
  const currentItemValue = index != null && hasArray && index >= 0 && index < arrayLength ? arrayValue[index] : initialDraftValue;
18
28
  let didSkipInitial = false;
19
- return (0, __formily_core.createForm)({
20
- values: { draft: currentItemValue },
21
- effects: () => {
22
- if (!autoSave || onDraftChange == null) return;
23
- (0, __formily_core.onFormValuesChange)((form) => {
24
- if (!didSkipInitial) {
25
- didSkipInitial = true;
26
- return;
27
- }
28
- onDraftChangeRef.current?.(form.values.draft);
29
- });
30
- }
31
- });
29
+ return {
30
+ form: (0, __formily_core.createForm)({
31
+ values: { draft: currentItemValue },
32
+ effects: () => {
33
+ if (onDraftChangeRef.current == null) return;
34
+ (0, __formily_core.onFormValuesChange)((form) => {
35
+ if (!didSkipInitial) {
36
+ didSkipInitial = true;
37
+ return;
38
+ }
39
+ onDraftChangeRef.current?.(form.values.draft);
40
+ });
41
+ }
42
+ }),
43
+ basePath: "draft",
44
+ validationPath: void 0,
45
+ isolatedForm: true
46
+ };
32
47
  }, [
48
+ autoSave,
49
+ arrayField.form,
50
+ arrayField.address,
33
51
  arrayField.value,
34
52
  index,
35
- autoSave,
36
- onDraftChange,
37
53
  initialDraftValue
38
54
  ]);
39
55
  }
@@ -8,29 +8,45 @@ function useArrayItemDraftForm({ arrayField, index, autoSave, onDraftChange, ini
8
8
  onDraftChangeRef.current = onDraftChange;
9
9
  }, [onDraftChange]);
10
10
  return React.useMemo(() => {
11
+ if (autoSave) {
12
+ const basePath = index ?? "draft";
13
+ const validationPath = index != null ? `${arrayField.address.toString()}.${index}.*` : void 0;
14
+ return {
15
+ form: arrayField.form,
16
+ basePath,
17
+ validationPath,
18
+ isolatedForm: false
19
+ };
20
+ }
11
21
  const arrayValue = arrayField.value;
12
22
  const hasArray = Array.isArray(arrayValue);
13
23
  const arrayLength = hasArray ? arrayValue.length : 0;
14
24
  const currentItemValue = index != null && hasArray && index >= 0 && index < arrayLength ? arrayValue[index] : initialDraftValue;
15
25
  let didSkipInitial = false;
16
- return createForm({
17
- values: { draft: currentItemValue },
18
- effects: () => {
19
- if (!autoSave || onDraftChange == null) return;
20
- onFormValuesChange((form) => {
21
- if (!didSkipInitial) {
22
- didSkipInitial = true;
23
- return;
24
- }
25
- onDraftChangeRef.current?.(form.values.draft);
26
- });
27
- }
28
- });
26
+ return {
27
+ form: createForm({
28
+ values: { draft: currentItemValue },
29
+ effects: () => {
30
+ if (onDraftChangeRef.current == null) return;
31
+ onFormValuesChange((form) => {
32
+ if (!didSkipInitial) {
33
+ didSkipInitial = true;
34
+ return;
35
+ }
36
+ onDraftChangeRef.current?.(form.values.draft);
37
+ });
38
+ }
39
+ }),
40
+ basePath: "draft",
41
+ validationPath: void 0,
42
+ isolatedForm: true
43
+ };
29
44
  }, [
45
+ autoSave,
46
+ arrayField.form,
47
+ arrayField.address,
30
48
  arrayField.value,
31
49
  index,
32
- autoSave,
33
- onDraftChange,
34
50
  initialDraftValue
35
51
  ]);
36
52
  }
@@ -5,30 +5,18 @@ const require_use_edit_handlers = require('./use-edit-handlers.cjs');
5
5
  const require_use_shake_animation = require('./use-shake-animation.cjs');
6
6
  let __formily_react = require("@formily/react");
7
7
  __formily_react = require_rolldown_runtime.__toESM(__formily_react);
8
- let react = require("react");
9
- react = require_rolldown_runtime.__toESM(react);
10
8
 
11
9
  //#region src/components/array-common/use-array-item-edit-state.ts
12
- function useArrayItemEditState({ schema, activeItemManager, onSave, onCancel, onAutoSave, autoSave }) {
10
+ function useArrayItemEditState({ schema, activeItemManager, onSave, onCancel, autoSave }) {
13
11
  const arrayField = (0, __formily_react.useField)();
14
12
  const activeIndex = activeItemManager.activeItem;
15
13
  const isNewItem = activeItemManager.isNew;
16
14
  const open = activeIndex !== void 0;
17
15
  const normalizedAutoSave = autoSave === true || autoSave === "true";
18
- const handleDraftChange = react.default.useCallback((nextValue) => {
19
- if (!normalizedAutoSave) return;
20
- if (activeIndex === void 0) return;
21
- onAutoSave?.(activeIndex, nextValue);
22
- }, [
23
- activeIndex,
24
- normalizedAutoSave,
25
- onAutoSave
26
- ]);
27
- const draftForm = require_use_array_item_draft_form.useArrayItemDraftForm({
16
+ const { form: draftForm, basePath, validationPath, isolatedForm } = require_use_array_item_draft_form.useArrayItemDraftForm({
28
17
  arrayField,
29
18
  index: activeIndex,
30
19
  autoSave: normalizedAutoSave,
31
- onDraftChange: normalizedAutoSave ? handleDraftChange : void 0,
32
20
  initialDraftValue: activeItemManager.draftInitialValue
33
21
  });
34
22
  const isDirty = !normalizedAutoSave && draftForm.modified;
@@ -52,6 +40,9 @@ function useArrayItemEditState({ schema, activeItemManager, onSave, onCancel, on
52
40
  open,
53
41
  normalizedAutoSave,
54
42
  draftForm,
43
+ basePath,
44
+ validationPath,
45
+ isolatedForm,
55
46
  isDirty,
56
47
  title,
57
48
  description,
@@ -3,29 +3,18 @@ import { useArrayItemEditLabels } from "./use-array-item-edit-labels.js";
3
3
  import { useEditHandlers } from "./use-edit-handlers.js";
4
4
  import { useShakeAnimation } from "./use-shake-animation.js";
5
5
  import { useField } from "@formily/react";
6
- import React from "react";
7
6
 
8
7
  //#region src/components/array-common/use-array-item-edit-state.ts
9
- function useArrayItemEditState({ schema, activeItemManager, onSave, onCancel, onAutoSave, autoSave }) {
8
+ function useArrayItemEditState({ schema, activeItemManager, onSave, onCancel, autoSave }) {
10
9
  const arrayField = useField();
11
10
  const activeIndex = activeItemManager.activeItem;
12
11
  const isNewItem = activeItemManager.isNew;
13
12
  const open = activeIndex !== void 0;
14
13
  const normalizedAutoSave = autoSave === true || autoSave === "true";
15
- const handleDraftChange = React.useCallback((nextValue) => {
16
- if (!normalizedAutoSave) return;
17
- if (activeIndex === void 0) return;
18
- onAutoSave?.(activeIndex, nextValue);
19
- }, [
20
- activeIndex,
21
- normalizedAutoSave,
22
- onAutoSave
23
- ]);
24
- const draftForm = useArrayItemDraftForm({
14
+ const { form: draftForm, basePath, validationPath, isolatedForm } = useArrayItemDraftForm({
25
15
  arrayField,
26
16
  index: activeIndex,
27
17
  autoSave: normalizedAutoSave,
28
- onDraftChange: normalizedAutoSave ? handleDraftChange : void 0,
29
18
  initialDraftValue: activeItemManager.draftInitialValue
30
19
  });
31
20
  const isDirty = !normalizedAutoSave && draftForm.modified;
@@ -49,6 +38,9 @@ function useArrayItemEditState({ schema, activeItemManager, onSave, onCancel, on
49
38
  open,
50
39
  normalizedAutoSave,
51
40
  draftForm,
41
+ basePath,
42
+ validationPath,
43
+ isolatedForm,
52
44
  isDirty,
53
45
  title,
54
46
  description,
@@ -1,4 +1,6 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_use_form_context = require('../../hooks/use-form-context.cjs');
3
+ require('../../hooks/index.cjs');
2
4
  const require_array_base = require('../array-base/array-base.cjs');
3
5
  const require_component_context = require('../array-base/component-context.cjs');
4
6
  require('../array-base/index.cjs');
@@ -25,7 +27,9 @@ react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
25
27
  const ArrayDialogBase = (0, __formily_react.observer)((props) => {
26
28
  const schema = (0, __formily_react.useFieldSchema)();
27
29
  const { onAdd, onRemove, onMoveDown, onMoveUp, onEdit, className, transformActions, dialogProps } = props;
28
- const { autoSave } = props;
30
+ const { settings = {} } = require_use_form_context.useFormContext();
31
+ const { autoSave: globalAutoSave } = settings.dialog || {};
32
+ const autoSave = props.autoSave ?? globalAutoSave ?? false;
29
33
  const { activeItemManager, handleAdd, handleEdit, isNewItem, handleSaveClick, handleLiveChange, handleCancelClick } = require_use_array_editor.useArrayEditor({
30
34
  onAdd,
31
35
  onEdit,
@@ -35,7 +39,7 @@ const ArrayDialogBase = (0, __formily_react.observer)((props) => {
35
39
  const items = require_use_array_item_schema.useArrayItemSchema();
36
40
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_array_base.ArrayBase, {
37
41
  ...props,
38
- autoSave: autoSave ?? false,
42
+ autoSave,
39
43
  transformActions,
40
44
  onAdd: handleAdd,
41
45
  onRemove,
@@ -57,10 +61,10 @@ const ArrayDialogBase = (0, __formily_react.observer)((props) => {
57
61
  })]
58
62
  });
59
63
  });
60
- const ArrayItemsCollapseComponent = (rest) => {
64
+ const ArrayItemsComponent = (rest) => {
61
65
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_component_context.ArrayComponentProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArrayDialogBase, { ...rest }) });
62
66
  };
63
- const ArrayDialog = ArrayItemsCollapseComponent;
67
+ const ArrayDialog = ArrayItemsComponent;
64
68
  ArrayDialog.displayName = "ArrayDialog";
65
69
  require_array_base.ArrayBase.mixin(ArrayDialog);
66
70
 
@@ -1,3 +1,5 @@
1
+ import { useFormContext } from "../../hooks/use-form-context.js";
2
+ import "../../hooks/index.js";
1
3
  import { ArrayBase } from "../array-base/array-base.js";
2
4
  import { ArrayComponentProvider, useArrayComponents } from "../array-base/component-context.js";
3
5
  import "../array-base/index.js";
@@ -21,7 +23,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
21
23
  const ArrayDialogBase = observer((props) => {
22
24
  const schema = useFieldSchema();
23
25
  const { onAdd, onRemove, onMoveDown, onMoveUp, onEdit, className, transformActions, dialogProps } = props;
24
- const { autoSave } = props;
26
+ const { settings = {} } = useFormContext();
27
+ const { autoSave: globalAutoSave } = settings.dialog || {};
28
+ const autoSave = props.autoSave ?? globalAutoSave ?? false;
25
29
  const { activeItemManager, handleAdd, handleEdit, isNewItem, handleSaveClick, handleLiveChange, handleCancelClick } = useArrayEditor({
26
30
  onAdd,
27
31
  onEdit,
@@ -31,7 +35,7 @@ const ArrayDialogBase = observer((props) => {
31
35
  const items = useArrayItemSchema();
32
36
  return /* @__PURE__ */ jsxs(ArrayBase, {
33
37
  ...props,
34
- autoSave: autoSave ?? false,
38
+ autoSave,
35
39
  transformActions,
36
40
  onAdd: handleAdd,
37
41
  onRemove,
@@ -53,10 +57,10 @@ const ArrayDialogBase = observer((props) => {
53
57
  })]
54
58
  });
55
59
  });
56
- const ArrayItemsCollapseComponent = (rest) => {
60
+ const ArrayItemsComponent = (rest) => {
57
61
  return /* @__PURE__ */ jsx(ArrayComponentProvider, { children: /* @__PURE__ */ jsx(ArrayDialogBase, { ...rest }) });
58
62
  };
59
- const ArrayDialog = ArrayItemsCollapseComponent;
63
+ const ArrayDialog = ArrayItemsComponent;
60
64
  ArrayDialog.displayName = "ArrayDialog";
61
65
  ArrayBase.mixin(ArrayDialog);
62
66
 
@@ -19,29 +19,75 @@ react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
19
19
  * Renders form fields based on the array item schema
20
20
  * RecursionField inherits component registry from parent SchemaField context (preserved through Radix Portal)
21
21
  */
22
- const EditDialog = (0, __formily_react.observer)(({ schema, onSave, onAutoSave, onCancel, activeItemManager, autoSave, className,...rest }) => {
23
- const { activeIndex: itemIndex, open, normalizedAutoSave, draftForm, isDirty, title, description, shouldShake, triggerShake, handleSave, handleCancel } = require_use_array_item_edit_state.useArrayItemEditState({
22
+ const EditDialog = (0, __formily_react.observer)(({ schema, onSave, onAutoSave: _onAutoSave, onCancel, activeItemManager, autoSave,...rest }) => {
23
+ const { arrayField, activeIndex: itemIndex, isNewItem, open, normalizedAutoSave, draftForm, basePath, validationPath, isolatedForm, isDirty, title, description, shouldShake, triggerShake, handleSave, handleCancel } = require_use_array_item_edit_state.useArrayItemEditState({
24
24
  schema,
25
25
  activeItemManager,
26
26
  onSave,
27
27
  onCancel,
28
- onAutoSave,
29
28
  autoSave
30
29
  });
30
+ /**
31
+ * Validate the current item's fields before allowing the dialog to close.
32
+ * In non-autoSave mode a dirty (modified but unsaved) form shakes instead.
33
+ * In autoSave mode the parent form fields are validated directly.
34
+ */
35
+ const validateAndClose = react.default.useCallback(() => {
36
+ if (isDirty) {
37
+ triggerShake();
38
+ return;
39
+ }
40
+ Promise.resolve(draftForm.validate(validationPath)).then(() => {
41
+ handleCancel();
42
+ }).catch(() => {
43
+ triggerShake();
44
+ });
45
+ }, [
46
+ draftForm,
47
+ handleCancel,
48
+ isDirty,
49
+ triggerShake,
50
+ validationPath
51
+ ]);
52
+ /**
53
+ * In autoSave mode, newly-added items are inserted into the parent array
54
+ * immediately. Discard removes the item so the user can abandon it.
55
+ */
56
+ const handleDiscard = react.default.useCallback(() => {
57
+ if (itemIndex !== void 0 && normalizedAutoSave && isNewItem) arrayField.remove?.(itemIndex).catch(console.error);
58
+ handleCancel();
59
+ }, [
60
+ arrayField,
61
+ handleCancel,
62
+ isNewItem,
63
+ itemIndex,
64
+ normalizedAutoSave
65
+ ]);
31
66
  const { settings = {} } = require_use_form_context.useFormContext();
67
+ const { autoSave: _globalAutoSave,...dialogSettings } = settings.dialog || {};
68
+ const dialogContentProps = {
69
+ ...dialogSettings,
70
+ ...rest
71
+ };
32
72
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn_ui.Dialog, {
33
73
  open,
34
74
  onOpenChange: (isOpen) => {
35
- if (!isOpen) handleCancel();
75
+ if (!isOpen) validateAndClose();
36
76
  },
37
77
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__pixpilot_shadcn_ui.DialogContent, {
38
- ...settings.dialog,
39
- ...rest,
40
- className: (0, __pixpilot_shadcn_ui.cn)("sm:max-w-[525px]", shouldShake && "pp-shake", className),
78
+ ...dialogContentProps,
79
+ className: (0, __pixpilot_shadcn_ui.cn)("sm:max-w-[525px]", shouldShake && "pp-shake", dialogContentProps.className),
41
80
  onInteractOutside: (event) => {
42
- if (!isDirty) return;
81
+ dialogContentProps.onInteractOutside?.(event);
82
+ if (event.defaultPrevented) return;
43
83
  event.preventDefault();
44
- triggerShake();
84
+ validateAndClose();
85
+ },
86
+ onEscapeKeyDown: (event) => {
87
+ dialogContentProps.onEscapeKeyDown?.(event);
88
+ if (event.defaultPrevented) return;
89
+ event.preventDefault();
90
+ validateAndClose();
45
91
  },
46
92
  children: [
47
93
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ShakeStyles.ShakeStyles, {}),
@@ -50,6 +96,8 @@ const EditDialog = (0, __formily_react.observer)(({ schema, onSave, onAutoSave,
50
96
  as: __pixpilot_shadcn_ui.DialogBody,
51
97
  schema,
52
98
  form: draftForm,
99
+ basePath,
100
+ isolated: isolatedForm,
53
101
  className: (0, __pixpilot_shadcn_ui.cn)("grid gap-4 py-4")
54
102
  }),
55
103
  !normalizedAutoSave && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__pixpilot_shadcn_ui.DialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn_ui.Button, {
@@ -61,6 +109,16 @@ const EditDialog = (0, __formily_react.observer)(({ schema, onSave, onAutoSave,
61
109
  type: "button",
62
110
  onClick: handleSave,
63
111
  children: "Save Changes"
112
+ })] }),
113
+ normalizedAutoSave && isNewItem && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__pixpilot_shadcn_ui.DialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn_ui.Button, {
114
+ type: "button",
115
+ variant: "outline",
116
+ onClick: handleDiscard,
117
+ children: "Discard"
118
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn_ui.Button, {
119
+ type: "button",
120
+ onClick: validateAndClose,
121
+ children: "Done"
64
122
  })] })
65
123
  ]
66
124
  })
@@ -14,29 +14,75 @@ import { jsx, jsxs } from "react/jsx-runtime";
14
14
  * Renders form fields based on the array item schema
15
15
  * RecursionField inherits component registry from parent SchemaField context (preserved through Radix Portal)
16
16
  */
17
- const EditDialog = observer(({ schema, onSave, onAutoSave, onCancel, activeItemManager, autoSave, className,...rest }) => {
18
- const { activeIndex: itemIndex, open, normalizedAutoSave, draftForm, isDirty, title, description, shouldShake, triggerShake, handleSave, handleCancel } = useArrayItemEditState({
17
+ const EditDialog = observer(({ schema, onSave, onAutoSave: _onAutoSave, onCancel, activeItemManager, autoSave,...rest }) => {
18
+ const { arrayField, activeIndex: itemIndex, isNewItem, open, normalizedAutoSave, draftForm, basePath, validationPath, isolatedForm, isDirty, title, description, shouldShake, triggerShake, handleSave, handleCancel } = useArrayItemEditState({
19
19
  schema,
20
20
  activeItemManager,
21
21
  onSave,
22
22
  onCancel,
23
- onAutoSave,
24
23
  autoSave
25
24
  });
25
+ /**
26
+ * Validate the current item's fields before allowing the dialog to close.
27
+ * In non-autoSave mode a dirty (modified but unsaved) form shakes instead.
28
+ * In autoSave mode the parent form fields are validated directly.
29
+ */
30
+ const validateAndClose = React.useCallback(() => {
31
+ if (isDirty) {
32
+ triggerShake();
33
+ return;
34
+ }
35
+ Promise.resolve(draftForm.validate(validationPath)).then(() => {
36
+ handleCancel();
37
+ }).catch(() => {
38
+ triggerShake();
39
+ });
40
+ }, [
41
+ draftForm,
42
+ handleCancel,
43
+ isDirty,
44
+ triggerShake,
45
+ validationPath
46
+ ]);
47
+ /**
48
+ * In autoSave mode, newly-added items are inserted into the parent array
49
+ * immediately. Discard removes the item so the user can abandon it.
50
+ */
51
+ const handleDiscard = React.useCallback(() => {
52
+ if (itemIndex !== void 0 && normalizedAutoSave && isNewItem) arrayField.remove?.(itemIndex).catch(console.error);
53
+ handleCancel();
54
+ }, [
55
+ arrayField,
56
+ handleCancel,
57
+ isNewItem,
58
+ itemIndex,
59
+ normalizedAutoSave
60
+ ]);
26
61
  const { settings = {} } = useFormContext();
62
+ const { autoSave: _globalAutoSave,...dialogSettings } = settings.dialog || {};
63
+ const dialogContentProps = {
64
+ ...dialogSettings,
65
+ ...rest
66
+ };
27
67
  return /* @__PURE__ */ jsx(Dialog, {
28
68
  open,
29
69
  onOpenChange: (isOpen) => {
30
- if (!isOpen) handleCancel();
70
+ if (!isOpen) validateAndClose();
31
71
  },
32
72
  children: /* @__PURE__ */ jsxs(DialogContent, {
33
- ...settings.dialog,
34
- ...rest,
35
- className: cn("sm:max-w-[525px]", shouldShake && "pp-shake", className),
73
+ ...dialogContentProps,
74
+ className: cn("sm:max-w-[525px]", shouldShake && "pp-shake", dialogContentProps.className),
36
75
  onInteractOutside: (event) => {
37
- if (!isDirty) return;
76
+ dialogContentProps.onInteractOutside?.(event);
77
+ if (event.defaultPrevented) return;
38
78
  event.preventDefault();
39
- triggerShake();
79
+ validateAndClose();
80
+ },
81
+ onEscapeKeyDown: (event) => {
82
+ dialogContentProps.onEscapeKeyDown?.(event);
83
+ if (event.defaultPrevented) return;
84
+ event.preventDefault();
85
+ validateAndClose();
40
86
  },
41
87
  children: [
42
88
  /* @__PURE__ */ jsx(ShakeStyles, {}),
@@ -45,6 +91,8 @@ const EditDialog = observer(({ schema, onSave, onAutoSave, onCancel, activeItemM
45
91
  as: DialogBody,
46
92
  schema,
47
93
  form: draftForm,
94
+ basePath,
95
+ isolated: isolatedForm,
48
96
  className: cn("grid gap-4 py-4")
49
97
  }),
50
98
  !normalizedAutoSave && /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
@@ -56,6 +104,16 @@ const EditDialog = observer(({ schema, onSave, onAutoSave, onCancel, activeItemM
56
104
  type: "button",
57
105
  onClick: handleSave,
58
106
  children: "Save Changes"
107
+ })] }),
108
+ normalizedAutoSave && isNewItem && /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
109
+ type: "button",
110
+ variant: "outline",
111
+ onClick: handleDiscard,
112
+ children: "Discard"
113
+ }), /* @__PURE__ */ jsx(Button, {
114
+ type: "button",
115
+ onClick: validateAndClose,
116
+ children: "Done"
59
117
  })] })
60
118
  ]
61
119
  })
@@ -1,4 +1,6 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_use_form_context = require('../../hooks/use-form-context.cjs');
3
+ require('../../hooks/index.cjs');
2
4
  const require_array_base = require('../array-base/array-base.cjs');
3
5
  const require_component_context = require('../array-base/component-context.cjs');
4
6
  require('../array-base/index.cjs');
@@ -19,7 +21,9 @@ __pixpilot_shadcn = require_rolldown_runtime.__toESM(__pixpilot_shadcn);
19
21
  //#region src/components/array-popover/ArrayPopover.tsx
20
22
  const ArrayPopoverBase = (0, __formily_react.observer)((props) => {
21
23
  const { onAdd, onRemove, onMoveDown, onMoveUp, onEdit, autoSave: autoSaveProp, className, children, transformActions, popoverProps,...rest } = props;
22
- const autoSave = autoSaveProp === true;
24
+ const { settings = {} } = require_use_form_context.useFormContext();
25
+ const { autoSave: globalAutoSave } = settings.popover || {};
26
+ const autoSave = autoSaveProp ?? globalAutoSave ?? true;
23
27
  const { activeItemManager, handleAdd, isNewItem, handleEdit, handleSaveClick, handleLiveChange, handleCancelClick } = require_use_array_editor.useArrayEditor({
24
28
  onAdd,
25
29
  onEdit,
@@ -35,22 +39,35 @@ const ArrayPopoverBase = (0, __formily_react.observer)((props) => {
35
39
  onMoveUp,
36
40
  onMoveDown,
37
41
  onEdit: handleEdit,
38
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
39
- ...rest,
40
- className: (0, __pixpilot_shadcn.cn)("space-y-2", className),
41
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ArrayItemsList.ArrayItemsList, { isNewItem }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
42
- className: "pt-2",
43
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Popover.ArrayItemsEditPopover, {
44
- activeItemManager,
45
- onCancel: handleCancelClick,
46
- onAutoSave: handleLiveChange,
47
- autoSave,
48
- schema,
49
- onSave: handleSaveClick,
50
- ...popoverProps,
51
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_array_base.ArrayBase.Addition, {})
52
- })
53
- })]
42
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.Popover, {
43
+ open: activeItemManager.activeItem !== void 0,
44
+ modal: true,
45
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
46
+ ...rest,
47
+ className: (0, __pixpilot_shadcn.cn)("space-y-2", className),
48
+ children: [
49
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ArrayItemsList.ArrayItemsList, {
50
+ isNewItem,
51
+ activeIndex: activeItemManager.activeItem
52
+ }),
53
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
54
+ className: "pt-2",
55
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.PopoverTrigger, {
56
+ asChild: true,
57
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_array_base.ArrayBase.Addition, {})
58
+ })
59
+ }),
60
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Popover.ArrayItemsEditPopover, {
61
+ activeItemManager,
62
+ onCancel: handleCancelClick,
63
+ onAutoSave: handleLiveChange,
64
+ autoSave,
65
+ schema,
66
+ onSave: handleSaveClick,
67
+ ...popoverProps
68
+ })
69
+ ]
70
+ })
54
71
  })
55
72
  });
56
73
  });