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

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 (194) hide show
  1. package/LICENSE +201 -661
  2. package/README.md +79 -10
  3. package/lib/JSRunner.d.ts +10 -1
  4. package/lib/JSRunner.js +50 -5
  5. package/lib/ViewScopedFlowEngine.js +5 -1
  6. package/lib/components/FieldModelRenderer.js +2 -2
  7. package/lib/components/FlowModelRenderer.d.ts +3 -1
  8. package/lib/components/FlowModelRenderer.js +12 -6
  9. package/lib/components/FormItem.d.ts +6 -0
  10. package/lib/components/FormItem.js +11 -3
  11. package/lib/components/MobilePopup.js +6 -5
  12. package/lib/components/dnd/gridDragPlanner.d.ts +59 -2
  13. package/lib/components/dnd/gridDragPlanner.js +613 -21
  14. package/lib/components/dnd/index.d.ts +31 -2
  15. package/lib/components/dnd/index.js +244 -23
  16. package/lib/components/settings/wrappers/component/SelectWithTitle.d.ts +2 -1
  17. package/lib/components/settings/wrappers/component/SelectWithTitle.js +14 -12
  18. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
  19. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +68 -10
  20. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +23 -43
  21. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +352 -295
  22. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +16 -2
  23. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
  24. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +274 -0
  25. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
  26. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +315 -0
  27. package/lib/components/subModel/AddSubModelButton.js +27 -1
  28. package/lib/components/subModel/LazyDropdown.js +96 -39
  29. package/lib/components/subModel/index.d.ts +1 -0
  30. package/lib/components/subModel/index.js +19 -0
  31. package/lib/components/subModel/utils.d.ts +1 -1
  32. package/lib/components/subModel/utils.js +9 -3
  33. package/lib/components/variables/VariableHybridInput.d.ts +27 -0
  34. package/lib/components/variables/VariableHybridInput.js +499 -0
  35. package/lib/components/variables/index.d.ts +2 -0
  36. package/lib/components/variables/index.js +3 -0
  37. package/lib/data-source/index.d.ts +75 -0
  38. package/lib/data-source/index.js +247 -5
  39. package/lib/executor/FlowExecutor.js +32 -9
  40. package/lib/flow-registry/DetachedFlowRegistry.d.ts +21 -0
  41. package/lib/flow-registry/DetachedFlowRegistry.js +80 -0
  42. package/lib/flow-registry/index.d.ts +1 -0
  43. package/lib/flow-registry/index.js +3 -1
  44. package/lib/flowContext.d.ts +3 -0
  45. package/lib/flowContext.js +43 -1
  46. package/lib/flowEngine.d.ts +151 -1
  47. package/lib/flowEngine.js +389 -15
  48. package/lib/flowI18n.js +2 -1
  49. package/lib/flowSettings.d.ts +14 -6
  50. package/lib/flowSettings.js +34 -6
  51. package/lib/index.d.ts +2 -0
  52. package/lib/index.js +7 -0
  53. package/lib/lazy-helper.d.ts +14 -0
  54. package/lib/lazy-helper.js +71 -0
  55. package/lib/locale/en-US.json +1 -0
  56. package/lib/locale/index.d.ts +2 -0
  57. package/lib/locale/zh-CN.json +1 -0
  58. package/lib/models/DisplayItemModel.d.ts +1 -1
  59. package/lib/models/EditableItemModel.d.ts +1 -1
  60. package/lib/models/FilterableItemModel.d.ts +1 -1
  61. package/lib/models/flowModel.d.ts +13 -10
  62. package/lib/models/flowModel.js +78 -18
  63. package/lib/provider.js +38 -23
  64. package/lib/reactive/observer.js +46 -16
  65. package/lib/runjs-context/registry.d.ts +1 -1
  66. package/lib/runjs-context/setup.js +20 -12
  67. package/lib/runjs-context/snippets/index.js +13 -2
  68. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
  69. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
  70. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
  71. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
  72. package/lib/scheduler/ModelOperationScheduler.d.ts +5 -1
  73. package/lib/scheduler/ModelOperationScheduler.js +3 -2
  74. package/lib/types.d.ts +50 -2
  75. package/lib/types.js +1 -0
  76. package/lib/utils/createCollectionContextMeta.js +6 -2
  77. package/lib/utils/index.d.ts +3 -2
  78. package/lib/utils/index.js +7 -0
  79. package/lib/utils/parsePathnameToViewParams.js +1 -1
  80. package/lib/utils/randomId.d.ts +39 -0
  81. package/lib/utils/randomId.js +45 -0
  82. package/lib/utils/runjsTemplateCompat.js +1 -1
  83. package/lib/utils/runjsValue.js +41 -11
  84. package/lib/utils/schema-utils.d.ts +7 -1
  85. package/lib/utils/schema-utils.js +19 -0
  86. package/lib/views/FlowView.d.ts +7 -1
  87. package/lib/views/FlowView.js +11 -1
  88. package/lib/views/PageComponent.js +8 -6
  89. package/lib/views/ViewNavigation.js +6 -2
  90. package/lib/views/runViewBeforeClose.d.ts +10 -0
  91. package/lib/views/runViewBeforeClose.js +45 -0
  92. package/lib/views/useDialog.d.ts +2 -1
  93. package/lib/views/useDialog.js +20 -3
  94. package/lib/views/useDrawer.d.ts +2 -1
  95. package/lib/views/useDrawer.js +20 -3
  96. package/lib/views/usePage.d.ts +5 -11
  97. package/lib/views/usePage.js +302 -144
  98. package/package.json +6 -5
  99. package/src/JSRunner.ts +68 -4
  100. package/src/ViewScopedFlowEngine.ts +4 -0
  101. package/src/__tests__/JSRunner.test.ts +27 -1
  102. package/src/__tests__/flow-engine.test.ts +166 -0
  103. package/src/__tests__/flowContext.test.ts +82 -1
  104. package/src/__tests__/flowEngine.modelLoaders.test.ts +245 -0
  105. package/src/__tests__/flowSettings.test.ts +94 -15
  106. package/src/__tests__/objectVariable.test.ts +24 -0
  107. package/src/__tests__/provider.test.tsx +24 -2
  108. package/src/__tests__/renderHiddenInConfig.test.tsx +6 -6
  109. package/src/__tests__/runjsContext.test.ts +16 -0
  110. package/src/__tests__/runjsContextRuntime.test.ts +2 -0
  111. package/src/__tests__/runjsPreprocessDefault.test.ts +23 -0
  112. package/src/__tests__/runjsSnippets.test.ts +21 -0
  113. package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
  114. package/src/components/FieldModelRenderer.tsx +2 -1
  115. package/src/components/FlowModelRenderer.tsx +18 -6
  116. package/src/components/FormItem.tsx +7 -1
  117. package/src/components/MobilePopup.tsx +4 -2
  118. package/src/components/__tests__/FlowModelRenderer.test.tsx +65 -2
  119. package/src/components/__tests__/FormItem.test.tsx +25 -0
  120. package/src/components/__tests__/dnd.test.ts +44 -0
  121. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +20 -10
  122. package/src/components/__tests__/gridDragPlanner.test.ts +558 -3
  123. package/src/components/dnd/__tests__/DndProvider.test.tsx +98 -0
  124. package/src/components/dnd/gridDragPlanner.ts +758 -19
  125. package/src/components/dnd/index.tsx +305 -28
  126. package/src/components/settings/wrappers/component/SelectWithTitle.tsx +21 -9
  127. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +88 -10
  128. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +487 -440
  129. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +18 -2
  130. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +189 -3
  131. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +778 -0
  132. package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +360 -0
  133. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +361 -0
  134. package/src/components/subModel/AddSubModelButton.tsx +32 -2
  135. package/src/components/subModel/LazyDropdown.tsx +107 -43
  136. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +319 -36
  137. package/src/components/subModel/__tests__/utils.test.ts +24 -0
  138. package/src/components/subModel/index.ts +1 -0
  139. package/src/components/subModel/utils.ts +7 -1
  140. package/src/components/variables/VariableHybridInput.tsx +531 -0
  141. package/src/components/variables/index.ts +2 -0
  142. package/src/data-source/__tests__/collection.test.ts +41 -2
  143. package/src/data-source/__tests__/index.test.ts +68 -1
  144. package/src/data-source/index.ts +304 -6
  145. package/src/executor/FlowExecutor.ts +35 -10
  146. package/src/executor/__tests__/flowExecutor.test.ts +57 -0
  147. package/src/flow-registry/DetachedFlowRegistry.ts +46 -0
  148. package/src/flow-registry/__tests__/detachedFlowRegistry.test.ts +47 -0
  149. package/src/flow-registry/index.ts +1 -0
  150. package/src/flowContext.ts +47 -3
  151. package/src/flowEngine.ts +445 -11
  152. package/src/flowI18n.ts +2 -1
  153. package/src/flowSettings.ts +40 -6
  154. package/src/index.ts +2 -0
  155. package/src/lazy-helper.tsx +57 -0
  156. package/src/locale/en-US.json +1 -0
  157. package/src/locale/zh-CN.json +1 -0
  158. package/src/models/DisplayItemModel.tsx +1 -1
  159. package/src/models/EditableItemModel.tsx +1 -1
  160. package/src/models/FilterableItemModel.tsx +1 -1
  161. package/src/models/__tests__/dispatchEvent.when.test.ts +214 -0
  162. package/src/models/__tests__/flowModel.test.ts +47 -3
  163. package/src/models/flowModel.tsx +119 -33
  164. package/src/provider.tsx +41 -25
  165. package/src/reactive/__tests__/observer.test.tsx +82 -0
  166. package/src/reactive/observer.tsx +87 -25
  167. package/src/runjs-context/registry.ts +1 -1
  168. package/src/runjs-context/setup.ts +22 -12
  169. package/src/runjs-context/snippets/index.ts +12 -1
  170. package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
  171. package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
  172. package/src/scheduler/ModelOperationScheduler.ts +14 -3
  173. package/src/types.ts +62 -0
  174. package/src/utils/__tests__/createCollectionContextMeta.test.ts +48 -0
  175. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +7 -0
  176. package/src/utils/__tests__/runjsValue.test.ts +11 -0
  177. package/src/utils/__tests__/utils.test.ts +62 -0
  178. package/src/utils/createCollectionContextMeta.ts +6 -2
  179. package/src/utils/index.ts +5 -1
  180. package/src/utils/parsePathnameToViewParams.ts +2 -2
  181. package/src/utils/randomId.ts +48 -0
  182. package/src/utils/runjsTemplateCompat.ts +1 -1
  183. package/src/utils/runjsValue.ts +50 -11
  184. package/src/utils/schema-utils.ts +30 -1
  185. package/src/views/FlowView.tsx +22 -2
  186. package/src/views/PageComponent.tsx +7 -4
  187. package/src/views/ViewNavigation.ts +6 -2
  188. package/src/views/__tests__/FlowView.usePage.test.tsx +243 -3
  189. package/src/views/__tests__/runViewBeforeClose.test.ts +30 -0
  190. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +13 -12
  191. package/src/views/runViewBeforeClose.ts +19 -0
  192. package/src/views/useDialog.tsx +25 -3
  193. package/src/views/useDrawer.tsx +25 -3
  194. package/src/views/usePage.tsx +365 -179
