@nocobase/flow-engine 2.1.0-alpha.4 → 2.1.0-alpha.45

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 (209) hide show
  1. package/LICENSE +201 -661
  2. package/README.md +79 -10
  3. package/lib/FlowContextProvider.d.ts +5 -1
  4. package/lib/FlowContextProvider.js +9 -2
  5. package/lib/JSRunner.d.ts +10 -1
  6. package/lib/JSRunner.js +50 -5
  7. package/lib/ViewScopedFlowEngine.js +5 -1
  8. package/lib/components/FieldModelRenderer.js +2 -2
  9. package/lib/components/FlowModelRenderer.d.ts +3 -1
  10. package/lib/components/FlowModelRenderer.js +12 -6
  11. package/lib/components/FormItem.d.ts +6 -0
  12. package/lib/components/FormItem.js +11 -3
  13. package/lib/components/MobilePopup.js +6 -5
  14. package/lib/components/dnd/gridDragPlanner.d.ts +59 -2
  15. package/lib/components/dnd/gridDragPlanner.js +613 -21
  16. package/lib/components/dnd/index.d.ts +31 -2
  17. package/lib/components/dnd/index.js +244 -23
  18. package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +2 -1
  19. package/lib/components/settings/wrappers/component/SelectWithTitle.js +14 -12
  20. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
  21. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +76 -11
  22. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +23 -43
  23. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +352 -295
  24. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +16 -2
  25. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
  26. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +274 -0
  27. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
  28. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +315 -0
  29. package/lib/components/subModel/AddSubModelButton.js +27 -1
  30. package/lib/components/subModel/LazyDropdown.js +293 -52
  31. package/lib/components/subModel/index.d.ts +1 -0
  32. package/lib/components/subModel/index.js +19 -0
  33. package/lib/components/subModel/utils.d.ts +1 -1
  34. package/lib/components/subModel/utils.js +9 -3
  35. package/lib/components/variables/VariableHybridInput.d.ts +27 -0
  36. package/lib/components/variables/VariableHybridInput.js +499 -0
  37. package/lib/components/variables/index.d.ts +2 -0
  38. package/lib/components/variables/index.js +3 -0
  39. package/lib/data-source/index.d.ts +84 -0
  40. package/lib/data-source/index.js +259 -5
  41. package/lib/executor/FlowExecutor.js +32 -9
  42. package/lib/flow-registry/DetachedFlowRegistry.d.ts +21 -0
  43. package/lib/flow-registry/DetachedFlowRegistry.js +80 -0
  44. package/lib/flow-registry/index.d.ts +1 -0
  45. package/lib/flow-registry/index.js +3 -1
  46. package/lib/flowContext.d.ts +3 -0
  47. package/lib/flowContext.js +46 -1
  48. package/lib/flowEngine.d.ts +151 -1
  49. package/lib/flowEngine.js +392 -18
  50. package/lib/flowI18n.js +2 -1
  51. package/lib/flowSettings.d.ts +14 -6
  52. package/lib/flowSettings.js +34 -6
  53. package/lib/index.d.ts +2 -0
  54. package/lib/index.js +7 -0
  55. package/lib/lazy-helper.d.ts +14 -0
  56. package/lib/lazy-helper.js +71 -0
  57. package/lib/locale/en-US.json +1 -0
  58. package/lib/locale/index.d.ts +2 -0
  59. package/lib/locale/zh-CN.json +1 -0
  60. package/lib/models/DisplayItemModel.d.ts +1 -1
  61. package/lib/models/EditableItemModel.d.ts +1 -1
  62. package/lib/models/FilterableItemModel.d.ts +1 -1
  63. package/lib/models/flowModel.d.ts +13 -10
  64. package/lib/models/flowModel.js +81 -21
  65. package/lib/provider.js +38 -23
  66. package/lib/reactive/observer.js +46 -16
  67. package/lib/runjs-context/registry.d.ts +1 -1
  68. package/lib/runjs-context/setup.js +20 -12
  69. package/lib/runjs-context/snippets/index.js +13 -2
  70. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
  71. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
  72. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
  73. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
  74. package/lib/scheduler/ModelOperationScheduler.d.ts +5 -1
  75. package/lib/scheduler/ModelOperationScheduler.js +3 -2
  76. package/lib/types.d.ts +50 -2
  77. package/lib/types.js +1 -0
  78. package/lib/utils/createCollectionContextMeta.js +6 -2
  79. package/lib/utils/index.d.ts +3 -2
  80. package/lib/utils/index.js +7 -0
  81. package/lib/utils/parsePathnameToViewParams.d.ts +5 -1
  82. package/lib/utils/parsePathnameToViewParams.js +29 -5
  83. package/lib/utils/randomId.d.ts +39 -0
  84. package/lib/utils/randomId.js +45 -0
  85. package/lib/utils/runjsTemplateCompat.js +1 -1
  86. package/lib/utils/runjsValue.js +41 -11
  87. package/lib/utils/schema-utils.d.ts +7 -1
  88. package/lib/utils/schema-utils.js +19 -0
  89. package/lib/views/FlowView.d.ts +7 -1
  90. package/lib/views/FlowView.js +11 -1
  91. package/lib/views/PageComponent.js +8 -6
  92. package/lib/views/ViewNavigation.d.ts +12 -2
  93. package/lib/views/ViewNavigation.js +28 -9
  94. package/lib/views/createViewMeta.js +114 -50
  95. package/lib/views/inheritLayoutContext.d.ts +10 -0
  96. package/lib/views/inheritLayoutContext.js +50 -0
  97. package/lib/views/runViewBeforeClose.d.ts +10 -0
  98. package/lib/views/runViewBeforeClose.js +45 -0
  99. package/lib/views/useDialog.d.ts +2 -1
  100. package/lib/views/useDialog.js +22 -3
  101. package/lib/views/useDrawer.d.ts +2 -1
  102. package/lib/views/useDrawer.js +22 -3
  103. package/lib/views/usePage.d.ts +5 -11
  104. package/lib/views/usePage.js +304 -144
  105. package/package.json +6 -5
  106. package/src/FlowContextProvider.tsx +9 -1
  107. package/src/JSRunner.ts +68 -4
  108. package/src/ViewScopedFlowEngine.ts +4 -0
  109. package/src/__tests__/JSRunner.test.ts +27 -1
  110. package/src/__tests__/createViewMeta.popup.test.ts +115 -1
  111. package/src/__tests__/flow-engine.test.ts +166 -0
  112. package/src/__tests__/flowContext.test.ts +82 -1
  113. package/src/__tests__/flowEngine.modelLoaders.test.ts +245 -0
  114. package/src/__tests__/flowEngine.removeModel.test.ts +47 -3
  115. package/src/__tests__/flowSettings.test.ts +94 -15
  116. package/src/__tests__/objectVariable.test.ts +24 -0
  117. package/src/__tests__/provider.test.tsx +24 -2
  118. package/src/__tests__/renderHiddenInConfig.test.tsx +6 -6
  119. package/src/__tests__/runjsContext.test.ts +16 -0
  120. package/src/__tests__/runjsContextRuntime.test.ts +2 -0
  121. package/src/__tests__/runjsPreprocessDefault.test.ts +23 -0
  122. package/src/__tests__/runjsSnippets.test.ts +21 -0
  123. package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
  124. package/src/components/FieldModelRenderer.tsx +2 -1
  125. package/src/components/FlowModelRenderer.tsx +18 -6
  126. package/src/components/FormItem.tsx +7 -1
  127. package/src/components/MobilePopup.tsx +4 -2
  128. package/src/components/__tests__/FlowModelRenderer.test.tsx +65 -2
  129. package/src/components/__tests__/FormItem.test.tsx +25 -0
  130. package/src/components/__tests__/dnd.test.ts +44 -0
  131. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +20 -10
  132. package/src/components/__tests__/gridDragPlanner.test.ts +558 -3
  133. package/src/components/dnd/__tests__/DndProvider.test.tsx +98 -0
  134. package/src/components/dnd/gridDragPlanner.ts +758 -19
  135. package/src/components/dnd/index.tsx +305 -28
  136. package/src/components/settings/wrappers/component/SelectWithTitle.tsx +21 -9
  137. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +99 -11
  138. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +487 -440
  139. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +18 -2
  140. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +194 -5
  141. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +778 -0
  142. package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +360 -0
  143. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +361 -0
  144. package/src/components/subModel/AddSubModelButton.tsx +32 -2
  145. package/src/components/subModel/LazyDropdown.tsx +332 -56
  146. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +522 -37
  147. package/src/components/subModel/__tests__/utils.test.ts +24 -0
  148. package/src/components/subModel/index.ts +1 -0
  149. package/src/components/subModel/utils.ts +7 -1
  150. package/src/components/variables/VariableHybridInput.tsx +531 -0
  151. package/src/components/variables/index.ts +2 -0
  152. package/src/data-source/__tests__/collection.test.ts +41 -2
  153. package/src/data-source/__tests__/index.test.ts +68 -1
  154. package/src/data-source/index.ts +322 -6
  155. package/src/executor/FlowExecutor.ts +35 -10
  156. package/src/executor/__tests__/flowExecutor.test.ts +85 -0
  157. package/src/flow-registry/DetachedFlowRegistry.ts +46 -0
  158. package/src/flow-registry/__tests__/detachedFlowRegistry.test.ts +47 -0
  159. package/src/flow-registry/index.ts +1 -0
  160. package/src/flowContext.ts +50 -3
  161. package/src/flowEngine.ts +449 -14
  162. package/src/flowI18n.ts +2 -1
  163. package/src/flowSettings.ts +40 -6
  164. package/src/index.ts +2 -0
  165. package/src/lazy-helper.tsx +57 -0
  166. package/src/locale/en-US.json +1 -0
  167. package/src/locale/zh-CN.json +1 -0
  168. package/src/models/DisplayItemModel.tsx +1 -1
  169. package/src/models/EditableItemModel.tsx +1 -1
  170. package/src/models/FilterableItemModel.tsx +1 -1
  171. package/src/models/__tests__/dispatchEvent.when.test.ts +214 -0
  172. package/src/models/__tests__/flowEngine.resolveUse.test.ts +0 -15
  173. package/src/models/__tests__/flowModel.test.ts +80 -37
  174. package/src/models/flowModel.tsx +122 -36
  175. package/src/provider.tsx +41 -25
  176. package/src/reactive/__tests__/observer.test.tsx +82 -0
  177. package/src/reactive/observer.tsx +87 -25
  178. package/src/runjs-context/registry.ts +1 -1
  179. package/src/runjs-context/setup.ts +22 -12
  180. package/src/runjs-context/snippets/index.ts +12 -1
  181. package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
  182. package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
  183. package/src/scheduler/ModelOperationScheduler.ts +14 -3
  184. package/src/types.ts +62 -0
  185. package/src/utils/__tests__/createCollectionContextMeta.test.ts +48 -0
  186. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +28 -0
  187. package/src/utils/__tests__/runjsValue.test.ts +11 -0
  188. package/src/utils/__tests__/utils.test.ts +62 -0
  189. package/src/utils/createCollectionContextMeta.ts +6 -2
  190. package/src/utils/index.ts +5 -1
  191. package/src/utils/parsePathnameToViewParams.ts +47 -7
  192. package/src/utils/randomId.ts +48 -0
  193. package/src/utils/runjsTemplateCompat.ts +1 -1
  194. package/src/utils/runjsValue.ts +50 -11
  195. package/src/utils/schema-utils.ts +30 -1
  196. package/src/views/FlowView.tsx +22 -2
  197. package/src/views/PageComponent.tsx +7 -4
  198. package/src/views/ViewNavigation.ts +46 -9
  199. package/src/views/__tests__/FlowView.usePage.test.tsx +243 -3
  200. package/src/views/__tests__/ViewNavigation.test.ts +52 -0
  201. package/src/views/__tests__/inheritLayoutContext.test.ts +53 -0
  202. package/src/views/__tests__/runViewBeforeClose.test.ts +30 -0
  203. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +13 -12
  204. package/src/views/createViewMeta.ts +106 -34
  205. package/src/views/inheritLayoutContext.ts +26 -0
  206. package/src/views/runViewBeforeClose.ts +19 -0
  207. package/src/views/useDialog.tsx +27 -3
  208. package/src/views/useDrawer.tsx +27 -3
  209. package/src/views/usePage.tsx +367 -179
