@hsu-react/ui 2.5.6 → 2.5.8
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/es/components/Checkbox/CheckboxGroup/index.js +4 -1
- package/es/components/FormItem/FormCodeMirror/index.js +3 -1
- package/es/components/FormItem/ItemContainer/index.js +15 -5
- package/es/components/Modal/index.d.ts +12 -0
- package/es/components/Modal/index.js +22 -1
- package/es/components/Modal/index.module.scss +7 -0
- package/es/components/Operate/index.js +4 -1
- package/es/components/Pagination/index.js +3 -1
- package/es/components/Search/_hooks/useSearchCommon.js +4 -1
- package/es/components/Select/AutoCompleteSelect/index.js +3 -1
- package/es/components/Spreadsheet/index.js +8 -2
- package/es/components/Table/_hooks/useTableColumns.js +4 -1
- package/es/components/Tree/_hooks/useTreeState.js +7 -4
- package/es/components/Tree/index.js +8 -2
- package/es/layout/Menu/index.module.scss +32 -0
- package/es/styles/tokens.d.ts +10 -0
- package/es/styles/tokens.js +11 -0
- package/es/styles/tokens.json +1 -0
- package/lib/components/Checkbox/CheckboxGroup/index.js +4 -1
- package/lib/components/FormItem/FormCodeMirror/index.js +3 -1
- package/lib/components/FormItem/ItemContainer/index.js +16 -6
- package/lib/components/Modal/index.d.ts +12 -0
- package/lib/components/Modal/index.js +22 -0
- package/lib/components/Modal/index.module.scss +7 -0
- package/lib/components/Operate/index.js +4 -1
- package/lib/components/Pagination/index.js +3 -1
- package/lib/components/Search/_hooks/useSearchCommon.js +4 -1
- package/lib/components/Select/AutoCompleteSelect/index.js +3 -1
- package/lib/components/Spreadsheet/index.js +8 -2
- package/lib/components/Table/_hooks/useTableColumns.js +4 -1
- package/lib/components/Tree/_hooks/useTreeState.js +6 -3
- package/lib/components/Tree/index.js +8 -2
- package/lib/layout/Menu/index.module.scss +32 -0
- package/lib/styles/tokens.d.ts +10 -0
- package/lib/styles/tokens.js +12 -1
- package/lib/styles/tokens.json +1 -0
- package/package.json +1 -1
- package/src/__tests__/depsScan.ts +62 -15
- package/src/__tests__/freshObjectDeps.test.tsx +380 -0
- package/src/__tests__/freshObjectDepsGuard.test.ts +54 -23
- package/src/components/Checkbox/CheckboxGroup/index.tsx +4 -1
- package/src/components/FormItem/FormCodeMirror/index.tsx +4 -1
- package/src/components/FormItem/ItemContainer/index.tsx +21 -6
- package/src/components/Modal/index.md +1 -0
- package/src/components/Modal/index.module.scss +7 -0
- package/src/components/Modal/index.tsx +40 -0
- package/src/components/Modal/minHeight.test.tsx +105 -0
- package/src/components/Operate/index.tsx +4 -1
- package/src/components/Pagination/index.tsx +4 -1
- package/src/components/Search/_hooks/useSearchCommon.ts +4 -1
- package/src/components/Select/AutoCompleteSelect/index.tsx +4 -1
- package/src/components/Spreadsheet/depsMemo.test.tsx +95 -0
- package/src/components/Spreadsheet/index.tsx +9 -2
- package/src/components/Table/_hooks/useTableColumns.tsx +4 -1
- package/src/components/Tree/_hooks/useTreeState.ts +14 -8
- package/src/components/Tree/depsMemo.test.tsx +64 -0
- package/src/components/Tree/index.tsx +9 -2
- package/src/layout/Menu/index.module.scss +32 -0
- package/src/layout/Menu/scrollGutter.test.ts +50 -0
- package/src/styles/tokens.json +1 -0
- package/src/styles/tokens.ts +11 -0
|
@@ -31,6 +31,13 @@
|
|
|
31
31
|
width: 100%;
|
|
32
32
|
height: 100%;
|
|
33
33
|
max-height: 90vh;
|
|
34
|
+
// 高度下界,由 `<Modal minHeight>` 写入 `--vita-modal-min-height`(不传就是 0)。
|
|
35
|
+
// 内容异步加载的弹窗不给下界的话,打开那一刻只有标题栏那么高,数据回来再撑开。
|
|
36
|
+
//
|
|
37
|
+
// 必须在这里与 90vh 取小:CSS 里 `min-height` 的优先级高于 `max-height`,
|
|
38
|
+
// 直接写 `min-height: 700px` 会让上面那行 `max-height: 90vh` 在矮窗口上失效,
|
|
39
|
+
// 弹窗被顶出屏幕。
|
|
40
|
+
min-height: min(var(--vita-modal-min-height, 0px), 90vh);
|
|
34
41
|
padding: 0px 0px 15px;
|
|
35
42
|
}
|
|
36
43
|
|
|
@@ -18,6 +18,9 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
18
18
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
19
19
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
20
20
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
|
+
// 解构默认值写成字面量会每次渲染新建一个数组,进依赖数组就让 memo 恒不命中;提到模块级常量
|
|
22
|
+
const EMPTY_MENU = [];
|
|
23
|
+
|
|
21
24
|
/**
|
|
22
25
|
* Render an icon
|
|
23
26
|
* @param icon - Icon configuration
|
|
@@ -44,7 +47,7 @@ const Operate = props => {
|
|
|
44
47
|
const {
|
|
45
48
|
title,
|
|
46
49
|
className,
|
|
47
|
-
menu =
|
|
50
|
+
menu = EMPTY_MENU,
|
|
48
51
|
icon,
|
|
49
52
|
delete: isDelete,
|
|
50
53
|
popconfirm,
|
|
@@ -14,10 +14,12 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
14
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
15
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
16
16
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
17
|
+
// 解构默认值写成字面量会每次渲染新建一个数组,进依赖数组就让 memo 恒不命中;提到模块级常量
|
|
18
|
+
const EMPTY_PAGE_SIZE_OPTIONS = [];
|
|
17
19
|
const Pagination = props => {
|
|
18
20
|
const {
|
|
19
21
|
simple,
|
|
20
|
-
pageSizeOptions =
|
|
22
|
+
pageSizeOptions = EMPTY_PAGE_SIZE_OPTIONS,
|
|
21
23
|
showSizeChanger,
|
|
22
24
|
onShowSizeChange,
|
|
23
25
|
onChange,
|
|
@@ -15,6 +15,9 @@ var _useSearchExpand = require("./useSearchExpand");
|
|
|
15
15
|
var _utils = require("../_utils");
|
|
16
16
|
var _indexModule = _interopRequireDefault(require("../index.module.scss"));
|
|
17
17
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
+
// 解构默认值写成字面量会每次渲染新建一个数组,进依赖数组就让 memo 恒不命中;提到模块级常量
|
|
19
|
+
const EMPTY_SEARCH_ITEMS = [];
|
|
20
|
+
|
|
18
21
|
/**
|
|
19
22
|
* Extracts the common logic shared by all Search components
|
|
20
23
|
*/
|
|
@@ -22,7 +25,7 @@ const useSearchCommon = params => {
|
|
|
22
25
|
const {
|
|
23
26
|
form,
|
|
24
27
|
searchItems,
|
|
25
|
-
moreSearchItems =
|
|
28
|
+
moreSearchItems = EMPTY_SEARCH_ITEMS,
|
|
26
29
|
searchData,
|
|
27
30
|
hasPermi,
|
|
28
31
|
beforeButtonGroup,
|
|
@@ -19,6 +19,8 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
19
19
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
20
20
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
21
21
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
22
|
+
// 解构默认值写成字面量会每次渲染新建一个数组,进依赖数组就让 memo 恒不命中;提到模块级常量
|
|
23
|
+
const EMPTY_OPTIONS = [];
|
|
22
24
|
const AutoCompleteSelect = props => {
|
|
23
25
|
const {
|
|
24
26
|
prefix,
|
|
@@ -32,7 +34,7 @@ const AutoCompleteSelect = props => {
|
|
|
32
34
|
popupClassName,
|
|
33
35
|
filterOption: customFilterOption,
|
|
34
36
|
onChange,
|
|
35
|
-
options =
|
|
37
|
+
options = EMPTY_OPTIONS,
|
|
36
38
|
placement = "bottomLeft",
|
|
37
39
|
onDropdownVisibleChange,
|
|
38
40
|
popupMatchSelectWidth,
|
|
@@ -11,20 +11,26 @@ var _hsuUtils = require("hsu-utils");
|
|
|
11
11
|
require("x-data-spreadsheet/dist/xspreadsheet.css");
|
|
12
12
|
var _classnames = _interopRequireDefault(require("classnames"));
|
|
13
13
|
var _xlsxspread = require("./xlsxspread");
|
|
14
|
+
var _useShallowStable = _interopRequireDefault(require("../../hooks/useShallowStable"));
|
|
14
15
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
16
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
17
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
17
18
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
19
|
+
// 解构默认值写成字面量会每次渲染新建一个对象,进依赖数组就让 effect 每渲染必重跑;提到模块级常量
|
|
20
|
+
const EMPTY_X_OPTIONS = {};
|
|
18
21
|
const Spreadsheet = props => {
|
|
19
22
|
const {
|
|
20
23
|
data,
|
|
21
|
-
xOptions =
|
|
24
|
+
xOptions = EMPTY_X_OPTIONS,
|
|
22
25
|
className
|
|
23
26
|
} = props;
|
|
24
27
|
const {
|
|
25
28
|
showBottomTool = true,
|
|
26
|
-
...
|
|
29
|
+
...restXOptions
|
|
27
30
|
} = xOptions;
|
|
31
|
+
// rest 解构出来的对象每次渲染都是新引用,直接进依赖数组会让 memo 恒不命中。
|
|
32
|
+
// useShallowStable 让它回到值语义:内容浅相等就复用同一引用,真变了立刻透出新引用。
|
|
33
|
+
const xOptionsRest = (0, _useShallowStable.default)(restXOptions);
|
|
28
34
|
const ref = (0, _react.useRef)(null);
|
|
29
35
|
const containerRef = (0, _react.useRef)(null);
|
|
30
36
|
const id = (0, _react.useMemo)(() => (0, _hsuUtils.generateRandomStr)(10), []);
|
|
@@ -15,6 +15,9 @@ var _tableUtils = require("../_utils/tableUtils");
|
|
|
15
15
|
var _usePermissions = _interopRequireDefault(require("../../../hooks/usePermissions"));
|
|
16
16
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
17
17
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
+
// 解构默认值写成字面量会每次渲染新建一个数组,进依赖数组就让 memo 恒不命中;提到模块级常量
|
|
19
|
+
const EMPTY_COLUMNS = [];
|
|
20
|
+
|
|
18
21
|
// measureAlign columns: measured at 14px, consistent with the table body and autoWidth title measurement
|
|
19
22
|
const MEASURE_ALIGN_FONT_SIZE = 14;
|
|
20
23
|
// Canvas measureText only returns the advance width, about 1px narrower than the actual DOM rendering; add a 2px buffer to avoid squeezing the widest row
|
|
@@ -56,7 +59,7 @@ const getMeasureAlignWidth = (column, dataSource) => {
|
|
|
56
59
|
};
|
|
57
60
|
const useTableColumns = params => {
|
|
58
61
|
const {
|
|
59
|
-
columns =
|
|
62
|
+
columns = EMPTY_COLUMNS,
|
|
60
63
|
scroll,
|
|
61
64
|
autoWidth,
|
|
62
65
|
dataSource,
|
|
@@ -34,11 +34,14 @@ const useExpandedKeys = (expandedKeysProps, defaultExpandedKeys) => {
|
|
|
34
34
|
}
|
|
35
35
|
}, [defaultExpandedKeys, expandedKeysProps]);
|
|
36
36
|
|
|
37
|
-
// Wrap setExpandedKeys to mark that the user has manually interacted
|
|
38
|
-
|
|
37
|
+
// Wrap setExpandedKeys to mark that the user has manually interacted.
|
|
38
|
+
// 必须 useCallback:这个函数被 Tree 的 handleExpand 当依赖用,
|
|
39
|
+
// 每渲染新建一个就让那个 useCallback 恒不命中——展开回调每渲染换引用透给 antd Tree。
|
|
40
|
+
// 函数体只碰 ref 和状态 setter,两者都恒定,所以依赖数组是空的。
|
|
41
|
+
const handleSetExpandedKeys = (0, _react.useCallback)(keys => {
|
|
39
42
|
hasUserInteractedRef.current = true;
|
|
40
43
|
setExpandedKeys(keys);
|
|
41
|
-
};
|
|
44
|
+
}, []);
|
|
42
45
|
return [expandedKeys, handleSetExpandedKeys];
|
|
43
46
|
};
|
|
44
47
|
|
|
@@ -17,11 +17,14 @@ var _useClearNodeTitle = require("./_hooks/useClearNodeTitle");
|
|
|
17
17
|
var _utils = require("./_utils");
|
|
18
18
|
var _TextEllipsis = _interopRequireDefault(require("../TextEllipsis"));
|
|
19
19
|
var _usePermissions = _interopRequireDefault(require("../../hooks/usePermissions"));
|
|
20
|
+
var _useShallowStable = _interopRequireDefault(require("../../hooks/useShallowStable"));
|
|
20
21
|
var _cssSupports = require("../../utils/cssSupports");
|
|
21
22
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
22
23
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
24
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
24
25
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
26
|
+
// 解构默认值写成字面量会每次渲染新建一个数组,进依赖数组就让 memo 恒不命中;提到模块级常量
|
|
27
|
+
const EMPTY_TREE_DATA = [];
|
|
25
28
|
const Tree = props => {
|
|
26
29
|
const {
|
|
27
30
|
title,
|
|
@@ -31,7 +34,7 @@ const Tree = props => {
|
|
|
31
34
|
titleClassName,
|
|
32
35
|
className,
|
|
33
36
|
search,
|
|
34
|
-
treeData =
|
|
37
|
+
treeData = EMPTY_TREE_DATA,
|
|
35
38
|
onChange,
|
|
36
39
|
onCheck,
|
|
37
40
|
onSelect,
|
|
@@ -52,8 +55,11 @@ const Tree = props => {
|
|
|
52
55
|
onSelectPath,
|
|
53
56
|
allowDeselect = true,
|
|
54
57
|
titleSearchBarClassName,
|
|
55
|
-
...
|
|
58
|
+
...restTreeConfig
|
|
56
59
|
} = props;
|
|
60
|
+
// rest 解构出来的对象每次渲染都是新引用,直接进依赖数组会让 memo 恒不命中。
|
|
61
|
+
// useShallowStable 让它回到值语义:内容浅相等就复用同一引用,真变了立刻透出新引用。
|
|
62
|
+
const treeConfig = (0, _useShallowStable.default)(restTreeConfig);
|
|
57
63
|
const {
|
|
58
64
|
permitted
|
|
59
65
|
} = (0, _usePermissions.default)(hasPermi);
|
|
@@ -28,6 +28,38 @@
|
|
|
28
28
|
overflow-y: auto;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/* ===== 滚动条占位不许吃掉菜单项的内缩 =====
|
|
32
|
+
上面那条规则把「谁滚」定在了菜单根上,但没有把几何契约收完:滚动条一旦
|
|
33
|
+
**实占宽度**(消费方常见做法:槽宽恒定、只切 thumb 颜色,这样悬浮时不抖),
|
|
34
|
+
它就从菜单根的内容盒里切走一条 —— 而菜单项的左右外边距量的正是这个内容盒。
|
|
35
|
+
于是展开子菜单、菜单一超高,右边多出一条空白,左边纹丝不动:
|
|
36
|
+
|
|
37
|
+
展开前 菜单项 8..220(左留白 8 / 右留白 10)
|
|
38
|
+
展开后 菜单项 8..206(左留白 8 / 右留白 24)← 展开的那一项看着「右边距变大了」
|
|
39
|
+
|
|
40
|
+
`scrollbar-gutter: stable both-edges` 把这条槽**两侧对称保留**,且不论当下滚不滚
|
|
41
|
+
都保留:左右留白从此相等,展开 / 收起也不再有宽度变化(连带把「展开那一瞬内容
|
|
42
|
+
重排」一并去掉)。槽宽由浏览器按该元素实际的滚动条算,**不是写死的 14px** ——
|
|
43
|
+
消费方把滚动条改窄改宽,留白跟着变。
|
|
44
|
+
|
|
45
|
+
配套把菜单项自己的左右外边距清零:留白改由这条槽提供,不再叠加。不清的话
|
|
46
|
+
留白变成 `8 + 槽宽`(实测 22/24),230px 的侧栏里「MCP 连接器」直接被截断。
|
|
47
|
+
纵向节奏与嵌套缩进不受影响 —— antd 的行内缩进走的是 padding,不是 margin。
|
|
48
|
+
|
|
49
|
+
`@supports` 兜底:不认这个属性的浏览器维持原样,不会两头落空。 */
|
|
50
|
+
@supports (scrollbar-gutter: stable both-edges) {
|
|
51
|
+
&:global(.ant-menu-inline) {
|
|
52
|
+
scrollbar-gutter: stable both-edges;
|
|
53
|
+
|
|
54
|
+
:global(.ant-menu-item),
|
|
55
|
+
:global(.ant-menu-submenu-title) {
|
|
56
|
+
width: 100%;
|
|
57
|
+
|
|
58
|
+
margin-inline: 0px;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
31
63
|
/* 子菜单在展开 / 收起动画期间被 rc-motion 逐帧改高度。antd 的
|
|
32
64
|
`.ant-motion-collapse` 自带 overflow hidden,这里补的是**动画结束、类名摘掉
|
|
33
65
|
之后**那一帧:此时 ul 的高度刚回到 auto,若父级恰好差几像素,浏览器会先画出
|
package/lib/styles/tokens.d.ts
CHANGED
|
@@ -93,6 +93,16 @@ export declare const modalWidth: {
|
|
|
93
93
|
md: number;
|
|
94
94
|
lg: number;
|
|
95
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* 内容异步加载的弹窗的**高度下界**(`<Modal minHeight>` 的默认档)。
|
|
98
|
+
*
|
|
99
|
+
* 取 700 不是拍的:`Panel.List.Modal` 从一开始就把自己钉在 `height: 700px`,那是
|
|
100
|
+
* 「搜索行 + 工具条 + 表头 + 十行左右 + 分页」放得下的高度。详情 / 消息 / 记录这类
|
|
101
|
+
* 弹窗与它同处一套后台,用同一个下界,纵向节奏才是一套的。
|
|
102
|
+
*
|
|
103
|
+
* 它只是**下界**:内容更高照常撑开,并且在 CSS 里与 `90vh` 取小,矮窗口不会被顶出屏幕。
|
|
104
|
+
*/
|
|
105
|
+
export declare const modalMinHeight: number;
|
|
96
106
|
/**
|
|
97
107
|
* 断点。与 `styles/_responsive.scss` 的 mixin 同源,所以 JS 判断不会和 CSS 媒体查询错开。
|
|
98
108
|
*/
|
package/lib/styles/tokens.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.withAlpha = exports.toAntdTheme = exports.toAntdComponents = exports.radius = exports.modalWidth = exports.lightTokens = exports.fontTokens = exports.defaultPrimaryColor = exports.darkTokens = exports.controlTokens = exports.breakpoints = void 0;
|
|
6
|
+
exports.withAlpha = exports.toAntdTheme = exports.toAntdComponents = exports.radius = exports.modalWidth = exports.modalMinHeight = exports.lightTokens = exports.fontTokens = exports.defaultPrimaryColor = exports.darkTokens = exports.controlTokens = exports.breakpoints = void 0;
|
|
7
7
|
var _tokens = _interopRequireDefault(require("./tokens.json"));
|
|
8
8
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
9
|
/**
|
|
@@ -56,6 +56,17 @@ const controlTokens = exports.controlTokens = _tokens.default.control;
|
|
|
56
56
|
*/
|
|
57
57
|
const modalWidth = exports.modalWidth = _tokens.default.modalWidth;
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* 内容异步加载的弹窗的**高度下界**(`<Modal minHeight>` 的默认档)。
|
|
61
|
+
*
|
|
62
|
+
* 取 700 不是拍的:`Panel.List.Modal` 从一开始就把自己钉在 `height: 700px`,那是
|
|
63
|
+
* 「搜索行 + 工具条 + 表头 + 十行左右 + 分页」放得下的高度。详情 / 消息 / 记录这类
|
|
64
|
+
* 弹窗与它同处一套后台,用同一个下界,纵向节奏才是一套的。
|
|
65
|
+
*
|
|
66
|
+
* 它只是**下界**:内容更高照常撑开,并且在 CSS 里与 `90vh` 取小,矮窗口不会被顶出屏幕。
|
|
67
|
+
*/
|
|
68
|
+
const modalMinHeight = exports.modalMinHeight = _tokens.default.modalMinHeight;
|
|
69
|
+
|
|
59
70
|
/**
|
|
60
71
|
* 断点。与 `styles/_responsive.scss` 的 mixin 同源,所以 JS 判断不会和 CSS 媒体查询错开。
|
|
61
72
|
*/
|
package/lib/styles/tokens.json
CHANGED
package/package.json
CHANGED
|
@@ -64,52 +64,99 @@ export function walkSources(dir: string, out: string[] = []) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* 找出每个匹配 `hookRe` 的 hook 调用的依赖数组,返回 `[行号,
|
|
67
|
+
* 找出每个匹配 `hookRe` 的 hook 调用的依赖数组,返回 `[行号, 依赖名, 依赖原文]`。
|
|
68
68
|
* `hookRe` 必须带 `g`,且以 `\(` 结尾(例如 `/use(?:Layout)?Effect\(/g`)。
|
|
69
|
+
*
|
|
70
|
+
* 依赖数组按「调用参数里最后一个顶层 `[...]`,且它后面到 `)` 之间只剩逗号/空白」
|
|
71
|
+
* 来定位。早先用 `/,\s*\[([\s\S]*)\]\s*$/` 正则从**最左**的 `, [` 起贪婪匹配,
|
|
72
|
+
* 回调体里只要出现一次 `, [`(JSX 的 `classNames(x, { [styles.a]: b })` 就会),
|
|
73
|
+
* 真正的依赖数组就被并进同一段,切出来的是带换行的 JSX 碎片而不是标识符 ——
|
|
74
|
+
* 结果是真命中被静默漏掉。这里改成括号配平扫描,不再漏。
|
|
69
75
|
*/
|
|
70
76
|
export function hookDeps(
|
|
71
77
|
src: string,
|
|
72
78
|
hookRe: RegExp,
|
|
73
|
-
): Array<[number, string]> {
|
|
74
|
-
const found: Array<[number, string]> = [];
|
|
79
|
+
): Array<[number, string, string]> {
|
|
80
|
+
const found: Array<[number, string, string]> = [];
|
|
75
81
|
const re = new RegExp(hookRe.source, "g");
|
|
76
82
|
let m: RegExpExecArray | null;
|
|
77
83
|
|
|
78
84
|
while ((m = re.exec(src))) {
|
|
79
|
-
|
|
85
|
+
const start = m.index + m[0].length;
|
|
86
|
+
let i = start;
|
|
80
87
|
let depth = 1;
|
|
81
88
|
let quote: string | null = null;
|
|
82
89
|
let prev = "";
|
|
90
|
+
/** 调用参数里所有顶层 `[...]` 的起止下标 */
|
|
91
|
+
const topArrays: Array<[number, number]> = [];
|
|
92
|
+
let openAt = -1;
|
|
83
93
|
|
|
84
94
|
while (i < src.length && depth > 0) {
|
|
85
95
|
const c = src[i];
|
|
86
96
|
if (quote) {
|
|
87
97
|
if (c === quote && prev !== "\\") quote = null;
|
|
88
98
|
} else if (c === '"' || c === "'" || c === "`") quote = c;
|
|
89
|
-
else if (c === "(" || c === "[" || c === "{")
|
|
90
|
-
|
|
99
|
+
else if (c === "(" || c === "[" || c === "{") {
|
|
100
|
+
if (depth === 1 && c === "[") openAt = i;
|
|
101
|
+
depth++;
|
|
102
|
+
} else if (c === ")" || c === "]" || c === "}") {
|
|
103
|
+
depth--;
|
|
104
|
+
if (depth === 1 && c === "]" && openAt >= 0) {
|
|
105
|
+
topArrays.push([openAt, i]);
|
|
106
|
+
openAt = -1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
91
109
|
prev = c;
|
|
92
110
|
i++;
|
|
93
111
|
}
|
|
94
112
|
|
|
95
|
-
const
|
|
96
|
-
const deps =
|
|
113
|
+
const closeParen = i - 1;
|
|
114
|
+
const deps = topArrays[topArrays.length - 1];
|
|
115
|
+
// 依赖数组必须是最后一个实参:前面紧邻一个顶层逗号(把 `useMemo(() => [x])`
|
|
116
|
+
// 这种「返回数组、根本没依赖数组」的写法排除掉),后面到 `)` 只剩逗号与空白
|
|
97
117
|
if (!deps) continue;
|
|
118
|
+
if (!/,\s*$/.test(src.slice(start, deps[0]))) continue;
|
|
119
|
+
if (!/^\s*,?\s*$/.test(src.slice(deps[1] + 1, closeParen))) continue;
|
|
98
120
|
|
|
99
121
|
const line = src.slice(0, m.index).split("\n").length;
|
|
100
|
-
for (const raw of deps[1]
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
.trim();
|
|
106
|
-
if (name) found.push([line, name]);
|
|
122
|
+
for (const raw of splitTopLevel(src.slice(deps[0] + 1, deps[1]))) {
|
|
123
|
+
const expr = raw.replace(/\/\/.*$/gm, "").trim();
|
|
124
|
+
if (!expr) continue;
|
|
125
|
+
const name = expr.split(/[.?[(!]/)[0].trim();
|
|
126
|
+
if (name) found.push([line, name, expr]);
|
|
107
127
|
}
|
|
108
128
|
}
|
|
109
129
|
|
|
110
130
|
return found;
|
|
111
131
|
}
|
|
112
132
|
|
|
133
|
+
/** 按顶层逗号切分(括号/引号内部的逗号不算) */
|
|
134
|
+
function splitTopLevel(text: string): string[] {
|
|
135
|
+
const parts: string[] = [];
|
|
136
|
+
let depth = 0;
|
|
137
|
+
let quote: string | null = null;
|
|
138
|
+
let prev = "";
|
|
139
|
+
let cur = "";
|
|
140
|
+
|
|
141
|
+
for (const c of text) {
|
|
142
|
+
if (quote) {
|
|
143
|
+
if (c === quote && prev !== "\\") quote = null;
|
|
144
|
+
} else if (c === '"' || c === "'" || c === "`") quote = c;
|
|
145
|
+
else if (c === "(" || c === "[" || c === "{") depth++;
|
|
146
|
+
else if (c === ")" || c === "]" || c === "}") depth--;
|
|
147
|
+
else if (c === "," && depth === 0) {
|
|
148
|
+
parts.push(cur);
|
|
149
|
+
cur = "";
|
|
150
|
+
prev = c;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
cur += c;
|
|
154
|
+
prev = c;
|
|
155
|
+
}
|
|
156
|
+
parts.push(cur);
|
|
157
|
+
return parts;
|
|
158
|
+
}
|
|
159
|
+
|
|
113
160
|
/**
|
|
114
161
|
* 找出「每次渲染都会新建一个对象/数组」的解构绑定,返回 `绑定名 → 说明`。
|
|
115
162
|
*
|