@@ -0,0 +1,315 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var useFloatToolbarVisibility_exports = {};
29
+ __export(useFloatToolbarVisibility_exports, {
30
+ useFloatToolbarVisibility: () => useFloatToolbarVisibility
31
+ });
32
+ module.exports = __toCommonJS(useFloatToolbarVisibility_exports);
33
+ var import_react = require("react");
34
+ var import_dnd = require("../../../dnd");
35
+ const TOOLBAR_HIDE_DELAY = 180;
36
+ const CHILD_FLOAT_MENU_ACTIVITY_EVENT = "nb-float-menu-child-activity";
37
+ const isNodeWithin = /* @__PURE__ */ __name((target, container) => {
38
+ return target instanceof Node && !!(container == null ? void 0 : container.contains(target));
39
+ }, "isNodeWithin");
40
+ const getToolbarModelUidFromTarget = /* @__PURE__ */ __name((target) => {
41
+ var _a;
42
+ if (!(target instanceof Element)) {
43
+ return null;
44
+ }
45
+ return ((_a = target.closest(".nb-toolbar-container[data-model-uid]")) == null ? void 0 : _a.getAttribute("data-model-uid")) || null;
46
+ }, "getToolbarModelUidFromTarget");
47
+ const isNodeWithinDescendantFloatToolbar = /* @__PURE__ */ __name((target, container, currentModelUid) => {
48
+ const targetModelUid = getToolbarModelUidFromTarget(target);
49
+ if (!container || !targetModelUid || targetModelUid === currentModelUid) {
50
+ return false;
51
+ }
52
+ return Array.from(
53
+ container.querySelectorAll('[data-has-float-menu="true"][data-float-menu-model-uid]')
54
+ ).some(
55
+ (hostElement) => hostElement !== container && hostElement.getAttribute("data-float-menu-model-uid") === targetModelUid
56
+ );
57
+ }, "isNodeWithinDescendantFloatToolbar");
58
+ const useFloatToolbarVisibility = /* @__PURE__ */ __name(({
59
+ modelUid,
60
+ containerRef,
61
+ toolbarContainerRef,
62
+ updatePortalRect,
63
+ schedulePortalRectUpdate
64
+ }) => {
65
+ const [hideMenu, setHideMenu] = (0, import_react.useState)(false);
66
+ const [isHostHovered, setIsHostHovered] = (0, import_react.useState)(false);
67
+ const [isToolbarHovered, setIsToolbarHovered] = (0, import_react.useState)(false);
68
+ const [isDraggingToolbar, setIsDraggingToolbar] = (0, import_react.useState)(false);
69
+ const [isDraggingToolbarItem, setIsDraggingToolbarItem] = (0, import_react.useState)(false);
70
+ const [isToolbarPinned, setIsToolbarPinned] = (0, import_react.useState)(false);
71
+ const [isHidePending, setIsHidePending] = (0, import_react.useState)(false);
72
+ const [activeChildToolbarIds, setActiveChildToolbarIds] = (0, import_react.useState)([]);
73
+ const hideToolbarTimerRef = (0, import_react.useRef)(null);
74
+ const reportedChildActivityToAncestorsRef = (0, import_react.useRef)(false);
75
+ const isHostHoveredRef = (0, import_react.useRef)(false);
76
+ const isToolbarHoveredRef = (0, import_react.useRef)(false);
77
+ const isDraggingToolbarRef = (0, import_react.useRef)(false);
78
+ const isDraggingToolbarItemRef = (0, import_react.useRef)(false);
79
+ const isToolbarPinnedRef = (0, import_react.useRef)(false);
80
+ const setHostHovered = (0, import_react.useCallback)((value) => {
81
+ isHostHoveredRef.current = value;
82
+ setIsHostHovered(value);
83
+ }, []);
84
+ const setToolbarHovered = (0, import_react.useCallback)((value) => {
85
+ isToolbarHoveredRef.current = value;
86
+ setIsToolbarHovered(value);
87
+ }, []);
88
+ const setDraggingToolbar = (0, import_react.useCallback)((value) => {
89
+ isDraggingToolbarRef.current = value;
90
+ setIsDraggingToolbar(value);
91
+ }, []);
92
+ const setDraggingToolbarItem = (0, import_react.useCallback)((value) => {
93
+ isDraggingToolbarItemRef.current = value;
94
+ setIsDraggingToolbarItem(value);
95
+ }, []);
96
+ const setToolbarPinned = (0, import_react.useCallback)((value) => {
97
+ isToolbarPinnedRef.current = value;
98
+ setIsToolbarPinned(value);
99
+ }, []);
100
+ const hasActiveChildToolbar = activeChildToolbarIds.length > 0;
101
+ const isToolbarVisible = !hideMenu && !hasActiveChildToolbar && (isHostHovered || isToolbarHovered || isDraggingToolbar || isDraggingToolbarItem || isToolbarPinned);
102
+ const shouldRenderToolbar = isToolbarVisible || isToolbarPinned || isDraggingToolbar || isDraggingToolbarItem;
103
+ const isToolbarInteractionActive = isHostHovered || isToolbarHovered || isDraggingToolbar || isDraggingToolbarItem || isToolbarPinned || isHidePending;
104
+ const clearHideToolbarTimer = (0, import_react.useCallback)(() => {
105
+ if (hideToolbarTimerRef.current !== null) {
106
+ window.clearTimeout(hideToolbarTimerRef.current);
107
+ hideToolbarTimerRef.current = null;
108
+ }
109
+ setIsHidePending(false);
110
+ }, []);
111
+ const scheduleHideToolbar = (0, import_react.useCallback)(() => {
112
+ clearHideToolbarTimer();
113
+ setIsHidePending(true);
114
+ hideToolbarTimerRef.current = window.setTimeout(() => {
115
+ hideToolbarTimerRef.current = null;
116
+ setIsHidePending(false);
117
+ if (isDraggingToolbarRef.current || isDraggingToolbarItemRef.current || isToolbarPinnedRef.current) {
118
+ return;
119
+ }
120
+ setHostHovered(false);
121
+ setToolbarHovered(false);
122
+ }, TOOLBAR_HIDE_DELAY);
123
+ }, [clearHideToolbarTimer, setHostHovered, setToolbarHovered]);
124
+ const handleSettingsMenuOpenChange = (0, import_react.useCallback)(
125
+ (open) => {
126
+ setToolbarPinned(open);
127
+ },
128
+ [setToolbarPinned]
129
+ );
130
+ (0, import_react.useEffect)(() => {
131
+ const hostElement = containerRef.current;
132
+ if (!hostElement) {
133
+ return;
134
+ }
135
+ const handleChildToolbarActivity = /* @__PURE__ */ __name((event) => {
136
+ var _a;
137
+ const customEvent = event;
138
+ if (!(customEvent.target instanceof HTMLElement) || customEvent.target === hostElement) {
139
+ return;
140
+ }
141
+ const childModelUid = (_a = customEvent.detail) == null ? void 0 : _a.modelUid;
142
+ if (!childModelUid) {
143
+ return;
144
+ }
145
+ setActiveChildToolbarIds((prevIds) => {
146
+ var _a2;
147
+ return ((_a2 = customEvent.detail) == null ? void 0 : _a2.active) ? prevIds.includes(childModelUid) ? prevIds : [...prevIds, childModelUid] : prevIds.filter((id) => id !== childModelUid);
148
+ });
149
+ }, "handleChildToolbarActivity");
150
+ hostElement.addEventListener(CHILD_FLOAT_MENU_ACTIVITY_EVENT, handleChildToolbarActivity);
151
+ return () => {
152
+ hostElement.removeEventListener(CHILD_FLOAT_MENU_ACTIVITY_EVENT, handleChildToolbarActivity);
153
+ };
154
+ }, [containerRef]);
155
+ (0, import_react.useEffect)(() => {
156
+ const hostElement = containerRef.current;
157
+ const ownerDocument = hostElement == null ? void 0 : hostElement.ownerDocument;
158
+ if (!ownerDocument) {
159
+ return;
160
+ }
161
+ const handleToolbarDragActivity = /* @__PURE__ */ __name((event) => {
162
+ var _a, _b;
163
+ const customEvent = event;
164
+ if (((_a = customEvent.detail) == null ? void 0 : _a.modelUid) !== modelUid) {
165
+ return;
166
+ }
167
+ if ((_b = customEvent.detail) == null ? void 0 : _b.active) {
168
+ clearHideToolbarTimer();
169
+ setDraggingToolbarItem(true);
170
+ return;
171
+ }
172
+ setDraggingToolbarItem(false);
173
+ if (isHostHoveredRef.current || isToolbarHoveredRef.current || isToolbarPinnedRef.current) {
174
+ clearHideToolbarTimer();
175
+ return;
176
+ }
177
+ scheduleHideToolbar();
178
+ }, "handleToolbarDragActivity");
179
+ ownerDocument.addEventListener(import_dnd.TOOLBAR_DRAG_ACTIVITY_EVENT, handleToolbarDragActivity);
180
+ return () => {
181
+ ownerDocument.removeEventListener(import_dnd.TOOLBAR_DRAG_ACTIVITY_EVENT, handleToolbarDragActivity);
182
+ };
183
+ }, [clearHideToolbarTimer, containerRef, modelUid, scheduleHideToolbar, setDraggingToolbarItem]);
184
+ (0, import_react.useEffect)(() => {
185
+ const hostElement = containerRef.current;
186
+ if (!hostElement || reportedChildActivityToAncestorsRef.current === isToolbarInteractionActive) {
187
+ return;
188
+ }
189
+ reportedChildActivityToAncestorsRef.current = isToolbarInteractionActive;
190
+ hostElement.dispatchEvent(
191
+ new CustomEvent(CHILD_FLOAT_MENU_ACTIVITY_EVENT, {
192
+ bubbles: true,
193
+ detail: { active: isToolbarInteractionActive, modelUid }
194
+ })
195
+ );
196
+ }, [containerRef, isToolbarInteractionActive, modelUid]);
197
+ (0, import_react.useEffect)(() => {
198
+ const hostElement = containerRef.current;
199
+ return () => {
200
+ if (hostElement && reportedChildActivityToAncestorsRef.current) {
201
+ hostElement.dispatchEvent(
202
+ new CustomEvent(CHILD_FLOAT_MENU_ACTIVITY_EVENT, {
203
+ bubbles: true,
204
+ detail: { active: false, modelUid }
205
+ })
206
+ );
207
+ reportedChildActivityToAncestorsRef.current = false;
208
+ }
209
+ clearHideToolbarTimer();
210
+ };
211
+ }, [clearHideToolbarTimer, containerRef, modelUid]);
212
+ (0, import_react.useEffect)(() => {
213
+ if (isToolbarPinned) {
214
+ clearHideToolbarTimer();
215
+ updatePortalRect();
216
+ }
217
+ }, [clearHideToolbarTimer, isToolbarPinned, updatePortalRect]);
218
+ const handleChildHover = (0, import_react.useCallback)(
219
+ (e) => {
220
+ const target = e.target;
221
+ const childWithMenu = target.closest("[data-has-float-menu]");
222
+ const isCurrentHostTarget = !childWithMenu || childWithMenu === containerRef.current;
223
+ if (isCurrentHostTarget) {
224
+ clearHideToolbarTimer();
225
+ setHostHovered(true);
226
+ }
227
+ setHideMenu(!!childWithMenu && childWithMenu !== containerRef.current);
228
+ },
229
+ [clearHideToolbarTimer, containerRef, setHostHovered]
230
+ );
231
+ const handleHostMouseEnter = (0, import_react.useCallback)(() => {
232
+ clearHideToolbarTimer();
233
+ setHideMenu(false);
234
+ updatePortalRect();
235
+ setHostHovered(true);
236
+ }, [clearHideToolbarTimer, setHostHovered, updatePortalRect]);
237
+ const handleHostMouseLeave = (0, import_react.useCallback)(
238
+ (e) => {
239
+ if (isToolbarPinnedRef.current) {
240
+ setHostHovered(false);
241
+ return;
242
+ }
243
+ if (isNodeWithin(e.relatedTarget, toolbarContainerRef.current)) {
244
+ clearHideToolbarTimer();
245
+ setHostHovered(false);
246
+ setToolbarHovered(true);
247
+ return;
248
+ }
249
+ if (isNodeWithinDescendantFloatToolbar(e.relatedTarget, containerRef.current, modelUid)) {
250
+ clearHideToolbarTimer();
251
+ setHideMenu(false);
252
+ setHostHovered(true);
253
+ return;
254
+ }
255
+ scheduleHideToolbar();
256
+ },
257
+ [
258
+ clearHideToolbarTimer,
259
+ containerRef,
260
+ modelUid,
261
+ scheduleHideToolbar,
262
+ setHostHovered,
263
+ setToolbarHovered,
264
+ toolbarContainerRef
265
+ ]
266
+ );
267
+ const handleToolbarMouseEnter = (0, import_react.useCallback)(() => {
268
+ clearHideToolbarTimer();
269
+ updatePortalRect();
270
+ setHostHovered(false);
271
+ setToolbarHovered(true);
272
+ }, [clearHideToolbarTimer, setHostHovered, setToolbarHovered, updatePortalRect]);
273
+ const handleToolbarMouseLeave = (0, import_react.useCallback)(
274
+ (e) => {
275
+ if (isToolbarPinnedRef.current || isDraggingToolbarItemRef.current) {
276
+ clearHideToolbarTimer();
277
+ setToolbarHovered(false);
278
+ return;
279
+ }
280
+ setToolbarHovered(false);
281
+ if (isNodeWithin(e.relatedTarget, containerRef.current)) {
282
+ clearHideToolbarTimer();
283
+ setHostHovered(true);
284
+ return;
285
+ }
286
+ scheduleHideToolbar();
287
+ },
288
+ [clearHideToolbarTimer, containerRef, scheduleHideToolbar, setHostHovered, setToolbarHovered]
289
+ );
290
+ const handleResizeDragStart = (0, import_react.useCallback)(() => {
291
+ updatePortalRect();
292
+ setDraggingToolbar(true);
293
+ schedulePortalRectUpdate();
294
+ }, [schedulePortalRectUpdate, setDraggingToolbar, updatePortalRect]);
295
+ const handleResizeDragEnd = (0, import_react.useCallback)(() => {
296
+ setDraggingToolbar(false);
297
+ schedulePortalRectUpdate();
298
+ }, [schedulePortalRectUpdate, setDraggingToolbar]);
299
+ return {
300
+ isToolbarVisible,
301
+ shouldRenderToolbar,
302
+ handleSettingsMenuOpenChange,
303
+ handleChildHover,
304
+ handleHostMouseEnter,
305
+ handleHostMouseLeave,
306
+ handleToolbarMouseEnter,
307
+ handleToolbarMouseLeave,
308
+ handleResizeDragStart,
309
+ handleResizeDragEnd
310
+ };
311
+ }, "useFloatToolbarVisibility");
312
+ // Annotate the CommonJS export names for ESM import in node:
313
+ 0 && (module.exports = {
314
+ useFloatToolbarVisibility
315
+ });
@@ -376,6 +376,21 @@ const AddSubModelButtonCore = /* @__PURE__ */ __name(function AddSubModelButton(
376
376
  }),
