@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.
Files changed (115) hide show
  1. package/lib/JSRunner.d.ts +1 -0
  2. package/lib/JSRunner.js +110 -20
  3. package/lib/acl/Acl.d.ts +2 -1
  4. package/lib/acl/Acl.js +28 -0
  5. package/lib/components/FieldModelRenderer.js +44 -31
  6. package/lib/components/FlowContextSelector.js +55 -12
  7. package/lib/components/FormItem.js +11 -7
  8. package/lib/components/MobilePopup.js +39 -10
  9. package/lib/components/MobilePopup.style.js +27 -6
  10. package/lib/components/dnd/index.js +9 -2
  11. package/lib/components/settings/wrappers/contextual/FlowsFloatContextMenu.js +86 -32
  12. package/lib/components/settings/wrappers/contextual/useFloatToolbarVisibility.js +20 -0
  13. package/lib/components/subModel/LazyDropdown.js +41 -26
  14. package/lib/components/variables/VariableHybridInput.d.ts +9 -0
  15. package/lib/components/variables/VariableHybridInput.js +146 -17
  16. package/lib/components/variables/VariableInput.js +19 -7
  17. package/lib/components/variables/VariableTag.js +48 -36
  18. package/lib/components/variables/types.d.ts +21 -0
  19. package/lib/flowContext.d.ts +1 -1
  20. package/lib/flowContext.js +97 -42
  21. package/lib/flowEngine.js +6 -0
  22. package/lib/flowI18n.js +3 -3
  23. package/lib/flowSettings.d.ts +5 -1
  24. package/lib/flowSettings.js +70 -0
  25. package/lib/locale/en-US.json +3 -0
  26. package/lib/locale/index.d.ts +6 -0
  27. package/lib/locale/zh-CN.json +3 -0
  28. package/lib/resources/apiResource.js +2 -1
  29. package/lib/resources/baseRecordResource.js +6 -17
  30. package/lib/resources/multiRecordResource.js +13 -3
  31. package/lib/resources/singleRecordResource.js +7 -2
  32. package/lib/runjs-context/helpers.js +12 -5
  33. package/lib/types.d.ts +15 -1
  34. package/lib/types.js +1 -0
  35. package/lib/utils/dataSourceDirty.d.ts +20 -0
  36. package/lib/utils/dataSourceDirty.js +139 -0
  37. package/lib/utils/dirtyAwareApiClient.d.ts +11 -0
  38. package/lib/utils/dirtyAwareApiClient.js +632 -0
  39. package/lib/utils/index.d.ts +1 -1
  40. package/lib/utils/index.js +11 -11
  41. package/lib/utils/loadedPageCache.d.ts +1 -0
  42. package/lib/utils/loadedPageCache.js +6 -0
  43. package/lib/utils/openViewRouteState.d.ts +28 -0
  44. package/lib/utils/openViewRouteState.js +125 -0
  45. package/lib/utils/parsePathnameToViewParams.d.ts +3 -0
  46. package/lib/utils/parsePathnameToViewParams.js +18 -1
  47. package/lib/utils/resolveRunJSObjectValues.js +3 -2
  48. package/lib/utils/runjsModuleLoader.js +0 -30
  49. package/lib/views/ViewNavigation.js +5 -0
  50. package/package.json +4 -4
  51. package/src/JSRunner.ts +112 -25
  52. package/src/__tests__/JSRunner.test.ts +4 -5
  53. package/src/__tests__/flowContext.test.ts +154 -0
  54. package/src/__tests__/flowEngine.dataSourceDirty.test.ts +51 -0
  55. package/src/__tests__/flowI18n.test.ts +11 -0
  56. package/src/__tests__/flowModel.openView.navigation.test.ts +28 -0
  57. package/src/__tests__/flowSettings.test.ts +72 -0
  58. package/src/__tests__/runjsRuntimeFeatures.test.ts +15 -2
  59. package/src/__tests__/viewScopedFlowEngine.test.ts +72 -6
  60. package/src/acl/Acl.tsx +36 -1
  61. package/src/acl/__tests__/Acl.test.tsx +70 -0
  62. package/src/components/FieldModelRenderer.tsx +50 -36
  63. package/src/components/FlowContextSelector.tsx +66 -11
  64. package/src/components/FormItem.tsx +12 -7
  65. package/src/components/MobilePopup.style.ts +34 -7
  66. package/src/components/MobilePopup.tsx +42 -10
  67. package/src/components/__tests__/FieldModelRenderer.test.tsx +165 -0
  68. package/src/components/__tests__/FormItem.test.tsx +17 -2
  69. package/src/components/__tests__/MobilePopup.style.test.tsx +103 -0
  70. package/src/components/__tests__/MobilePopup.test.tsx +150 -0
  71. package/src/components/dnd/index.tsx +11 -2
  72. package/src/components/settings/wrappers/contextual/FlowsFloatContextMenu.tsx +105 -35
  73. package/src/components/settings/wrappers/contextual/__tests__/FlowsFloatContextMenu.test.tsx +381 -12
  74. package/src/components/settings/wrappers/contextual/useFloatToolbarVisibility.ts +28 -0
  75. package/src/components/subModel/LazyDropdown.tsx +44 -26
  76. package/src/components/subModel/__tests__/AddSubModelButton.test.tsx +85 -2
  77. package/src/components/variables/VariableHybridInput.tsx +185 -14
  78. package/src/components/variables/VariableInput.tsx +32 -7
  79. package/src/components/variables/VariableTag.tsx +51 -37
  80. package/src/components/variables/__tests__/FlowContextSelector.test.tsx +60 -3
  81. package/src/components/variables/__tests__/VariableHybridInput.test.tsx +212 -0
  82. package/src/components/variables/__tests__/VariableInput.test.tsx +202 -6
  83. package/src/components/variables/__tests__/VariableTag.test.tsx +80 -0
  84. package/src/components/variables/types.ts +21 -0
  85. package/src/flowContext.ts +104 -36
  86. package/src/flowEngine.ts +6 -0
  87. package/src/flowI18n.ts +8 -3
  88. package/src/flowSettings.ts +85 -1
  89. package/src/locale/__tests__/index.test.ts +21 -0
  90. package/src/locale/en-US.json +3 -0
  91. package/src/locale/zh-CN.json +3 -0
  92. package/src/resources/apiResource.ts +2 -1
  93. package/src/resources/baseRecordResource.ts +6 -23
  94. package/src/resources/multiRecordResource.ts +13 -3
  95. package/src/resources/singleRecordResource.ts +6 -1
  96. package/src/runjs-context/helpers.ts +12 -6
  97. package/src/types.ts +16 -0
  98. package/src/utils/__tests__/dirtyAwareApiClient.test.ts +713 -0
  99. package/src/utils/__tests__/openViewRouteState.test.ts +40 -0
  100. package/src/utils/__tests__/parsePathnameToViewParams.test.ts +36 -0
  101. package/src/utils/dataSourceDirty.ts +126 -0
  102. package/src/utils/dirtyAwareApiClient.ts +742 -0
  103. package/src/utils/index.ts +10 -9
  104. package/src/utils/loadedPageCache.ts +7 -0
  105. package/src/utils/openViewRouteState.ts +107 -0
  106. package/src/utils/parsePathnameToViewParams.ts +23 -1
  107. package/src/utils/resolveRunJSObjectValues.ts +5 -2
  108. package/src/utils/runjsModuleLoader.ts +0 -32
  109. package/src/views/ViewNavigation.ts +6 -1
  110. package/src/views/__tests__/ViewNavigation.test.ts +15 -0
  111. package/lib/utils/safeGlobals.d.ts +0 -28
  112. package/lib/utils/safeGlobals.js +0 -367
  113. package/src/utils/__tests__/runjsRequireAsyncAutoWhitelist.test.ts +0 -38
  114. package/src/utils/__tests__/safeGlobals.test.ts +0 -106
  115. package/src/utils/safeGlobals.ts +0 -406