@@ -7,18 +7,47 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  import { DndContextProps } from '@dnd-kit/core';
10
+ import type { Transform } from '@dnd-kit/utilities';
10
11
  import React, { FC } from 'react';
11
12
  import { FlowModel } from '../../models';
12
13
  import { PersistOptions } from '../../types';
13
14
  export * from './findModelUidPosition';
14
15
  export * from './gridDragPlanner';
15
16
  export declare const EMPTY_COLUMN_UID = "EMPTY_COLUMN";
17
+ export declare const TOOLBAR_DRAG_ACTIVITY_EVENT = "nb-toolbar-drag-activity";
18
+ type ToolbarDragAnchorPoint = {
19
+ x: number;
20
+ y: number;
21
+ };
22
+ export declare const resolveOverlayAnchorTransform: ({ activeId, active, transform, activeNodeRect, dragAnchorPoint, }: {
23
+ activeId: string | null;
24
+ active: {
25
+ id: string | number;
26
+ } | null | undefined;
27
+ transform: Transform;
28
+ activeNodeRect: {
29
+ top: number;
30
+ left: number;
31
+ } | null;
32
+ dragAnchorPoint: ToolbarDragAnchorPoint | null;
33
+ }) => Transform;
16
34
  export declare const DragHandler: FC<{
17
35
  model: FlowModel;
18
- children: React.ReactNode;
36
+ children?: React.ReactNode;
19
37
  }>;
