@nocobase/flow-engine 2.2.0-beta.14 → 2.2.0-beta.15
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/FlowContextSelector.js +55 -12
- package/lib/components/FormItem.js +11 -7
- 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/flowI18n.js +3 -3
- package/lib/types.d.ts +3 -1
- package/lib/types.js +1 -0
- package/package.json +4 -4
- package/src/__tests__/flowI18n.test.ts +11 -0
- package/src/components/FlowContextSelector.tsx +66 -11
- package/src/components/FormItem.tsx +12 -7
- package/src/components/__tests__/FormItem.test.tsx +17 -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/flowI18n.ts +8 -3
- package/src/types.ts +2 -0
|
@@ -57,6 +57,15 @@ const cascaderPopupAutoHeightClassName = import_css.css`
|
|
|
57
57
|
max-height: 50vh;
|
|
58
58
|
}
|
|
59
59
|
`;
|
|
60
|
+
function getMetaNodeTooltip(meta) {
|
|
61
|
+
if (!meta) {
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
const metaWithTooltip = meta;
|
|
65
|
+
const options = meta.options;
|
|
66
|
+
return metaWithTooltip.tooltip ?? (options == null ? void 0 : options.tooltip);
|
|
67
|
+
}
|
|
68
|
+
__name(getMetaNodeTooltip, "getMetaNodeTooltip");
|
|
60
69
|
const normalizePath = /* @__PURE__ */ __name((path) => {
|
|
61
70
|
if (!Array.isArray(path)) {
|
|
62
71
|
return void 0;
|
|
@@ -90,6 +99,7 @@ const FlowContextSelectorComponent = /* @__PURE__ */ __name(({
|
|
|
90
99
|
value,
|
|
91
100
|
onChange,
|
|
92
101
|
children,
|
|
102
|
+
active,
|
|
93
103
|
metaTree,
|
|
94
104
|
showSearch = false,
|
|
95
105
|
parseValueToPath: customParseValueToPath = import_utils.parseValueToPath,
|
|
@@ -97,6 +107,7 @@ const FlowContextSelectorComponent = /* @__PURE__ */ __name(({
|
|
|
97
107
|
open,
|
|
98
108
|
onlyLeafSelectable = false,
|
|
99
109
|
ignoreFieldNames,
|
|
110
|
+
dropdownFooter,
|
|
100
111
|
...cascaderProps
|
|
101
112
|
}) => {
|
|
102
113
|
const { token } = import_antd.theme.useToken();
|
|
@@ -111,15 +122,27 @@ const FlowContextSelectorComponent = /* @__PURE__ */ __name(({
|
|
|
111
122
|
const disabled = meta ? !!(typeof meta.disabled === "function" ? meta.disabled() : meta.disabled) : false;
|
|
112
123
|
const disabledReason = meta ? typeof meta.disabledReason === "function" ? meta.disabledReason() : meta.disabledReason : void 0;
|
|
113
124
|
const baseLabel = typeof o.label === "string" ? flowCtx.t(o.label) : o.label;
|
|
114
|
-
const
|
|
125
|
+
const labelText = typeof baseLabel === "string" ? baseLabel : String(o.value);
|
|
126
|
+
const tooltip = getMetaNodeTooltip(meta);
|
|
127
|
+
const tooltipTitle = disabled ? disabledReason || tooltip || flowCtx.t("This variable is not available") : tooltip;
|
|
128
|
+
const label = tooltipTitle ? /* @__PURE__ */ import_react.default.createElement("span", null, baseLabel, /* @__PURE__ */ import_react.default.createElement(
|
|
115
129
|
import_antd.Tooltip,
|
|
116
130
|
{
|
|
117
|
-
title:
|
|
118
|
-
placement: "
|
|
119
|
-
|
|
131
|
+
title: typeof tooltipTitle === "string" ? flowCtx.t(tooltipTitle) : tooltipTitle,
|
|
132
|
+
placement: "top",
|
|
133
|
+
classNames: { root: "flow-variable-tip" },
|
|
120
134
|
destroyTooltipOnHide: true
|
|
121
135
|
},
|
|
122
|
-
/* @__PURE__ */ import_react.default.createElement(
|
|
136
|
+
/* @__PURE__ */ import_react.default.createElement(
|
|
137
|
+
import_icons.QuestionCircleOutlined,
|
|
138
|
+
{
|
|
139
|
+
"aria-label": `${labelText} tooltip`,
|
|
140
|
+
style: {
|
|
141
|
+
marginLeft: token.marginXXS,
|
|
142
|
+
color: disabled ? token.colorTextDisabled : token.colorTextDescription
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
)
|
|
123
146
|
)) : baseLabel;
|
|
124
147
|
return {
|
|
125
148
|
...o,
|
|
@@ -129,7 +152,7 @@ const FlowContextSelectorComponent = /* @__PURE__ */ __name(({
|
|
|
129
152
|
};
|
|
130
153
|
});
|
|
131
154
|
},
|
|
132
|
-
[flowCtx]
|
|
155
|
+
[flowCtx, token.colorTextDescription, token.colorTextDisabled, token.marginXXS]
|
|
133
156
|
);
|
|
134
157
|
const [updateFlag, setUpdateFlag] = (0, import_react.useState)(0);
|
|
135
158
|
const [searchText, setSearchText] = (0, import_react.useState)("");
|
|
@@ -219,9 +242,9 @@ const FlowContextSelectorComponent = /* @__PURE__ */ __name(({
|
|
|
219
242
|
(0, import_utils.preloadContextSelectorPath)(options, pathToPreload, triggerUpdate);
|
|
220
243
|
}, [options, pathToPreload, triggerUpdate]);
|
|
221
244
|
const defaultChildren = (0, import_react.useMemo)(() => {
|
|
222
|
-
const hasSelected = currentPath && currentPath.length > 0;
|
|
223
|
-
return /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: hasSelected ? "primary" : "default", style: defaultButtonStyle }, "x");
|
|
224
|
-
}, [currentPath]);
|
|
245
|
+
const hasSelected = active ?? Boolean(currentPath && currentPath.length > 0);
|
|
246
|
+
return /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: hasSelected ? "primary" : "default", style: defaultButtonStyle, disabled: cascaderProps.disabled }, "x");
|
|
247
|
+
}, [active, cascaderProps.disabled, currentPath]);
|
|
225
248
|
const handleChange = (0, import_react.useCallback)(
|
|
226
249
|
(selectedValues, selectedOptions) => {
|
|
227
250
|
const lastOption = selectedOptions == null ? void 0 : selectedOptions[selectedOptions.length - 1];
|
|
@@ -289,12 +312,32 @@ const FlowContextSelectorComponent = /* @__PURE__ */ __name(({
|
|
|
289
312
|
},
|
|
290
313
|
[cascaderOnDropdownVisibleChange, open]
|
|
291
314
|
);
|
|
315
|
+
const footerNode = (0, import_react.useMemo)(() => {
|
|
316
|
+
if (dropdownFooter !== void 0) {
|
|
317
|
+
return dropdownFooter;
|
|
318
|
+
}
|
|
319
|
+
if (onlyLeafSelectable) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
323
|
+
"div",
|
|
324
|
+
{
|
|
325
|
+
className: import_css.css`
|
|
326
|
+
padding: 6px 12px;
|
|
327
|
+
color: ${token.colorTextDescription};
|
|
328
|
+
border-top: 1px solid ${token.colorSplit};
|
|
329
|
+
font-size: ${token.fontSizeSM}px;
|
|
330
|
+
`
|
|
331
|
+
},
|
|
332
|
+
flowCtx.t("Double click to choose entire object")
|
|
333
|
+
);
|
|
334
|
+
}, [dropdownFooter, onlyLeafSelectable, token, flowCtx]);
|
|
292
335
|
const renderDropdown = (0, import_react.useCallback)(
|
|
293
336
|
(menu) => {
|
|
294
337
|
const cascaderMenuNode = cascaderDropdownRender ? cascaderDropdownRender(menu) : menu;
|
|
295
338
|
const cascaderMenu = import_react.default.isValidElement(cascaderMenuNode) ? cascaderMenuNode : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, cascaderMenuNode);
|
|
296
339
|
if (!isSearchEnabled || children === null) {
|
|
297
|
-
return cascaderMenu;
|
|
340
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, cascaderMenu, footerNode);
|
|
298
341
|
}
|
|
299
342
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: cascaderSearchInputClassName }, /* @__PURE__ */ import_react.default.createElement(
|
|
300
343
|
import_antd.Input,
|
|
@@ -306,9 +349,9 @@ const FlowContextSelectorComponent = /* @__PURE__ */ __name(({
|
|
|
306
349
|
onChange: (e) => setSearchText(e.target.value),
|
|
307
350
|
onKeyDown: (e) => e.stopPropagation()
|
|
308
351
|
}
|
|
309
|
-
)), cascaderMenu);
|
|
352
|
+
)), cascaderMenu, footerNode);
|
|
310
353
|
},
|
|
311
|
-
[cascaderDropdownRender, cascaderSearchInputClassName, children, flowCtx, isSearchEnabled, searchText]
|
|
354
|
+
[cascaderDropdownRender, cascaderSearchInputClassName, children, flowCtx, isSearchEnabled, searchText, footerNode]
|
|
312
355
|
);
|
|
313
356
|
const inlinePlaceholder = typeof restCascaderProps.placeholder === "string" ? restCascaderProps.placeholder : flowCtx.t("Search");
|
|
314
357
|
const hasSelectedPath = Array.isArray(effectivePath) && effectivePath.length > 0;
|
|
@@ -77,14 +77,18 @@ const formItemPropKeys = [
|
|
|
77
77
|
"required",
|
|
78
78
|
"showLabel"
|
|
79
79
|
];
|
|
80
|
+
const modelInternalPropKeys = ["globalSort"];
|
|
80
81
|
const FormItem = /* @__PURE__ */ __name(({
|
|
81
82
|
children,
|
|
82
83
|
showLabel = true,
|
|
83
84
|
labelWidth,
|
|
84
85
|
...rest
|
|
85
86
|
}) => {
|
|
87
|
+
const forwardedRest = Object.fromEntries(
|
|
88
|
+
Object.entries(rest).filter(([key]) => !modelInternalPropKeys.includes(key))
|
|
89
|
+
);
|
|
86
90
|
const childProps = Object.fromEntries(
|
|
87
|
-
Object.entries(
|
|
91
|
+
Object.entries(forwardedRest).filter(([key]) => !formItemPropKeys.includes(key))
|
|
88
92
|
);
|
|
89
93
|
const processedChildren = typeof children === "function" ? children : import_react.default.Children.map(children, (child) => {
|
|
90
94
|
if (import_react.default.isValidElement(child)) {
|
|
@@ -92,7 +96,7 @@ const FormItem = /* @__PURE__ */ __name(({
|
|
|
92
96
|
}
|
|
93
97
|
return child;
|
|
94
98
|
});
|
|
95
|
-
const { label, labelWrap, colon = true, layout } =
|
|
99
|
+
const { label, labelWrap, colon = true, layout } = forwardedRest;
|
|
96
100
|
const effectiveLabelWrap = !layout || layout === "vertical" ? true : labelWrap;
|
|
97
101
|
const labelColStyle = layout === "vertical" ? { width: labelWidth, ...verticalFormItemLabelStyle } : { width: labelWidth };
|
|
98
102
|
const renderLabel = /* @__PURE__ */ __name(() => {
|
|
@@ -136,15 +140,15 @@ const FormItem = /* @__PURE__ */ __name(({
|
|
|
136
140
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
137
141
|
import_antd.Form.Item,
|
|
138
142
|
{
|
|
139
|
-
...
|
|
140
|
-
style: { ...formItemStyle, ...
|
|
143
|
+
...forwardedRest,
|
|
144
|
+
style: { ...formItemStyle, ...forwardedRest.style },
|
|
141
145
|
labelCol: { style: labelColStyle },
|
|
142
146
|
layout,
|
|
143
147
|
label: renderLabel(),
|
|
144
148
|
colon: false,
|
|
145
|
-
extra:
|
|
146
|
-
tooltip:
|
|
147
|
-
title:
|
|
149
|
+
extra: forwardedRest.extra && /* @__PURE__ */ import_react.default.createElement("span", { style: { whiteSpace: "pre-wrap" } }, forwardedRest.extra),
|
|
150
|
+
tooltip: forwardedRest.tooltip && {
|
|
151
|
+
title: forwardedRest.tooltip,
|
|
148
152
|
overlayInnerStyle: { whiteSpace: "pre-line" }
|
|
149
153
|
}
|
|
150
154
|
},
|
|
@@ -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>;
|
|
@@ -42,6 +42,7 @@ __export(VariableHybridInput_exports, {
|
|
|
42
42
|
module.exports = __toCommonJS(VariableHybridInput_exports);
|
|
43
43
|
var import_css = require("@emotion/css");
|
|
44
44
|
var import_antd = require("antd");
|
|
45
|
+
var import_context = require("antd/es/form/context");
|
|
45
46
|
var import_react = __toESM(require("react"));
|
|
46
47
|
var import_FlowContextProvider = require("../../FlowContextProvider");
|
|
47
48
|
var import_FlowContextSelector = require("../FlowContextSelector");
|
|
@@ -83,14 +84,28 @@ function normalizeVariableKey(value) {
|
|
|
83
84
|
return value.replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "").trim();
|
|
84
85
|
}
|
|
85
86
|
__name(normalizeVariableKey, "normalizeVariableKey");
|
|
86
|
-
function renderHTML(value,
|
|
87
|
+
function renderHTML(value, regExp, resolveLabel) {
|
|
87
88
|
const re = new RegExp(regExp.source, regExp.flags.includes("g") ? regExp.flags : `${regExp.flags}g`);
|
|
88
89
|
return escapeHtml(value || "").replace(re, (matched) => {
|
|
89
|
-
const label =
|
|
90
|
+
const label = resolveLabel(matched) || matched;
|
|
90
91
|
return createTagHTML(matched, label);
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
94
|
__name(renderHTML, "renderHTML");
|
|
95
|
+
function resolveTitlesByPath(roots, path, ctxT) {
|
|
96
|
+
if (!roots || !path || !path.length) return void 0;
|
|
97
|
+
const titles = [];
|
|
98
|
+
let nodes = roots;
|
|
99
|
+
for (const segment of path) {
|
|
100
|
+
if (!nodes) return void 0;
|
|
101
|
+
const matched = nodes.find((node) => node.name === segment);
|
|
102
|
+
if (!matched) return void 0;
|
|
103
|
+
titles.push(reactNodeToPlainText(matched.title || matched.name));
|
|
104
|
+
nodes = Array.isArray(matched.children) ? matched.children : void 0;
|
|
105
|
+
}
|
|
106
|
+
return titles.map(ctxT).join("/");
|
|
107
|
+
}
|
|
108
|
+
__name(resolveTitlesByPath, "resolveTitlesByPath");
|
|
94
109
|
function buildLabelMap(nodes, ctxT, converters) {
|
|
95
110
|
const map = /* @__PURE__ */ new Map();
|
|
96
111
|
function walk(items = [], parentTitles = []) {
|
|
@@ -112,6 +127,34 @@ function buildLabelMap(nodes, ctxT, converters) {
|
|
|
112
127
|
return map;
|
|
113
128
|
}
|
|
114
129
|
__name(buildLabelMap, "buildLabelMap");
|
|
130
|
+
function collectReferencePaths(value, regExp, parseValueToPath) {
|
|
131
|
+
const re = new RegExp(regExp.source, regExp.flags.includes("g") ? regExp.flags : `${regExp.flags}g`);
|
|
132
|
+
const paths = [];
|
|
133
|
+
for (const matched of value.match(re) ?? []) {
|
|
134
|
+
const path = parseValueToPath(matched);
|
|
135
|
+
if (path && path.length) {
|
|
136
|
+
paths.push(path);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return paths;
|
|
140
|
+
}
|
|
141
|
+
__name(collectReferencePaths, "collectReferencePaths");
|
|
142
|
+
async function preloadReferencePath(path, roots) {
|
|
143
|
+
let nodes = roots;
|
|
144
|
+
let didLoad = false;
|
|
145
|
+
for (const segment of path) {
|
|
146
|
+
if (!nodes) break;
|
|
147
|
+
const matched = nodes.find((node) => node.name === segment);
|
|
148
|
+
if (!matched) break;
|
|
149
|
+
if (typeof matched.children === "function") {
|
|
150
|
+
matched.children = await (0, import_utils.loadMetaTreeChildren)(matched);
|
|
151
|
+
didLoad = true;
|
|
152
|
+
}
|
|
153
|
+
nodes = Array.isArray(matched.children) ? matched.children : void 0;
|
|
154
|
+
}
|
|
155
|
+
return didLoad;
|
|
156
|
+
}
|
|
157
|
+
__name(preloadReferencePath, "preloadReferencePath");
|
|
115
158
|
function pasteHTML(container, html, indexes) {
|
|
116
159
|
var _a;
|
|
117
160
|
const selection = (_a = window.getSelection) == null ? void 0 : _a.call(window);
|
|
@@ -213,21 +256,64 @@ function getCurrentRange(element) {
|
|
|
213
256
|
}
|
|
214
257
|
__name(getCurrentRange, "getCurrentRange");
|
|
215
258
|
const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
216
|
-
|
|
259
|
+
var _a;
|
|
260
|
+
const { addonBefore, className, converters, disabled, metaTree, onChange, placeholder, readOnly, style } = props;
|
|
217
261
|
const { token } = import_antd.theme.useToken();
|
|
218
262
|
const ctx = (0, import_FlowContextProvider.useFlowContext)();
|
|
219
263
|
const { resolvedMetaTree } = (0, import_useResolvedMetaTree.useResolvedMetaTree)(metaTree);
|
|
264
|
+
const formItemStatus = (_a = (0, import_react.useContext)(import_context.FormItemInputContext)) == null ? void 0 : _a.status;
|
|
265
|
+
const effectiveStatus = props.status ?? formItemStatus;
|
|
220
266
|
const inputRef = (0, import_react.useRef)(null);
|
|
221
267
|
const [isComposing, setIsComposing] = (0, import_react.useState)(false);
|
|
222
268
|
const [changed, setChanged] = (0, import_react.useState)(false);
|
|
223
269
|
const [range, setRange] = (0, import_react.useState)([-1, 0, -1, 0]);
|
|
224
270
|
const value = typeof props.value === "string" ? props.value : props.value == null ? "" : String(props.value);
|
|
225
271
|
const variableRegExp = (converters == null ? void 0 : converters.variableRegExp) ?? DEFAULT_VARIABLE_REGEXP;
|
|
272
|
+
const parseValueToPath = (converters == null ? void 0 : converters.parseValueToPath) ?? import_utils.parseValueToPath;
|
|
273
|
+
const [loadedFlag, setLoadedFlag] = (0, import_react.useState)(0);
|
|
274
|
+
(0, import_react.useEffect)(() => {
|
|
275
|
+
if (!value || !Array.isArray(resolvedMetaTree) || !resolvedMetaTree.length) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const paths = collectReferencePaths(value, variableRegExp, parseValueToPath);
|
|
279
|
+
if (!paths.length) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
let cancelled = false;
|
|
283
|
+
const run = /* @__PURE__ */ __name(async () => {
|
|
284
|
+
let didLoad = false;
|
|
285
|
+
for (const path of paths) {
|
|
286
|
+
const loaded = await preloadReferencePath(path, resolvedMetaTree);
|
|
287
|
+
if (cancelled) return;
|
|
288
|
+
didLoad = didLoad || loaded;
|
|
289
|
+
}
|
|
290
|
+
if (didLoad && !cancelled) {
|
|
291
|
+
setLoadedFlag((prev) => prev + 1);
|
|
292
|
+
}
|
|
293
|
+
}, "run");
|
|
294
|
+
run();
|
|
295
|
+
return () => {
|
|
296
|
+
cancelled = true;
|
|
297
|
+
};
|
|
298
|
+
}, [value, resolvedMetaTree, variableRegExp, parseValueToPath]);
|
|
226
299
|
const labelMap = (0, import_react.useMemo)(
|
|
227
300
|
() => buildLabelMap(resolvedMetaTree, ctx.t, converters),
|
|
228
|
-
|
|
301
|
+
// `loadedFlag` is read so the map recomputes after a lazy level resolves.
|
|
302
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
303
|
+
[resolvedMetaTree, ctx, converters, loadedFlag]
|
|
229
304
|
);
|
|
230
|
-
const
|
|
305
|
+
const resolveLabel = (0, import_react.useCallback)(
|
|
306
|
+
(matched) => {
|
|
307
|
+
const mapped = labelMap.get(normalizeVariableKey(matched));
|
|
308
|
+
if (mapped) return mapped;
|
|
309
|
+
const path = parseValueToPath(matched);
|
|
310
|
+
return resolveTitlesByPath(resolvedMetaTree, path, ctx.t);
|
|
311
|
+
},
|
|
312
|
+
// `loadedFlag` is read so a resolved lazy level re-creates this callback and re-renders the tags. `ctx` carries the translation fn.
|
|
313
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
314
|
+
[labelMap, parseValueToPath, resolvedMetaTree, ctx, loadedFlag]
|
|
315
|
+
);
|
|
316
|
+
const [html, setHtml] = (0, import_react.useState)(() => renderHTML(value, variableRegExp, resolveLabel));
|
|
231
317
|
const emitChange = (0, import_react.useCallback)(
|
|
232
318
|
(target) => {
|
|
233
319
|
onChange == null ? void 0 : onChange(getDomValue(target).trim());
|
|
@@ -235,20 +321,20 @@ const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
|
235
321
|
[onChange]
|
|
236
322
|
);
|
|
237
323
|
(0, import_react.useEffect)(() => {
|
|
238
|
-
setHtml(renderHTML(value,
|
|
324
|
+
setHtml(renderHTML(value, variableRegExp, resolveLabel));
|
|
239
325
|
if (!changed) {
|
|
240
326
|
setRange([-1, 0, -1, 0]);
|
|
241
327
|
}
|
|
242
|
-
}, [value,
|
|
328
|
+
}, [value, resolveLabel]);
|
|
243
329
|
(0, import_react.useEffect)(() => {
|
|
244
|
-
var
|
|
330
|
+
var _a2;
|
|
245
331
|
const element = inputRef.current;
|
|
246
332
|
if (!element) return;
|
|
247
333
|
if (document.activeElement !== element) return;
|
|
248
334
|
const nextRange = new Range();
|
|
249
335
|
if (changed) {
|
|
250
336
|
if (range.join() === "-1,0,-1,0") return;
|
|
251
|
-
const selection = (
|
|
337
|
+
const selection = (_a2 = window.getSelection) == null ? void 0 : _a2.call(window);
|
|
252
338
|
if (!selection) return;
|
|
253
339
|
try {
|
|
254
340
|
const children = Array.from(element.childNodes);
|
|
@@ -304,12 +390,13 @@ const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
|
304
390
|
);
|
|
305
391
|
const handleInput = (0, import_react.useCallback)(
|
|
306
392
|
({ currentTarget }) => {
|
|
393
|
+
if (readOnly) return;
|
|
307
394
|
if (isComposing) return;
|
|
308
395
|
setChanged(true);
|
|
309
396
|
setRange(getCurrentRange(currentTarget));
|
|
310
397
|
emitChange(currentTarget);
|
|
311
398
|
},
|
|
312
|
-
[emitChange, isComposing]
|
|
399
|
+
[emitChange, isComposing, readOnly]
|
|
313
400
|
);
|
|
314
401
|
const handleBlur = (0, import_react.useCallback)(({ currentTarget }) => {
|
|
315
402
|
setRange(getCurrentRange(currentTarget));
|
|
@@ -322,6 +409,7 @@ const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
|
322
409
|
const handlePaste = (0, import_react.useCallback)(
|
|
323
410
|
(event) => {
|
|
324
411
|
event.preventDefault();
|
|
412
|
+
if (readOnly) return;
|
|
325
413
|
const text = event.clipboardData.getData("text/plain").replace(/\n/g, " ");
|
|
326
414
|
if (!text) return;
|
|
327
415
|
setChanged(true);
|
|
@@ -329,17 +417,18 @@ const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
|
329
417
|
setRange(getCurrentRange(event.currentTarget));
|
|
330
418
|
emitChange(event.currentTarget);
|
|
331
419
|
},
|
|
332
|
-
[emitChange]
|
|
420
|
+
[emitChange, readOnly]
|
|
333
421
|
);
|
|
334
422
|
const handleCompositionStart = (0, import_react.useCallback)(() => setIsComposing(true), []);
|
|
335
423
|
const handleCompositionEnd = (0, import_react.useCallback)(
|
|
336
424
|
({ currentTarget }) => {
|
|
337
425
|
setIsComposing(false);
|
|
426
|
+
if (readOnly) return;
|
|
338
427
|
setChanged(true);
|
|
339
428
|
setRange(getCurrentRange(currentTarget));
|
|
340
429
|
emitChange(currentTarget);
|
|
341
430
|
},
|
|
342
|
-
[emitChange]
|
|
431
|
+
[emitChange, readOnly]
|
|
343
432
|
);
|
|
344
433
|
const wrapperClassName = (0, import_react.useMemo)(
|
|
345
434
|
() => import_css.css`
|
|
@@ -457,6 +546,42 @@ const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
|
457
546
|
border-color: ${token.colorBorder};
|
|
458
547
|
}
|
|
459
548
|
}
|
|
549
|
+
|
|
550
|
+
&.is-readonly {
|
|
551
|
+
cursor: default;
|
|
552
|
+
|
|
553
|
+
&:hover {
|
|
554
|
+
border-color: ${token.colorBorder};
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
&.is-error {
|
|
559
|
+
border-color: ${token.colorError};
|
|
560
|
+
|
|
561
|
+
&:hover {
|
|
562
|
+
border-color: ${token.colorErrorBorderHover};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
&:focus,
|
|
566
|
+
&:focus-visible {
|
|
567
|
+
border-color: ${token.colorError};
|
|
568
|
+
box-shadow: 0 0 0 ${token.controlOutlineWidth}px ${token.colorErrorOutline};
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
&.is-warning {
|
|
573
|
+
border-color: ${token.colorWarning};
|
|
574
|
+
|
|
575
|
+
&:hover {
|
|
576
|
+
border-color: ${token.colorWarningBorderHover};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
&:focus,
|
|
580
|
+
&:focus-visible {
|
|
581
|
+
border-color: ${token.colorWarning};
|
|
582
|
+
box-shadow: 0 0 0 ${token.controlOutlineWidth}px ${token.colorWarningOutline};
|
|
583
|
+
}
|
|
584
|
+
}
|
|
460
585
|
`;
|
|
461
586
|
}, [token, addonBefore]);
|
|
462
587
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_antd.Space.Compact, { className: (0, import_css.cx)("nb-variable-hybrid-input", wrapperClassName, className), style }, addonBefore != null && /* @__PURE__ */ import_react.default.createElement("span", { className: addonClassName }, addonBefore), /* @__PURE__ */ import_react.default.createElement(
|
|
@@ -466,9 +591,13 @@ const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
|
466
591
|
role: "textbox",
|
|
467
592
|
"aria-label": "textbox",
|
|
468
593
|
className: (0, import_css.cx)(editorClassName, {
|
|
469
|
-
"is-disabled": disabled
|
|
594
|
+
"is-disabled": disabled,
|
|
595
|
+
"is-readonly": readOnly,
|
|
596
|
+
"is-error": effectiveStatus === "error",
|
|
597
|
+
"is-warning": effectiveStatus === "warning"
|
|
470
598
|
}),
|
|
471
|
-
contentEditable: !disabled,
|
|
599
|
+
contentEditable: !disabled && !readOnly,
|
|
600
|
+
"aria-readonly": readOnly,
|
|
472
601
|
"data-placeholder": placeholder,
|
|
473
602
|
onInput: handleInput,
|
|
474
603
|
onBlur: handleBlur,
|
|
@@ -483,10 +612,10 @@ const VariableHybridInputComponent = /* @__PURE__ */ __name((props) => {
|
|
|
483
612
|
{
|
|
484
613
|
metaTree,
|
|
485
614
|
disabled,
|
|
486
|
-
parseValueToPath
|
|
615
|
+
parseValueToPath,
|
|
487
616
|
formatPathToValue: (item) => {
|
|
488
|
-
var
|
|
489
|
-
return ((
|
|
617
|
+
var _a2;
|
|
618
|
+
return ((_a2 = converters == null ? void 0 : converters.formatPathToValue) == null ? void 0 : _a2.call(converters, item)) || (0, import_utils.formatPathToValue)(item);
|
|
490
619
|
},
|
|
491
620
|
onChange: handleSelectorChange
|
|
492
621
|
}
|
|
@@ -132,16 +132,18 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
132
132
|
},
|
|
133
133
|
[onChange]
|
|
134
134
|
);
|
|
135
|
+
const resolvedPath = (0, import_react.useMemo)(() => {
|
|
136
|
+
return resolvePathFromValue == null ? void 0 : resolvePathFromValue(innerValue);
|
|
137
|
+
}, [innerValue, resolvePathFromValue]);
|
|
135
138
|
const resolvedMetaTreeNode = (0, import_react.useMemo)(() => {
|
|
136
139
|
if (currentMetaTreeNode) return currentMetaTreeNode;
|
|
137
140
|
if (Array.isArray(resolvedMetaTree)) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return findMetaTreeNodeByPath(resolvedMetaTree, path);
|
|
141
|
+
if (resolvedPath) {
|
|
142
|
+
return findMetaTreeNodeByPath(resolvedMetaTree, resolvedPath);
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
return null;
|
|
144
|
-
}, [currentMetaTreeNode,
|
|
146
|
+
}, [currentMetaTreeNode, resolvedMetaTree, resolvedPath]);
|
|
145
147
|
(0, import_react.useEffect)(() => {
|
|
146
148
|
const restoreFromValue = /* @__PURE__ */ __name(async () => {
|
|
147
149
|
if (!Array.isArray(resolvedMetaTree) || value == null) return;
|
|
@@ -188,13 +190,17 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
188
190
|
}
|
|
189
191
|
}, "restoreFromValue");
|
|
190
192
|
restoreFromValue();
|
|
191
|
-
}, [resolvedMetaTree, innerValue, resolvePathFromValue, currentMetaTreeNode]);
|
|
193
|
+
}, [resolvedMetaTree, innerValue, resolvePathFromValue, currentMetaTreeNode, value]);
|
|
192
194
|
const ValueComponent = (0, import_react.useMemo)(() => {
|
|
193
195
|
const Component = renderInputComponent == null ? void 0 : renderInputComponent(resolvedMetaTreeNode);
|
|
194
196
|
const CustomComponent = resolvedMetaTreeNode == null ? void 0 : resolvedMetaTreeNode.render;
|
|
195
|
-
const
|
|
197
|
+
const shouldRenderVariableTag = (0, import_utils.isVariableValue)(innerValue) || Array.isArray(resolvedPath) && resolvedPath.length > 0 && !Component && !CustomComponent;
|
|
198
|
+
const finalComponent = shouldRenderVariableTag ? import_VariableTag.VariableTag : Component || CustomComponent || import_antd.Input;
|
|
196
199
|
return finalComponent;
|
|
197
|
-
}, [renderInputComponent, resolvedMetaTreeNode, innerValue]);
|
|
200
|
+
}, [renderInputComponent, resolvedMetaTreeNode, innerValue, resolvedPath]);
|
|
201
|
+
const isVariableActive = (0, import_react.useMemo)(() => {
|
|
202
|
+
return (0, import_utils.isVariableValue)(innerValue) || Array.isArray(resolvedPath) && resolvedPath.length > 0 && !(renderInputComponent == null ? void 0 : renderInputComponent(resolvedMetaTreeNode)) && !(resolvedMetaTreeNode == null ? void 0 : resolvedMetaTreeNode.render);
|
|
203
|
+
}, [innerValue, renderInputComponent, resolvedMetaTreeNode, resolvedPath]);
|
|
198
204
|
(0, import_react.useEffect)(() => {
|
|
199
205
|
if (!resolvedMetaTreeNode) return;
|
|
200
206
|
if (!Array.isArray(resolvedMetaTree) || innerValue == null) return;
|
|
@@ -278,8 +284,11 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
278
284
|
return {
|
|
279
285
|
...baseProps,
|
|
280
286
|
onClear: handleClear,
|
|
287
|
+
disabled,
|
|
288
|
+
allowCustomTagInput: false,
|
|
281
289
|
metaTreeNode: resolvedMetaTreeNode,
|
|
282
290
|
metaTree,
|
|
291
|
+
resolvedPath,
|
|
283
292
|
style: stableProps.style
|
|
284
293
|
};
|
|
285
294
|
}
|
|
@@ -300,6 +309,7 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
300
309
|
disabled,
|
|
301
310
|
handleClear,
|
|
302
311
|
resolvedMetaTreeNode,
|
|
312
|
+
resolvedPath,
|
|
303
313
|
metaTree,
|
|
304
314
|
ValueComponent,
|
|
305
315
|
stableProps
|
|
@@ -325,6 +335,8 @@ const VariableInputComponent = /* @__PURE__ */ __name(({
|
|
|
325
335
|
{
|
|
326
336
|
metaTree: resolvedMetaTree,
|
|
327
337
|
value: innerValue,
|
|
338
|
+
active: isVariableActive,
|
|
339
|
+
disabled,
|
|
328
340
|
onChange: handleVariableSelect,
|
|
329
341
|
parseValueToPath: resolvePathFromValue,
|
|
330
342
|
formatPathToValue: resolveValueFromPath,
|