flow-lib-creomnia 1.0.17 → 1.0.19-dev.2

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.
@@ -1,4 +1,3 @@
1
- import React, { Ref } from "react";
2
1
  import { PointType } from "../../../common/types";
3
2
  import { NodeType } from "../../../node/types";
4
3
  import { ConnectionCurveEnum } from "../../enums";
@@ -9,8 +8,7 @@ interface IProps {
9
8
  childNodeId: string;
10
9
  node: NodeType;
11
10
  curveType?: ConnectionCurveEnum;
12
- onClick?: (event: React.MouseEvent<SVGSVGElement>) => void;
13
- innerRef: Ref<any>;
11
+ onOpen?: (anchorRect: DOMRect) => void;
14
12
  }
15
- export declare const AddButton: ({ endPoint, startPoint, node, curveType, parentId, childNodeId, onClick, innerRef }: IProps) => import("react/jsx-runtime").JSX.Element;
13
+ export declare const AddButton: ({ endPoint, startPoint, node, curveType, parentId, childNodeId, onOpen, }: IProps) => import("react/jsx-runtime").JSX.Element;
16
14
  export {};
@@ -10,7 +10,7 @@ const ConnectionWithButton_1 = require("../ConnectionWithButton");
10
10
  const enums_1 = require("../../enums");
11
11
  const colors_1 = require("../../../../config/colors");
12
12
  const material_1 = require("@mui/material");
13
- const AddButton = ({ endPoint, startPoint, node, curveType, parentId, childNodeId, onClick, innerRef }) => {
13
+ const AddButton = ({ endPoint, startPoint, node, curveType, parentId, childNodeId, onOpen, }) => {
14
14
  const theme = (0, material_1.useTheme)();
15
15
  const background = theme.palette?.background?.default || colors_1.Colors.DIRTY_WHITE;
16
16
  const positionIntoEmptyChoiceNode = !curveType ? 0 : curveType === enums_1.ConnectionCurveEnum.RIGHT ? 2 : 1;
@@ -31,15 +31,34 @@ const AddButton = ({ endPoint, startPoint, node, curveType, parentId, childNodeI
31
31
  const yPosition = y + ConnectionWithButton_1.nodeHeightByType[node.type] / 2 + config_1.Config.ADD_BUTTON_SHIFT;
32
32
  const PlusButton = (0, styled_1.createAddButton)({
33
33
  background,
34
+ });
35
+ const PlusButtonWrapper = (0, styled_1.createAddButtonWrapper)({
34
36
  x: xPosition,
35
37
  y: yPosition,
36
38
  });
37
39
  const Placeholder = (0, styled_1.createPlaceholder)(isOver, canDrop);
38
40
  const xDropZone = xPosition - (config_1.Config.NODE_WIDTH / 2 - 5);
39
41
  const yDropZone = yPosition - (config_1.Config.NODE_HEIGHT / 2 - config_1.Config.ADD_BUTTON_WIDTH / 2);
42
+ // The add button lives inside the zoom/pan surface. Without
43
+ // stopping the initial press event, the canvas can start a pan
44
+ // gesture first, and the browser may never emit the follow-up
45
+ // click that opens the nodes menu. This shows up most clearly in
46
+ // the tool-flow modal, where the nested sandbox is rendered inside
47
+ // a Dialog on top of another live canvas.
48
+ const stopCanvasGesture = (event) => {
49
+ event.stopPropagation();
50
+ };
51
+ const handlePressStart = (event) => {
52
+ // Keep the canvas from treating the press as pan/scroll start,
53
+ // then open the menu immediately instead of waiting for a full
54
+ // click sequence that may never fire once a gesture begins.
55
+ event.preventDefault();
56
+ stopCanvasGesture(event);
57
+ onOpen?.(event.currentTarget.getBoundingClientRect());
58
+ };
40
59
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Placeholder, { ref: drop, sx: {
41
60
  top: yDropZone,
42
61
  left: xDropZone,
43
- } }), (0, jsx_runtime_1.jsx)(PlusButton, { onClick: onClick, ref: innerRef })] }));
62
+ } }), (0, jsx_runtime_1.jsx)(PlusButtonWrapper, { "data-flow-interactive": 'true', onMouseDown: handlePressStart, onPointerDown: handlePressStart, onTouchStart: handlePressStart, onClick: stopCanvasGesture, children: (0, jsx_runtime_1.jsx)(PlusButton, {}) })] }));
44
63
  };