20
38
  export declare const Droppable: FC<{
21
39
  model: FlowModel<any>;
22
40
  children: React.ReactNode;
23
41
  }>;
24
- export declare const DndProvider: FC<DndContextProps & PersistOptions>;
42
+ export interface DndProviderProps extends DndContextProps, PersistOptions {
43
+ /**
44
+ * Whether to render the built-in `DragOverlay` (the "Dragging" pill that
45
+ * follows the cursor). Defaults to `true` for backwards compatibility with
46
+ * existing flow-engine drag interactions. Set to `false` when the
47
+ * surrounding UI already gives clear visual feedback (e.g. a drag-sort
48
+ * table that highlights the drop position) and the floating pill would be
49
+ * redundant.
50
+ */
51
+ showDragOverlay?: boolean;
52
+ }
53
+ export declare const DndProvider: FC<DndProviderProps>;
@@ -41,7 +41,9 @@ __export(dnd_exports, {
41
41
  DndProvider: () => DndProvider,
42
42
  DragHandler: () => DragHandler,
43
43
  Droppable: () => Droppable,
44
- EMPTY_COLUMN_UID: () => EMPTY_COLUMN_UID
44
+ EMPTY_COLUMN_UID: () => EMPTY_COLUMN_UID,
45
+ TOOLBAR_DRAG_ACTIVITY_EVENT: () => TOOLBAR_DRAG_ACTIVITY_EVENT,
46
+ resolveOverlayAnchorTransform: () => resolveOverlayAnchorTransform
45
47
  });
46
48
  module.exports = __toCommonJS(dnd_exports);
47
49
  var import_icons = require("@ant-design/icons");
@@ -52,17 +54,186 @@ var import_provider = require("../../provider");
52
54
  __reExport(dnd_exports, require("./findModelUidPosition"), module.exports);