377
377
  [model, subModelKey, subModelType]
378
378
  );
379
+ import_react.default.useEffect(() => {
380
+ var _a, _b, _c;
381
+ const handleSubModelChanged = /* @__PURE__ */ __name(() => {
382
+ setRefreshTick((x) => x + 1);
383
+ }, "handleSubModelChanged");
384
+ (_a = model.emitter) == null ? void 0 : _a.on("onSubModelAdded", handleSubModelChanged);
385
+ (_b = model.emitter) == null ? void 0 : _b.on("onSubModelRemoved", handleSubModelChanged);
386
+ (_c = model.emitter) == null ? void 0 : _c.on("onSubModelReplaced", handleSubModelChanged);
387
+ return () => {
388
+ var _a2, _b2, _c2;
389
+ (_a2 = model.emitter) == null ? void 0 : _a2.off("onSubModelAdded", handleSubModelChanged);
390
+ (_b2 = model.emitter) == null ? void 0 : _b2.off("onSubModelRemoved", handleSubModelChanged);
391
+ (_c2 = model.emitter) == null ? void 0 : _c2.off("onSubModelReplaced", handleSubModelChanged);
392
+ };
393
+ }, [model]);
379
394
  const onClick = /* @__PURE__ */ __name(async (info) => {
380
395
  const clickedItem = info.originalItem || info;
381
396
  const item = clickedItem.originalItem || clickedItem;
@@ -415,7 +430,7 @@ const AddSubModelButtonCore = /* @__PURE__ */ __name(function AddSubModelButton(
415
430
  }
416
431
  let addedModel;
417
432
  try {
418
- addedModel = model.flowEngine.createModel({
433
+ addedModel = await model.flowEngine.createModelAsync({
419
434
  ...import_lodash.default.cloneDeep(createOpts),
420
435
  parentId: model.uid,
421
436
  subKey: subModelKey,
@@ -461,6 +476,17 @@ const AddSubModelButtonCore = /* @__PURE__ */ __name(function AddSubModelButton(
461
476
  () => transformItems(finalItems, model, subModelKey, subModelType),
462
477
  [finalItems, model, subModelKey, subModelType]
463
478
  );
479
+ (0, import_react.useEffect)(() => {
480
+ const handleSubModelChange = /* @__PURE__ */ __name(() => {
481
+ setRefreshTick((x) => x + 1);
482
+ }, "handleSubModelChange");
483
+ model.emitter.on("onSubModelAdded", handleSubModelChange);
484
+ model.emitter.on("onSubModelRemoved", handleSubModelChange);
485
+ return () => {
486
+ model.emitter.off("onSubModelAdded", handleSubModelChange);
487
+ model.emitter.off("onSubModelRemoved", handleSubModelChange);
488
+ };
489
+ }, [model]);
464
490
  return /* @__PURE__ */ import_react.default.createElement(
465
491
  import_LazyDropdown.default,
466
492
  {
@@ -253,6 +253,28 @@ const SearchInputWithAutoFocus = /* @__PURE__ */ __name((props) => {
253
253
  return /* @__PURE__ */ import_react.default.createElement(import_antd.Input, { ref: inputRef, ...rest });
254
254
  }, "SearchInputWithAutoFocus");
255
255
  const getKeyPath = /* @__PURE__ */ __name((path, key) => [...path, key].join("/"), "getKeyPath");
256
+ const normalizeOpenKeys = /* @__PURE__ */ __name((nextOpenKeys) => {
257
+ const latestKey = nextOpenKeys[nextOpenKeys.length - 1];
258
+ if (!latestKey) {
259
+ return [];
260
+ }
261
+ return nextOpenKeys.filter((key) => latestKey === key || latestKey.startsWith(`${key}/`));
262
+ }, "normalizeOpenKeys");
263
+ const getLabelSearchText = /* @__PURE__ */ __name((label) => {
264
+ if (label === null || label === void 0 || typeof label === "boolean") {
265
+ return "";
266
+ }
267
+ if (typeof label === "string" || typeof label === "number") {
268
+ return String(label);
269
+ }
270
+ if (Array.isArray(label)) {
271
+ return label.map(getLabelSearchText).join(" ");
272
+ }
273
+ if (import_react.default.isValidElement(label)) {
274
+ return getLabelSearchText(label.props.children);
275
+ }
276
+ return "";
277
+ }, "getLabelSearchText");
256
278
  const createSearchItem = /* @__PURE__ */ __name((item, searchKey, currentSearchValue, menuVisible, t, updateSearchValue) => ({
257
279
  key: `${searchKey}-search`,
258
280
  type: "group",
@@ -286,6 +308,10 @@ const createEmptyItem = /* @__PURE__ */ __name((itemKey, t) => ({
286
308
  label: /* @__PURE__ */ import_react.default.createElement("div", { style: { padding: "16px", textAlign: "center" } }, /* @__PURE__ */ import_react.default.createElement(import_antd.Empty, { image: import_antd.Empty.PRESENTED_IMAGE_SIMPLE, description: t("No data"), style: { margin: 0 } })),
287
309
  disabled: true
288
310
  }), "createEmptyItem");
311
+ const KEEP_OPEN_LABEL_STYLE = {
312
+ display: "block",
313
+ width: "100%"
314
+ };
289
315
  const DROPDOWN_PERSIST_TTL_MS = 350;
290
316
  const dropdownPersistRegistry = /* @__PURE__ */ new Map();
291
317
  const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
@@ -307,6 +333,19 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
307
333
  const { searchValues, isSearching, updateSearchValue } = useMenuSearch();
308
334
  const { requestKeepOpen, shouldPreventClose } = useKeepDropdownOpen();
309
335
  useSubmenuStyles(menuVisible, dropdownMaxHeight);
336
+ const handleMenuOpenChange = (0, import_react.useCallback)(
337
+ (nextOpenKeys) => {
338
+ var _a, _b;
339
+ if (!nextOpenKeys.length && shouldPreventClose()) {
340
+ (_a = dropdownMenuProps.onOpenChange) == null ? void 0 : _a.call(dropdownMenuProps, Array.from(openKeys));
341
+ return;
342
+ }
343
+ const normalized = normalizeOpenKeys(nextOpenKeys);
344
+ setOpenKeys(new Set(normalized));
345
+ (_b = dropdownMenuProps.onOpenChange) == null ? void 0 : _b.call(dropdownMenuProps, normalized);
346
+ },
347
+ [dropdownMenuProps, openKeys, shouldPreventClose]
348
+ );
310
349
  (0, import_react.useEffect)(() => {
311
350
  if (!persistKey) return;
312
351
  const until = dropdownPersistRegistry.get(persistKey) || 0;
@@ -326,6 +365,11 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
326
365
  }
327
366
  };
328
367
  }, [persistKey, menuVisible]);
368
+ (0, import_react.useEffect)(() => {
369
+ if (!menuVisible) {
370
+ setOpenKeys(/* @__PURE__ */ new Set());
371
+ }
372
+ }, [menuVisible]);
329
373
  (0, import_react.useEffect)(() => {
330
374
  const loadRootItems = /* @__PURE__ */ __name(async () => {
331
375
  let resolvedItems;
@@ -349,13 +393,9 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
349
393
  const currentSearchValue = searchValues[searchKey] || "";
350
394
  const filteredChildren = currentSearchValue ? (/* @__PURE__ */ __name(function deepFilter(items2) {
351
395
  const searchText = currentSearchValue.toLowerCase();
352
- const tryString = /* @__PURE__ */ __name((v) => {
353
- if (!v) return "";
354
- return typeof v === "string" ? v : String(v);
355
- }, "tryString");
356
396
  return items2.map((child) => {
357
- const labelStr = tryString(child.label).toLowerCase();
358
- const selfMatch = labelStr.includes(searchText) || child.key && String(child.key).toLowerCase().includes(searchText);
397
+ const labelStr = getLabelSearchText(child.label).toLowerCase();
398
+ const selfMatch = labelStr.includes(searchText);
359
399
  if (child.type === "group" && Array.isArray(child.children)) {
360
400
  const nested = deepFilter(child.children);
361
401
  if (selfMatch || nested.length > 0) {
@@ -419,51 +459,66 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
419
459
  if (item.type === "divider") {
420
460
  return { type: "divider", key: keyPath };
421
461
  }
462
+ const label = typeof item.label === "string" ? t(item.label) : item.label;
422
463
  if (item.searchable && children) {
423
464
  return {
424
- key: item.key,
425
- label: typeof item.label === "string" ? t(item.label) : item.label,
465
+ key: keyPath,
466
+ label,
426
467
  onClick: /* @__PURE__ */ __name((info) => {
427
468
  }, "onClick"),
428
- onMouseEnter: /* @__PURE__ */ __name(() => {
429
- setOpenKeys((prev) => {
430
- if (prev.has(keyPath)) return prev;
431
- const next = new Set(prev);
432
- next.add(keyPath);
433
- return next;
434
- });
435
- }, "onMouseEnter"),
436
469
  children: buildSearchChildren(children, item, keyPath, path, menuVisible, resolveItems)
437
470
  };
438
471
  }
472
+ const itemShouldKeepOpen = !children && (item.keepDropdownOpen ?? keepDropdownOpen ?? false);
473
+ const handleLeafClick = /* @__PURE__ */ __name((info) => {
474
+ var _a;
475
+ if (children) {
476
+ return;
477
+ }
478
+ if (itemShouldKeepOpen) {
479
+ requestKeepOpen();
480
+ }
481
+ const extendedInfo = {
482
+ ...info,
483
+ key: (info == null ? void 0 : info.key) ?? keyPath,
484
+ keyPath: (info == null ? void 0 : info.keyPath) ?? [keyPath],
485
+ item: (info == null ? void 0 : info.item) || item,
486
+ originalItem: item,
487
+ keepDropdownOpen: itemShouldKeepOpen
488
+ };
489
+ (_a = menu.onClick) == null ? void 0 : _a.call(menu, extendedInfo);
490
+ }, "handleLeafClick");
439
491
  return {
440
492
  key: keyPath,
441
- label: typeof item.label === "string" ? t(item.label) : item.label,
493
+ label: itemShouldKeepOpen ? /* @__PURE__ */ import_react.default.createElement(
494
+ "div",
495
+ {
496
+ style: KEEP_OPEN_LABEL_STYLE,
497
+ onMouseDown: (event) => {
498
+ event.stopPropagation();
499
+ requestKeepOpen();
500
+ },
501
+ onClick: (event) => {
502
+ event.stopPropagation();
503
+ handleLeafClick({
504
+ key: keyPath,
505
+ keyPath: [keyPath],
506
+ item,
507
+ domEvent: event
508
+ });
509
+ }
510
+ },
511
+ label
512
+ ) : label,
442
513
  onClick: /* @__PURE__ */ __name((info) => {
443
- var _a;
444
- if (children) {
514
+ if (!itemShouldKeepOpen) handleLeafClick(info);
515
+ }, "onClick"),
516
+ onMouseDown: /* @__PURE__ */ __name(() => {
517
+ if (!itemShouldKeepOpen) {
445
518
  return;
446
519
  }
447
- const itemShouldKeepOpen = item.keepDropdownOpen ?? keepDropdownOpen ?? false;
448
- if (itemShouldKeepOpen) {
449
- requestKeepOpen();
450
- }
451
- const extendedInfo = {
452
- ...info,
453
- item: info.item || item,
454
- originalItem: item,
455
- keepDropdownOpen: itemShouldKeepOpen
456
- };
457
- (_a = menu.onClick) == null ? void 0 : _a.call(menu, extendedInfo);
458
- }, "onClick"),
459
- onMouseEnter: /* @__PURE__ */ __name(() => {
460
- setOpenKeys((prev) => {
461
- if (prev.has(keyPath)) return prev;
462
- const next = new Set(prev);
463
- next.add(keyPath);
464
- return next;
465
- });
466
- }, "onMouseEnter"),
520
+ requestKeepOpen();
521
+ }, "onMouseDown"),
467
522
  children: children && children.length > 0 ? resolveItems(children, [...path, item.key]) : children && children.length === 0 ? [createEmptyItem(keyPath, t)] : void 0
468
523
  };
469
524
  });
@@ -498,9 +553,11 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
498
553
  placement: "bottomLeft",
499
554
  menu: {
500
555
  ...dropdownMenuProps,
556
+ openKeys: Array.from(openKeys),
501
557
  items,
502
558
  onClick: /* @__PURE__ */ __name(() => {
503
559
  }, "onClick"),
560
+ onOpenChange: handleMenuOpenChange,
504
561
  style: {
505
562
  maxHeight: dropdownMaxHeight,
506
563
  overflowY: "auto",
@@ -7,4 +7,5 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  export * from './AddSubModelButton';
10
+ export { default as LazyDropdown } from './LazyDropdown';
10
11
  export * from './utils';
@@ -7,10 +7,16 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
+ var __create = Object.create;
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
13
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
13
15
  var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
14
20
  var __copyProps = (to, from, except, desc) => {
15
21
  if (from && typeof from === "object" || typeof from === "function") {
16
22
  for (let key of __getOwnPropNames(from))
@@ -20,13 +26,26 @@ var __copyProps = (to, from, except, desc) => {
20
26
  return to;
21
27
  };
22
28
  var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
29
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
30
+ // If the importer is in node compatibility mode or this is not an ESM
31
+ // file that has been converted to a CommonJS file using a Babel-
32
+ // compatible transform (i.e. "__esModule" has not been set), then set
33
+ // "default" to the CommonJS "module.exports" for node compatibility.
34
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
+ mod
36
+ ));
23
37
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
38
  var subModel_exports = {};
39
+ __export(subModel_exports, {
40
+ LazyDropdown: () => import_LazyDropdown.default
41
+ });
25
42
  module.exports = __toCommonJS(subModel_exports);
26
43
  __reExport(subModel_exports, require("./AddSubModelButton"), module.exports);
44
+ var import_LazyDropdown = __toESM(require("./LazyDropdown"));
27
45
  __reExport(subModel_exports, require("./utils"), module.exports);
28
46
  // Annotate the CommonJS export names for ESM import in node:
29
47
  0 && (module.exports = {
48
+ LazyDropdown,
30
49
  ...require("./AddSubModelButton"),
31
50
  ...require("./utils")
32
51
  });
@@ -29,6 +29,6 @@ export declare function buildWrapperFieldChildren(ctx: FlowModelContext, options
29
29
  label: string;
30
30
  type: "group";
31
31
  searchable: boolean;
32
- searchPlaceholder: any;
32
+ searchPlaceholder: string;
33
33
  children: SubModelItem[];
34
34
  }[];
@@ -44,7 +44,7 @@ __export(utils_exports, {
44
44
  buildWrapperFieldChildren: () => buildWrapperFieldChildren
45
45
  });
46
46
  module.exports = __toCommonJS(utils_exports);
47
- var _ = __toESM(require("lodash"));
47
+ var import_lodash = __toESM(require("lodash"));
48
48
  var import_utils = require("../../utils");
49
49
  async function callHideFunction(hide, ctx) {
50
50
  if (typeof hide === "function") {
@@ -107,7 +107,7 @@ function buildSubModelChildren(M, ctx) {
107
107
  const extraArg = args && args.length > 0 ? args[args.length - 1] : void 0;
108
108
  const defaultOpts = await (0, import_utils.resolveCreateModelOptions)(meta == null ? void 0 : meta.createModelOptions, ctx, extraArg);
109
109
  const childOpts = await (0, import_utils.resolveCreateModelOptions)(src, ctx, extraArg);
110
- return _.merge({}, _.cloneDeep(defaultOpts), childOpts);
110
+ return import_lodash.default.merge({}, import_lodash.default.cloneDeep(defaultOpts), childOpts);
111
111
  };
112
112
  }
113
113
  return node;
@@ -172,7 +172,7 @@ function buildSubModelItems(subModelBaseClass, exclude = []) {
172
172
  __name(buildSubModelItems, "buildSubModelItems");
173
173
  function buildSubModelGroups(subModelBaseClasses = []) {
174
174
  return async (ctx) => {
175
- var _a, _b, _c;
175
+ var _a, _b, _c, _d, _e;
176
176
  const items = [];
177
177
  const exclude = [];
178
178
  for (const subModelBaseClass of subModelBaseClasses) {
@@ -203,11 +203,15 @@ function buildSubModelGroups(subModelBaseClasses = []) {
203
203
  const baseKey = typeof subModelBaseClass === "string" ? subModelBaseClass : BaseClass.name;
204
204
  const menuType = ((_b = BaseClass == null ? void 0 : BaseClass.meta) == null ? void 0 : _b.menuType) || "group";
205
205
  const groupSort = ((_c = BaseClass == null ? void 0 : BaseClass.meta) == null ? void 0 : _c.sort) ?? 1e3;
206
+ const searchable = !!((_d = BaseClass == null ? void 0 : BaseClass.meta) == null ? void 0 : _d.searchable);
207
+ const searchPlaceholder = (_e = BaseClass == null ? void 0 : BaseClass.meta) == null ? void 0 : _e.searchPlaceholder;
206
208
  if (menuType === "submenu") {
207
209
  items.push({
208
210
  key: baseKey,
209
211
  label: groupLabel,
210
212
  sort: groupSort,
213
+ searchable,
214
+ searchPlaceholder,
211
215
  children
212
216
  });
213
217
  } else {
@@ -216,6 +220,8 @@ function buildSubModelGroups(subModelBaseClasses = []) {
216
220
  type: "group",
217
221
  label: groupLabel,
218
222
  sort: groupSort,
223
+ searchable,
224
+ searchPlaceholder,
219
225
  children
220
226
  });
221
227
  }