@nocobase/flow-engine 2.1.0-beta.2 → 2.1.0-beta.21

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 (126) 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/FlowModelRenderer.d.ts +1 -1
  7. package/lib/components/FlowModelRenderer.js +10 -6
  8. package/lib/components/MobilePopup.js +6 -5
  9. package/lib/components/dnd/gridDragPlanner.js +6 -2
  10. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
  11. package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +48 -9
  12. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +19 -43
  13. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +339 -295
  14. package/lib/components/settings/wrappers/contextual/StepSettingsDialog.js +16 -2
  15. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
  16. package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +272 -0
  17. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
  18. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +247 -0
  19. package/lib/components/subModel/AddSubModelButton.js +27 -1
  20. package/lib/components/subModel/utils.js +2 -2
  21. package/lib/data-source/index.js +6 -0
  22. package/lib/executor/FlowExecutor.js +31 -8
  23. package/lib/flowContext.js +31 -1
  24. package/lib/flowEngine.d.ts +151 -1
  25. package/lib/flowEngine.js +389 -15
  26. package/lib/flowSettings.d.ts +14 -6
  27. package/lib/flowSettings.js +34 -6
  28. package/lib/lazy-helper.d.ts +14 -0
  29. package/lib/lazy-helper.js +71 -0
  30. package/lib/locale/en-US.json +1 -0
  31. package/lib/locale/index.d.ts +2 -0
  32. package/lib/locale/zh-CN.json +1 -0
  33. package/lib/models/flowModel.d.ts +2 -1
  34. package/lib/models/flowModel.js +28 -9
  35. package/lib/reactive/observer.js +46 -16
  36. package/lib/runjs-context/registry.d.ts +1 -1
  37. package/lib/runjs-context/setup.js +20 -12
  38. package/lib/runjs-context/snippets/index.js +13 -2
  39. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
  40. package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
  41. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
  42. package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
  43. package/lib/scheduler/ModelOperationScheduler.d.ts +5 -1
  44. package/lib/scheduler/ModelOperationScheduler.js +3 -2
  45. package/lib/types.d.ts +47 -1
  46. package/lib/utils/index.d.ts +2 -2
  47. package/lib/utils/index.js +4 -0
  48. package/lib/utils/parsePathnameToViewParams.js +1 -1
  49. package/lib/utils/runjsTemplateCompat.js +1 -1
  50. package/lib/utils/runjsValue.js +41 -11
  51. package/lib/utils/schema-utils.d.ts +7 -1
  52. package/lib/utils/schema-utils.js +19 -0
  53. package/lib/views/FlowView.d.ts +7 -1
  54. package/lib/views/runViewBeforeClose.d.ts +10 -0
  55. package/lib/views/runViewBeforeClose.js +45 -0
  56. package/lib/views/useDialog.d.ts +2 -1
  57. package/lib/views/useDialog.js +20 -3
  58. package/lib/views/useDrawer.d.ts +2 -1
  59. package/lib/views/useDrawer.js +20 -3
  60. package/lib/views/usePage.d.ts +2 -1
  61. package/lib/views/usePage.js +10 -3
  62. package/package.json +6 -5
  63. package/src/JSRunner.ts +68 -4
  64. package/src/ViewScopedFlowEngine.ts +4 -0
  65. package/src/__tests__/JSRunner.test.ts +27 -1
  66. package/src/__tests__/flow-engine.test.ts +166 -0
  67. package/src/__tests__/flowContext.test.ts +65 -1
  68. package/src/__tests__/flowEngine.modelLoaders.test.ts +245 -0
  69. package/src/__tests__/flowSettings.test.ts +94 -15
  70. package/src/__tests__/renderHiddenInConfig.test.tsx +6 -6
  71. package/src/__tests__/runjsContext.test.ts +16 -0
  72. package/src/__tests__/runjsContextRuntime.test.ts +2 -0
  73. package/src/__tests__/runjsPreprocessDefault.test.ts +23 -0
  74. package/src/__tests__/runjsSnippets.test.ts +21 -0
  75. package/src/__tests__/viewScopedFlowEngine.test.ts +3 -3
  76. package/src/components/FlowModelRenderer.tsx +12 -6
  77. package/src/components/MobilePopup.tsx +4 -2
  78. package/src/components/__tests__/FlowModelRenderer.test.tsx +65 -2
  79. package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +20 -10
  80. package/src/components/__tests__/gridDragPlanner.test.ts +88 -0
  81. package/src/components/dnd/gridDragPlanner.ts +8 -2
  82. package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +63 -9
  83. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +468 -440
  84. package/src/components/settings/wrappers/contextual/StepSettingsDialog.tsx +18 -2
  85. package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +95 -0
  86. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +609 -0
  87. package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +358 -0
  88. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +281 -0
  89. package/src/components/subModel/AddSubModelButton.tsx +32 -2
  90. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +142 -32
  91. package/src/components/subModel/utils.ts +1 -1
  92. package/src/data-source/index.ts +6 -0
  93. package/src/executor/FlowExecutor.ts +34 -9
  94. package/src/executor/__tests__/flowExecutor.test.ts +57 -0
  95. package/src/flowContext.ts +35 -3
  96. package/src/flowEngine.ts +445 -11
  97. package/src/flowSettings.ts +40 -6
  98. package/src/lazy-helper.tsx +57 -0
  99. package/src/locale/en-US.json +1 -0
  100. package/src/locale/zh-CN.json +1 -0
  101. package/src/models/__tests__/dispatchEvent.when.test.ts +214 -0
  102. package/src/models/flowModel.tsx +31 -10
  103. package/src/reactive/__tests__/observer.test.tsx +82 -0
  104. package/src/reactive/observer.tsx +87 -25
  105. package/src/runjs-context/registry.ts +1 -1
  106. package/src/runjs-context/setup.ts +22 -12
  107. package/src/runjs-context/snippets/index.ts +12 -1
  108. package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
  109. package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
  110. package/src/scheduler/ModelOperationScheduler.ts +14 -3
  111. package/src/types.ts +60 -0
  112. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +7 -0
  113. package/src/utils/__tests__/runjsValue.test.ts +11 -0
  114. package/src/utils/__tests__/utils.test.ts +62 -0
  115. package/src/utils/index.ts +2 -1
  116. package/src/utils/parsePathnameToViewParams.ts +2 -2
  117. package/src/utils/runjsTemplateCompat.ts +1 -1
  118. package/src/utils/runjsValue.ts +50 -11
  119. package/src/utils/schema-utils.ts +30 -1
  120. package/src/views/FlowView.tsx +11 -1
  121. package/src/views/__tests__/runViewBeforeClose.test.ts +30 -0
  122. package/src/views/__tests__/useDialog.closeDestroy.test.tsx +13 -12
  123. package/src/views/runViewBeforeClose.ts +19 -0
  124. package/src/views/useDialog.tsx +25 -3
  125. package/src/views/useDrawer.tsx +25 -3
  126. package/src/views/usePage.tsx +12 -3