package/lib/JSRunner.d.ts CHANGED
@@ -27,6 +27,7 @@ export interface JSRunnerOptions {
27
27
  * 3. Fallback keeps v1-compatible behavior (enabled).
28
28
  */
29
29
  export declare function shouldPreprocessRunJSTemplates(options?: Pick<JSRunnerOptions, 'preprocessTemplates' | 'version'>): boolean;
30
+ export declare const RUNJS_ALLOWED_BARE_GLOBAL_NAMES: readonly ["ctx", "console", "window", "document", "navigator", "setTimeout", "clearTimeout", "setInterval", "clearInterval", "Array", "ArrayBuffer", "BigInt", "BigInt64Array", "BigUint64Array", "Boolean", "DataView", "Date", "Error", "EvalError", "FinalizationRegistry", "Float32Array", "Float64Array", "Int8Array", "Int16Array", "Int32Array", "Map", "Math", "Number", "Object", "Promise", "Proxy", "RangeError", "ReferenceError", "Reflect", "RegExp", "Set", "String", "Symbol", "SyntaxError", "TypeError", "URIError", "Uint8Array", "Uint8ClampedArray", "Uint16Array", "Uint32Array", "WeakMap", "WeakRef", "WeakSet", "JSON", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "isFinite", "isNaN", "parseFloat", "parseInt", "undefined", "NaN", "Infinity", "fetch", "localStorage", "sessionStorage", "XMLHttpRequest", "WebSocket", "Worker", "SharedWorker", "ServiceWorker", "BroadcastChannel", "EventSource", "indexedDB", "caches", "Function", "eval", "globalThis", "Intl", "Blob", "URL", "location"];
30
31
  export declare class JSRunner {
31
32
  private globals;
32
33
  private timeoutMs;
package/lib/JSRunner.js CHANGED
@@ -28,6 +28,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
28
28
  var JSRunner_exports = {};
29
29
  __export(JSRunner_exports, {
30
30
  JSRunner: () => JSRunner,
31
+ RUNJS_ALLOWED_BARE_GLOBAL_NAMES: () => RUNJS_ALLOWED_BARE_GLOBAL_NAMES,
31
32
  shouldPreprocessRunJSTemplates: () => shouldPreprocessRunJSTemplates
32
33
  });
33
34
  module.exports = __toCommonJS(JSRunner_exports);
@@ -40,6 +41,113 @@ function shouldPreprocessRunJSTemplates(options) {
40
41
  return (options == null ? void 0 : options.version) !== "v2";
41
42
  }
42
43
  __name(shouldPreprocessRunJSTemplates, "shouldPreprocessRunJSTemplates");
44
+ const RUNJS_BROWSER_GLOBAL_NAMES = [
45
+ "fetch",
46
+ "localStorage",
47
+ "sessionStorage",
48
+ "XMLHttpRequest",
49
+ "WebSocket",
50
+ "Worker",
51
+ "SharedWorker",
52
+ "ServiceWorker",
53
+ "BroadcastChannel",
54
+ "EventSource",
55
+ "indexedDB",
56
+ "caches",
57
+ "Function",
58
+ "eval",
59
+ "globalThis",
60
+ "Intl",
61
+ "Blob",
62
+ "URL",
63
+ "location"
64
+ ];
65
+ const RUNJS_ALLOWED_BARE_GLOBAL_NAMES = [
66
+ "ctx",
67
+ "console",
68
+ "window",
69
+ "document",
70
+ "navigator",
71
+ "setTimeout",
72
+ "clearTimeout",
73
+ "setInterval",
74
+ "clearInterval",
75
+ "Array",
76
+ "ArrayBuffer",
77
+ "BigInt",
78
+ "BigInt64Array",
79
+ "BigUint64Array",
80
+ "Boolean",
81
+ "DataView",
82
+ "Date",
83
+ "Error",
84
+ "EvalError",
85
+ "FinalizationRegistry",
86
+ "Float32Array",
87
+ "Float64Array",
88
+ "Int8Array",
89
+ "Int16Array",
90
+ "Int32Array",
91
+ "Map",
92
+ "Math",
93
+ "Number",
94
+ "Object",
95
+ "Promise",
96
+ "Proxy",
97
+ "RangeError",
98
+ "ReferenceError",
99
+ "Reflect",
100
+ "RegExp",
101
+ "Set",
102
+ "String",
103
+ "Symbol",
104
+ "SyntaxError",
105
+ "TypeError",
106
+ "URIError",
107
+ "Uint8Array",
108
+ "Uint8ClampedArray",
109
+ "Uint16Array",
110
+ "Uint32Array",
111
+ "WeakMap",
112
+ "WeakRef",
113
+ "WeakSet",
114
+ "JSON",
115
+ "decodeURI",
116
+ "decodeURIComponent",
117
+ "encodeURI",
118
+ "encodeURIComponent",
119
+ "isFinite",
120
+ "isNaN",
121
+ "parseFloat",
122
+ "parseInt",
123
+ "undefined",
124
+ "NaN",
125
+ "Infinity",
126
+ ...RUNJS_BROWSER_GLOBAL_NAMES
127
+ ];
128
+ function collectRunJSBrowserGlobals(providedGlobals = {}) {
129
+ const windowGlobal = providedGlobals.window;
130
+ if (!windowGlobal || typeof windowGlobal !== "object") {
131
+ return {};
132
+ }
133
+ const windowRecord = windowGlobal;
134
+ const globals = {};
135
+ RUNJS_BROWSER_GLOBAL_NAMES.forEach((name) => {
136
+ if (Object.prototype.hasOwnProperty.call(providedGlobals, name)) {
137
+ return;
138
+ }
139
+ try {
140
+ const value = windowRecord[name];
141
+ if (typeof value === "undefined") {
142
+ return;
143
+ }
144
+ globals[name] = name === "fetch" && typeof value === "function" ? value.bind(windowGlobal) : value;
145
+ } catch {
146
+ }
147
+ });
148
+ return globals;
149
+ }
150
+ __name(collectRunJSBrowserGlobals, "collectRunJSBrowserGlobals");
43
151
  const BARE_CTX_TEMPLATE_RE = /(^|[=(:,[\s)])(\{\{\s*(ctx(?:\.|\[|\?\.)[^}]*)\s*\}\})/m;
44
152
  function extractDeprecatedCtxTemplateUsage(code) {
45
153
  const src = String(code || "");
@@ -78,7 +186,6 @@ const _JSRunner = class _JSRunner {
78
186
  globals;
79
187
  timeoutMs;
80
188
  constructor(options = {}) {
81
- var _a, _b;
82
189
  const bindWindowFn = /* @__PURE__ */ __name((key) => {
83
190
  if (typeof window !== "undefined" && typeof window[key] === "function") {
84
191
  return window[key].bind(window);
@@ -87,25 +194,7 @@ const _JSRunner = class _JSRunner {
87
194
  return typeof fn === "function" ? fn.bind(globalThis) : fn;
88
195
  }, "bindWindowFn");
89
196
  const providedGlobals = options.globals || {};
90
- const liftedGlobals = {};
91
- if (!Object.prototype.hasOwnProperty.call(providedGlobals, "Blob")) {
92
- try {
93
- const blobCtor = (_a = providedGlobals.window) == null ? void 0 : _a.Blob;
94
- if (typeof blobCtor !== "undefined") {
95
- liftedGlobals.Blob = blobCtor;
96
- }
97
- } catch {
98
- }
99
- }
100
- if (!Object.prototype.hasOwnProperty.call(providedGlobals, "URL")) {
101
- try {
102
- const urlCtor = (_b = providedGlobals.window) == null ? void 0 : _b.URL;
103
- if (typeof urlCtor !== "undefined") {
104
- liftedGlobals.URL = urlCtor;
105
- }
106
- } catch {
107
- }
108
- }
197
+ const liftedGlobals = collectRunJSBrowserGlobals(providedGlobals);
109
198
  this.globals = {
110
199
  console,
111
200
  setTimeout: bindWindowFn("setTimeout"),
@@ -169,5 +258,6 @@ let JSRunner = _JSRunner;
169
258
  // Annotate the CommonJS export names for ESM import in node:
170
259
  0 && (module.exports = {
171
260
  JSRunner,
261
+ RUNJS_ALLOWED_BARE_GLOBAL_NAMES,
172
262
  shouldPreprocessRunJSTemplates
173
263
  });
package/lib/acl/Acl.d.ts CHANGED
@@ -5,7 +5,7 @@ interface CheckOptions {
5
5
  actionName: string;
6
6
  fields?: string[];
7
7
  recordPkValue?: string | number;
8
- allowedActions: any[];
8
+ allowedActions?: Record<string, Array<string | number>>;
9
9
  }
10
10
  export declare class ACL {
11
11
  private flowEngine;
@@ -26,6 +26,7 @@ export declare class ACL {
26
26
  verifyScope: (actionName: string, recordPkValue: any, allowedActions: any) => boolean;
27
27
  parseAction(options: CheckOptions): any;
28
28
  parseField(options: CheckOptions): boolean;
29
+ can(options: CheckOptions): boolean;
29
30
  aclCheck(options: CheckOptions): Promise<boolean>;
30
31
  }
31
32
  export {};
package/lib/acl/Acl.js CHANGED
@@ -154,6 +154,34 @@ const _ACL = class _ACL {
154
154
  const allowed = whitelist.includes(fields[0]);
155
155
  return allowed;
156
156
  }
157
+ can(options) {
158
+ var _a;
159
+ const { allowAll } = this.data;
160
+ if (allowAll) {
161
+ return true;
162
+ }
163
+ const { actionName, allowedActions, recordPkValue } = options;
164
+ const hasRecordPkValue = recordPkValue !== void 0 && recordPkValue !== null;
165
+ const recordPermission = hasRecordPkValue && allowedActions ? this.verifyScope(actionName, recordPkValue, allowedActions) : null;
166
+ if (hasRecordPkValue && allowedActions && recordPermission !== true) {
167
+ return false;
168
+ }
169
+ const params = this.parseAction(options);
170
+ if (!params) {
171
+ return false;
172
+ }
173
+ if (!import_lodash.default.isEmpty(params.filter) && recordPermission !== true) {
174
+ return false;
175
+ }
176
+ if (!((_a = options.fields) == null ? void 0 : _a.length)) {
177
+ return true;
178
+ }
179
+ const allowedFields = [].concat(params.whitelist || []).concat(params.fields || []).concat(params.appends || []);
180
+ if (!allowedFields.length) {
181
+ return true;
182
+ }
183
+ return options.fields.every((field) => allowedFields.includes(field));
184
+ }
157
185
  async aclCheck(options) {
158
186
  const { allowAll } = this.data;
159
187
  if (allowAll) {
@@ -58,41 +58,54 @@ const flowModelRendererPropKeys = [
58
58
  "extraToolbarItems"
59
59
  ];
60
60
  function FieldModelRenderer(props) {
61
- const { model, ...rest } = props;
61
+ const { model, onChange, ...rest } = props;
62
62
  const composingRef = (0, import_react.useRef)(false);
63
- const handleChange = /* @__PURE__ */ __name((e) => {
64
- var _a;
65
- let val;
66
- if (e && e.target && typeof e.target.value !== "undefined") {
67
- val = e.target.value;
68
- } else if (typeof e === "string" || typeof e === "number" || typeof e === "boolean" || typeof e === "object" && !(e instanceof Event)) {
69
- val = e;
70
- } else {
71
- val = null;
72
- }
73
- model.setProps({ value: val });
74
- if (!composingRef.current) {
75
- (_a = props.onChange) == null ? void 0 : _a.call(props, val);
76
- }
77
- }, "handleChange");
78
- const handleCompositionStart = /* @__PURE__ */ __name(() => {
63
+ const handleChange = (0, import_react.useCallback)(
64
+ (e) => {
65
+ var _a;
66
+ let val;
67
+ if (e && e.target && typeof e.target.value !== "undefined") {
68
+ val = e.target.value;
69
+ } else if (typeof e === "string" || typeof e === "number" || typeof e === "boolean" || typeof e === "object" && !(e instanceof Event)) {
70
+ val = e;
71
+ } else {
72
+ val = null;
73
+ }
74
+ const isComposing = composingRef.current || ((_a = e == null ? void 0 : e.nativeEvent) == null ? void 0 : _a.isComposing);
75
+ if (isComposing) {
76
+ return;
77
+ }
78
+ model.setProps({ value: val });
79
+ if (!composingRef.current) {
80
+ onChange == null ? void 0 : onChange(val);
81
+ }
82
+ },
83
+ [model, onChange]
84
+ );
85
+ const handleCompositionStart = (0, import_react.useCallback)(() => {
79
86
  composingRef.current = true;
80
- }, "handleCompositionStart");
81
- const handleCompositionEnd = /* @__PURE__ */ __name((e, flag = true) => {
82
- composingRef.current = false;
83
- if (flag) {
84
- props.onChange(e);
85
- }
86
- }, "handleCompositionEnd");
87
- const modelProps = {
88
- onCompositionStart: handleCompositionStart,
89
- onCompositionEnd: handleCompositionEnd,
90
- ...import_lodash.default.omit(rest, flowModelRendererPropKeys),
91
- onChange: handleChange
92
- };
87
+ }, []);
88
+ const handleCompositionEnd = (0, import_react.useCallback)(
89
+ (e, flag = true) => {
90
+ composingRef.current = false;
91
+ if (flag) {
92
+ handleChange(e);
93
+ }
94
+ },
95
+ [handleChange]
96
+ );
97
+ const modelProps = (0, import_react.useMemo)(
98
+ () => ({
99
+ onCompositionStart: handleCompositionStart,
100
+ onCompositionEnd: handleCompositionEnd,
101
+ ...import_lodash.default.omit(rest, flowModelRendererPropKeys),
102
+ onChange: handleChange
103
+ }),
104
+ [handleChange, handleCompositionEnd, handleCompositionStart, rest]
105
+ );
93
106
  (0, import_react.useEffect)(() => {
94
107
  model && model.setProps(modelProps);
95
- }, [modelProps]);
108
+ }, [model, modelProps]);
96
109
  return /* @__PURE__ */ import_react.default.createElement(import_FlowModelRenderer.FlowModelRenderer, { model, ...rest });
97
110
  }
98
111
  __name(FieldModelRenderer, "FieldModelRenderer");
@@ -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 label = disabled ? /* @__PURE__ */ import_react.default.createElement("span", null, baseLabel, /* @__PURE__ */ import_react.default.createElement(
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: disabledReason || flowCtx.t("This variable is not available"),
118
- placement: "right",
119
- overlayClassName: "flow-variable-disabled-tip",
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(import_icons.QuestionCircleOutlined, { style: { marginLeft: 6, color: "rgba(0,0,0,0.35)" } })
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(rest).filter(([key]) => !formItemPropKeys.includes(key))
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 } = rest;
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
- ...rest,
140
- style: { ...formItemStyle, ...rest.style },
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: rest.extra && /* @__PURE__ */ import_react.default.createElement("span", { style: { whiteSpace: "pre-wrap" } }, rest.extra),
146
- tooltip: rest.tooltip && {
147
- title: rest.tooltip,
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
  },
@@ -47,15 +47,46 @@ var import_react_i18next = require("react-i18next");
47
47
  var import_lazy_helper = require("../lazy-helper");
48
48
  const { Popup } = (0, import_lazy_helper.lazy)(() => import("antd-mobile"), "Popup");
49
49
  const { CloseOutline } = (0, import_lazy_helper.lazy)(() => import("antd-mobile-icons"), "CloseOutline");
50
+ const getMobilePopupMaxHeight = /* @__PURE__ */ __name(() => {
51
+ var _a;
52
+ if (typeof CSS !== "undefined" && ((_a = CSS.supports) == null ? void 0 : _a.call(CSS, "height", "100dvh"))) {
53
+ return "calc(100dvh - var(--nb-mobile-page-header-height, 46px))";
54
+ }
55
+ return "calc(100vh - var(--nb-mobile-page-header-height, 46px))";
56
+ }, "getMobilePopupMaxHeight");
50
57
  const MobilePopup = /* @__PURE__ */ __name((props) => {
58
+ var _a;
51
59
  const { title, visible, onClose: closePopup, children, minHeight, className, footer } = props;
52
60
  const { t } = (0, import_react_i18next.useTranslation)();
53
61
  const { componentCls, hashId } = (0, import_MobilePopup.useMobileActionDrawerStyle)();
54
- const style = (0, import_react.useMemo)(() => {
62
+ const bodyStyles = (_a = props.styles) == null ? void 0 : _a.body;
63
+ const defaultMaxHeight = getMobilePopupMaxHeight();
64
+ const popupStyle = (0, import_react.useMemo)(() => {
65
+ return {
66
+ minHeight: (bodyStyles == null ? void 0 : bodyStyles.minHeight) ?? minHeight,
67
+ height: bodyStyles == null ? void 0 : bodyStyles.height,
68
+ maxHeight: (bodyStyles == null ? void 0 : bodyStyles.maxHeight) ?? defaultMaxHeight
69
+ };
70
+ }, [bodyStyles == null ? void 0 : bodyStyles.height, bodyStyles == null ? void 0 : bodyStyles.maxHeight, bodyStyles == null ? void 0 : bodyStyles.minHeight, defaultMaxHeight, minHeight]);
71
+ const bodyStyle = (0, import_react.useMemo)(() => {
55
72
  return {
56
- minHeight
73
+ padding: 0,
74
+ maxHeight: defaultMaxHeight,
75
+ overflowY: "auto",
76
+ overflowX: "hidden",
77
+ ...bodyStyles
57
78
  };
58
- }, [minHeight]);
79
+ }, [bodyStyles, defaultMaxHeight]);
80
+ const handleCloseKeyDown = (0, import_react.useCallback)(
81
+ (event) => {
82
+ if (event.key !== "Enter" && event.key !== " ") {
83
+ return;
84
+ }
85
+ event.preventDefault();
86
+ closePopup();
87
+ },
88
+ [closePopup]
89
+ );
59
90
  const theme = (0, import_react.useMemo)(() => {
60
91
  return {
61
92
  token: {
@@ -75,21 +106,19 @@ const MobilePopup = /* @__PURE__ */ __name((props) => {
75
106
  onClose: closePopup,
76
107
  onMaskClick: closePopup,
77
108
  bodyClassName: "nb-mobile-action-drawer-body",
78
- bodyStyle: {
79
- padding: 0
80
- },
81
- maskStyle: style,
82
- style,
109
+ bodyStyle,
110
+ style: popupStyle,
83
111
  destroyOnClose: true
84
112
  },
85
- /* @__PURE__ */ import_react.default.createElement("div", { className: "nb-mobile-action-drawer-header" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "nb-mobile-action-drawer-placeholder" }, /* @__PURE__ */ import_react.default.createElement(CloseOutline, null)), /* @__PURE__ */ import_react.default.createElement("span", null, title), /* @__PURE__ */ import_react.default.createElement(
113
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "nb-mobile-action-drawer-header" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "nb-mobile-action-drawer-placeholder" }, /* @__PURE__ */ import_react.default.createElement(CloseOutline, null)), /* @__PURE__ */ import_react.default.createElement("span", { className: "nb-mobile-action-drawer-title" }, title), /* @__PURE__ */ import_react.default.createElement(
86
114
  "span",
87
115
  {
88
116
  className: "nb-mobile-action-drawer-close-icon",
89
117
  onClick: closePopup,
90
118
  role: "button",
91
119
  tabIndex: 0,
92
- "aria-label": t("Close")
120
+ "aria-label": t("Close"),
121
+ onKeyDown: handleCloseKeyDown
93
122
  },
94
123
  /* @__PURE__ */ import_react.default.createElement(CloseOutline, null)
95
124
  )),
@@ -96,9 +96,17 @@ const genStyleHook = /* @__PURE__ */ __name((component, styleFn) => {
96
96
  return [genCommonStyle(token, prefixCls), styleInterpolation];
97
97
  }
98
98
  );
99
- const memoizedWrapSSR = (0, import_react.useMemo)(() => {
100
- return wrapSSR;
101
- }, [theme2, token, hashId, prefixCls, iconPrefixCls, rootPrefixCls, props]);
99
+ const wrapSSRDeps = [theme2, token, hashId, prefixCls, iconPrefixCls, rootPrefixCls, props];
100
+ const wrapSSRCacheRef = (0, import_react.useRef)();
101
+ const currentCache = wrapSSRCacheRef.current;
102
+ let memoizedWrapSSR = (currentCache == null ? void 0 : currentCache.wrapSSR) || wrapSSR;
103
+ if (!currentCache || wrapSSRDeps.some((dep, index) => dep !== currentCache.deps[index])) {
104
+ wrapSSRCacheRef.current = {
105
+ deps: wrapSSRDeps,
106
+ wrapSSR
107
+ };
108
+ memoizedWrapSSR = wrapSSR;
109
+ }
102
110
  return {
103
111
  wrapSSR: memoizedWrapSSR,
104
112
  hashId,
@@ -112,14 +120,14 @@ const useMobileActionDrawerStyle = genStyleHook("nb-mobile-action-drawer", (toke
112
120
  return {
113
121
  [componentCls]: {
114
122
  ".nb-mobile-action-drawer-header": {
115
- height: "var(--nb-mobile-page-header-height)",
123
+ height: "var(--nb-mobile-page-header-height, 46px)",
116
124
  display: "flex",
117
125
  alignItems: "center",
118
126
  justifyContent: "space-between",
119
127
  borderBottom: `1px solid ${token.colorSplit}`,
120
128
  position: "sticky",
121
129
  top: 0,
122
- backgroundColor: "white",
130
+ backgroundColor: token.colorBgContainer,
123
131
  zIndex: 1e3,
124
132
  // to match the button named 'Add block'
125
133
  "& + .nb-grid-container > .nb-grid > .nb-grid-warp > .ant-btn": {
@@ -129,17 +137,30 @@ const useMobileActionDrawerStyle = genStyleHook("nb-mobile-action-drawer", (toke
129
137
  ".nb-mobile-action-drawer-placeholder": {
130
138
  display: "inline-block",
131
139
  padding: 12,
140
+ flex: "0 0 auto",
132
141
  visibility: "hidden"
133
142
  },
143
+ ".nb-mobile-action-drawer-title": {
144
+ flex: "1 1 auto",
145
+ minWidth: 0,
146
+ overflow: "hidden",
147
+ textAlign: "center",
148
+ textOverflow: "ellipsis",
149
+ whiteSpace: "nowrap"
150
+ },
134
151
  ".nb-mobile-action-drawer-close-icon": {
135
152
  display: "inline-block",
136
153
  padding: 12,
154
+ flex: "0 0 auto",
137
155
  cursor: "pointer"
138
156
  },
139
157
  ".nb-mobile-action-drawer-body": {
140
158
  borderTopLeftRadius: 8,
141
159
  borderTopRightRadius: 8,
142
- maxHeight: "calc(100% - var(--nb-mobile-page-header-height))",
160
+ maxHeight: "calc(100vh - var(--nb-mobile-page-header-height, 46px))",
161
+ "@supports (height: 100dvh)": {
162
+ maxHeight: "calc(100dvh - var(--nb-mobile-page-header-height, 46px))"
163
+ },
143
164
  overflowY: "auto",
144
165
  overflowX: "hidden",
145
166
  backgroundColor: token.colorBgLayout,