@nocobase/flow-engine 2.1.21 → 2.1.22

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.
@@ -48,14 +48,34 @@ 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
50
  const MobilePopup = /* @__PURE__ */ __name((props) => {
51
+ var _a;
51
52
  const { title, visible, onClose: closePopup, children, minHeight, className, footer } = props;
52
53
  const { t } = (0, import_react_i18next.useTranslation)();
53
54
  const { componentCls, hashId } = (0, import_MobilePopup.useMobileActionDrawerStyle)();
54
- const style = (0, import_react.useMemo)(() => {
55
+ const bodyStyles = (_a = props.styles) == null ? void 0 : _a.body;
56
+ const popupStyle = (0, import_react.useMemo)(() => {
55
57
  return {
56
- minHeight
58
+ minHeight: (bodyStyles == null ? void 0 : bodyStyles.minHeight) ?? minHeight,
59
+ height: bodyStyles == null ? void 0 : bodyStyles.height,
60
+ maxHeight: bodyStyles == null ? void 0 : bodyStyles.maxHeight
57
61
  };
58
- }, [minHeight]);
62
+ }, [bodyStyles == null ? void 0 : bodyStyles.height, bodyStyles == null ? void 0 : bodyStyles.maxHeight, bodyStyles == null ? void 0 : bodyStyles.minHeight, minHeight]);
63
+ const bodyStyle = (0, import_react.useMemo)(() => {
64
+ return {
65
+ padding: 0,
66
+ ...bodyStyles
67
+ };
68
+ }, [bodyStyles]);
69
+ const handleCloseKeyDown = (0, import_react.useCallback)(
70
+ (event) => {
71
+ if (event.key !== "Enter" && event.key !== " ") {
72
+ return;
73
+ }
74
+ event.preventDefault();
75
+ closePopup();
76
+ },
77
+ [closePopup]
78
+ );
59
79
  const theme = (0, import_react.useMemo)(() => {
60
80
  return {
61
81
  token: {
@@ -75,21 +95,19 @@ const MobilePopup = /* @__PURE__ */ __name((props) => {
75
95
  onClose: closePopup,
76
96
  onMaskClick: closePopup,
77
97
  bodyClassName: "nb-mobile-action-drawer-body",
78
- bodyStyle: {
79
- padding: 0
80
- },
81
- maskStyle: style,
82
- style,
98
+ bodyStyle,
99
+ style: popupStyle,
83
100
  destroyOnClose: true
84
101
  },
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(
102
+ /* @__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
103
  "span",
87
104
  {
88
105
  className: "nb-mobile-action-drawer-close-icon",
89
106
  onClick: closePopup,
90
107
  role: "button",
91
108
  tabIndex: 0,
92
- "aria-label": t("Close")
109
+ "aria-label": t("Close"),
110
+ onKeyDown: handleCloseKeyDown
93
111
  },
94
112
  /* @__PURE__ */ import_react.default.createElement(CloseOutline, null)
95
113
  )),
@@ -98,7 +98,7 @@ const genStyleHook = /* @__PURE__ */ __name((component, styleFn) => {
98
98
  );
99
99
  const memoizedWrapSSR = (0, import_react.useMemo)(() => {
100
100
  return wrapSSR;
101
- }, [theme2, token, hashId, prefixCls, iconPrefixCls, rootPrefixCls, props]);
101
+ }, [wrapSSR]);
102
102
  return {
103
103
  wrapSSR: memoizedWrapSSR,
104
104
  hashId,
@@ -119,7 +119,7 @@ const useMobileActionDrawerStyle = genStyleHook("nb-mobile-action-drawer", (toke
119
119
  borderBottom: `1px solid ${token.colorSplit}`,
120
120
  position: "sticky",
121
121
  top: 0,
122
- backgroundColor: "white",
122
+ backgroundColor: token.colorBgContainer,
123
123
  zIndex: 1e3,
124
124
  // to match the button named 'Add block'
125
125
  "& + .nb-grid-container > .nb-grid > .nb-grid-warp > .ant-btn": {
@@ -129,11 +129,21 @@ const useMobileActionDrawerStyle = genStyleHook("nb-mobile-action-drawer", (toke
129
129
  ".nb-mobile-action-drawer-placeholder": {
130
130
  display: "inline-block",
131
131
  padding: 12,
132
+ flex: "0 0 auto",
132
133
  visibility: "hidden"
133
134
  },
135
+ ".nb-mobile-action-drawer-title": {
136
+ flex: "1 1 auto",
137
+ minWidth: 0,
138
+ overflow: "hidden",
139
+ textAlign: "center",
140
+ textOverflow: "ellipsis",
141
+ whiteSpace: "nowrap"
142
+ },
134
143
  ".nb-mobile-action-drawer-close-icon": {
135
144
  display: "inline-block",
136
145
  padding: 12,
146
+ flex: "0 0 auto",
137
147
  cursor: "pointer"
138
148
  },
139
149
  ".nb-mobile-action-drawer-body": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/flow-engine",
3
- "version": "2.1.21",
3
+ "version": "2.1.22",
4
4
  "private": false,
5
5
  "description": "A standalone flow engine for NocoBase, managing workflows, models, and actions.",
6
6
  "main": "lib/index.js",
@@ -8,8 +8,8 @@
8
8
  "dependencies": {
9
9
  "@formily/antd-v5": "1.x",
10
10
  "@formily/reactive": "2.x",
11
- "@nocobase/sdk": "2.1.21",
12
- "@nocobase/shared": "2.1.21",
11
+ "@nocobase/sdk": "2.1.22",
12
+ "@nocobase/shared": "2.1.22",
13
13
  "ahooks": "^3.7.2",
14
14
  "axios": "^1.7.0",
15
15
  "dayjs": "^1.11.9",
@@ -37,5 +37,5 @@
37
37
  ],
38
38
  "author": "NocoBase Team",
39
39
  "license": "Apache-2.0",
40
- "gitHead": "491141417d8338022651c9e99afbd2d84c1e2b0b"
40
+ "gitHead": "811fc3d272389739babdfa4338faf843d5bf04ff"
41
41
  }
@@ -124,7 +124,7 @@ const genStyleHook = <ComponentName extends OverrideComponent>(
124
124
  // 等 https://github.com/ant-design/cssinjs/pull/176 合并后,可以去掉这层缓存
125
125
  const memoizedWrapSSR = useMemo(() => {
126
126
  return wrapSSR;
127
- }, [theme, token, hashId, prefixCls, iconPrefixCls, rootPrefixCls, props]);
127
+ }, [wrapSSR]);
128
128
 
129
129
  return {
130
130
  wrapSSR: memoizedWrapSSR,
@@ -147,7 +147,7 @@ export const useMobileActionDrawerStyle = genStyleHook('nb-mobile-action-drawer'
147
147
  borderBottom: `1px solid ${token.colorSplit}`,
148
148
  position: 'sticky',
149
149
  top: 0,
150
- backgroundColor: 'white',
150
+ backgroundColor: token.colorBgContainer,
151
151
  zIndex: 1000,
152
152
 
153
153
  // to match the button named 'Add block'
@@ -159,12 +159,23 @@ export const useMobileActionDrawerStyle = genStyleHook('nb-mobile-action-drawer'
159
159
  '.nb-mobile-action-drawer-placeholder': {
160
160
  display: 'inline-block',
161
161
  padding: 12,
162
+ flex: '0 0 auto',
162
163
  visibility: 'hidden',
163
164
  },
164
165
 
166
+ '.nb-mobile-action-drawer-title': {
167
+ flex: '1 1 auto',
168
+ minWidth: 0,
169
+ overflow: 'hidden',
170
+ textAlign: 'center',
171
+ textOverflow: 'ellipsis',
172
+ whiteSpace: 'nowrap',
173
+ },
174
+
165
175
  '.nb-mobile-action-drawer-close-icon': {
166
176
  display: 'inline-block',
167
177
  padding: 12,
178
+ flex: '0 0 auto',
168
179
  cursor: 'pointer',
169
180
  },
170
181
 
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { ConfigProvider } from 'antd';
11
- import React, { FC, ReactNode, useMemo } from 'react';
11
+ import React, { FC, ReactNode, useCallback, useMemo } from 'react';
12
12
  import { useMobileActionDrawerStyle } from './MobilePopup.style';
13
13
  import { useTranslation } from 'react-i18next';
14
14
  import { lazy } from '../lazy-helper';
@@ -31,11 +31,33 @@ export const MobilePopup: FC<MobilePopupProps> = (props) => {
31
31
  const { t } = useTranslation();
32
32
  const { componentCls, hashId } = useMobileActionDrawerStyle();
33
33
 
34
- const style = useMemo(() => {
34
+ const bodyStyles = (props as MobilePopupProps & { styles?: { body?: React.CSSProperties } }).styles?.body;
35
+ const popupStyle = useMemo(() => {
35
36
  return {
36
- minHeight,
37
+ minHeight: bodyStyles?.minHeight ?? minHeight,
38
+ height: bodyStyles?.height,
39
+ maxHeight: bodyStyles?.maxHeight,
37
40
  };
38
- }, [minHeight]);
41
+ }, [bodyStyles?.height, bodyStyles?.maxHeight, bodyStyles?.minHeight, minHeight]);
42
+
43
+ const bodyStyle = useMemo(() => {
44
+ return {
45
+ padding: 0,
46
+ ...bodyStyles,
47
+ };
48
+ }, [bodyStyles]);
49
+
50
+ const handleCloseKeyDown = useCallback(
51
+ (event: React.KeyboardEvent<HTMLSpanElement>) => {
52
+ if (event.key !== 'Enter' && event.key !== ' ') {
53
+ return;
54
+ }
55
+
56
+ event.preventDefault();
57
+ closePopup();
58
+ },
59
+ [closePopup],
60
+ );
39
61
 
40
62
  const theme = useMemo(() => {
41
63
  return {
@@ -57,11 +79,8 @@ export const MobilePopup: FC<MobilePopupProps> = (props) => {
57
79
  onClose={closePopup}
58
80
  onMaskClick={closePopup}
59
81
  bodyClassName="nb-mobile-action-drawer-body"
60
- bodyStyle={{
61
- padding: 0,
62
- }}
63
- maskStyle={style}
64
- style={style}
82
+ bodyStyle={bodyStyle}
83
+ style={popupStyle}
65
84
  destroyOnClose
66
85
  >
67
86
  <div className="nb-mobile-action-drawer-header">
@@ -69,13 +88,14 @@ export const MobilePopup: FC<MobilePopupProps> = (props) => {
69
88
  <span className="nb-mobile-action-drawer-placeholder">
70
89
  <CloseOutline />
71
90
  </span>
72
- <span>{title}</span>
91
+ <span className="nb-mobile-action-drawer-title">{title}</span>
73
92
  <span
74
93
  className="nb-mobile-action-drawer-close-icon"
75
94
  onClick={closePopup}
76
95
  role="button"
77
96
  tabIndex={0}
78
97
  aria-label={t('Close')}
98
+ onKeyDown={handleCloseKeyDown}
79
99
  >
80
100
  <CloseOutline />
81
101
  </span>
@@ -0,0 +1,109 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import React from 'react';
11
+ import { fireEvent, render, screen } from '@testing-library/react';
12
+ import { describe, expect, it, vi } from 'vitest';
13
+ import { MobilePopup } from '../MobilePopup';
14
+
15
+ vi.mock('react-i18next', () => ({
16
+ useTranslation: () => ({
17
+ t: (key: string) => key,
18
+ }),
19
+ }));
20
+
21
+ vi.mock('../MobilePopup.style', () => ({
22
+ useMobileActionDrawerStyle: () => ({
23
+ componentCls: 'nb-mobile-action-drawer',
24
+ hashId: 'hash',
25
+ }),
26
+ }));
27
+
28
+ vi.mock('../../lazy-helper', () => ({
29
+ lazy: (_loader: unknown, name: string) => {
30
+ if (name === 'Popup') {
31
+ const Popup = ({
32
+ children,
33
+ bodyStyle,
34
+ maskStyle,
35
+ style,
36
+ }: {
37
+ children: React.ReactNode;
38
+ bodyStyle?: React.CSSProperties;
39
+ maskStyle?: React.CSSProperties;
40
+ style?: React.CSSProperties;
41
+ }) => (
42
+ <div data-testid="mobile-popup" style={style}>
43
+ <div data-testid="mobile-popup-mask" style={maskStyle} />
44
+ <div data-testid="mobile-popup-body" style={bodyStyle}>
45
+ {children}
46
+ </div>
47
+ </div>
48
+ );
49
+
50
+ return { Popup };
51
+ }
52
+
53
+ return {
54
+ CloseOutline: () => <span data-testid="close-outline" />,
55
+ };
56
+ },
57
+ }));
58
+
59
+ describe('MobilePopup', () => {
60
+ const MobilePopupWithDrawerStyles = MobilePopup as React.ComponentType<
61
+ React.ComponentProps<typeof MobilePopup> & { styles?: { body?: React.CSSProperties } }
62
+ >;
63
+
64
+ it('applies drawer body styles as max bounds without forcing fixed half-window height', () => {
65
+ render(
66
+ <MobilePopupWithDrawerStyles visible title="Title" styles={{ body: { maxHeight: '50vh' } }} onClose={vi.fn()}>
67
+ body
68
+ </MobilePopupWithDrawerStyles>,
69
+ );
70
+
71
+ expect(screen.getByTestId('mobile-popup')).toHaveStyle({
72
+ maxHeight: '50vh',
73
+ });
74
+ expect(screen.getByTestId('mobile-popup-body')).toHaveStyle({
75
+ maxHeight: '50vh',
76
+ });
77
+ expect(screen.getByTestId('mobile-popup-mask')).not.toHaveStyle({
78
+ maxHeight: '50vh',
79
+ });
80
+ });
81
+
82
+ it('closes from the header close icon with Enter or Space', () => {
83
+ const onClose = vi.fn();
84
+ render(
85
+ <MobilePopup visible title="Title" onClose={onClose}>
86
+ body
87
+ </MobilePopup>,
88
+ );
89
+
90
+ const closeButton = screen.getByRole('button', { name: 'Close' });
91
+ fireEvent.keyDown(closeButton, { key: 'Enter' });
92
+ fireEvent.keyDown(closeButton, { key: ' ' });
93
+
94
+ expect(onClose).toHaveBeenCalledTimes(2);
95
+ });
96
+
97
+ it('keeps long header titles in a constrained title element separate from the close button', () => {
98
+ const longTitle = 'A very long table column title that should not push the close button outside the drawer';
99
+
100
+ render(
101
+ <MobilePopup visible title={longTitle} onClose={vi.fn()}>
102
+ body
103
+ </MobilePopup>,
104
+ );
105
+
106
+ expect(screen.getByText(longTitle)).toHaveClass('nb-mobile-action-drawer-title');
107
+ expect(screen.getByRole('button', { name: 'Close' })).toHaveClass('nb-mobile-action-drawer-close-icon');
108
+ });
109
+ });