@nocobase/flow-engine 2.1.0-beta.10 → 2.1.0-beta.12
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.
- package/lib/components/FlowModelRenderer.d.ts +1 -1
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.d.ts +3 -0
- package/lib/components/settings/wrappers/contextual/DefaultSettingsIcon.js +48 -9
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.d.ts +19 -43
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +332 -296
- package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.d.ts +36 -0
- package/lib/components/settings/wrappers/contextual/useFloatToolbarPortal.js +272 -0
- package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.d.ts +30 -0
- package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +247 -0
- package/lib/components/subModel/AddSubModelButton.js +11 -0
- package/lib/flowContext.js +27 -0
- package/lib/runjs-context/setup.js +1 -0
- package/lib/runjs-context/snippets/index.js +13 -2
- package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/detail/set-field-style.snippet.js +50 -0
- package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.d.ts +11 -0
- package/lib/runjs-context/snippets/scene/table/set-cell-style.snippet.js +54 -0
- package/package.json +5 -4
- package/src/__tests__/flowContext.test.ts +65 -1
- package/src/__tests__/runjsContext.test.ts +3 -0
- package/src/__tests__/runjsContextRuntime.test.ts +2 -0
- package/src/__tests__/runjsSnippets.test.ts +21 -0
- package/src/components/FlowModelRenderer.tsx +3 -1
- package/src/components/__tests__/flow-model-render-error-fallback.test.tsx +17 -7
- package/src/components/settings/wrappers/contextual/DefaultSettingsIcon.tsx +63 -9
- package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +457 -440
- package/src/components/settings/wrappers/contextual/__tests__/DefaultSettingsIcon.test.tsx +95 -0
- package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +547 -0
- package/src/components/settings/wrappers/contextual/useFloatToolbarPortal.ts +358 -0
- package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +281 -0
- package/src/components/subModel/AddSubModelButton.tsx +15 -1
- package/src/flowContext.ts +30 -0
- package/src/runjs-context/setup.ts +1 -0
- package/src/runjs-context/snippets/index.ts +12 -1
- package/src/runjs-context/snippets/scene/detail/set-field-style.snippet.ts +30 -0
- package/src/runjs-context/snippets/scene/table/set-cell-style.snippet.ts +34 -0
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
import type { CSSProperties, RefObject } from 'react';
|
|
10
|
+
type ToolbarPortalPositioningMode = 'fixed' | 'absolute';
|
|
11
|
+
export interface ToolbarPortalRenderSnapshot {
|
|
12
|
+
mountElement: HTMLElement;
|
|
13
|
+
positioningMode: ToolbarPortalPositioningMode;
|
|
14
|
+
}
|
|
15
|
+
export interface ToolbarPortalRect {
|
|
16
|
+
top: number;
|
|
17
|
+
left: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
}
|
|
21
|
+
interface UseFloatToolbarPortalOptions {
|
|
22
|
+
active: boolean;
|
|
23
|
+
containerRef: RefObject<HTMLDivElement>;
|
|
24
|
+
toolbarContainerRef: RefObject<HTMLDivElement>;
|
|
25
|
+
toolbarStyle?: CSSProperties;
|
|
26
|
+
}
|
|
27
|
+
interface UseFloatToolbarPortalResult {
|
|
28
|
+
portalRect: ToolbarPortalRect;
|
|
29
|
+
portalRenderSnapshot: ToolbarPortalRenderSnapshot | null;
|
|
30
|
+
getPopupContainer: (triggerNode?: HTMLElement) => HTMLElement;
|
|
31
|
+
updatePortalRect: () => void;
|
|
32
|
+
schedulePortalRectUpdate: () => void;
|
|
33
|
+
}
|
|
34
|
+
export declare const omitToolbarPortalInsetStyle: (toolbarStyle?: CSSProperties) => CSSProperties | undefined;
|
|
35
|
+
export declare const useFloatToolbarPortal: ({ active, containerRef, toolbarContainerRef, toolbarStyle, }: UseFloatToolbarPortalOptions) => UseFloatToolbarPortalResult;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,272 @@
|
|
|
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 useFloatToolbarPortal_exports = {};
|
|
29
|
+
__export(useFloatToolbarPortal_exports, {
|
|
30
|
+
omitToolbarPortalInsetStyle: () => omitToolbarPortalInsetStyle,
|
|
31
|
+
useFloatToolbarPortal: () => useFloatToolbarPortal
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(useFloatToolbarPortal_exports);
|
|
34
|
+
var import_react = require("react");
|
|
35
|
+
const APP_CONTAINER_SELECTOR = "#nocobase-app-container";
|
|
36
|
+
const DRAWER_CONTENT_WRAPPER_SELECTOR = ".ant-drawer-content-wrapper";
|
|
37
|
+
const DRAWER_CONTENT_SELECTOR = ".ant-drawer-content";
|
|
38
|
+
const DRAWER_ROOT_SELECTOR = ".ant-drawer-root";
|
|
39
|
+
const MODAL_SELECTOR = ".ant-modal";
|
|
40
|
+
const MODAL_WRAP_SELECTOR = ".ant-modal-wrap";
|
|
41
|
+
const MODAL_ROOT_SELECTOR = ".ant-modal-root";
|
|
42
|
+
const defaultPortalRect = {
|
|
43
|
+
top: 0,
|
|
44
|
+
left: 0,
|
|
45
|
+
width: 0,
|
|
46
|
+
height: 0
|
|
47
|
+
};
|
|
48
|
+
const getClosestElement = /* @__PURE__ */ __name((hostEl, selector) => hostEl == null ? void 0 : hostEl.closest(selector), "getClosestElement");
|
|
49
|
+
const createAbsolutePortalHostConfig = /* @__PURE__ */ __name((element) => ({
|
|
50
|
+
mountElement: element,
|
|
51
|
+
positioningElement: element,
|
|
52
|
+
positioningMode: "absolute"
|
|
53
|
+
}), "createAbsolutePortalHostConfig");
|
|
54
|
+
const popupPortalHostResolvers = [
|
|
55
|
+
(hostEl) => getClosestElement(hostEl, DRAWER_CONTENT_WRAPPER_SELECTOR),
|
|
56
|
+
(hostEl) => getClosestElement(hostEl, MODAL_WRAP_SELECTOR),
|
|
57
|
+
(hostEl) => getClosestElement(hostEl, MODAL_SELECTOR),
|
|
58
|
+
(hostEl) => {
|
|
59
|
+
const drawerContent = getClosestElement(hostEl, DRAWER_CONTENT_SELECTOR);
|
|
60
|
+
return drawerContent ? getClosestElement(drawerContent, DRAWER_CONTENT_WRAPPER_SELECTOR) || drawerContent : null;
|
|
61
|
+
},
|
|
62
|
+
(hostEl) => getClosestElement(hostEl, DRAWER_ROOT_SELECTOR),
|
|
63
|
+
(hostEl) => getClosestElement(hostEl, MODAL_ROOT_SELECTOR)
|
|
64
|
+
];
|
|
65
|
+
const getPopupPortalHostConfig = /* @__PURE__ */ __name((hostEl) => {
|
|
66
|
+
for (const resolveHost of popupPortalHostResolvers) {
|
|
67
|
+
const popupHost = resolveHost(hostEl);
|
|
68
|
+
if (popupHost) {
|
|
69
|
+
return createAbsolutePortalHostConfig(popupHost);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}, "getPopupPortalHostConfig");
|
|
74
|
+
const getToolbarPortalHostConfig = /* @__PURE__ */ __name((hostEl) => {
|
|
75
|
+
if (typeof document === "undefined") {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const popupRootConfig = getPopupPortalHostConfig(hostEl);
|
|
79
|
+
if (popupRootConfig) {
|
|
80
|
+
return popupRootConfig;
|
|
81
|
+
}
|
|
82
|
+
const appContainer = document.querySelector(APP_CONTAINER_SELECTOR);
|
|
83
|
+
if (appContainer) {
|
|
84
|
+
return createAbsolutePortalHostConfig(appContainer);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
mountElement: document.body,
|
|
88
|
+
positioningElement: document.body,
|
|
89
|
+
positioningMode: "fixed"
|
|
90
|
+
};
|
|
91
|
+
}, "getToolbarPortalHostConfig");
|
|
92
|
+
const parseToolbarInsetValue = /* @__PURE__ */ __name((value) => {
|
|
93
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
if (typeof value === "string") {
|
|
97
|
+
const trimmedValue = value.trim();
|
|
98
|
+
if (/^-?\d+(\.\d+)?(px)?$/.test(trimmedValue)) {
|
|
99
|
+
return Number.parseFloat(trimmedValue);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return 0;
|
|
103
|
+
}, "parseToolbarInsetValue");
|
|
104
|
+
const resolveToolbarPortalInset = /* @__PURE__ */ __name((toolbarStyle) => {
|
|
105
|
+
return {
|
|
106
|
+
top: parseToolbarInsetValue(toolbarStyle == null ? void 0 : toolbarStyle.top),
|
|
107
|
+
left: parseToolbarInsetValue(toolbarStyle == null ? void 0 : toolbarStyle.left),
|
|
108
|
+
right: parseToolbarInsetValue(toolbarStyle == null ? void 0 : toolbarStyle.right),
|
|
109
|
+
bottom: parseToolbarInsetValue(toolbarStyle == null ? void 0 : toolbarStyle.bottom)
|
|
110
|
+
};
|
|
111
|
+
}, "resolveToolbarPortalInset");
|
|
112
|
+
const getAbsolutePositioningElement = /* @__PURE__ */ __name((toolbarEl, portalHostConfig) => {
|
|
113
|
+
if (!portalHostConfig || portalHostConfig.positioningMode !== "absolute") {
|
|
114
|
+
return (portalHostConfig == null ? void 0 : portalHostConfig.positioningElement) || null;
|
|
115
|
+
}
|
|
116
|
+
const offsetParent = toolbarEl == null ? void 0 : toolbarEl.offsetParent;
|
|
117
|
+
if (offsetParent instanceof HTMLElement && offsetParent !== document.body && offsetParent !== document.documentElement) {
|
|
118
|
+
return offsetParent;
|
|
119
|
+
}
|
|
120
|
+
return portalHostConfig.positioningElement;
|
|
121
|
+
}, "getAbsolutePositioningElement");
|
|
122
|
+
const calculatePortalRect = /* @__PURE__ */ __name((hostEl, portalHostConfig, toolbarStyle, toolbarEl) => {
|
|
123
|
+
if (!hostEl) {
|
|
124
|
+
return defaultPortalRect;
|
|
125
|
+
}
|
|
126
|
+
const inset = resolveToolbarPortalInset(toolbarStyle);
|
|
127
|
+
const hostRect = hostEl.getBoundingClientRect();
|
|
128
|
+
let rect;
|
|
129
|
+
if (!portalHostConfig || portalHostConfig.positioningMode === "fixed") {
|
|
130
|
+
rect = {
|
|
131
|
+
top: hostRect.top,
|
|
132
|
+
left: hostRect.left,
|
|
133
|
+
width: hostRect.width,
|
|
134
|
+
height: hostRect.height
|
|
135
|
+
};
|
|
136
|
+
} else {
|
|
137
|
+
const positioningElement = getAbsolutePositioningElement(toolbarEl || null, portalHostConfig);
|
|
138
|
+
const portalHostRect = (positioningElement == null ? void 0 : positioningElement.getBoundingClientRect()) || portalHostConfig.positioningElement.getBoundingClientRect();
|
|
139
|
+
const scrollTop = (positioningElement == null ? void 0 : positioningElement.scrollTop) ?? portalHostConfig.positioningElement.scrollTop;
|
|
140
|
+
const scrollLeft = (positioningElement == null ? void 0 : positioningElement.scrollLeft) ?? portalHostConfig.positioningElement.scrollLeft;
|
|
141
|
+
rect = {
|
|
142
|
+
top: hostRect.top - portalHostRect.top + scrollTop,
|
|
143
|
+
left: hostRect.left - portalHostRect.left + scrollLeft,
|
|
144
|
+
width: hostRect.width,
|
|
145
|
+
height: hostRect.height
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
top: rect.top + inset.top,
|
|
150
|
+
left: rect.left + inset.left,
|
|
151
|
+
width: Math.max(0, rect.width - inset.left - inset.right),
|
|
152
|
+
height: Math.max(0, rect.height - inset.top - inset.bottom)
|
|
153
|
+
};
|
|
154
|
+
}, "calculatePortalRect");
|
|
155
|
+
const omitToolbarPortalInsetStyle = /* @__PURE__ */ __name((toolbarStyle) => {
|
|
156
|
+
if (!toolbarStyle) {
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
const nextStyle = { ...toolbarStyle };
|
|
160
|
+
delete nextStyle.top;
|
|
161
|
+
delete nextStyle.left;
|
|
162
|
+
delete nextStyle.right;
|
|
163
|
+
delete nextStyle.bottom;
|
|
164
|
+
return nextStyle;
|
|
165
|
+
}, "omitToolbarPortalInsetStyle");
|
|
166
|
+
const useFloatToolbarPortal = /* @__PURE__ */ __name(({
|
|
167
|
+
active,
|
|
168
|
+
containerRef,
|
|
169
|
+
toolbarContainerRef,
|
|
170
|
+
toolbarStyle
|
|
171
|
+
}) => {
|
|
172
|
+
const [portalRect, setPortalRect] = (0, import_react.useState)(defaultPortalRect);
|
|
173
|
+
const [portalRenderSnapshot, setPortalRenderSnapshot] = (0, import_react.useState)(null);
|
|
174
|
+
const portalHostConfigRef = (0, import_react.useRef)(null);
|
|
175
|
+
const portalRafIdRef = (0, import_react.useRef)(null);
|
|
176
|
+
const updatePortalRect = (0, import_react.useCallback)(() => {
|
|
177
|
+
const hostElement = containerRef.current;
|
|
178
|
+
if (!hostElement) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const nextPortalHostConfig = getToolbarPortalHostConfig(hostElement);
|
|
182
|
+
portalHostConfigRef.current = nextPortalHostConfig;
|
|
183
|
+
setPortalRenderSnapshot((prevSnapshot) => {
|
|
184
|
+
if (!nextPortalHostConfig) {
|
|
185
|
+
return prevSnapshot === null ? prevSnapshot : null;
|
|
186
|
+
}
|
|
187
|
+
if ((prevSnapshot == null ? void 0 : prevSnapshot.mountElement) === nextPortalHostConfig.mountElement && (prevSnapshot == null ? void 0 : prevSnapshot.positioningMode) === nextPortalHostConfig.positioningMode) {
|
|
188
|
+
return prevSnapshot;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
mountElement: nextPortalHostConfig.mountElement,
|
|
192
|
+
positioningMode: nextPortalHostConfig.positioningMode
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
const nextRect = calculatePortalRect(hostElement, nextPortalHostConfig, toolbarStyle, toolbarContainerRef.current);
|
|
196
|
+
setPortalRect((prevRect) => {
|
|
197
|
+
if (prevRect.top === nextRect.top && prevRect.left === nextRect.left && prevRect.width === nextRect.width && prevRect.height === nextRect.height) {
|
|
198
|
+
return prevRect;
|
|
199
|
+
}
|
|
200
|
+
return nextRect;
|
|
201
|
+
});
|
|
202
|
+
}, [containerRef, toolbarContainerRef, toolbarStyle]);
|
|
203
|
+
const schedulePortalRectUpdate = (0, import_react.useCallback)(() => {
|
|
204
|
+
if (portalRafIdRef.current !== null) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
portalRafIdRef.current = window.requestAnimationFrame(() => {
|
|
208
|
+
portalRafIdRef.current = null;
|
|
209
|
+
updatePortalRect();
|
|
210
|
+
});
|
|
211
|
+
}, [updatePortalRect]);
|
|
212
|
+
const getPopupContainer = (0, import_react.useCallback)(
|
|
213
|
+
(triggerNode) => {
|
|
214
|
+
var _a, _b, _c, _d, _e;
|
|
215
|
+
const fallbackContainer = ((_a = triggerNode == null ? void 0 : triggerNode.ownerDocument) == null ? void 0 : _a.body) || ((_c = (_b = containerRef.current) == null ? void 0 : _b.ownerDocument) == null ? void 0 : _c.body) || (typeof document !== "undefined" ? document.body : null);
|
|
216
|
+
return ((_d = portalHostConfigRef.current) == null ? void 0 : _d.mountElement) || ((_e = getToolbarPortalHostConfig(triggerNode || containerRef.current)) == null ? void 0 : _e.mountElement) || fallbackContainer;
|
|
217
|
+
},
|
|
218
|
+
[containerRef]
|
|
219
|
+
);
|
|
220
|
+
(0, import_react.useEffect)(() => {
|
|
221
|
+
var _a, _b;
|
|
222
|
+
if (!active) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
updatePortalRect();
|
|
226
|
+
const handleViewportChange = /* @__PURE__ */ __name(() => {
|
|
227
|
+
schedulePortalRectUpdate();
|
|
228
|
+
}, "handleViewportChange");
|
|
229
|
+
const container = containerRef.current;
|
|
230
|
+
const mountElement = (_a = portalHostConfigRef.current) == null ? void 0 : _a.mountElement;
|
|
231
|
+
const positioningElement = (_b = portalHostConfigRef.current) == null ? void 0 : _b.positioningElement;
|
|
232
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" && container ? new ResizeObserver(() => {
|
|
233
|
+
schedulePortalRectUpdate();
|
|
234
|
+
}) : null;
|
|
235
|
+
if (container) {
|
|
236
|
+
resizeObserver == null ? void 0 : resizeObserver.observe(container);
|
|
237
|
+
}
|
|
238
|
+
if (mountElement && mountElement !== container) {
|
|
239
|
+
resizeObserver == null ? void 0 : resizeObserver.observe(mountElement);
|
|
240
|
+
}
|
|
241
|
+
if (positioningElement && positioningElement !== container && positioningElement !== mountElement) {
|
|
242
|
+
resizeObserver == null ? void 0 : resizeObserver.observe(positioningElement);
|
|
243
|
+
}
|
|
244
|
+
window.addEventListener("resize", handleViewportChange);
|
|
245
|
+
window.addEventListener("scroll", handleViewportChange, true);
|
|
246
|
+
return () => {
|
|
247
|
+
resizeObserver == null ? void 0 : resizeObserver.disconnect();
|
|
248
|
+
window.removeEventListener("resize", handleViewportChange);
|
|
249
|
+
window.removeEventListener("scroll", handleViewportChange, true);
|
|
250
|
+
};
|
|
251
|
+
}, [active, containerRef, schedulePortalRectUpdate, updatePortalRect]);
|
|
252
|
+
(0, import_react.useEffect)(() => {
|
|
253
|
+
return () => {
|
|
254
|
+
if (portalRafIdRef.current !== null) {
|
|
255
|
+
window.cancelAnimationFrame(portalRafIdRef.current);
|
|
256
|
+
}
|
|
257
|
+
portalHostConfigRef.current = null;
|
|
258
|
+
};
|
|
259
|
+
}, []);
|
|
260
|
+
return {
|
|
261
|
+
portalRect,
|
|
262
|
+
portalRenderSnapshot,
|
|
263
|
+
getPopupContainer,
|
|
264
|
+
updatePortalRect,
|
|
265
|
+
schedulePortalRectUpdate
|
|
266
|
+
};
|
|
267
|
+
}, "useFloatToolbarPortal");
|
|
268
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
269
|
+
0 && (module.exports = {
|
|
270
|
+
omitToolbarPortalInsetStyle,
|
|
271
|
+
useFloatToolbarPortal
|
|
272
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
import type { MouseEvent as ReactMouseEvent, RefObject } from 'react';
|
|
10
|
+
interface UseFloatToolbarVisibilityOptions {
|
|
11
|
+
modelUid: string;
|
|
12
|
+
containerRef: RefObject<HTMLDivElement>;
|
|
13
|
+
toolbarContainerRef: RefObject<HTMLDivElement>;
|
|
14
|
+
updatePortalRect: () => void;
|
|
15
|
+
schedulePortalRectUpdate: () => void;
|
|
16
|
+
}
|
|
17
|
+
interface UseFloatToolbarVisibilityResult {
|
|
18
|
+
isToolbarVisible: boolean;
|
|
19
|
+
shouldRenderToolbar: boolean;
|
|
20
|
+
handleSettingsMenuOpenChange: (open: boolean) => void;
|
|
21
|
+
handleChildHover: (e: ReactMouseEvent) => void;
|
|
22
|
+
handleHostMouseEnter: () => void;
|
|
23
|
+
handleHostMouseLeave: (e: ReactMouseEvent<HTMLDivElement>) => void;
|
|
24
|
+
handleToolbarMouseEnter: () => void;
|
|
25
|
+
handleToolbarMouseLeave: (e: ReactMouseEvent<HTMLDivElement>) => void;
|
|
26
|
+
handleResizeDragStart: () => void;
|
|
27
|
+
handleResizeDragEnd: () => void;
|
|
28
|
+
}
|
|
29
|
+
export declare const useFloatToolbarVisibility: ({ modelUid, containerRef, toolbarContainerRef, updatePortalRect, schedulePortalRectUpdate, }: UseFloatToolbarVisibilityOptions) => UseFloatToolbarVisibilityResult;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,247 @@
|
|
|
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
|
+
const TOOLBAR_HIDE_DELAY = 180;
|
|
35
|
+
const CHILD_FLOAT_MENU_ACTIVITY_EVENT = "nb-float-menu-child-activity";
|
|
36
|
+
const isNodeWithin = /* @__PURE__ */ __name((target, container) => {
|
|
37
|
+
return target instanceof Node && !!(container == null ? void 0 : container.contains(target));
|
|
38
|
+
}, "isNodeWithin");
|
|
39
|
+
const getToolbarModelUidFromTarget = /* @__PURE__ */ __name((target) => {
|
|
40
|
+
var _a;
|
|
41
|
+
if (!(target instanceof Element)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return ((_a = target.closest(".nb-toolbar-container[data-model-uid]")) == null ? void 0 : _a.getAttribute("data-model-uid")) || null;
|
|
45
|
+
}, "getToolbarModelUidFromTarget");
|
|
46
|
+
const isNodeWithinDescendantFloatToolbar = /* @__PURE__ */ __name((target, container, currentModelUid) => {
|
|
47
|
+
const targetModelUid = getToolbarModelUidFromTarget(target);
|
|
48
|
+
if (!container || !targetModelUid || targetModelUid === currentModelUid) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return Array.from(
|
|
52
|
+
container.querySelectorAll('[data-has-float-menu="true"][data-float-menu-model-uid]')
|
|
53
|
+
).some(
|
|
54
|
+
(hostElement) => hostElement !== container && hostElement.getAttribute("data-float-menu-model-uid") === targetModelUid
|
|
55
|
+
);
|
|
56
|
+
}, "isNodeWithinDescendantFloatToolbar");
|
|
57
|
+
const useFloatToolbarVisibility = /* @__PURE__ */ __name(({
|
|
58
|
+
modelUid,
|
|
59
|
+
containerRef,
|
|
60
|
+
toolbarContainerRef,
|
|
61
|
+
updatePortalRect,
|
|
62
|
+
schedulePortalRectUpdate
|
|
63
|
+
}) => {
|
|
64
|
+
const [hideMenu, setHideMenu] = (0, import_react.useState)(false);
|
|
65
|
+
const [isHostHovered, setIsHostHovered] = (0, import_react.useState)(false);
|
|
66
|
+
const [isToolbarHovered, setIsToolbarHovered] = (0, import_react.useState)(false);
|
|
67
|
+
const [isDraggingToolbar, setIsDraggingToolbar] = (0, import_react.useState)(false);
|
|
68
|
+
const [isToolbarPinned, setIsToolbarPinned] = (0, import_react.useState)(false);
|
|
69
|
+
const [isHidePending, setIsHidePending] = (0, import_react.useState)(false);
|
|
70
|
+
const [activeChildToolbarIds, setActiveChildToolbarIds] = (0, import_react.useState)([]);
|
|
71
|
+
const hideToolbarTimerRef = (0, import_react.useRef)(null);
|
|
72
|
+
const reportedChildActivityToAncestorsRef = (0, import_react.useRef)(false);
|
|
73
|
+
const hasActiveChildToolbar = activeChildToolbarIds.length > 0;
|
|
74
|
+
const isToolbarVisible = !hideMenu && !hasActiveChildToolbar && (isHostHovered || isToolbarHovered || isDraggingToolbar || isToolbarPinned);
|
|
75
|
+
const shouldRenderToolbar = isToolbarVisible || isToolbarPinned || isDraggingToolbar;
|
|
76
|
+
const isToolbarInteractionActive = isHostHovered || isToolbarHovered || isDraggingToolbar || isToolbarPinned || isHidePending;
|
|
77
|
+
const clearHideToolbarTimer = (0, import_react.useCallback)(() => {
|
|
78
|
+
if (hideToolbarTimerRef.current !== null) {
|
|
79
|
+
window.clearTimeout(hideToolbarTimerRef.current);
|
|
80
|
+
hideToolbarTimerRef.current = null;
|
|
81
|
+
}
|
|
82
|
+
setIsHidePending(false);
|
|
83
|
+
}, []);
|
|
84
|
+
const scheduleHideToolbar = (0, import_react.useCallback)(() => {
|
|
85
|
+
clearHideToolbarTimer();
|
|
86
|
+
setIsHidePending(true);
|
|
87
|
+
hideToolbarTimerRef.current = window.setTimeout(() => {
|
|
88
|
+
hideToolbarTimerRef.current = null;
|
|
89
|
+
setIsHidePending(false);
|
|
90
|
+
if (isDraggingToolbar || isToolbarPinned) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
setIsHostHovered(false);
|
|
94
|
+
setIsToolbarHovered(false);
|
|
95
|
+
}, TOOLBAR_HIDE_DELAY);
|
|
96
|
+
}, [clearHideToolbarTimer, isDraggingToolbar, isToolbarPinned]);
|
|
97
|
+
const handleSettingsMenuOpenChange = (0, import_react.useCallback)((open) => {
|
|
98
|
+
setIsToolbarPinned(open);
|
|
99
|
+
}, []);
|
|
100
|
+
(0, import_react.useEffect)(() => {
|
|
101
|
+
const hostElement = containerRef.current;
|
|
102
|
+
if (!hostElement) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const handleChildToolbarActivity = /* @__PURE__ */ __name((event) => {
|
|
106
|
+
var _a;
|
|
107
|
+
const customEvent = event;
|
|
108
|
+
if (!(customEvent.target instanceof HTMLElement) || customEvent.target === hostElement) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const childModelUid = (_a = customEvent.detail) == null ? void 0 : _a.modelUid;
|
|
112
|
+
if (!childModelUid) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
setActiveChildToolbarIds((prevIds) => {
|
|
116
|
+
var _a2;
|
|
117
|
+
return ((_a2 = customEvent.detail) == null ? void 0 : _a2.active) ? prevIds.includes(childModelUid) ? prevIds : [...prevIds, childModelUid] : prevIds.filter((id) => id !== childModelUid);
|
|
118
|
+
});
|
|
119
|
+
}, "handleChildToolbarActivity");
|
|
120
|
+
hostElement.addEventListener(CHILD_FLOAT_MENU_ACTIVITY_EVENT, handleChildToolbarActivity);
|
|
121
|
+
return () => {
|
|
122
|
+
hostElement.removeEventListener(CHILD_FLOAT_MENU_ACTIVITY_EVENT, handleChildToolbarActivity);
|
|
123
|
+
};
|
|
124
|
+
}, [containerRef]);
|
|
125
|
+
(0, import_react.useEffect)(() => {
|
|
126
|
+
const hostElement = containerRef.current;
|
|
127
|
+
if (!hostElement || reportedChildActivityToAncestorsRef.current === isToolbarInteractionActive) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
reportedChildActivityToAncestorsRef.current = isToolbarInteractionActive;
|
|
131
|
+
hostElement.dispatchEvent(
|
|
132
|
+
new CustomEvent(CHILD_FLOAT_MENU_ACTIVITY_EVENT, {
|
|
133
|
+
bubbles: true,
|
|
134
|
+
detail: { active: isToolbarInteractionActive, modelUid }
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
}, [containerRef, isToolbarInteractionActive, modelUid]);
|
|
138
|
+
(0, import_react.useEffect)(() => {
|
|
139
|
+
const hostElement = containerRef.current;
|
|
140
|
+
return () => {
|
|
141
|
+
if (hostElement && reportedChildActivityToAncestorsRef.current) {
|
|
142
|
+
hostElement.dispatchEvent(
|
|
143
|
+
new CustomEvent(CHILD_FLOAT_MENU_ACTIVITY_EVENT, {
|
|
144
|
+
bubbles: true,
|
|
145
|
+
detail: { active: false, modelUid }
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
reportedChildActivityToAncestorsRef.current = false;
|
|
149
|
+
}
|
|
150
|
+
clearHideToolbarTimer();
|
|
151
|
+
};
|
|
152
|
+
}, [clearHideToolbarTimer, containerRef, modelUid]);
|
|
153
|
+
(0, import_react.useEffect)(() => {
|
|
154
|
+
if (isToolbarPinned) {
|
|
155
|
+
clearHideToolbarTimer();
|
|
156
|
+
updatePortalRect();
|
|
157
|
+
}
|
|
158
|
+
}, [clearHideToolbarTimer, isToolbarPinned, updatePortalRect]);
|
|
159
|
+
const handleChildHover = (0, import_react.useCallback)(
|
|
160
|
+
(e) => {
|
|
161
|
+
const target = e.target;
|
|
162
|
+
const childWithMenu = target.closest("[data-has-float-menu]");
|
|
163
|
+
const isCurrentHostTarget = !childWithMenu || childWithMenu === containerRef.current;
|
|
164
|
+
if (isCurrentHostTarget) {
|
|
165
|
+
clearHideToolbarTimer();
|
|
166
|
+
setIsHostHovered(true);
|
|
167
|
+
}
|
|
168
|
+
setHideMenu(!!childWithMenu && childWithMenu !== containerRef.current);
|
|
169
|
+
},
|
|
170
|
+
[clearHideToolbarTimer, containerRef]
|
|
171
|
+
);
|
|
172
|
+
const handleHostMouseEnter = (0, import_react.useCallback)(() => {
|
|
173
|
+
clearHideToolbarTimer();
|
|
174
|
+
setHideMenu(false);
|
|
175
|
+
updatePortalRect();
|
|
176
|
+
setIsHostHovered(true);
|
|
177
|
+
}, [clearHideToolbarTimer, updatePortalRect]);
|
|
178
|
+
const handleHostMouseLeave = (0, import_react.useCallback)(
|
|
179
|
+
(e) => {
|
|
180
|
+
if (isToolbarPinned) {
|
|
181
|
+
setIsHostHovered(false);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (isNodeWithin(e.relatedTarget, toolbarContainerRef.current)) {
|
|
185
|
+
clearHideToolbarTimer();
|
|
186
|
+
setIsHostHovered(false);
|
|
187
|
+
setIsToolbarHovered(true);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (isNodeWithinDescendantFloatToolbar(e.relatedTarget, containerRef.current, modelUid)) {
|
|
191
|
+
clearHideToolbarTimer();
|
|
192
|
+
setHideMenu(false);
|
|
193
|
+
setIsHostHovered(true);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
scheduleHideToolbar();
|
|
197
|
+
},
|
|
198
|
+
[clearHideToolbarTimer, containerRef, isToolbarPinned, modelUid, scheduleHideToolbar, toolbarContainerRef]
|
|
199
|
+
);
|
|
200
|
+
const handleToolbarMouseEnter = (0, import_react.useCallback)(() => {
|
|
201
|
+
clearHideToolbarTimer();
|
|
202
|
+
updatePortalRect();
|
|
203
|
+
setIsHostHovered(false);
|
|
204
|
+
setIsToolbarHovered(true);
|
|
205
|
+
}, [clearHideToolbarTimer, updatePortalRect]);
|
|
206
|
+
const handleToolbarMouseLeave = (0, import_react.useCallback)(
|
|
207
|
+
(e) => {
|
|
208
|
+
if (isToolbarPinned) {
|
|
209
|
+
setIsToolbarHovered(false);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
setIsToolbarHovered(false);
|
|
213
|
+
if (isNodeWithin(e.relatedTarget, containerRef.current)) {
|
|
214
|
+
clearHideToolbarTimer();
|
|
215
|
+
setIsHostHovered(true);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
scheduleHideToolbar();
|
|
219
|
+
},
|
|
220
|
+
[clearHideToolbarTimer, containerRef, isToolbarPinned, scheduleHideToolbar]
|
|
221
|
+
);
|
|
222
|
+
const handleResizeDragStart = (0, import_react.useCallback)(() => {
|
|
223
|
+
updatePortalRect();
|
|
224
|
+
setIsDraggingToolbar(true);
|
|
225
|
+
schedulePortalRectUpdate();
|
|
226
|
+
}, [schedulePortalRectUpdate, updatePortalRect]);
|
|
227
|
+
const handleResizeDragEnd = (0, import_react.useCallback)(() => {
|
|
228
|
+
setIsDraggingToolbar(false);
|
|
229
|
+
schedulePortalRectUpdate();
|
|
230
|
+
}, [schedulePortalRectUpdate]);
|
|
231
|
+
return {
|
|
232
|
+
isToolbarVisible,
|
|
233
|
+
shouldRenderToolbar,
|
|
234
|
+
handleSettingsMenuOpenChange,
|
|
235
|
+
handleChildHover,
|
|
236
|
+
handleHostMouseEnter,
|
|
237
|
+
handleHostMouseLeave,
|
|
238
|
+
handleToolbarMouseEnter,
|
|
239
|
+
handleToolbarMouseLeave,
|
|
240
|
+
handleResizeDragStart,
|
|
241
|
+
handleResizeDragEnd
|
|
242
|
+
};
|
|
243
|
+
}, "useFloatToolbarVisibility");
|
|
244
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
245
|
+
0 && (module.exports = {
|
|
246
|
+
useFloatToolbarVisibility
|
|
247
|
+
});
|
|
@@ -476,6 +476,17 @@ const AddSubModelButtonCore = /* @__PURE__ */ __name(function AddSubModelButton(
|
|
|
476
476
|
() => transformItems(finalItems, model, subModelKey, subModelType),
|
|
477
477
|
[finalItems, model, subModelKey, subModelType]
|
|
478
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]);
|
|
479
490
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
480
491
|
import_LazyDropdown.default,
|
|
481
492
|
{
|
package/lib/flowContext.js
CHANGED
|
@@ -57,6 +57,7 @@ __export(flowContext_exports, {
|
|
|
57
57
|
});
|
|
58
58
|
module.exports = __toCommonJS(flowContext_exports);
|
|
59
59
|
var import_reactive = require("@formily/reactive");
|
|
60
|
+
var import_axios = __toESM(require("axios"));
|
|
60
61
|
var antd = __toESM(require("antd"));
|
|
61
62
|
var import_lodash = __toESM(require("lodash"));
|
|
62
63
|
var import_qs = __toESM(require("qs"));
|
|
@@ -81,6 +82,28 @@ var import_dayjs = __toESM(require("dayjs"));
|
|
|
81
82
|
var import_runjsLibs = require("./runjsLibs");
|
|
82
83
|
var import_runjsModuleLoader = require("./utils/runjsModuleLoader");
|
|
83
84
|
var _proxy, _FlowContext_instances, createChildNodes_fn, findMetaByPath_fn, findMetaInDelegatesDeep_fn, findMetaInProperty_fn, resolvePathInMeta_fn, resolvePathInMetaAsync_fn, buildParentTitles_fn, toTreeNode_fn;
|
|
85
|
+
function normalizePathname(pathname) {
|
|
86
|
+
return pathname.endsWith("/") ? pathname : `${pathname}/`;
|
|
87
|
+
}
|
|
88
|
+
__name(normalizePathname, "normalizePathname");
|
|
89
|
+
function shouldBypassApiClient(url, app) {
|
|
90
|
+
try {
|
|
91
|
+
const requestUrl = new URL(url);
|
|
92
|
+
if (!["http:", "https:"].includes(requestUrl.protocol)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if (!(app == null ? void 0 : app.getApiUrl)) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
const apiUrl = new URL(app.getApiUrl());
|
|
99
|
+
const apiPath = normalizePathname(apiUrl.pathname);
|
|
100
|
+
const requestPath = normalizePathname(requestUrl.pathname);
|
|
101
|
+
return requestUrl.origin !== apiUrl.origin || !requestPath.startsWith(apiPath);
|
|
102
|
+
} catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
__name(shouldBypassApiClient, "shouldBypassApiClient");
|
|
84
107
|
function isRecordRefLike(val) {
|
|
85
108
|
return !!(val && typeof val === "object" && "collection" in val && "filterByTk" in val);
|
|
86
109
|
}
|
|
@@ -2211,6 +2234,10 @@ const _BaseFlowEngineContext = class _BaseFlowEngineContext extends FlowContext
|
|
|
2211
2234
|
return this.engine.getModel(modelName, searchInPreviousEngines);
|
|
2212
2235
|
});
|
|
2213
2236
|
this.defineMethod("request", (options) => {
|
|
2237
|
+
const app = this.app;
|
|
2238
|
+
if (typeof (options == null ? void 0 : options.url) === "string" && shouldBypassApiClient(options.url, app)) {
|
|
2239
|
+
return import_axios.default.request(options);
|
|
2240
|
+
}
|
|
2214
2241
|
return this.api.request(options);
|
|
2215
2242
|
});
|
|
2216
2243
|
this.defineMethod(
|
|
@@ -73,6 +73,7 @@ async function setupRunJSContexts() {
|
|
|
73
73
|
import_registry.RunJSContextRegistry.register(version, "JSFieldModel", JSFieldRunJSContext, { scenes: ["detail"] });
|
|
74
74
|
import_registry.RunJSContextRegistry.register(version, "JSEditableFieldModel", JSEditableFieldRunJSContext, { scenes: ["form"] });
|
|
75
75
|
import_registry.RunJSContextRegistry.register(version, "JSItemModel", JSItemRunJSContext, { scenes: ["form"] });
|
|
76
|
+
import_registry.RunJSContextRegistry.register(version, "JSItemActionModel", JSItemRunJSContext, { scenes: ["table"] });
|
|
76
77
|
import_registry.RunJSContextRegistry.register(version, "JSColumnModel", JSColumnRunJSContext, { scenes: ["table"] });
|
|
77
78
|
import_registry.RunJSContextRegistry.register(version, "FormJSFieldItemModel", FormJSFieldItemRunJSContext, { scenes: ["form"] });
|
|
78
79
|
import_registry.RunJSContextRegistry.register(version, "JSRecordActionModel", JSRecordActionRunJSContext, { scenes: ["table"] });
|