53
55
  __reExport(dnd_exports, require("./gridDragPlanner"), module.exports);
54
56
  const EMPTY_COLUMN_UID = "EMPTY_COLUMN";
57
+ const TOOLBAR_DRAG_ACTIVITY_EVENT = "nb-toolbar-drag-activity";
58
+ const TOOLBAR_DRAG_ANCHOR_EVENT = "nb-toolbar-drag-anchor";
59
+ const MENU_SUBMENU_POPUP_SELECTOR = ".ant-menu-submenu-popup";
60
+ const resolveOverlayAnchorTransform = /* @__PURE__ */ __name(({
61
+ activeId,
62
+ active,
63
+ transform,
64
+ activeNodeRect,
65
+ dragAnchorPoint
66
+ }) => {
67
+ if (!activeId || (active == null ? void 0 : active.id) !== activeId || !dragAnchorPoint || !activeNodeRect) {
68
+ return transform;
69
+ }
70
+ return {
71
+ ...transform,
72
+ x: transform.x + dragAnchorPoint.x - activeNodeRect.left,
73
+ y: transform.y + dragAnchorPoint.y - activeNodeRect.top
74
+ };
75
+ }, "resolveOverlayAnchorTransform");
76
+ const resolveDraggableHostNode = /* @__PURE__ */ __name((activatorNode) => {
77
+ const ownerDocument = activatorNode == null ? void 0 : activatorNode.ownerDocument;
78
+ const floatToolbarContainer = activatorNode == null ? void 0 : activatorNode.closest(".nb-toolbar-container[data-model-uid]");
79
+ const toolbarModelUid = floatToolbarContainer == null ? void 0 : floatToolbarContainer.getAttribute("data-model-uid");
80
+ if (!ownerDocument || !toolbarModelUid) {
81
+ return activatorNode;
82
+ }
83
+ const matchedHosts = Array.from(
84
+ ownerDocument.querySelectorAll(
85
+ `[data-has-float-menu="true"][data-float-menu-model-uid="${toolbarModelUid}"]`
86
+ )
87
+ );
88
+ const popupRoot = floatToolbarContainer == null ? void 0 : floatToolbarContainer.closest(MENU_SUBMENU_POPUP_SELECTOR);
89
+ if (popupRoot) {
90
+ return matchedHosts.find((hostNode) => hostNode.closest(MENU_SUBMENU_POPUP_SELECTOR) === popupRoot) || activatorNode;
91
+ }
92
+ return matchedHosts.find((hostNode) => !hostNode.closest(MENU_SUBMENU_POPUP_SELECTOR)) || matchedHosts[0] || activatorNode;
93
+ }, "resolveDraggableHostNode");
55
94
  const DragHandler = /* @__PURE__ */ __name(({
56
95
  model,
57
96
  children = /* @__PURE__ */ import_react.default.createElement(import_icons.DragOutlined, null)
58
97
  }) => {
59
- const { attributes, listeners, setNodeRef } = (0, import_core.useDraggable)({ id: model.uid });
98
+ const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef } = (0, import_core.useDraggable)({ id: model.uid });
99
+ const dragHandlerRef = (0, import_react.useRef)(null);
100
+ const draggableNodeRef = (0, import_react.useRef)(null);
101
+ const pointerPressCleanupRef = (0, import_react.useRef)(null);
102
+ const isDraggingRef = (0, import_react.useRef)(isDragging);
103
+ const isPointerPressActiveRef = (0, import_react.useRef)(false);
104
+ const isToolbarDragActiveRef = (0, import_react.useRef)(false);
105
+ const syncDraggableNodeRef = (0, import_react.useCallback)(
106
+ (activatorNode) => {
107
+ const nextNode = resolveDraggableHostNode(activatorNode);
108
+ if (draggableNodeRef.current === nextNode) {
109
+ return;
110
+ }
111
+ draggableNodeRef.current = nextNode;
112
+ setNodeRef(nextNode);
113
+ },
114
+ [setNodeRef]
115
+ );
116
+ const setDragHandlerNodeRef = (0, import_react.useCallback)(
117
+ (node) => {
118
+ dragHandlerRef.current = node;
119
+ setActivatorNodeRef(node);
120
+ syncDraggableNodeRef(node);
121
+ },
122
+ [setActivatorNodeRef, syncDraggableNodeRef]
123
+ );
124
+ const dispatchToolbarDragActivity = (0, import_react.useCallback)(
125
+ (active) => {
126
+ var _a;
127
+ const ownerDocument = (_a = dragHandlerRef.current) == null ? void 0 : _a.ownerDocument;
128
+ if (!ownerDocument) {
129
+ return;
130
+ }
131
+ ownerDocument.dispatchEvent(
132
+ new CustomEvent(TOOLBAR_DRAG_ACTIVITY_EVENT, {
133
+ detail: { active, modelUid: model.uid }
134
+ })
135
+ );
136
+ },
137
+ [model.uid]
138
+ );
139
+ const dispatchToolbarDragAnchor = (0, import_react.useCallback)(
140
+ (detail) => {
141
+ var _a;
142
+ const ownerDocument = (_a = dragHandlerRef.current) == null ? void 0 : _a.ownerDocument;
143
+ if (!ownerDocument) {
144
+ return;
145
+ }
146
+ ownerDocument.dispatchEvent(
147
+ new CustomEvent(TOOLBAR_DRAG_ANCHOR_EVENT, {
148
+ detail: { modelUid: model.uid, point: detail.point }
149
+ })
150
+ );
151
+ },
152
+ [model.uid]
153
+ );
154
+ const clearPointerPressListeners = (0, import_react.useCallback)(() => {
155
+ var _a;
156
+ (_a = pointerPressCleanupRef.current) == null ? void 0 : _a.call(pointerPressCleanupRef);
157
+ pointerPressCleanupRef.current = null;
158
+ }, []);
159
+ const syncToolbarDragActivity = (0, import_react.useCallback)(() => {
160
+ const nextActive = isPointerPressActiveRef.current || isDraggingRef.current;
161
+ if (nextActive === isToolbarDragActiveRef.current) {
162
+ return;
163
+ }
164
+ isToolbarDragActiveRef.current = nextActive;
165
+ dispatchToolbarDragActivity(nextActive);
166
+ }, [dispatchToolbarDragActivity]);
167
+ const handlePointerPressEnd = (0, import_react.useCallback)(() => {
168
+ isPointerPressActiveRef.current = false;
169
+ clearPointerPressListeners();
170
+ syncToolbarDragActivity();
171
+ }, [clearPointerPressListeners, syncToolbarDragActivity]);
172
+ const registerPointerPressListeners = (0, import_react.useCallback)(() => {
173
+ var _a;
174
+ const ownerDocument = (_a = dragHandlerRef.current) == null ? void 0 : _a.ownerDocument;
175
+ const ownerWindow = ownerDocument == null ? void 0 : ownerDocument.defaultView;
176
+ if (!ownerDocument) {
177
+ return;
178
+ }
179
+ clearPointerPressListeners();
180
+ const handlePointerEnd = /* @__PURE__ */ __name(() => {
181
+ handlePointerPressEnd();
182
+ }, "handlePointerEnd");
183
+ const handleKeyDown = /* @__PURE__ */ __name((event) => {
184
+ if (event.key === "Escape") {
185
+ handlePointerPressEnd();
186
+ }
187
+ }, "handleKeyDown");
188
+ ownerDocument.addEventListener("pointerup", handlePointerEnd, true);
189
+ ownerDocument.addEventListener("pointercancel", handlePointerEnd, true);
190
+ ownerDocument.addEventListener("keydown", handleKeyDown, true);
191
+ ownerWindow == null ? void 0 : ownerWindow.addEventListener("blur", handlePointerEnd);
192
+ pointerPressCleanupRef.current = () => {
193
+ ownerDocument.removeEventListener("pointerup", handlePointerEnd, true);
194
+ ownerDocument.removeEventListener("pointercancel", handlePointerEnd, true);
195
+ ownerDocument.removeEventListener("keydown", handleKeyDown, true);
196
+ ownerWindow == null ? void 0 : ownerWindow.removeEventListener("blur", handlePointerEnd);
197
+ };
198
+ }, [clearPointerPressListeners, handlePointerPressEnd]);
199
+ (0, import_react.useEffect)(() => {
200
+ syncDraggableNodeRef(dragHandlerRef.current);
201
+ }, [syncDraggableNodeRef]);
202
+ (0, import_react.useEffect)(() => {
203
+ isDraggingRef.current = isDragging;
204
+ syncToolbarDragActivity();
205
+ }, [isDragging, syncToolbarDragActivity]);
206
+ (0, import_react.useEffect)(() => {
207
+ return () => {
208
+ if (isToolbarDragActiveRef.current) {
209
+ dispatchToolbarDragActivity(false);
210
+ }
211
+ isPointerPressActiveRef.current = false;
212
+ isDraggingRef.current = false;
213
+ isToolbarDragActiveRef.current = false;
214
+ clearPointerPressListeners();
215
+ };
216
+ }, [clearPointerPressListeners, dispatchToolbarDragActivity]);
60
217
  return /* @__PURE__ */ import_react.default.createElement(
61
218
  "span",
62
219
  {
63
- ref: setNodeRef,
220
+ ref: setDragHandlerNodeRef,
64
221
  ...listeners,
65
222
  ...attributes,
223
+ onPointerDownCapture: (event) => {
224
+ if (event.button !== 0) {
225
+ return;
226
+ }
227
+ dispatchToolbarDragAnchor({
228
+ point: {
229
+ x: event.clientX,
230
+ y: event.clientY
231
+ }
232
+ });
233
+ isPointerPressActiveRef.current = true;
234
+ syncToolbarDragActivity();
235
+ registerPointerPressListeners();
236
+ },
66
237
  style: {
67
238
  cursor: "grab"
68
239
  }
@@ -103,22 +274,54 @@ const Droppable = /* @__PURE__ */ __name(({ model, children }) => {
103
274
  }, "Droppable");
104
275
  const DndProvider = /* @__PURE__ */ __name(({
105
276
  persist = true,
277
+ showDragOverlay = true,
106
278
  children,
279
+ onDragStart,
107
280
  onDragEnd,
281
+ onDragCancel,
108
282
  ...restProps
109
283
  }) => {
110
284
  const [activeId, setActiveId] = (0, import_react.useState)(null);
285
+ const [dragAnchorPoint, setDragAnchorPoint] = (0, import_react.useState)(null);
111
286
  const flowEngine = (0, import_provider.useFlowEngine)();
287
+ (0, import_react.useEffect)(() => {
288
+ if (typeof document === "undefined") {
289
+ return;
290
+ }
291
+ const handleToolbarDragAnchor = /* @__PURE__ */ __name((event) => {
292
+ var _a;
293
+ const customEvent = event;
294
+ setDragAnchorPoint(((_a = customEvent.detail) == null ? void 0 : _a.point) || null);
295
+ }, "handleToolbarDragAnchor");
296
+ document.addEventListener(TOOLBAR_DRAG_ANCHOR_EVENT, handleToolbarDragAnchor);
297
+ return () => {
298
+ document.removeEventListener(TOOLBAR_DRAG_ANCHOR_EVENT, handleToolbarDragAnchor);
299
+ };
300
+ }, []);
301
+ const overlayAnchorModifier = (0, import_react.useCallback)(
302
+ ({ active, activeNodeRect, transform }) => {
303
+ const nextTransform = resolveOverlayAnchorTransform({
304
+ activeId,
305
+ active,
306
+ transform,
307
+ activeNodeRect,
308
+ dragAnchorPoint
309
+ });
310
+ return nextTransform;
311
+ },
312
+ [activeId, dragAnchorPoint]
313
+ );
112
314
  return /* @__PURE__ */ import_react.default.createElement(
113
315
  import_core.DndContext,
114
316
  {
317
+ ...restProps,
115
318
  onDragStart: (event) => {
116
- var _a;
117
319
  setActiveId(event.active.id);
118
- (_a = restProps.onDragStart) == null ? void 0 : _a.call(restProps, event);
320
+ onDragStart == null ? void 0 : onDragStart(event);
119
321
  },
120
322
  onDragEnd: (event) => {
121
323
  setActiveId(null);
324
+ setDragAnchorPoint(null);
122
325
  if (!onDragEnd) {
123
326
  if (event.over) {
124
327
  flowEngine.moveModel(event.active.id, event.over.id, { persist });
@@ -127,30 +330,46 @@ const DndProvider = /* @__PURE__ */ __name(({
127
330
  onDragEnd(event);
128
331
  }
129
332
  },
333
+ onDragCancel: (event) => {
334
+ setActiveId(null);
335
+ setDragAnchorPoint(null);
336
+ onDragCancel == null ? void 0 : onDragCancel(event);
337
+ },
130
338
  ...restProps
131
339
  },
132
340
  children,
133
- (0, import_react_dom.createPortal)(
134
- /* @__PURE__ */ import_react.default.createElement(import_core.DragOverlay, { dropAnimation: null, zIndex: 2e3 }, activeId && /* @__PURE__ */ import_react.default.createElement(
135
- "span",
341
+ showDragOverlay && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(
342
+ /* @__PURE__ */ import_react.default.createElement(
343
+ import_core.DragOverlay,
136
344
  {
137
- style: {
138
- display: "inline-flex",
139
- alignItems: "center",
140
- whiteSpace: "nowrap",
141
- background: "#fff",
142
- border: "1px solid #1890ff",
143
- borderRadius: 4,
144
- padding: "4px 12px",
145
- color: "#1890ff",
146
- // fontSize: 18,
147
- boxShadow: "0 2px 8px rgba(0,0,0,0.15)"
148
- }
345
+ dropAnimation: null,
346
+ modifiers: [overlayAnchorModifier],
347
+ zIndex: 2e3,
348
+ style: { pointerEvents: "none" }
149
349
  },
150
- flowEngine.translate("Dragging")
151
- )),
350
+ activeId && /* @__PURE__ */ import_react.default.createElement(
351
+ "span",
352
+ {
353
+ "data-testid": "flow-drag-preview",
354
+ style: {
355
+ display: "inline-flex",
356
+ alignItems: "center",
357
+ whiteSpace: "nowrap",
358
+ background: "#fff",
359
+ border: "1px solid #1890ff",
360
+ borderRadius: 4,
361
+ padding: "4px 12px",
362
+ color: "#1890ff",
363
+ pointerEvents: "none",
364
+ // fontSize: 18,
365
+ boxShadow: "0 2px 8px rgba(0,0,0,0.15)"
366
+ }
367
+ },
368
+ flowEngine.translate("Dragging")
369
+ )
370
+ ),
152
371
  document.body
153
- )
372
+ ) : null
154
373
  );
155
374
  }, "DndProvider");
156
375
  // Annotate the CommonJS export names for ESM import in node:
@@ -159,6 +378,8 @@ const DndProvider = /* @__PURE__ */ __name(({
159
378
  DragHandler,
160
379
  Droppable,
161
380
  EMPTY_COLUMN_UID,
381
+ TOOLBAR_DRAG_ACTIVITY_EVENT,
382
+ resolveOverlayAnchorTransform,
162
383
  ...require("./findModelUidPosition"),
163
384
  ...require("./gridDragPlanner")
164
385
  });
@@ -15,5 +15,6 @@ export interface SelectWithTitleProps {
15
15
  itemKey?: string;
16
16
  onChange?: (...args: any[]) => void;
17
17
  dropdownRender?: any;
18
+ tooltip?: any;
18
19
  }
19
- export declare function SelectWithTitle({ title, getDefaultValue, onChange, options, fieldNames, itemKey, ...others }: SelectWithTitleProps): React.JSX.Element;
20
+ export declare function SelectWithTitle({ title, getDefaultValue, onChange, options, fieldNames, itemKey, tooltip, ...others }: SelectWithTitleProps): React.JSX.Element;
@@ -50,6 +50,7 @@ function SelectWithTitle({
50
50
  options,
51
51
  fieldNames,
52
52
  itemKey,
53
+ tooltip,
53
54
  ...others
54
55
  }) {
55
56
  const [open, setOpen] = (0, import_react.useState)(false);
@@ -80,6 +81,18 @@ function SelectWithTitle({
80
81
  setValue(val);
81
82
  onChange == null ? void 0 : onChange({ [itemKey]: val });
82
83
  }, "handleChange");
84
+ const titleNode = /* @__PURE__ */ import_react.default.createElement(
85
+ "span",
86
+ {
87
+ style: {
88
+ whiteSpace: "nowrap",
89
+ // 不换行
90
+ flexShrink: 0
91
+ // 不被挤压
92
+ }
93
+ },
94
+ title
95
+ );
83
96
  return /* @__PURE__ */ import_react.default.createElement(
84
97
  "div",
85
98
  {
@@ -94,18 +107,7 @@ function SelectWithTitle({
94
107
  }, 200);
95
108
  }
96
109
  },
97
- /* @__PURE__ */ import_react.default.createElement(
98
- "span",
99
- {
100
- style: {
101
- whiteSpace: "nowrap",
102
- // 不换行
103
- flexShrink: 0
104
- // 不被挤压
105
- }
106
- },
107
- title
108
- ),
110
+ tooltip ? /* @__PURE__ */ import_react.default.createElement(import_antd.Tooltip, { title: tooltip, placement: "top", destroyTooltipOnHide: true }, titleNode) : titleNode,
109
111
  /* @__PURE__ */ import_react.default.createElement(
110
112
  import_antd.Select,
111
113
  {
@@ -6,6 +6,7 @@
6
6
  * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
+ import type { DropdownProps } from 'antd';
9
10
  import React from 'react';
10
11
  import { FlowModel } from '../../../../models';
11
12
  /**
@@ -18,6 +19,8 @@ interface DefaultSettingsIconProps {
18
19
  showCopyUidButton?: boolean;
19
20
  menuLevels?: number;
20
21
  flattenSubMenus?: boolean;
22
+ onDropdownVisibleChange?: (open: boolean) => void;
23
+ getPopupContainer?: DropdownProps['getPopupContainer'];
21
24
  [key: string]: any;
22
25
  }
23
26
  export declare const DefaultSettingsIcon: React.FC<DefaultSettingsIconProps>;
@@ -41,6 +41,7 @@ __export(DefaultSettingsIcon_exports, {
41
41
  });
42
42
  module.exports = __toCommonJS(DefaultSettingsIcon_exports);
43
43
  var import_icons = require("@ant-design/icons");
44
+ var import_css = require("@emotion/css");
44
45
  var import_antd = require("antd");
45
46
  var import_react = __toESM(require("react"));
46
47
  var import_models = require("../../../../models");
@@ -48,6 +49,22 @@ var import_utils = require("../../../../utils");
48
49
  var import_hooks = require("../../../../hooks");
49
50
  var import_SwitchWithTitle = require("../component/SwitchWithTitle");
50
51
  var import_SelectWithTitle = require("../component/SelectWithTitle");
52
+ const findExtraMenuItemByKey = /* @__PURE__ */ __name((items, targetKey) => {
53
+ var _a;
54
+ for (const item of items) {
55
+ const itemKey = String((item == null ? void 0 : item.key) ?? "");
56
+ if (itemKey === targetKey) {
57
+ return item;
58
+ }
59
+ if ((_a = item.children) == null ? void 0 : _a.length) {
60
+ const matched = findExtraMenuItemByKey(item.children, targetKey);
61
+ if (matched) {
62
+ return matched;
63
+ }
64
+ }
65
+ }
66
+ return void 0;
67
+ }, "findExtraMenuItemByKey");
51
68
  const walkSubModels = /* @__PURE__ */ __name((rootModel, options, cb) => {
52
69
  const maxDepth = options.maxDepth;
53
70
  const arrayLimit = typeof options.arrayLimit === "number" ? options.arrayLimit : Number.POSITIVE_INFINITY;
@@ -149,13 +166,39 @@ const MenuLabelItem = /* @__PURE__ */ __name(({ title, uiMode, itemProps }) => {
149
166
  }
150
167
  return /* @__PURE__ */ import_react.default.createElement("span", { style: { display: "inline-flex", alignItems: "center", gap: 6 } }, content, /* @__PURE__ */ import_react.default.createElement(import_antd.Tooltip, { title: disabledReason, placement: "right", destroyTooltipOnHide: true }, /* @__PURE__ */ import_react.default.createElement(import_icons.QuestionCircleOutlined, { style: { color: disabledIconColor } })));
151
168
  }, "MenuLabelItem");
169
+ const TOOLBAR_ICONS_SELECTOR = ".nb-toolbar-container-icons";
170
+ const TOOLBAR_CONTAINER_SELECTOR = ".nb-toolbar-container";
171
+ const TOOLBAR_DROPDOWN_OVERLAY_CLASS = import_css.css`
172
+ width: max-content;
173
+ min-width: max-content;
174
+
175
+ .ant-dropdown-menu {
176
+ width: max-content;
177
+ min-width: max-content;
178
+ }
179
+ `;
180
+ const getToolbarPopupContainer = /* @__PURE__ */ __name((triggerNode) => {
181
+ if (!triggerNode) {
182
+ return null;
183
+ }
184
+ return triggerNode.closest(TOOLBAR_ICONS_SELECTOR) || triggerNode.closest(TOOLBAR_CONTAINER_SELECTOR);
185
+ }, "getToolbarPopupContainer");
186
+ const removeExtraMenuItemClickHandlers = /* @__PURE__ */ __name((item) => {
187
+ const { onClick: _onClick, children, ...rest } = item;
188
+ return {
189
+ ...rest,
190
+ children: (children == null ? void 0 : children.length) ? children.map(removeExtraMenuItemClickHandlers) : void 0
191
+ };
192
+ }, "removeExtraMenuItemClickHandlers");
152
193
  const DefaultSettingsIcon = /* @__PURE__ */ __name(({
153
194
  model,
154
195
  showDeleteButton = true,
155
196
  showCopyUidButton = true,
156
197
  menuLevels = 1,
157
198
  // 默认一级菜单
158
- flattenSubMenus = true
199
+ flattenSubMenus = true,
200
+ onDropdownVisibleChange,
201
+ getPopupContainer
159
202
  }) => {
160
203
  const { message } = import_antd.App.useApp();
161
204
  const t = (0, import_react.useMemo)(() => (0, import_utils.getT)(model), [model]);
@@ -168,14 +211,30 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
168
211
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
169
212
  const closeDropdown = (0, import_react.useCallback)(() => {
170
213
  setVisible(false);
171
- }, []);
172
- const handleOpenChange = (0, import_react.useCallback)((nextOpen, info) => {
173
- if (info.source === "trigger" || nextOpen) {
174
- (0, import_react.startTransition)(() => {
175
- setVisible(nextOpen);
176
- });
177
- }
178
- }, []);
214
+ onDropdownVisibleChange == null ? void 0 : onDropdownVisibleChange(false);
215
+ }, [onDropdownVisibleChange]);
216
+ const resolvePopupContainer = (0, import_react.useCallback)(
217
+ (triggerNode) => {
218
+ return getToolbarPopupContainer(triggerNode) || (getPopupContainer == null ? void 0 : getPopupContainer(triggerNode)) || (triggerNode == null ? void 0 : triggerNode.parentElement) || document.body;
219
+ },
220
+ [getPopupContainer]
221
+ );
222
+ const handleOpenChange = (0, import_react.useCallback)(
223
+ (nextOpen, info) => {
224
+ if (info.source === "trigger" || nextOpen) {
225
+ (0, import_react.startTransition)(() => {
226
+ setVisible(nextOpen);
227
+ });
228
+ onDropdownVisibleChange == null ? void 0 : onDropdownVisibleChange(nextOpen);
229
+ }
230
+ },
231
+ [onDropdownVisibleChange]
232
+ );
233
+ (0, import_react.useEffect)(() => {
234
+ return () => {
235
+ onDropdownVisibleChange == null ? void 0 : onDropdownVisibleChange(false);
236
+ };
237
+ }, [onDropdownVisibleChange]);
179
238
  const dropdownMaxHeight = (0, import_hooks.useNiceDropdownMaxHeight)([visible]);
180
239
  (0, import_react.useEffect)(() => {
181
240
  let mounted = true;
@@ -353,7 +412,10 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
353
412
  handleCopyPopupUid(cleanKey);
354
413
  return;
355
414
  }
356
- const extra = extraMenuItems.find((it) => (it == null ? void 0 : it.key) === originalKey || (it == null ? void 0 : it.key) === cleanKey);
415
+ const extra = findExtraMenuItemByKey(extraMenuItems, originalKey) || findExtraMenuItemByKey(extraMenuItems, cleanKey);
416
+ if (extra == null ? void 0 : extra.disabled) {
417
+ return;
418
+ }
357
419
  if (extra == null ? void 0 : extra.onClick) {
358
420
  closeDropdown();
359
421
  extra.onClick();
@@ -643,7 +705,7 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
643
705
  type: "divider"
644
706
  });
645
707
  if (commonExtras.length > 0) {
646
- items.push(...commonExtras);
708
+ items.push(...commonExtras.map(removeExtraMenuItemClickHandlers));
647
709
  }
648
710
  if (showCopyUidButton && model.uid) {
649
711
  items.push({
@@ -671,6 +733,9 @@ const DefaultSettingsIcon = /* @__PURE__ */ __name(({
671
733
  return /* @__PURE__ */ import_react.default.createElement(
672
734
  import_antd.Dropdown,
673
735
  {
736
+ getPopupContainer: resolvePopupContainer,
737
+ overlayClassName: TOOLBAR_DROPDOWN_OVERLAY_CLASS,
738
+ overlayStyle: { width: "max-content", minWidth: "max-content" },
674
739
  onOpenChange: handleOpenChange,
675
740
  open: visible,
676
741
  menu: {