@@ -41,6 +41,7 @@ __export(FlowsFloatContextMenu_exports, {
41
41
  });
42
42
  module.exports = __toCommonJS(FlowsFloatContextMenu_exports);
43
43
  var import_react = __toESM(require("react"));
44
+ var import_react_dom = require("react-dom");
44
45
  var import_antd = require("antd");
45
46
  var import_css = require("@emotion/css");
46
47
  var import_hooks = require("../../../../hooks");
@@ -48,238 +49,259 @@ var import_provider = require("../../../../provider");
48
49
  var import_utils = require("../../../../utils");
49
50
  var import__ = require("../../../..");
50
51
  var import_reactive = require("../../../../reactive");
51
- const detectButtonInDOM = /* @__PURE__ */ __name((container) => {
52
- if (!container) return false;
53
- const directChildren = container.children;
54
- for (let i = 0; i < directChildren.length; i++) {
55
- const child = directChildren[i];
56
- if (child.tagName === "BUTTON" || child.getAttribute("role") === "button" || child.classList.contains("ant-btn")) {
57
- return true;
58
- }
52
+ var import_useFloatToolbarPortal = require("./useFloatToolbarPortal");
53
+ var import_useFloatToolbarVisibility = require("./useFloatToolbarVisibility");
54
+ const TOOLBAR_Z_INDEX = 999;
55
+ const getFloatMenuInstanceId = /* @__PURE__ */ __name((model) => {
56
+ if (!model) {
57
+ return "";
59
58
  }
60
- return false;
61
- }, "detectButtonInDOM");
62
- const renderToolbarItems = /* @__PURE__ */ __name((model, showDeleteButton, showCopyUidButton, flowEngine, settingsMenuLevel, extraToolbarItems) => {
63
- var _a, _b;
64
- const toolbarItems = ((_b = (_a = flowEngine == null ? void 0 : flowEngine.flowSettings) == null ? void 0 : _a.getToolbarItems) == null ? void 0 : _b.call(_a)) || [];
65
- const allToolbarItems = [...toolbarItems, ...extraToolbarItems || []];
66
- allToolbarItems.sort((a, b) => (a.sort || 0) - (b.sort || 0)).reverse();
67
- return allToolbarItems.filter((itemConfig) => {
68
- return itemConfig.visible ? itemConfig.visible(model) : true;
69
- }).map((itemConfig) => {
70
- const ItemComponent = itemConfig.component;
71
- if (itemConfig.key === "settings-menu") {
72
- return /* @__PURE__ */ import_react.default.createElement(
73
- ItemComponent,
74
- {
75
- key: itemConfig.key,
76
- model,
77
- id: model.uid,
78
- showDeleteButton,
79
- showCopyUidButton,
80
- menuLevels: settingsMenuLevel
81
- }
82
- );
83
- }
84
- return /* @__PURE__ */ import_react.default.createElement(ItemComponent, { key: itemConfig.key, model });
85
- });
86
- }, "renderToolbarItems");
87
- const TOOLBAR_ITEM_WIDTH = 19;
88
- const toolbarPositionToCSS = {
89
- inside: `
90
- top: 2px;
91
- `,
92
- above: `
93
- top: 0px;
94
- transform: translateY(-100%);
95
- padding-bottom: 0px;
96
- margin-bottom: -2px;
97
- `,
98
- below: `
99
- top: 0px;
100
- transform: translateY(100%);
101
- padding-top: 2px;
102
- margin-top: -2px;
103
- `
104
- };
105
- const floatContainerStyles = /* @__PURE__ */ __name(({ showBackground, showBorder, ctx, toolbarPosition = "inside", toolbarCount }) => import_css.css`
59
+ const forkId = (model == null ? void 0 : model.isFork) ? model == null ? void 0 : model.forkId : void 0;
60
+ return forkId == null || forkId === "" ? String(model.uid || "") : `${String(model.uid || "")}::${String(forkId)}`;
61
+ }, "getFloatMenuInstanceId");
62
+ const hostContainerStyles = import_css.css`
106
63
  position: relative;
107
64
 
108
- /* 当检测到button时使用inline-block */
109
65
  &.has-button-child {
110
66
  display: inline-block;
111
67
  }
68
+ `;
69
+ const toolbarPositionClassNames = {
70
+ inside: "nb-toolbar-position-inside",
71
+ above: "nb-toolbar-position-above",
72
+ below: "nb-toolbar-position-below"
73
+ };
74
+ const toolbarContainerStyles = /* @__PURE__ */ __name(({
75
+ showBackground,
76
+ showBorder,
77
+ ctx
78
+ }) => import_css.css`
79
+ z-index: ${TOOLBAR_Z_INDEX};
80
+ opacity: 0;
81
+ pointer-events: none;
82
+ overflow: visible;
83
+ transition: opacity 0.12s ease;
84
+ background: ${showBackground ? "var(--colorBgSettingsHover)" : "transparent"};
85
+ border: ${showBorder ? "2px solid var(--colorBorderSettingsHover)" : "none"};
86
+ border-radius: ${ctx.themeToken.borderRadiusLG}px;
112
87
 
113
- /* 正常的hover行为 - 添加延迟显示 */
114
- &:hover > .nb-toolbar-container {
88
+ &.nb-toolbar-visible {
115
89
  opacity: 1;
116
90
  transition-delay: 0.1s;
91
+ }
117
92
 
118
- .nb-toolbar-container-icons {
119
- display: block;
120
- }
93
+ &.nb-toolbar-portal {
94
+ top: 0;
95
+ left: 0;
121
96
  }
122
97
 
123
- /* 当有.hide-parent-menu类时隐藏菜单 */
124
- &.hide-parent-menu > .nb-toolbar-container {
125
- opacity: 0 !important;
98
+ &.nb-toolbar-portal-fixed {
99
+ position: fixed;
126
100
  }
127
101
 
128
- > .nb-toolbar-container {
102
+ &.nb-toolbar-portal-absolute {
129
103
  position: absolute;
130
- top: 0;
131
- bottom: 0;
132
- left: 0;
133
- right: 0;
134
- z-index: 999;
135
- opacity: 0;
136
- background: ${showBackground ? "var(--colorBgSettingsHover)" : ""};
137
- border: ${showBorder ? "2px solid var(--colorBorderSettingsHover)" : ""};
138
- border-radius: ${ctx.themeToken.borderRadiusLG}px;
104
+ }
105
+
106
+ &.nb-in-template {
107
+ background: var(--colorTemplateBgSettingsHover);
108
+ }
109
+
110
+ > .nb-toolbar-container-title {
139
111
  pointer-events: none;
140
- min-width: ${TOOLBAR_ITEM_WIDTH * toolbarCount}px;
112
+ position: absolute;
113
+ top: 2px;
114
+ left: 2px;
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 4px;
118
+ height: 16px;
119
+ padding: 0;
120
+ font-size: 12px;
121
+ line-height: 16px;
122
+ border-bottom-right-radius: 2px;
123
+ border-radius: 2px;
141
124
 
142
- &.nb-in-template {
143
- background: var(--colorTemplateBgSettingsHover);
125
+ .title-tag {
126
+ display: inline-flex;
127
+ padding: 0 3px;
128
+ border-radius: 2px;
129
+ background: var(--colorSettings);
130
+ color: #fff;
144
131
  }
132
+ }
145
133
 
146
- > .nb-toolbar-container-title {
147
- pointer-events: none;
148
- position: absolute;
149
- font-size: 12px;
150
- padding: 0;
151
- line-height: 16px;
152
- height: 16px;
153
- border-bottom-right-radius: 2px;
154
- border-radius: 2px;
155
- top: 2px;
156
- left: 2px;
157
- display: flex;
158
- align-items: center;
159
- gap: 4px;
134
+ > .nb-toolbar-container-icons {
135
+ display: none;
136
+ position: absolute;
137
+ right: 2px;
138
+ line-height: 16px;
139
+ pointer-events: all;
160
140
 
161
- .title-tag {
162
- padding: 0 3px;
163
- border-radius: 2px;
164
- background: var(--colorSettings);
165
- color: #fff;
166
- display: inline-flex;
167
- }
141
+ &.nb-toolbar-position-inside {
142
+ top: 2px;
168
143
  }
169
144
 
170
- > .nb-toolbar-container-icons {
171
- display: none; // 防止遮挡其它 icons
172
- position: absolute;
173
- right: 2px;
174
- ${toolbarPositionToCSS[toolbarPosition] || ""}
175
- line-height: 16px;
176
- pointer-events: all;
145
+ &.nb-toolbar-position-above {
146
+ top: 0;
147
+ transform: translateY(-100%);
148
+ padding-bottom: 0;
149
+ margin-bottom: -2px;
150
+ }
177
151
 
178
- .ant-space-item {
179
- background-color: var(--colorSettings);
180
- color: #fff;
181
- line-height: 16px;
182
- width: 16px;
183
- height: 16px;
184
- padding: 2px;
185
- display: flex;
186
- align-items: center;
187
- justify-content: center;
188
- }
152
+ &.nb-toolbar-position-below {
153
+ top: 0;
154
+ transform: translateY(100%);
155
+ padding-top: 2px;
156
+ margin-top: -2px;
189
157
  }
190
158
 
191
- /* 拖拽把手样式 - 参考 AirTable 样式 */
192
- > .resize-handle {
193
- position: absolute;
194
- pointer-events: all;
195
- background: var(--colorSettings);
196
- opacity: 0.6;
197
- border-radius: 4px;
159
+ .ant-space-item {
198
160
  display: flex;
199
161
  align-items: center;
200
162
  justify-content: center;
163
+ width: 16px;
164
+ height: 16px;
165
+ padding: 2px;
166
+ line-height: 16px;
167
+ background-color: var(--colorSettings);
168
+ color: #fff;
169
+ }
170
+ }
201
171
 
202
- &:hover {
203
- opacity: 0.9;
204
- background: var(--colorSettingsHover, var(--colorSettings));
205
- }
172
+ &.nb-toolbar-visible > .nb-toolbar-container-icons {
173
+ display: block;
174
+ }
206
175
 
207
- &::before {
208
- content: '';
209
- position: absolute;
210
- background: rgba(255, 255, 255, 0.9);
211
- border-radius: 50%;
212
- }
176
+ > .resize-handle {
177
+ position: absolute;
178
+ display: flex;
179
+ align-items: center;
180
+ justify-content: center;
181
+ pointer-events: all;
182
+ opacity: 0.6;
183
+ border-radius: 4px;
184
+ background: var(--colorSettings);
213
185
 
214
- &::after {
215
- content: '';
216
- position: absolute;
217
- background: rgba(255, 255, 255, 0.9);
218
- border-radius: 50%;
219
- }
186
+ &:hover {
187
+ opacity: 0.9;
188
+ background: var(--colorSettingsHover, var(--colorSettings));
220
189
  }
221
190
 
222
- > .resize-handle-left {
223
- left: -4px;
224
- top: 50%;
225
- transform: translateY(-50%);
226
- width: 6px;
227
- height: 20px;
228
- cursor: ew-resize;
191
+ &::before {
192
+ content: '';
193
+ position: absolute;
194
+ border-radius: 50%;
195
+ background: rgba(255, 255, 255, 0.9);
196
+ }
229
197
 
230
- &::before {
231
- width: 2px;
232
- height: 2px;
233
- top: 6px;
234
- left: 50%;
235
- transform: translateX(-50%);
236
- box-shadow:
237
- 0 4px 0 rgba(255, 255, 255, 0.9),
238
- 0 8px 0 rgba(255, 255, 255, 0.9);
239
- }
198
+ &::after {
199
+ content: '';
200
+ position: absolute;
201
+ border-radius: 50%;
202
+ background: rgba(255, 255, 255, 0.9);
240
203
  }
204
+ }
241
205
 
242
- > .resize-handle-right {
243
- right: -4px;
244
- top: 50%;
245
- transform: translateY(-50%);
246
- width: 6px;
247
- height: 20px;
248
- cursor: ew-resize;
206
+ > .resize-handle-left {
207
+ top: 50%;
208
+ left: -4px;
209
+ width: 6px;
210
+ height: 20px;
211
+ cursor: ew-resize;
212
+ transform: translateY(-50%);
249
213
 
250
- &::before {
251
- width: 2px;
252
- height: 2px;
253
- top: 6px;
254
- left: 50%;
255
- transform: translateX(-50%);
256
- box-shadow:
257
- 0 4px 0 rgba(255, 255, 255, 0.9),
258
- 0 8px 0 rgba(255, 255, 255, 0.9);
259
- }
214
+ &::before {
215
+ top: 6px;
216
+ left: 50%;
217
+ width: 2px;
218
+ height: 2px;
219
+ transform: translateX(-50%);
220
+ box-shadow:
221
+ 0 4px 0 rgba(255, 255, 255, 0.9),
222
+ 0 8px 0 rgba(255, 255, 255, 0.9);
260
223
  }
224
+ }
225
+
226
+ > .resize-handle-right {
227
+ top: 50%;
228
+ right: -4px;
229
+ width: 6px;
230
+ height: 20px;
231
+ cursor: ew-resize;
232
+ transform: translateY(-50%);
261
233
 
262
- > .resize-handle-bottom {
263
- bottom: -4px;
234
+ &::before {
235
+ top: 6px;
264
236
  left: 50%;
237
+ width: 2px;
238
+ height: 2px;
265
239
  transform: translateX(-50%);
266
- width: 20px;
267
- height: 6px;
268
- cursor: ns-resize;
269
-
270
- &::before {
271
- width: 2px;
272
- height: 2px;
273
- left: 6px;
274
- top: 50%;
275
- transform: translateY(-50%);
276
- box-shadow:
277
- 4px 0 0 rgba(255, 255, 255, 0.9),
278
- 8px 0 0 rgba(255, 255, 255, 0.9);
279
- }
240
+ box-shadow:
241
+ 0 4px 0 rgba(255, 255, 255, 0.9),
242
+ 0 8px 0 rgba(255, 255, 255, 0.9);
243
+ }
244
+ }
245
+ `, "toolbarContainerStyles");
246
+ const detectButtonInDOM = /* @__PURE__ */ __name((container) => {
247
+ if (!container) return false;
248
+ const directChildren = container.children;
249
+ for (let i = 0; i < directChildren.length; i++) {
250
+ const child = directChildren[i];
251
+ if (child.tagName === "BUTTON" || child.getAttribute("role") === "button" || child.classList.contains("ant-btn")) {
252
+ return true;
280
253
  }
281
254
  }
282
- `, "floatContainerStyles");
255
+ return false;
256
+ }, "detectButtonInDOM");
257
+ const renderToolbarItems = /* @__PURE__ */ __name((model, modelInstanceId, showDeleteButton, showCopyUidButton, flowEngine, settingsMenuLevel, extraToolbarItems, onSettingsMenuOpenChange, getPopupContainer) => {
258
+ var _a, _b;
259
+ const toolbarItems = ((_b = (_a = flowEngine == null ? void 0 : flowEngine.flowSettings) == null ? void 0 : _a.getToolbarItems) == null ? void 0 : _b.call(_a)) || [];
260
+ const allToolbarItems = [...toolbarItems, ...extraToolbarItems || []];
261
+ allToolbarItems.sort((a, b) => (a.sort || 0) - (b.sort || 0)).reverse();
262
+ return allToolbarItems.filter((itemConfig) => {
263
+ return itemConfig.visible ? itemConfig.visible(model) : true;
264
+ }).map((itemConfig) => {
265
+ const ItemComponent = itemConfig.component;
266
+ if (itemConfig.key === "settings-menu") {
267
+ return /* @__PURE__ */ import_react.default.createElement(
268
+ ItemComponent,
269
+ {
270
+ key: itemConfig.key,
271
+ model,
272
+ id: modelInstanceId,
273
+ showDeleteButton,
274
+ showCopyUidButton,
275
+ menuLevels: settingsMenuLevel,
276
+ onDropdownVisibleChange: onSettingsMenuOpenChange,
277
+ getPopupContainer
278
+ }
279
+ );
280
+ }
281
+ return /* @__PURE__ */ import_react.default.createElement(ItemComponent, { key: itemConfig.key, model });
282
+ });
283
+ }, "renderToolbarItems");
284
+ const buildToolbarContainerClassName = /* @__PURE__ */ __name(({
285
+ showBackground,
286
+ showBorder,
287
+ ctx,
288
+ portalRenderSnapshot,
289
+ isToolbarVisible,
290
+ className
291
+ }) => [
292
+ toolbarContainerStyles({ showBackground, showBorder, ctx }),
293
+ "nb-toolbar-portal",
294
+ (portalRenderSnapshot == null ? void 0 : portalRenderSnapshot.positioningMode) === "absolute" ? "nb-toolbar-portal-absolute" : "nb-toolbar-portal-fixed",
295
+ isToolbarVisible ? "nb-toolbar-visible" : "",
296
+ (className == null ? void 0 : className.includes("nb-in-template")) ? "nb-in-template" : ""
297
+ ].filter(Boolean).join(" "), "buildToolbarContainerClassName");
298
+ const buildToolbarContainerStyle = /* @__PURE__ */ __name((portalRect, toolbarStyle) => ({
299
+ top: `${portalRect.top}px`,
300
+ left: `${portalRect.left}px`,
301
+ width: `${portalRect.width}px`,
302
+ height: `${portalRect.height}px`,
303
+ ...(0, import_useFloatToolbarPortal.omitToolbarPortalInsetStyle)(toolbarStyle)
304
+ }), "buildToolbarContainerStyle");
283
305
  const isModelByIdProps = /* @__PURE__ */ __name((props) => {
284
306
  return "uid" in props && "modelClassName" in props && Boolean(props.uid) && Boolean(props.modelClassName);
285
307
  }, "isModelByIdProps");
@@ -290,9 +312,8 @@ const FlowsFloatContextMenu = (0, import_reactive.observer)((props) => {
290
312
  }
291
313
  if (isModelByIdProps(props)) {
292
314
  return /* @__PURE__ */ import_react.default.createElement(FlowsFloatContextMenuWithModelById, { ...props });
293
- } else {
294
- return /* @__PURE__ */ import_react.default.createElement(FlowsFloatContextMenuWithModel, { ...props });
295
315
  }
316
+ return /* @__PURE__ */ import_react.default.createElement(FlowsFloatContextMenuWithModel, { ...props });
296
317
  });
297
318
  const ResizeHandles = /* @__PURE__ */ __name((props) => {
298
319
  const isDraggingRef = (0, import_react.useRef)(false);
@@ -303,27 +324,13 @@ const ResizeHandles = /* @__PURE__ */ __name((props) => {
303
324
  (e) => {
304
325
  if (!isDraggingRef.current || !dragTypeRef.current) return;
305
326
  const deltaX = e.clientX - dragStartPosRef.current.x;
306
- const deltaY = e.clientY - dragStartPosRef.current.y;
307
- let resizeDistance = 0;
308
327
  switch (dragTypeRef.current) {
309
328
  case "left":
310
- resizeDistance = -deltaX;
311
- props.model.parent.emitter.emit("onResizeLeft", { resizeDistance, model: props.model });
329
+ props.model.parent.emitter.emit("onResizeLeft", { resizeDistance: -deltaX, model: props.model });
312
330
  break;
313
331
  case "right":
314
- resizeDistance = deltaX;
315
- props.model.parent.emitter.emit("onResizeRight", { resizeDistance, model: props.model });
332
+ props.model.parent.emitter.emit("onResizeRight", { resizeDistance: deltaX, model: props.model });
316
333
  break;
317
- case "bottom":
318
- resizeDistance = deltaY;
319
- props.model.parent.emitter.emit("onResizeBottom", { resizeDistance, model: props.model });
320
- break;
321
- case "corner": {
322
- const widthDelta = deltaX;
323
- const heightDelta = deltaY;
324
- props.model.parent.emitter.emit("onResizeCorner", { widthDelta, heightDelta, model: props.model });
325
- break;
326
- }
327
334
  }
328
335
  },
329
336
  [props.model]
@@ -336,7 +343,7 @@ const ResizeHandles = /* @__PURE__ */ __name((props) => {
336
343
  document.removeEventListener("mouseup", handleDragEnd);
337
344
  props.model.parent.emitter.emit("onResizeEnd");
338
345
  onDragEnd == null ? void 0 : onDragEnd();
339
- }, [handleDragMove, props.model, onDragEnd]);
346
+ }, [handleDragMove, onDragEnd, props.model]);
340
347
  const handleDragStart = (0, import_react.useCallback)(
341
348
  (e, type) => {
342
349
  e.preventDefault();
@@ -355,6 +362,8 @@ const ResizeHandles = /* @__PURE__ */ __name((props) => {
355
362
  {
356
363
  className: "resize-handle resize-handle-left",
357
364
  title: "\u62D6\u62FD\u8C03\u8282\u5BBD\u5EA6",
365
+ onMouseEnter: props.onMouseEnter,
366
+ onMouseLeave: props.onMouseLeave,
358
367
  onMouseDown: (e) => handleDragStart(e, "left")
359
368
  }
360
369
  ), /* @__PURE__ */ import_react.default.createElement(
@@ -362,6 +371,8 @@ const ResizeHandles = /* @__PURE__ */ __name((props) => {
362
371
  {
363
372
  className: "resize-handle resize-handle-right",
364
373
  title: "\u62D6\u62FD\u8C03\u8282\u5BBD\u5EA6",
374
+ onMouseEnter: props.onMouseEnter,
375
+ onMouseLeave: props.onMouseLeave,
365
376
  onMouseDown: (e) => handleDragStart(e, "right")
366
377
  }
367
378
  ));
@@ -384,28 +395,83 @@ const FlowsFloatContextMenuWithModel = (0, import_reactive.observer)(
384
395
  toolbarStyle,
385
396
  toolbarPosition = "inside"
386
397
  }) => {
387
- const [hideMenu, setHideMenu] = (0, import_react.useState)(false);
388
398
  const [hasButton, setHasButton] = (0, import_react.useState)(false);
389
399
  const containerRef = (0, import_react.useRef)(null);
390
- const flowEngine = (0, import_provider.useFlowEngine)();
391
- const [style, setStyle] = (0, import_react.useState)({});
392
400
  const toolbarContainerRef = (0, import_react.useRef)(null);
393
- const toolbarContainerStyle = (0, import_react.useMemo)(() => ({ ...toolbarStyle, ...style }), [style, toolbarStyle]);
401
+ const portalActionsRef = (0, import_react.useRef)({
402
+ updatePortalRect: /* @__PURE__ */ __name(() => {
403
+ }, "updatePortalRect"),
404
+ schedulePortalRectUpdate: /* @__PURE__ */ __name(() => {
405
+ }, "schedulePortalRectUpdate")
406
+ });
407
+ const modelUid = getFloatMenuInstanceId(model);
408
+ const flowEngine = (0, import_provider.useFlowEngine)();
409
+ const updatePortalRectProxy = (0, import_react.useCallback)(() => {
410
+ portalActionsRef.current.updatePortalRect();
411
+ }, []);
412
+ const schedulePortalRectUpdateProxy = (0, import_react.useCallback)(() => {
413
+ portalActionsRef.current.schedulePortalRectUpdate();
414
+ }, []);
415
+ const {
416
+ isToolbarVisible,
417
+ shouldRenderToolbar,
418
+ handleSettingsMenuOpenChange,
419
+ handleChildHover,
420
+ handleHostMouseEnter,
421
+ handleHostMouseLeave,
422
+ handleToolbarMouseEnter,
423
+ handleToolbarMouseLeave,
424
+ handleResizeDragStart,
425
+ handleResizeDragEnd
426
+ } = (0, import_useFloatToolbarVisibility.useFloatToolbarVisibility)({
427
+ modelUid,
428
+ containerRef,
429
+ toolbarContainerRef,
430
+ updatePortalRect: updatePortalRectProxy,
431
+ schedulePortalRectUpdate: schedulePortalRectUpdateProxy
432
+ });
433
+ const { portalRect, portalRenderSnapshot, getPopupContainer, updatePortalRect, schedulePortalRectUpdate } = (0, import_useFloatToolbarPortal.useFloatToolbarPortal)({
434
+ active: shouldRenderToolbar,
435
+ containerRef,
436
+ toolbarContainerRef,
437
+ toolbarStyle
438
+ });
439
+ portalActionsRef.current.updatePortalRect = updatePortalRect;
440
+ portalActionsRef.current.schedulePortalRectUpdate = schedulePortalRectUpdate;
441
+ const toolbarItems = (0, import_react.useMemo)(
442
+ () => model ? renderToolbarItems(
443
+ model,
444
+ modelUid,
445
+ showDeleteButton,
446
+ showCopyUidButton,
447
+ flowEngine,
448
+ settingsMenuLevel,
449
+ extraToolbarItems,
450
+ handleSettingsMenuOpenChange,
451
+ getPopupContainer
452
+ ) : [],
453
+ [
454
+ extraToolbarItems,
455
+ flowEngine,
456
+ getPopupContainer,
457
+ handleSettingsMenuOpenChange,
458
+ model,
459
+ settingsMenuLevel,
460
+ showCopyUidButton,
461
+ showDeleteButton
462
+ ]
463
+ );
394
464
  (0, import_react.useEffect)(() => {
395
- if (containerRef.current) {
396
- const hasButtonElement = detectButtonInDOM(containerRef.current);
397
- setHasButton(hasButtonElement);
465
+ const container = containerRef.current;
466
+ if (!container) {
467
+ return;
398
468
  }
399
- }, [children]);
400
- (0, import_react.useEffect)(() => {
401
- if (!containerRef.current) return;
402
- const observer2 = new MutationObserver(() => {
403
- if (containerRef.current) {
404
- const hasButtonElement = detectButtonInDOM(containerRef.current);
405
- setHasButton(hasButtonElement);
406
- }
407
- });
408
- observer2.observe(containerRef.current, {
469
+ const syncHasButton = /* @__PURE__ */ __name(() => {
470
+ setHasButton(detectButtonInDOM(container));
471
+ }, "syncHasButton");
472
+ syncHasButton();
473
+ const observer2 = new MutationObserver(syncHasButton);
474
+ observer2.observe(container, {
409
475
  childList: true,
410
476
  subtree: true,
411
477
  attributes: true,
@@ -415,15 +481,6 @@ const FlowsFloatContextMenuWithModel = (0, import_reactive.observer)(
415
481
  observer2.disconnect();
416
482
  };
417
483
  }, []);
418
- const handleChildHover = (0, import_react.useCallback)((e) => {
419
- const target = e.target;
420
- const childWithMenu = target.closest("[data-has-float-menu]");
421
- if (childWithMenu && childWithMenu !== containerRef.current) {
422
- setHideMenu(true);
423
- } else {
424
- setHideMenu(false);
425
- }
426
- }, []);
427
484
  if (!model) {
428
485
  const t = (0, import_utils.getT)(model || {});
429
486
  return /* @__PURE__ */ import_react.default.createElement(import_antd.Alert, { message: t("Invalid model provided"), type: "error" });
@@ -431,39 +488,61 @@ const FlowsFloatContextMenuWithModel = (0, import_reactive.observer)(
431
488
  if (!enabled || !children) {
432
489
  return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, children);
433
490
  }
434
- return /* @__PURE__ */ import_react.default.createElement(
491
+ const toolbarContainerClassName = buildToolbarContainerClassName({
492
+ showBackground,
493
+ showBorder,
494
+ ctx: model.context,
495
+ portalRenderSnapshot,
496
+ isToolbarVisible,
497
+ className
498
+ });
499
+ const toolbarContainerStyle = buildToolbarContainerStyle(portalRect, toolbarStyle);
500
+ const toolbarNode = shouldRenderToolbar ? /* @__PURE__ */ import_react.default.createElement(
435
501
  "div",
436
502
  {
437
- ref: containerRef,
438
- className: `${floatContainerStyles({
439
- showBackground,
440
- showBorder,
441
- ctx: model.context,
442
- toolbarPosition,
443
- toolbarCount: getToolbarCount(flowEngine, extraToolbarItems)
444
- })} ${hideMenu ? "hide-parent-menu" : ""} ${hasButton ? "has-button-child" : ""} ${className || ""}`,
445
- style: containerStyle,
446
- "data-has-float-menu": "true",
447
- onMouseMove: handleChildHover
503
+ ref: toolbarContainerRef,
504
+ className: `nb-toolbar-container ${toolbarContainerClassName}`,
505
+ style: toolbarContainerStyle,
506
+ "data-model-uid": modelUid
448
507
  },
449
- children,
450
- /* @__PURE__ */ import_react.default.createElement("div", { ref: toolbarContainerRef, className: "nb-toolbar-container", style: toolbarContainerStyle }, showTitle && (model.title || model.extraTitle) && /* @__PURE__ */ import_react.default.createElement("div", { className: "nb-toolbar-container-title" }, model.title && /* @__PURE__ */ import_react.default.createElement("span", { className: "title-tag" }, model.title), model.extraTitle && /* @__PURE__ */ import_react.default.createElement("span", { className: "title-tag" }, model.extraTitle)), /* @__PURE__ */ import_react.default.createElement(
508
+ showTitle && (model.title || model.extraTitle) && /* @__PURE__ */ import_react.default.createElement("div", { className: "nb-toolbar-container-title" }, model.title && /* @__PURE__ */ import_react.default.createElement("span", { className: "title-tag" }, model.title), model.extraTitle && /* @__PURE__ */ import_react.default.createElement("span", { className: "title-tag" }, model.extraTitle)),
509
+ /* @__PURE__ */ import_react.default.createElement(
451
510
  "div",
452
511
  {
453
- className: "nb-toolbar-container-icons",
512
+ className: `nb-toolbar-container-icons ${toolbarPositionClassNames[toolbarPosition]}`,
454
513
  onClick: (e) => e.stopPropagation(),
455
514
  onMouseDown: (e) => e.stopPropagation(),
456
- onMouseMove: (e) => e.stopPropagation()
515
+ onMouseMove: (e) => e.stopPropagation(),
516
+ onMouseEnter: handleToolbarMouseEnter,
517
+ onMouseLeave: handleToolbarMouseLeave
457
518
  },
458
- /* @__PURE__ */ import_react.default.createElement(import_antd.Space, { size: 3, align: "center" }, renderToolbarItems(
519
+ /* @__PURE__ */ import_react.default.createElement(import_antd.Space, { size: 3, align: "center" }, toolbarItems)
520
+ ),
521
+ showDragHandle && /* @__PURE__ */ import_react.default.createElement(
522
+ ResizeHandles,
523
+ {
459
524
  model,
460
- showDeleteButton,
461
- showCopyUidButton,
462
- flowEngine,
463
- settingsMenuLevel,
464
- extraToolbarItems
465
- ))
466
- ), showDragHandle && /* @__PURE__ */ import_react.default.createElement(ResizeHandles, { model, onDragStart: () => setStyle({ opacity: 1 }), onDragEnd: () => setStyle({}) }))
525
+ onMouseEnter: handleToolbarMouseEnter,
526
+ onMouseLeave: handleToolbarMouseLeave,
527
+ onDragStart: handleResizeDragStart,
528
+ onDragEnd: handleResizeDragEnd
529
+ }
530
+ )
531
+ ) : null;
532
+ return /* @__PURE__ */ import_react.default.createElement(
533
+ "div",
534
+ {
535
+ ref: containerRef,
536
+ className: `${hostContainerStyles} ${hasButton ? "has-button-child" : ""} ${className || ""}`,
537
+ style: containerStyle,
538
+ "data-has-float-menu": "true",
539
+ "data-float-menu-model-uid": modelUid,
540
+ onMouseMove: handleChildHover,
541
+ onMouseEnter: handleHostMouseEnter,
542
+ onMouseLeave: handleHostMouseLeave
543
+ },
544
+ children,
545
+ toolbarNode && ((portalRenderSnapshot == null ? void 0 : portalRenderSnapshot.mountElement) ? (0, import_react_dom.createPortal)(toolbarNode, portalRenderSnapshot.mountElement) : toolbarNode)
467
546
  );
468
547
  },
469
548
  {
@@ -471,53 +550,18 @@ const FlowsFloatContextMenuWithModel = (0, import_reactive.observer)(
471
550
  }
472
551
  );
473
552
  const FlowsFloatContextMenuWithModelById = (0, import_reactive.observer)(
474
- ({
475
- uid,
476
- modelClassName,
477
- children,
478
- enabled = true,
479
- showDeleteButton = true,
480
- showCopyUidButton = true,
481
- containerStyle,
482
- className,
483
- showTitle = false,
484
- settingsMenuLevel,
485
- extraToolbarItems,
486
- toolbarPosition
487
- }) => {
553
+ ({ uid, modelClassName, children, ...restProps }) => {
488
554
  const model = (0, import_hooks.useFlowModelById)(uid, modelClassName);
489
555
  const flowEngine = (0, import_provider.useFlowEngine)();
490
556
  if (!model) {
491
557
  return /* @__PURE__ */ import_react.default.createElement(import_antd.Alert, { message: flowEngine.translate("Model with ID {{uid}} not found", { uid }), type: "error" });
492
558
  }
493
- return /* @__PURE__ */ import_react.default.createElement(
494
- FlowsFloatContextMenuWithModel,
495
- {
496
- model,
497
- enabled,
498
- showDeleteButton,
499
- showCopyUidButton,
500
- containerStyle,
501
- className,
502
- showTitle,
503
- settingsMenuLevel,
504
- extraToolbarItems,
505
- toolbarPosition
506
- },
507
- children
508
- );
559
+ return /* @__PURE__ */ import_react.default.createElement(FlowsFloatContextMenuWithModel, { model, ...restProps }, children);
509
560
  },
510
561
  {
511
562
  displayName: "FlowsFloatContextMenuWithModelById"
512
563
  }
513
564
  );
514
- function getToolbarCount(flowEngine, extraToolbarItems) {
515
- var _a, _b;
516
- const toolbarItems = ((_b = (_a = flowEngine == null ? void 0 : flowEngine.flowSettings) == null ? void 0 : _a.getToolbarItems) == null ? void 0 : _b.call(_a)) || [];
517
- const allToolbarItems = [...toolbarItems, ...extraToolbarItems || []];
518
- return allToolbarItems.length;
519
- }
520
- __name(getToolbarCount, "getToolbarCount");
521
565
  // Annotate the CommonJS export names for ESM import in node:
522
566
  0 && (module.exports = {
523
567
  FlowsFloatContextMenu