45
64
  exports.AddButton = AddButton;
@@ -4,7 +4,8 @@ type AddButtonPropsType = {
4
4
  x: number;
5
5
  y: number;
6
6
  };
7
- export declare const createAddButton: ({ background, x, y, }: AddButtonPropsType) => import("@emotion/styled").StyledComponent<{
7
+ export declare const createAddButtonWrapper: ({ x, y, }: Omit<AddButtonPropsType, 'background'>) => import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<import("@mui/system").Theme>, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
8
+ export declare const createAddButton: ({ background, }: Omit<AddButtonPropsType, 'x' | 'y'>) => import("@emotion/styled").StyledComponent<{
8
9
  children?: import("react").ReactNode;
9
10
  classes?: Partial<import("@mui/material").SvgIconClasses> | undefined;
10
11
  color?: import("@mui/types").OverridableStringUnion<"error" | "inherit" | "action" | "disabled" | "success" | "info" | "warning" | "primary" | "secondary", import("@mui/material").SvgIconPropsColorOverrides> | undefined;
@@ -3,24 +3,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createPlaceholder = exports.createAddButton = void 0;
6
+ exports.createPlaceholder = exports.createAddButton = exports.createAddButtonWrapper = void 0;
7
7
  const system_1 = require("@mui/system");
8
8
  const Add_1 = __importDefault(require("@mui/icons-material/Add"));
9
9
  const config_1 = require("../../../../config");
10
10
  const colors_1 = require("../../../../config/colors");
11
11
  const material_1 = require("@mui/material");
12
- const createAddButton = ({ background = colors_1.Colors.WHITE, x, y, }) => (0, system_1.styled)(Add_1.default) `
13
- height: ${config_1.Config.ADD_BUTTON_WIDTH}px;
14
- width: ${config_1.Config.ADD_BUTTON_WIDTH}px;
12
+ const createAddButtonWrapper = ({ x, y, }) => (0, system_1.styled)('div') `
15
13
  position: absolute;
16
14
  top: ${y}px;
17
15
  left: ${x}px;
16
+ width: ${config_1.Config.ADD_BUTTON_WIDTH}px;
17
+ height: ${config_1.Config.ADD_BUTTON_WIDTH}px;
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ cursor: pointer;
22
+ z-index: 1000;
23
+ `;
24
+ exports.createAddButtonWrapper = createAddButtonWrapper;
25
+ const createAddButton = ({ background = colors_1.Colors.WHITE, }) => (0, system_1.styled)(Add_1.default) `
26
+ height: ${config_1.Config.ADD_BUTTON_WIDTH}px;
27
+ width: ${config_1.Config.ADD_BUTTON_WIDTH}px;
18
28
  font-size: ${config_1.Config.ADD_BUTTON_WIDTH}px;
19
29
  background: ${background};
20
30
  color: ${colors_1.Colors.NAVY_BLUE};
21
31
  border-radius: 50%;
22
- cursor: pointer;
23
- z-index: 1000;
24
32
  :hover {
25
33
  background: ${colors_1.Colors.BLUE};
26
34
  color: ${colors_1.Colors.WHITE};
@@ -24,9 +24,7 @@ exports.nodeHeightByType = {
24
24
  [enums_1.NodeTypeEnum.ParallelNode]: 0,
25
25
  };
26
26
  const ConnectionWithButton = ({ parentId, menuTabs, startPoint, endPoint, addNewNodeCallback, node, connectionIndex, curveType, isProcessed, childNodeId, emptyMenuItemsComponent, searchPlaceholder }) => {
27
- const popperRef = (0, react_1.useRef)();
28
- const [anchorEl, setAnchorEl] = (0, react_1.useState)(false);
29
- const [styles, setStyles] = (0, react_1.useState)({});
27
+ const [anchorRect, setAnchorRect] = (0, react_1.useState)(null);
30
28
  const ConnectionLine = (0, react_1.useMemo)(() => {
31
29
  const { width, height, x, y, top, bottom, left, right } = connectionParametersServices_1.connectionParametersServices.calculateConnectionParameters({
32
30
  endPoint,
@@ -48,19 +46,18 @@ const ConnectionWithButton = ({ parentId, menuTabs, startPoint, endPoint, addNew
48
46
  });
49
47
  }, [curveType, endPoint, node, startPoint]);
50
48
  const handleClose = () => {
51
- setAnchorEl(false);
49
+ setAnchorRect(null);
52
50
  };
53
- const handleClick = (event) => {
54
- const rect = popperRef?.current?.getBoundingClientRect();
55
- const left = rect?.left || 0;
56
- const top = rect?.top || 0;
57
- const style = {
58
- transform: `translate(${left - 400}px, ${top - 228}px)`,
59
- overflow: 'visible',
60
- };
61
- setStyles(style);
62
- setAnchorEl(true);
51
+ const handleOpen = (nextAnchorRect) => {
52
+ setAnchorRect(nextAnchorRect);
63
53
  };
54
+ const anchorEl = (0, react_1.useMemo)(() => {
55
+ if (!anchorRect)
56
+ return null;
57
+ return {
58
+ getBoundingClientRect: () => anchorRect,
59
+ };
60
+ }, [anchorRect]);
64
61
  const isOpen = Boolean(anchorEl);
65
62
  const props = (0, web_1.useSpring)({
66
63
  borderColor: isProcessed ? colors_1.Colors.GREEN : colors_1.Colors.NAVY_BLUE,
@@ -76,9 +73,11 @@ const ConnectionWithButton = ({ parentId, menuTabs, startPoint, endPoint, addNew
76
73
  curveType,
77
74
  parentId,
78
75
  childNodeId,
79
- onClick: handleClick,
80
- innerRef: popperRef
76
+ onOpen: handleOpen,
81
77
  };
82
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(AddButton_1.AddButton, { ...buttonProps }), (0, jsx_runtime_1.jsx)(AnimatedConnectionLine, { style: props }), (0, jsx_runtime_1.jsx)(material_1.ClickAwayListener, { onClickAway: () => isOpen && handleClose(), mouseEvent: "onMouseDown", touchEvent: "onTouchStart", children: (0, jsx_runtime_1.jsx)(styled_1.StyledPopper, { placement: 'left', open: isOpen, sx: styles, modifiers: [{ name: 'arrow', enabled: true }], children: (0, jsx_runtime_1.jsx)(NodesMenu_1.default, { addNewNodeCallback: addNewNodeCallback, data: { parentId, connectionIndex }, menuTabs: menuTabs, onCloseMenu: handleClose, emptyMenuItemsComponent: emptyMenuItemsComponent, searchPlaceholder: searchPlaceholder }) }) })] }));
78
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(AddButton_1.AddButton, { ...buttonProps }), (0, jsx_runtime_1.jsx)(AnimatedConnectionLine, { style: props }), (0, jsx_runtime_1.jsx)(material_1.ClickAwayListener, { onClickAway: () => isOpen && handleClose(), mouseEvent: "onMouseDown", touchEvent: "onTouchStart", children: (0, jsx_runtime_1.jsx)(styled_1.StyledPopper, { anchorEl: anchorEl, placement: 'left', open: isOpen, modifiers: [
79
+ { name: 'arrow', enabled: true },
80
+ { name: 'offset', options: { offset: [0, 0] } },
81
+ ], children: (0, jsx_runtime_1.jsx)(NodesMenu_1.default, { addNewNodeCallback: addNewNodeCallback, data: { parentId, connectionIndex }, menuTabs: menuTabs, onCloseMenu: handleClose, emptyMenuItemsComponent: emptyMenuItemsComponent, searchPlaceholder: searchPlaceholder }) }) })] }));
83
82
  };
84
83
  exports.default = (0, react_1.memo)(ConnectionWithButton);
@@ -49,7 +49,7 @@ const createAddButton = ({ background = colors_1.Colors.WHITE, x, y, }) => (0, s
49
49
  `;
50
50
  exports.createAddButton = createAddButton;
51
51
  exports.StyledPopper = (0, system_1.styled)(material_1.Popper) `
52
- z-index: 1000;
52
+ z-index: 1400;
53
53
  overflow: hidden;
54
54
  border-radius: 16px;
55
55
  `;
@@ -13,10 +13,11 @@ const ThemeContext_1 = require("../../../common/contexts/ThemeContext");
13
13
  const expandCoefficientServices_1 = require("../../../node/services/expandCoefficientServices");
14
14
  const material_1 = require("@mui/material");
15
15
  const FlowPosition_1 = require("../../context/FlowPosition");
16
+ const FlowActions_1 = require("../../context/FlowActions");
16
17
  const react_dnd_html5_backend_1 = require("react-dnd-html5-backend");
17
18
  const react_dnd_1 = require("react-dnd");
18
19
  const colors_1 = require("../../../../config/colors");
19
- const NodesFlow = ({ theme, nodes, menuTabs, addNewNodeCallback, permissions, drawerProps, processedNodeIds, failedNodeId, failedNodeColor, onRedirect, onUpdateNodePosition, emptyMenuItemsComponent, searchPlaceholder, }) => {
20
+ const NodesFlow = ({ theme, nodes, menuTabs, addNewNodeCallback, permissions, drawerProps, processedNodeIds, failedNodeId, failedNodeColor, onRedirect, onUpdateNodePosition, emptyMenuItemsComponent, searchPlaceholder, onStartClick, }) => {
20
21
  const nodeDrawers = (0, react_1.useMemo)(() => {
21
22
  const { startNodeList, nodeListWithEndNode } = nodeServices_1.nodeServices.createListOfStartNodesAndEndNodes(nodes);
22
23
  const nodeListWithExpandCoefficients = expandCoefficientServices_1.expandCoefficientServices.calculateNodeExpandCoefficient(nodeListWithEndNode);
@@ -31,6 +32,6 @@ const NodesFlow = ({ theme, nodes, menuTabs, addNewNodeCallback, permissions, dr
31
32
  addNewNodeCallback,
32
33
  }), [nodeDrawers, menuTabs, addNewNodeCallback, processedNodeIds]);
33
34
  const containerRef = (0, react_1.useRef)(null);
34
- return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: permissions.canRead && ((0, jsx_runtime_1.jsx)(ThemeContext_1.ThemeContextProvider, { themContextValue: theme, children: (0, jsx_runtime_1.jsx)(react_dnd_1.DndProvider, { backend: react_dnd_html5_backend_1.HTML5Backend, children: (0, jsx_runtime_1.jsx)(material_1.Box, { ref: containerRef, style: { position: "relative", height: "100%", width: "100%", background: theme?.palette.background.default || colors_1.Colors.DIRTY_WHITE }, children: (0, jsx_runtime_1.jsx)(SettingsContext_1.NodeSettingsProvider, { permissions: permissions, drawerProps: drawerProps, children: (0, jsx_runtime_1.jsx)(FlowPosition_1.FlowPositionProvider, { children: (0, jsx_runtime_1.jsx)(FlowSandbox_1.default, { permissions: permissions, connectionDrawers: connectionDrawers, nodeDrawers: nodeDrawers, containerRef: containerRef, processedNodeIds: processedNodeIds, failedNodeId: failedNodeId, failedNodeColor: failedNodeColor, onRedirect: onRedirect, onUpdateNodePosition: onUpdateNodePosition, emptyMenuItemsComponent: emptyMenuItemsComponent, searchPlaceholder: searchPlaceholder }) }) }) }) }) })) }));
35
+ return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: permissions.canRead && ((0, jsx_runtime_1.jsx)(ThemeContext_1.ThemeContextProvider, { themContextValue: theme, children: (0, jsx_runtime_1.jsx)(react_dnd_1.DndProvider, { backend: react_dnd_html5_backend_1.HTML5Backend, children: (0, jsx_runtime_1.jsx)(material_1.Box, { ref: containerRef, style: { position: "relative", height: "100%", width: "100%", background: theme?.palette.background.default || colors_1.Colors.DIRTY_WHITE }, children: (0, jsx_runtime_1.jsx)(SettingsContext_1.NodeSettingsProvider, { permissions: permissions, drawerProps: drawerProps, children: (0, jsx_runtime_1.jsx)(FlowActions_1.FlowActionsProvider, { onStartClick: onStartClick, children: (0, jsx_runtime_1.jsx)(FlowPosition_1.FlowPositionProvider, { children: (0, jsx_runtime_1.jsx)(FlowSandbox_1.default, { permissions: permissions, connectionDrawers: connectionDrawers, nodeDrawers: nodeDrawers, containerRef: containerRef, processedNodeIds: processedNodeIds, failedNodeId: failedNodeId, failedNodeColor: failedNodeColor, onRedirect: onRedirect, onUpdateNodePosition: onUpdateNodePosition, emptyMenuItemsComponent: emptyMenuItemsComponent, searchPlaceholder: searchPlaceholder }) }) }) }) }) }) })) }));
35
36
  };
36
37
  exports.default = NodesFlow;
@@ -11,6 +11,10 @@ const Space = ({ children }) => {
11
11
  const [scrollLeft, setScrollLeft] = (0, react_1.useState)(0);
12
12
  const [scrollTop, setScrollTop] = (0, react_1.useState)(0);
13
13
  const handleMouseDown = (event) => {
14
+ const target = event.target;
15
+ if (target?.closest('[data-flow-interactive="true"]')) {
16
+ return;
17
+ }
14
18
  setIsDragging(true);
15
19
  setStartX(event.pageX - spaceRef.current.offsetLeft);
16
20
  setStartY(event.pageY - spaceRef.current.offsetTop);
@@ -0,0 +1,8 @@
1
+ import React, { FC, PropsWithChildren } from 'react';
2
+ type FlowActionsValue = {
3
+ onStartClick?: () => void;
4
+ };
5
+ declare const FlowActionsContext: React.Context<FlowActionsValue>;
6
+ type ProviderProps = PropsWithChildren & FlowActionsValue;
7
+ declare const FlowActionsProvider: FC<ProviderProps>;
8
+ export { FlowActionsContext, FlowActionsProvider };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FlowActionsProvider = exports.FlowActionsContext = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const FlowActionsContext = (0, react_1.createContext)({});
7
+ exports.FlowActionsContext = FlowActionsContext;
8
+ const FlowActionsProvider = ({ children, onStartClick }) => ((0, jsx_runtime_1.jsx)(FlowActionsContext.Provider, { value: { onStartClick }, children: children }));
9
+ exports.FlowActionsProvider = FlowActionsProvider;
@@ -22,6 +22,7 @@ export type NodeFlowPropsType = {
22
22
  theme: Theme;
23
23
  emptyMenuItemsComponent?: JSX.Element;
24
24
  searchPlaceholder?: string;
25
+ onStartClick?: () => void;
25
26
  };
26
27
  export type IDrawerProps = {
27
28
  isOpen: boolean;
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const react_1 = require("react");
4
5
  const styled_1 = require("./styled");
6
+ const FlowActions_1 = require("../../../flow/context/FlowActions");
5
7
  const StartNode = () => {
6
- return ((0, jsx_runtime_1.jsx)(styled_1.IconContainer, { children: (0, jsx_runtime_1.jsx)(styled_1.Icon, {}) }));
8
+ const { onStartClick } = (0, react_1.useContext)(FlowActions_1.FlowActionsContext);
9
+ const clickable = !!onStartClick;
10
+ return ((0, jsx_runtime_1.jsx)(styled_1.IconContainer, { onClick: onStartClick, role: clickable ? "button" : undefined, style: clickable ? { cursor: "pointer" } : undefined, children: (0, jsx_runtime_1.jsx)(styled_1.Icon, {}) }));
7
11
  };
8
12
  exports.default = StartNode;
@@ -47,8 +47,13 @@ const NodeSettingsProvider = ({ children, permissions: { canUpdate, canDelete },
47
47
  setInternalNodeBase(null);
48
48
  }, config_1.Config.CLEAR_NODE_DELAY);
49
49
  };
50
- const onSaveNode = () => {
51
- const result = node?.settings?.footer?.onSave?.(node?.id);
50
+ const onSaveNode = async () => {
51
+ // `onSave` is allowed to be sync OR async — host apps that wrap a
52
+ // server call in an async handler need to surface validation errors
53
+ // BEFORE the drawer closes. Awaiting handles both cases: a sync
54
+ // `false` short-circuits, a `Promise<false>` resolves and short-
55
+ // circuits, anything else closes the drawer.
56
+ const result = await node?.settings?.footer?.onSave?.(node?.id);
52
57
  if (result === false)
53
58
  return;
54
59
  handleClose();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flow-lib-creomnia",
3
- "version": "1.0.17",
3
+ "version": "1.0.19-dev.2",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",