@nocobase/flow-engine 2.2.0-alpha.1 → 2.2.0-alpha.10
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/JSRunner.d.ts +1 -0
- package/lib/JSRunner.js +110 -20
- package/lib/acl/Acl.d.ts +2 -1
- package/lib/acl/Acl.js +28 -0
- package/lib/components/FieldModelRenderer.js +44 -31
- package/lib/components/FlowContextSelector.js +55 -12
- package/lib/components/FormItem.js +11 -7
- package/lib/components/MobilePopup.js +39 -10
- package/lib/components/MobilePopup.style.js +27 -6
- package/lib/components/dnd/index.js +9 -2
- package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +86 -32
- package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +20 -0
- package/lib/components/subModel/LazyDropdown.js +41 -26
- package/lib/components/variables/VariableHybridInput.d.ts +9 -0
- package/lib/components/variables/VariableHybridInput.js +146 -17
- package/lib/components/variables/VariableInput.js +19 -7
- package/lib/components/variables/VariableTag.js +48 -36
- package/lib/components/variables/types.d.ts +21 -0
- package/lib/flowContext.d.ts +1 -1
- package/lib/flowContext.js +97 -42
- package/lib/flowEngine.js +6 -0
- package/lib/flowI18n.js +3 -3
- package/lib/flowSettings.d.ts +5 -1
- package/lib/flowSettings.js +70 -0
- package/lib/locale/en-US.json +3 -0
- package/lib/locale/index.d.ts +6 -0
- package/lib/locale/zh-CN.json +3 -0
- package/lib/resources/apiResource.js +2 -1
- package/lib/resources/baseRecordResource.js +6 -17
- package/lib/resources/multiRecordResource.js +13 -3
- package/lib/resources/singleRecordResource.js +7 -2
- package/lib/runjs-context/helpers.js +12 -5
- package/lib/types.d.ts +15 -1
- package/lib/types.js +1 -0
- package/lib/utils/dataSourceDirty.d.ts +20 -0
- package/lib/utils/dataSourceDirty.js +139 -0
- package/lib/utils/dirtyAwareApiClient.d.ts +11 -0
- package/lib/utils/dirtyAwareApiClient.js +632 -0
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.js +11 -11
- package/lib/utils/loadedPageCache.d.ts +1 -0
- package/lib/utils/loadedPageCache.js +6 -0
- package/lib/utils/openViewRouteState.d.ts +28 -0
- package/lib/utils/openViewRouteState.js +125 -0
- package/lib/utils/parsePathnameToViewParams.d.ts +3 -0
- package/lib/utils/parsePathnameToViewParams.js +18 -1
- package/lib/utils/resolveRunJSObjectValues.js +3 -2
- package/lib/utils/runjsModuleLoader.js +0 -30
- package/lib/views/ViewNavigation.js +5 -0
- package/package.json +4 -4
- package/src/JSRunner.ts +112 -25
- package/src/__tests__/JSRunner.test.ts +4 -5
- package/src/__tests__/flowContext.test.ts +154 -0
- package/src/__tests__/flowEngine.dataSourceDirty.test.ts +51 -0
- package/src/__tests__/flowI18n.test.ts +11 -0
- package/src/__tests__/flowModel.openView.navigation.test.ts +28 -0
- package/src/__tests__/flowSettings.test.ts +72 -0
- package/src/__tests__/runjsRuntimeFeatures.test.ts +15 -2
- package/src/__tests__/viewScopedFlowEngine.test.ts +72 -6
- package/src/acl/Acl.tsx +36 -1
- package/src/acl/__tests__/Acl.test.tsx +70 -0
- package/src/components/FieldModelRenderer.tsx +50 -36
- package/src/components/FlowContextSelector.tsx +66 -11
- package/src/components/FormItem.tsx +12 -7
- package/src/components/MobilePopup.style.ts +34 -7
- package/src/components/MobilePopup.tsx +42 -10
- package/src/components/__tests__/FieldModelRenderer.test.tsx +165 -0
- package/src/components/__tests__/FormItem.test.tsx +17 -2
- package/src/components/__tests__/MobilePopup.style.test.tsx +103 -0
- package/src/components/__tests__/MobilePopup.test.tsx +150 -0
- package/src/components/dnd/index.tsx +11 -2
- package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +105 -35
- package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +381 -12
- package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +28 -0
- package/src/components/subModel/LazyDropdown.tsx +44 -26
- package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +85 -2
- package/src/components/variables/VariableHybridInput.tsx +185 -14
- package/src/components/variables/VariableInput.tsx +32 -7
- package/src/components/variables/VariableTag.tsx +51 -37
- package/src/components/variables/__tests__/FlowContextSelector.test.tsx +60 -3
- package/src/components/variables/__tests__/VariableHybridInput.test.tsx +212 -0
- package/src/components/variables/__tests__/VariableInput.test.tsx +202 -6
- package/src/components/variables/__tests__/VariableTag.test.tsx +80 -0
- package/src/components/variables/types.ts +21 -0
- package/src/flowContext.ts +104 -36
- package/src/flowEngine.ts +6 -0
- package/src/flowI18n.ts +8 -3
- package/src/flowSettings.ts +85 -1
- package/src/locale/__tests__/index.test.ts +21 -0
- package/src/locale/en-US.json +3 -0
- package/src/locale/zh-CN.json +3 -0
- package/src/resources/apiResource.ts +2 -1
- package/src/resources/baseRecordResource.ts +6 -23
- package/src/resources/multiRecordResource.ts +13 -3
- package/src/resources/singleRecordResource.ts +6 -1
- package/src/runjs-context/helpers.ts +12 -6
- package/src/types.ts +16 -0
- package/src/utils/__tests__/dirtyAwareApiClient.test.ts +713 -0
- package/src/utils/__tests__/openViewRouteState.test.ts +40 -0
- package/src/utils/__tests__/parsePathnameToViewParams.test.ts +36 -0
- package/src/utils/dataSourceDirty.ts +126 -0
- package/src/utils/dirtyAwareApiClient.ts +742 -0
- package/src/utils/index.ts +10 -9
- package/src/utils/loadedPageCache.ts +7 -0
- package/src/utils/openViewRouteState.ts +107 -0
- package/src/utils/parsePathnameToViewParams.ts +23 -1
- package/src/utils/resolveRunJSObjectValues.ts +5 -2
- package/src/utils/runjsModuleLoader.ts +0 -32
- package/src/views/ViewNavigation.ts +6 -1
- package/src/views/__tests__/ViewNavigation.test.ts +15 -0
- package/lib/utils/safeGlobals.d.ts +0 -28
- package/lib/utils/safeGlobals.js +0 -367
- package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +0 -38
- package/src/utils/__tests__/safeGlobals.test.ts +0 -106
- package/src/utils/safeGlobals.ts +0 -406
|
@@ -57,6 +57,10 @@ const EMPTY_COLUMN_UID = "EMPTY_COLUMN";
|
|
|
57
57
|
const TOOLBAR_DRAG_ACTIVITY_EVENT = "nb-toolbar-drag-activity";
|
|
58
58
|
const TOOLBAR_DRAG_ANCHOR_EVENT = "nb-toolbar-drag-anchor";
|
|
59
59
|
const MENU_SUBMENU_POPUP_SELECTOR = ".ant-menu-submenu-popup";
|
|
60
|
+
const getToolbarModelUidFromNode = /* @__PURE__ */ __name((node) => {
|
|
61
|
+
var _a;
|
|
62
|
+
return ((_a = node == null ? void 0 : node.closest(".nb-toolbar-container[data-model-uid]")) == null ? void 0 : _a.getAttribute("data-model-uid")) || null;
|
|
63
|
+
}, "getToolbarModelUidFromNode");
|
|
60
64
|
const resolveOverlayAnchorTransform = /* @__PURE__ */ __name(({
|
|
61
65
|
activeId,
|
|
62
66
|
active,
|
|
@@ -76,7 +80,7 @@ const resolveOverlayAnchorTransform = /* @__PURE__ */ __name(({
|
|
|
76
80
|
const resolveDraggableHostNode = /* @__PURE__ */ __name((activatorNode) => {
|
|
77
81
|
const ownerDocument = activatorNode == null ? void 0 : activatorNode.ownerDocument;
|
|
78
82
|
const floatToolbarContainer = activatorNode == null ? void 0 : activatorNode.closest(".nb-toolbar-container[data-model-uid]");
|
|
79
|
-
const toolbarModelUid =
|
|
83
|
+
const toolbarModelUid = getToolbarModelUidFromNode(activatorNode);
|
|
80
84
|
if (!ownerDocument || !toolbarModelUid) {
|
|
81
85
|
return activatorNode;
|
|
82
86
|
}
|
|
@@ -99,6 +103,7 @@ const DragHandler = /* @__PURE__ */ __name(({
|
|
|
99
103
|
const dragHandlerRef = (0, import_react.useRef)(null);
|
|
100
104
|
const draggableNodeRef = (0, import_react.useRef)(null);
|
|
101
105
|
const pointerPressCleanupRef = (0, import_react.useRef)(null);
|
|
106
|
+
const toolbarDragModelUidRef = (0, import_react.useRef)(null);
|
|
102
107
|
const isDraggingRef = (0, import_react.useRef)(isDragging);
|
|
103
108
|
const isPointerPressActiveRef = (0, import_react.useRef)(false);
|
|
104
109
|
const isToolbarDragActiveRef = (0, import_react.useRef)(false);
|
|
@@ -128,9 +133,11 @@ const DragHandler = /* @__PURE__ */ __name(({
|
|
|
128
133
|
if (!ownerDocument) {
|
|
129
134
|
return;
|
|
130
135
|
}
|
|
136
|
+
const toolbarModelUid = getToolbarModelUidFromNode(dragHandlerRef.current) || toolbarDragModelUidRef.current || model.uid;
|
|
137
|
+
toolbarDragModelUidRef.current = active ? toolbarModelUid : null;
|
|
131
138
|
ownerDocument.dispatchEvent(
|
|
132
139
|
new CustomEvent(TOOLBAR_DRAG_ACTIVITY_EVENT, {
|
|
133
|
-
detail: { active, modelUid:
|
|
140
|
+
detail: { active, modelUid: toolbarModelUid }
|
|
134
141
|
})
|
|
135
142
|
);
|
|
136
143
|
},
|
|
@@ -44,6 +44,7 @@ var import_react = __toESM(require("react"));
|
|
|
44
44
|
var import_react_dom = require("react-dom");
|
|
45
45
|
var import_antd = require("antd");
|
|
46
46
|
var import_css = require("@emotion/css");
|
|
47
|
+
var import_ahooks = require("ahooks");
|
|
47
48
|
var import_hooks = require("../../../../hooks");
|
|
48
49
|
var import_provider = require("../../../../provider");
|
|
49
50
|
var import_utils = require("../../../../utils");
|
|
@@ -312,6 +313,38 @@ const buildToolbarContainerStyle = /* @__PURE__ */ __name((portalRect, toolbarSt
|
|
|
312
313
|
const isModelByIdProps = /* @__PURE__ */ __name((props) => {
|
|
313
314
|
return "uid" in props && "modelClassName" in props && Boolean(props.uid) && Boolean(props.modelClassName);
|
|
314
315
|
}, "isModelByIdProps");
|
|
316
|
+
const stopResizeInteractionEvent = /* @__PURE__ */ __name((event) => {
|
|
317
|
+
var _a;
|
|
318
|
+
if (!event) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
event.preventDefault();
|
|
322
|
+
event.stopPropagation();
|
|
323
|
+
const nativeEvent = "nativeEvent" in event ? event.nativeEvent : event;
|
|
324
|
+
(_a = nativeEvent.stopImmediatePropagation) == null ? void 0 : _a.call(nativeEvent);
|
|
325
|
+
}, "stopResizeInteractionEvent");
|
|
326
|
+
const pendingResizeClickSuppressions = /* @__PURE__ */ new WeakMap();
|
|
327
|
+
const clearPendingResizeClickSuppression = /* @__PURE__ */ __name((ownerDocument) => {
|
|
328
|
+
const pending = pendingResizeClickSuppressions.get(ownerDocument);
|
|
329
|
+
if (!pending) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
ownerDocument.removeEventListener("click", pending.listener, true);
|
|
333
|
+
(ownerDocument.defaultView || window).clearTimeout(pending.timer);
|
|
334
|
+
pendingResizeClickSuppressions.delete(ownerDocument);
|
|
335
|
+
}, "clearPendingResizeClickSuppression");
|
|
336
|
+
const suppressNextResizeClick = /* @__PURE__ */ __name((ownerDocument) => {
|
|
337
|
+
clearPendingResizeClickSuppression(ownerDocument);
|
|
338
|
+
const listener = /* @__PURE__ */ __name((event) => {
|
|
339
|
+
stopResizeInteractionEvent(event);
|
|
340
|
+
clearPendingResizeClickSuppression(ownerDocument);
|
|
341
|
+
}, "listener");
|
|
342
|
+
const timer = (ownerDocument.defaultView || window).setTimeout(() => {
|
|
343
|
+
clearPendingResizeClickSuppression(ownerDocument);
|
|
344
|
+
}, 0);
|
|
345
|
+
pendingResizeClickSuppressions.set(ownerDocument, { listener, timer });
|
|
346
|
+
ownerDocument.addEventListener("click", listener, true);
|
|
347
|
+
}, "suppressNextResizeClick");
|
|
315
348
|
const FlowsFloatContextMenu = (0, import_reactive.observer)((props) => {
|
|
316
349
|
const ctx = (0, import__.useFlowContext)();
|
|
317
350
|
if (!ctx.flowSettingsEnabled) {
|
|
@@ -326,44 +359,64 @@ const ResizeHandles = /* @__PURE__ */ __name((props) => {
|
|
|
326
359
|
const isDraggingRef = (0, import_react.useRef)(false);
|
|
327
360
|
const dragTypeRef = (0, import_react.useRef)(null);
|
|
328
361
|
const dragStartPosRef = (0, import_react.useRef)({ x: 0, y: 0 });
|
|
362
|
+
const dragOwnerDocumentRef = (0, import_react.useRef)(null);
|
|
329
363
|
const { onDragStart, onDragEnd } = props;
|
|
330
|
-
const handleDragMove = (0,
|
|
331
|
-
(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
364
|
+
const handleDragMove = (0, import_ahooks.useMemoizedFn)((e) => {
|
|
365
|
+
if (!isDraggingRef.current || !dragTypeRef.current) return;
|
|
366
|
+
stopResizeInteractionEvent(e);
|
|
367
|
+
const deltaX = e.clientX - dragStartPosRef.current.x;
|
|
368
|
+
switch (dragTypeRef.current) {
|
|
369
|
+
case "left":
|
|
370
|
+
props.model.parent.emitter.emit("onResizeLeft", { resizeDistance: -deltaX, model: props.model });
|
|
371
|
+
break;
|
|
372
|
+
case "right":
|
|
373
|
+
props.model.parent.emitter.emit("onResizeRight", { resizeDistance: deltaX, model: props.model });
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
const handleDragEnd = (0, import_ahooks.useMemoizedFn)((e) => {
|
|
378
|
+
if (!isDraggingRef.current) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
stopResizeInteractionEvent(e);
|
|
382
|
+
const ownerDocument = dragOwnerDocumentRef.current || document;
|
|
383
|
+
ownerDocument.removeEventListener("mousemove", handleDragMove, true);
|
|
384
|
+
ownerDocument.removeEventListener("mouseup", handleDragEnd, true);
|
|
385
|
+
suppressNextResizeClick(ownerDocument);
|
|
346
386
|
isDraggingRef.current = false;
|
|
347
387
|
dragTypeRef.current = null;
|
|
348
388
|
dragStartPosRef.current = { x: 0, y: 0 };
|
|
349
|
-
|
|
350
|
-
document.removeEventListener("mouseup", handleDragEnd);
|
|
389
|
+
dragOwnerDocumentRef.current = null;
|
|
351
390
|
props.model.parent.emitter.emit("onResizeEnd");
|
|
352
391
|
onDragEnd == null ? void 0 : onDragEnd();
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
(
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
392
|
+
});
|
|
393
|
+
(0, import_react.useEffect)(() => {
|
|
394
|
+
return () => {
|
|
395
|
+
const dragOwnerDocument = dragOwnerDocumentRef.current;
|
|
396
|
+
dragOwnerDocument == null ? void 0 : dragOwnerDocument.removeEventListener("mousemove", handleDragMove, true);
|
|
397
|
+
dragOwnerDocument == null ? void 0 : dragOwnerDocument.removeEventListener("mouseup", handleDragEnd, true);
|
|
398
|
+
if (isDraggingRef.current) {
|
|
399
|
+
suppressNextResizeClick(dragOwnerDocument || document);
|
|
400
|
+
props.model.parent.emitter.emit("onResizeEnd");
|
|
401
|
+
onDragEnd == null ? void 0 : onDragEnd();
|
|
402
|
+
}
|
|
403
|
+
isDraggingRef.current = false;
|
|
404
|
+
dragTypeRef.current = null;
|
|
405
|
+
dragStartPosRef.current = { x: 0, y: 0 };
|
|
406
|
+
dragOwnerDocumentRef.current = null;
|
|
407
|
+
};
|
|
408
|
+
}, [handleDragMove, handleDragEnd, onDragEnd, props.model]);
|
|
409
|
+
const handleDragStart = (0, import_ahooks.useMemoizedFn)((e, type) => {
|
|
410
|
+
stopResizeInteractionEvent(e);
|
|
411
|
+
const ownerDocument = e.currentTarget.ownerDocument;
|
|
412
|
+
isDraggingRef.current = true;
|
|
413
|
+
dragTypeRef.current = type;
|
|
414
|
+
dragStartPosRef.current = { x: e.clientX, y: e.clientY };
|
|
415
|
+
dragOwnerDocumentRef.current = ownerDocument;
|
|
416
|
+
ownerDocument.addEventListener("mousemove", handleDragMove, true);
|
|
417
|
+
ownerDocument.addEventListener("mouseup", handleDragEnd, true);
|
|
418
|
+
onDragStart == null ? void 0 : onDragStart();
|
|
419
|
+
});
|
|
367
420
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
|
|
368
421
|
"div",
|
|
369
422
|
{
|
|
@@ -466,6 +519,7 @@ const FlowsFloatContextMenuWithModel = (0, import_reactive.observer)(
|
|
|
466
519
|
getPopupContainer,
|
|
467
520
|
handleSettingsMenuOpenChange,
|
|
468
521
|
model,
|
|
522
|
+
modelUid,
|
|
469
523
|
settingsMenuLevel,
|
|
470
524
|
showCopyUidButton,
|
|
471
525
|
showDeleteButton,
|
|
@@ -44,6 +44,17 @@ const getToolbarModelUidFromTarget = /* @__PURE__ */ __name((target) => {
|
|
|
44
44
|
}
|
|
45
45
|
return ((_a = target.closest(".nb-toolbar-container[data-model-uid]")) == null ? void 0 : _a.getAttribute("data-model-uid")) || null;
|
|
46
46
|
}, "getToolbarModelUidFromTarget");
|
|
47
|
+
const escapeCssAttributeValue = /* @__PURE__ */ __name((value) => {
|
|
48
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\a ").replace(/\r/g, "\\d ").replace(/\f/g, "\\c ");
|
|
49
|
+
}, "escapeCssAttributeValue");
|
|
50
|
+
const isToolbarModelUidRendered = /* @__PURE__ */ __name((ownerDocument, modelUid) => {
|
|
51
|
+
if (!ownerDocument) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return !!ownerDocument.querySelector(
|
|
55
|
+
`.nb-toolbar-container[data-model-uid="${escapeCssAttributeValue(modelUid)}"]`
|
|
56
|
+
);
|
|
57
|
+
}, "isToolbarModelUidRendered");
|
|
47
58
|
const isNodeWithinDescendantFloatToolbar = /* @__PURE__ */ __name((target, container, currentModelUid) => {
|
|
48
59
|
const targetModelUid = getToolbarModelUidFromTarget(target);
|
|
49
60
|
if (!container || !targetModelUid || targetModelUid === currentModelUid) {
|
|
@@ -222,6 +233,15 @@ const useFloatToolbarVisibility = /* @__PURE__ */ __name(({
|
|
|
222
233
|
const isCurrentHostTarget = !childWithMenu || childWithMenu === containerRef.current;
|
|
223
234
|
if (isCurrentHostTarget) {
|
|
224
235
|
clearHideToolbarTimer();
|
|
236
|
+
setActiveChildToolbarIds((prevIds) => {
|
|
237
|
+
var _a;
|
|
238
|
+
if (!prevIds.length) {
|
|
239
|
+
return prevIds;
|
|
240
|
+
}
|
|
241
|
+
const ownerDocument = ((_a = containerRef.current) == null ? void 0 : _a.ownerDocument) ?? null;
|
|
242
|
+
const nextIds = prevIds.filter((id) => isToolbarModelUidRendered(ownerDocument, id));
|
|
243
|
+
return nextIds.length === prevIds.length ? prevIds : nextIds;
|
|
244
|
+
});
|
|
225
245
|
setHostHovered(true);
|
|
226
246
|
}
|
|
227
247
|
setHideMenu(!!childWithMenu && childWithMenu !== containerRef.current);
|
|
@@ -347,19 +347,15 @@ const createSearchItem = /* @__PURE__ */ __name((item, searchKey, currentSearchV
|
|
|
347
347
|
e.stopPropagation();
|
|
348
348
|
},
|
|
349
349
|
onChange: (e) => {
|
|
350
|
-
var _a;
|
|
351
350
|
e.stopPropagation();
|
|
352
351
|
const value = e.target.value;
|
|
353
352
|
if (shouldActivateSearchSubmenu) {
|
|
354
353
|
activateSearchSubmenu(searchKey);
|
|
355
354
|
}
|
|
356
|
-
if (
|
|
355
|
+
if (e.nativeEvent.isComposing || searchHandlers.isComposing(searchKey)) {
|
|
357
356
|
searchHandlers.updateInputValue(searchKey, value);
|
|
358
357
|
return;
|
|
359
358
|
}
|
|
360
|
-
if (!value && shouldActivateSearchSubmenu) {
|
|
361
|
-
deactivateSearchSubmenu(searchKey);
|
|
362
|
-
}
|
|
363
359
|
searchHandlers.updateSearchValue(searchKey, value);
|
|
364
360
|
},
|
|
365
361
|
onCompositionStart: (e) => {
|
|
@@ -373,11 +369,7 @@ const createSearchItem = /* @__PURE__ */ __name((item, searchKey, currentSearchV
|
|
|
373
369
|
e.stopPropagation();
|
|
374
370
|
const value = e.currentTarget.value;
|
|
375
371
|
if (shouldActivateSearchSubmenu) {
|
|
376
|
-
|
|
377
|
-
activateSearchSubmenu(searchKey);
|
|
378
|
-
} else {
|
|
379
|
-
deactivateSearchSubmenu(searchKey);
|
|
380
|
-
}
|
|
372
|
+
activateSearchSubmenu(searchKey);
|
|
381
373
|
}
|
|
382
374
|
searchHandlers.endComposition(searchKey, value);
|
|
383
375
|
},
|
|
@@ -385,10 +377,20 @@ const createSearchItem = /* @__PURE__ */ __name((item, searchKey, currentSearchV
|
|
|
385
377
|
e.stopPropagation();
|
|
386
378
|
},
|
|
387
379
|
onKeyDown: (e) => {
|
|
380
|
+
if (e.key === "Escape" || e.key === "Tab") {
|
|
381
|
+
deactivateSearchSubmenu(searchKey);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (shouldActivateSearchSubmenu) {
|
|
385
|
+
activateSearchSubmenu(searchKey);
|
|
386
|
+
}
|
|
388
387
|
e.stopPropagation();
|
|
389
388
|
},
|
|
390
389
|
onMouseDown: (e) => {
|
|
391
390
|
e.stopPropagation();
|
|
391
|
+
if (shouldActivateSearchSubmenu) {
|
|
392
|
+
activateSearchSubmenu(searchKey);
|
|
393
|
+
}
|
|
392
394
|
},
|
|
393
395
|
size: "small",
|
|
394
396
|
style: {
|
|
@@ -409,7 +411,7 @@ const KEEP_OPEN_LABEL_STYLE = {
|
|
|
409
411
|
width: "100%"
|
|
410
412
|
};
|
|
411
413
|
const DROPDOWN_PERSIST_TTL_MS = 350;
|
|
412
|
-
const
|
|
414
|
+
const MENU_CLOSE_DELAY = 0.3;
|
|
413
415
|
const SUBMENU_MOTION_DISABLED = {
|
|
414
416
|
motionEnter: false,
|
|
415
417
|
motionLeave: false
|
|
@@ -417,13 +419,18 @@ const SUBMENU_MOTION_DISABLED = {
|
|
|
417
419
|
const dropdownPersistRegistry = /* @__PURE__ */ new Map();
|
|
418
420
|
const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
419
421
|
const engine = (0, import_provider.useFlowEngine)();
|
|
422
|
+
const { getPrefixCls } = import_react.default.useContext(import_antd.ConfigProvider.ConfigContext);
|
|
423
|
+
const triggerId = import_react.default.useId();
|
|
420
424
|
const [menuVisible, setMenuVisible] = (0, import_react.useState)(false);
|
|
421
425
|
const [openKeys, setOpenKeys] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
422
|
-
const [activeSearchKey, setActiveSearchKey] = (0, import_react.useState)(null);
|
|
423
426
|
const [rootItems, setRootItems] = (0, import_react.useState)([]);
|
|
424
427
|
const [rootLoading, setRootLoading] = (0, import_react.useState)(false);
|
|
428
|
+
const activeSearchKeyRef = (0, import_react.useRef)(null);
|
|
425
429
|
const closeByOutsideClickRef = (0, import_react.useRef)(false);
|
|
426
430
|
const skipPreserveActiveSearchRef = (0, import_react.useRef)(false);
|
|
431
|
+
const triggerOpenClassName = `nb-lazy-dropdown-trigger-${triggerId.replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
432
|
+
const defaultOpenClassName = `${getPrefixCls("dropdown", props.prefixCls)}-open`;
|
|
433
|
+
const mergedOpenClassName = [props.openClassName ?? defaultOpenClassName, triggerOpenClassName].filter(Boolean).join(" ");
|
|
427
434
|
const dropdownMaxHeight = useNiceDropdownMaxHeight();
|
|
428
435
|
const t = engine.translate.bind(engine);
|
|
429
436
|
const { items: menuItems, keepDropdownOpen, persistKey, stateVersion, refreshKeys, ...dropdownMenuProps } = menu;
|
|
@@ -440,12 +447,12 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
440
447
|
useSubmenuStyles(menuVisible, dropdownMaxHeight);
|
|
441
448
|
const closeMenu = (0, import_react.useCallback)(() => {
|
|
442
449
|
setMenuVisible(false);
|
|
443
|
-
|
|
450
|
+
activeSearchKeyRef.current = null;
|
|
444
451
|
setOpenKeys(/* @__PURE__ */ new Set());
|
|
445
452
|
clearAllSearchValues();
|
|
446
453
|
}, [clearAllSearchValues]);
|
|
447
454
|
const activateSearchSubmenu = (0, import_react.useCallback)((key) => {
|
|
448
|
-
|
|
455
|
+
activeSearchKeyRef.current = key;
|
|
449
456
|
setOpenKeys((prev) => {
|
|
450
457
|
if (prev.has(key)) return prev;
|
|
451
458
|
const next = new Set(prev);
|
|
@@ -454,34 +461,38 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
454
461
|
});
|
|
455
462
|
}, []);
|
|
456
463
|
const deactivateSearchSubmenu = (0, import_react.useCallback)((key) => {
|
|
457
|
-
|
|
464
|
+
if (activeSearchKeyRef.current === key) {
|
|
465
|
+
activeSearchKeyRef.current = null;
|
|
466
|
+
}
|
|
458
467
|
}, []);
|
|
459
468
|
const closeActiveSearchForPath = (0, import_react.useCallback)(
|
|
460
469
|
(keyPath) => {
|
|
470
|
+
const activeSearchKey = activeSearchKeyRef.current;
|
|
461
471
|
if (!activeSearchKey || keyPath === activeSearchKey || keyPath.startsWith(`${activeSearchKey}/`) || activeSearchKey.startsWith(`${keyPath}/`)) {
|
|
462
472
|
return;
|
|
463
473
|
}
|
|
464
474
|
skipPreserveActiveSearchRef.current = true;
|
|
465
475
|
clearSearchValue(activeSearchKey);
|
|
466
|
-
|
|
476
|
+
activeSearchKeyRef.current = null;
|
|
467
477
|
setOpenKeys((prev) => {
|
|
468
478
|
const next = new Set(prev);
|
|
469
479
|
next.delete(activeSearchKey);
|
|
470
480
|
return next;
|
|
471
481
|
});
|
|
472
482
|
},
|
|
473
|
-
[
|
|
483
|
+
[clearSearchValue]
|
|
474
484
|
);
|
|
475
485
|
const handleMenuOpenChange = (0, import_react.useCallback)(
|
|
476
486
|
(nextOpenKeys) => {
|
|
477
487
|
var _a, _b;
|
|
478
488
|
let normalized = normalizeOpenKeys(nextOpenKeys);
|
|
479
|
-
|
|
480
|
-
|
|
489
|
+
const activeSearchKey = activeSearchKeyRef.current;
|
|
490
|
+
if (activeSearchKey && !normalized.includes(activeSearchKey)) {
|
|
491
|
+
if (skipPreserveActiveSearchRef.current) {
|
|
481
492
|
clearSearchValue(activeSearchKey);
|
|
482
|
-
|
|
493
|
+
activeSearchKeyRef.current = null;
|
|
483
494
|
} else {
|
|
484
|
-
normalized =
|
|
495
|
+
normalized = Array.from(openKeys);
|
|
485
496
|
}
|
|
486
497
|
}
|
|
487
498
|
if (!normalized.length && shouldPreventClose()) {
|
|
@@ -498,13 +509,15 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
498
509
|
(_b = dropdownMenuProps.onOpenChange) == null ? void 0 : _b.call(dropdownMenuProps, normalized);
|
|
499
510
|
skipPreserveActiveSearchRef.current = false;
|
|
500
511
|
},
|
|
501
|
-
[
|
|
512
|
+
[clearSearchValue, dropdownMenuProps, openKeys, shouldPreventClose]
|
|
502
513
|
);
|
|
503
514
|
(0, import_react.useEffect)(() => {
|
|
504
515
|
if (!menuVisible) return;
|
|
505
516
|
const markOutsideClick = /* @__PURE__ */ __name((event) => {
|
|
506
517
|
const target = event.target;
|
|
507
|
-
const
|
|
518
|
+
const isInsidePopup = target == null ? void 0 : target.closest(".ant-dropdown, .ant-dropdown-menu, .ant-dropdown-menu-submenu-popup");
|
|
519
|
+
const isInsideCurrentTrigger = target == null ? void 0 : target.closest(`.${triggerOpenClassName}`);
|
|
520
|
+
const isOutside = !isInsidePopup && !isInsideCurrentTrigger;
|
|
508
521
|
closeByOutsideClickRef.current = isOutside;
|
|
509
522
|
if (isOutside) {
|
|
510
523
|
closeMenu();
|
|
@@ -516,7 +529,7 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
516
529
|
document.removeEventListener("pointerdown", markOutsideClick, true);
|
|
517
530
|
document.removeEventListener("mousedown", markOutsideClick, true);
|
|
518
531
|
};
|
|
519
|
-
}, [closeMenu, menuVisible]);
|
|
532
|
+
}, [closeMenu, menuVisible, triggerOpenClassName]);
|
|
520
533
|
(0, import_react.useEffect)(() => {
|
|
521
534
|
if (!persistKey) return;
|
|
522
535
|
const until = dropdownPersistRegistry.get(persistKey) || 0;
|
|
@@ -734,13 +747,15 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
734
747
|
...props,
|
|
735
748
|
open: menuVisible,
|
|
736
749
|
destroyPopupOnHide: true,
|
|
750
|
+
mouseLeaveDelay: props.mouseLeaveDelay ?? MENU_CLOSE_DELAY,
|
|
751
|
+
openClassName: mergedOpenClassName,
|
|
737
752
|
overlayClassName,
|
|
738
753
|
placement: "bottomLeft",
|
|
739
754
|
menu: {
|
|
740
755
|
...dropdownMenuProps,
|
|
741
756
|
openKeys: Array.from(openKeys),
|
|
742
757
|
items,
|
|
743
|
-
subMenuCloseDelay: dropdownMenuProps.subMenuCloseDelay ??
|
|
758
|
+
subMenuCloseDelay: dropdownMenuProps.subMenuCloseDelay ?? MENU_CLOSE_DELAY,
|
|
744
759
|
motion: dropdownMenuProps.motion ?? SUBMENU_MOTION_DISABLED,
|
|
745
760
|
onClick: /* @__PURE__ */ __name(() => {
|
|
746
761
|
}, "onClick"),
|
|
@@ -752,7 +767,7 @@ const LazyDropdown = /* @__PURE__ */ __name(({ menu, ...props }) => {
|
|
|
752
767
|
}
|
|
753
768
|
},
|
|
754
769
|
onOpenChange: (visible, info) => {
|
|
755
|
-
if (!visible &&
|
|
770
|
+
if (!visible && activeSearchKeyRef.current && (info == null ? void 0 : info.source) === "trigger" && !closeByOutsideClickRef.current) {
|
|
756
771
|
return;
|
|
757
772
|
}
|
|
758
773
|
if (!visible && shouldPreventClose()) {
|
|
@@ -17,11 +17,20 @@ export interface VariableHybridInputProps {
|
|
|
17
17
|
value?: string;
|
|
18
18
|
onChange?: (value: string) => void;
|
|
19
19
|
disabled?: boolean;
|
|
20
|
+
readOnly?: boolean;
|
|
20
21
|
placeholder?: string;
|
|
21
22
|
addonBefore?: React.ReactNode;
|
|
22
23
|
metaTree?: MetaTreeNode[] | (() => MetaTreeNode[] | Promise<MetaTreeNode[]>);
|
|
23
24
|
converters?: VariableHybridInputConverters;
|
|
24
25
|
style?: React.CSSProperties;
|
|
25
26
|
className?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Validation status — turns the input border red (`error`) or amber
|
|
29
|
+
* (`warning`). Usually omitted: when rendered inside an antd `Form.Item`, the
|
|
30
|
+
* status is read automatically from `FormItemInputContext`, so dropping this
|
|
31
|
+
* into a `Form.Item` with failing rules colours the border with no extra
|
|
32
|
+
* wiring. An explicit prop wins over the inherited form status.
|
|
33
|
+
*/
|
|
34
|
+
status?: 'error' | 'warning';
|
|
26
35
|
}
|
|
27
36
|
export declare const VariableHybridInput: React.NamedExoticComponent<VariableHybridInputProps>;
|