@nocobase/flow-engine
Version:
A standalone flow engine for NocoBase, managing workflows, models, and actions.
303 lines (301 loc) • 11.3 kB
JavaScript
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var SlateVariableEditor_exports = {};
__export(SlateVariableEditor_exports, {
SlateVariableEditor: () => SlateVariableEditor
});
module.exports = __toCommonJS(SlateVariableEditor_exports);
var import_react = __toESM(require("react"));
var import_slate = require("slate");
var import_slate_react = require("slate-react");
var import_slate_history = require("slate-history");
var import_InlineVariableTag = require("./InlineVariableTag");
var import_VariableTrigger = require("./VariableTrigger");
var import_utils = require("./utils");
var import_shared = require("@formily/shared");
const SlateVariableEditor = /* @__PURE__ */ __name(({
value = "",
onChange,
metaTree,
multiline = false,
placeholder = "\u8F93\u5165\u6587\u672C\uFF0C\u4F7F\u7528 {{ \u63D2\u5165\u53D8\u91CF",
style = {},
...restProps
}) => {
const editor = (0, import_react.useMemo)(() => {
const e = (0, import_slate_react.withReact)((0, import_slate_history.withHistory)((0, import_slate.createEditor)()));
const { isInline, isVoid } = e;
e.isInline = (element) => {
return element.type === "variable" || element.type === "variable-trigger" ? true : isInline(element);
};
e.isVoid = (element) => {
return element.type === "variable" || element.type === "variable-trigger" ? true : isVoid(element);
};
return e;
}, []);
const [resolvedMetaTree, setResolvedMetaTree] = import_react.default.useState(null);
import_react.default.useEffect(() => {
const resolveMetaTree = /* @__PURE__ */ __name(async () => {
if (!metaTree) {
setResolvedMetaTree(null);
return;
}
try {
if (typeof metaTree === "function") {
const resolved = await metaTree();
setResolvedMetaTree(resolved);
} else {
setResolvedMetaTree(metaTree);
}
} catch (error) {
console.warn("Failed to resolve metaTree:", error);
setResolvedMetaTree(null);
}
}, "resolveMetaTree");
resolveMetaTree();
}, [metaTree]);
const parseValueToSlate = (0, import_react.useCallback)(
(text = "") => {
if (!text) {
return [
{
type: "paragraph",
children: [{ text: "" }]
}
];
}
const variableRegex = /\{\{[^}]+\}\}/g;
let lastIndex = 0;
let match;
const children = [];
while ((match = variableRegex.exec(text)) !== null) {
if (match.index > lastIndex) {
children.push({ text: text.slice(lastIndex, match.index) });
}
const variableValue = match[0];
const path = (0, import_utils.parseValueToPath)(variableValue);
const contextSelectorItem = void 0;
if (path && resolvedMetaTree) {
}
children.push({
type: "variable",
value: variableValue,
meta: contextSelectorItem,
children: [{ text: "" }]
// Slate 要求 void 元素有空文本子节点
});
lastIndex = match.index + match[0].length;
}
if (lastIndex < text.length) {
children.push({ text: text.slice(lastIndex) });
}
if (children.length === 0) {
children.push({ text: "" });
}
return [
{
type: "paragraph",
children
}
];
},
[resolvedMetaTree]
);
const initialValue = (0, import_react.useMemo)(() => parseValueToSlate(value || ""), [value, parseValueToSlate]);
const slateToText = (0, import_react.useCallback)((nodes) => {
return nodes.map((n) => {
if (import_slate.Element.isElement(n)) {
if (n.type === "variable") {
return n.value;
}
return slateToText(n.children);
}
return n.text;
}).join("");
}, []);
const handleChange = (0, import_react.useCallback)(
(newValue) => {
const text = slateToText(newValue);
onChange == null ? void 0 : onChange(text);
},
[onChange, slateToText]
);
const handleVariableSelectFromTrigger = (0, import_react.useCallback)(
(triggerId, value2, item) => {
const [triggerMatch] = import_slate.Editor.nodes(editor, {
match: /* @__PURE__ */ __name((n) => import_slate.Element.isElement(n) && n.type === "variable-trigger" && n.triggerId === triggerId, "match")
});
if (triggerMatch) {
const [, triggerPath] = triggerMatch;
const variableElement = {
type: "variable",
value: value2,
meta: item,
children: [{ text: "" }]
};
import_slate.Transforms.setNodes(editor, variableElement, { at: triggerPath });
const nextPoint = import_slate.Editor.after(editor, triggerPath);
if (nextPoint) {
import_slate.Transforms.select(editor, nextPoint);
}
import_slate_react.ReactEditor.focus(editor);
}
},
[editor]
);
const handleTriggerClose = (0, import_react.useCallback)(
(triggerId) => {
const [triggerMatch] = import_slate.Editor.nodes(editor, {
match: /* @__PURE__ */ __name((n) => import_slate.Element.isElement(n) && n.type === "variable-trigger" && n.triggerId === triggerId, "match")
});
if (triggerMatch) {
const [, triggerPath] = triggerMatch;
import_slate.Transforms.select(editor, triggerPath);
import_slate.Transforms.removeNodes(editor, { at: triggerPath });
import_slate.Transforms.insertText(editor, "{{");
import_slate_react.ReactEditor.focus(editor);
}
},
[editor]
);
const renderElement = (0, import_react.useCallback)(
(props) => {
switch (props.element.type) {
case "variable":
return /* @__PURE__ */ import_react.default.createElement(VariableElementComponent, { ...props, metaTree: resolvedMetaTree });
case "variable-trigger":
return /* @__PURE__ */ import_react.default.createElement(
import_VariableTrigger.VariableTrigger,
{
...props,
element: props.element,
metaTree,
onVariableSelect: handleVariableSelectFromTrigger,
onTriggerClose: handleTriggerClose
}
);
default:
return /* @__PURE__ */ import_react.default.createElement("p", { ...props.attributes }, props.children);
}
},
[metaTree, resolvedMetaTree, handleVariableSelectFromTrigger, handleTriggerClose]
);
const renderLeaf = (0, import_react.useCallback)((props) => {
return /* @__PURE__ */ import_react.default.createElement("span", { ...props.attributes, style: { fontWeight: props.leaf.bold ? "bold" : "normal" } }, props.children);
}, []);
const handleKeyDown = (0, import_react.useCallback)(
(event) => {
if (event.key === "{") {
const { selection } = editor;
if (selection && import_slate.Range.isCollapsed(selection)) {
const [start] = import_slate.Range.edges(selection);
const beforePoint = import_slate.Editor.before(editor, start);
if (beforePoint) {
const beforeRange = import_slate.Editor.range(editor, beforePoint, start);
const beforeText = import_slate.Editor.string(editor, beforeRange);
if (beforeText === "{") {
event.preventDefault();
import_slate.Transforms.delete(editor, { at: beforeRange });
const triggerId = (0, import_shared.uid)();
const triggerElement = {
type: "variable-trigger",
triggerId,
children: [{ text: "" }]
};
import_slate.Transforms.insertNodes(editor, triggerElement);
}
}
}
}
},
[editor]
);
return /* @__PURE__ */ import_react.default.createElement(import_slate_react.Slate, { editor, initialValue, onChange: handleChange }, /* @__PURE__ */ import_react.default.createElement(
import_slate_react.Editable,
{
renderElement,
renderLeaf,
placeholder,
onKeyDown: handleKeyDown,
style: {
minHeight: multiline ? 100 : 32,
padding: "4px 11px",
border: "1px solid #d9d9d9",
borderRadius: 6,
fontSize: 14,
lineHeight: 1.5714285714285714,
...style
},
...restProps
}
));
}, "SlateVariableEditor");
const VariableElementComponent = /* @__PURE__ */ __name(({
attributes,
children,
element,
metaTree
}) => {
const variableElement = element;
const contextSelectorItem = import_react.default.useMemo(() => {
if (variableElement.meta) {
return variableElement.meta;
}
if (metaTree && variableElement.value) {
const path = (0, import_utils.parseValueToPath)(variableElement.value);
}
return null;
}, [variableElement.meta, variableElement.value, metaTree]);
return /* @__PURE__ */ import_react.default.createElement("span", { ...attributes, contentEditable: false }, /* @__PURE__ */ import_react.default.createElement(
import_InlineVariableTag.InlineVariableTag,
{
value: variableElement.value,
metaTreeNode: contextSelectorItem,
metaTree,
style: {
marginLeft: 2,
marginRight: 2,
verticalAlign: "baseline",
display: "inline-block"
}
}
), children);
}, "VariableElementComponent");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SlateVariableEditor
});