@arcblock/ux 2.1.34 → 2.1.37

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.
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _propTypes = _interopRequireDefault(require("prop-types"));
9
+
10
+ var _styledComponents = _interopRequireDefault(require("styled-components"));
11
+
12
+ var _Box = _interopRequireDefault(require("@mui/material/Box"));
13
+
14
+ var _jsxRuntime = require("react/jsx-runtime");
15
+
16
+ const _excluded = ["height"];
17
+
18
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
+
20
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
21
+
22
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
23
+
24
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
25
+
26
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
27
+
28
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
29
+
30
+ /**
31
+ * 一个容器组件, 当子元素 width 超出该容器时自动隐藏子元素, 必须设置明确的 height 值
32
+ */
33
+ function AutoHidden(_ref) {
34
+ let {
35
+ height
36
+ } = _ref,
37
+ rest = _objectWithoutProperties(_ref, _excluded);
38
+
39
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(Root, _objectSpread({
40
+ height: height
41
+ }, rest));
42
+ }
43
+
44
+ AutoHidden.propTypes = {
45
+ height: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired
46
+ };
47
+ const Root = (0, _styledComponents.default)(_Box.default).withConfig({
48
+ displayName: "auto-hidden__Root",
49
+ componentId: "sc-1vwixkj-0"
50
+ })(["overflow:hidden;&:before{content:'';display:inline-block;width:1px;height:100%;float:left;}> *{float:left;white-space:nowrap;}"]);
51
+ var _default = AutoHidden;
52
+ exports.default = _default;
@@ -15,6 +15,8 @@ var _Container = _interopRequireDefault(require("@mui/material/Container"));
15
15
 
16
16
  var _styles = require("@mui/material/styles");
17
17
 
18
+ var _autoHidden = _interopRequireDefault(require("./auto-hidden"));
19
+
18
20
  var _jsxRuntime = require("react/jsx-runtime");
19
21
 
20
22
  const _excluded = ["logo", "brand", "brandAddon", "description", "children", "addons", "prepend"];
@@ -55,20 +57,29 @@ function Header(_ref) {
55
57
  children: [prepend, logo && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
56
58
  className: "header-logo",
57
59
  children: logo
58
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
59
- className: "header-brand",
60
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
61
- className: "header-brand-title",
62
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("h2", {
63
- children: brand
60
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_autoHidden.default, {
61
+ height: 44,
62
+ sx: {
63
+ flexShrink: {
64
+ xs: 1,
65
+ md: 0
66
+ }
67
+ },
68
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
69
+ className: "header-brand",
70
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
71
+ className: "header-brand-title",
72
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("h2", {
73
+ children: brand
74
+ })
64
75
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
65
- className: "header-brand-addon",
66
- children: brandAddon
76
+ className: "header-brand-desc",
77
+ children: description
67
78
  })]
68
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
69
- className: "header-brand-desc",
70
- children: description
71
- })]
79
+ })
80
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
81
+ className: "header-brand-addon",
82
+ children: brandAddon
72
83
  }), children, /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
73
84
  flexGrow: 1
74
85
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
@@ -107,7 +118,7 @@ Header.defaultProps = {
107
118
  const Root = _styledComponents.default.div.withConfig({
108
119
  displayName: "header__Root",
109
120
  componentId: "sc-15qnwg1-0"
110
- })(["position:relative;z-index:", ";font-size:14px;background:", ";.header-container{display:flex;align-items:center;height:64px;}.header-logo{display:inline-flex;position:relative;height:44px;margin-right:16px;img,svg{width:auto;height:100%;}> a{height:100%;line-height:1;}> a::before{position:absolute;top:0;right:0;bottom:0;left:0;background-color:transparent;content:'';}}.header-brand{display:flex;flex-direction:column;flex-shrink:0;margin-right:16px;a{color:inherit;text-decoration:none;}.header-brand-title{display:flex;align-items:center;h2{margin:0;font-size:16px;}.header-brand-addon{margin-left:8px;}}.header-brand-desc{color:#9397a1;}}.header-addons{display:flex;align-items:center;}", "{.header-brand{margin-right:12px;.header-brand-title{h2{font-size:14px;}}}}", "{.header-container{height:56px;}.header-menu{display:inline-block;}.header-logo{height:32px;}.header-brand{display:none;}}"], props => props.$theme.zIndex.appBar, props => props.$theme.palette.common.white, props => props.$theme.breakpoints.down('lg'), props => props.$theme.breakpoints.down('md'));
121
+ })(["position:relative;z-index:", ";font-size:14px;background:", ";.header-container{display:flex;align-items:center;height:64px;}.header-logo{display:inline-flex;position:relative;height:44px;margin-right:16px;img,svg{width:auto;height:100%;max-height:100%;}> a{height:100%;line-height:1;}> a::before{position:absolute;top:0;right:0;bottom:0;left:0;background-color:transparent;content:'';}}.header-brand{display:flex;flex-direction:column;justify-content:center;height:44px;margin-right:16px;line-height:1;a{color:inherit;text-decoration:none;}.header-brand-title{display:flex;align-items:center;h2{margin:0;font-size:16px;}}.header-brand-desc{margin-top:4px;color:#9397a1;}}.header-brand-addon{margin-right:16px;}.header-addons{display:flex;align-items:center;}", "{.header-brand{margin-right:12px;.header-brand-title{h2{font-size:14px;}}}}", "{.header-menu{display:inline-block;}.header-logo{height:32px;}.header-brand{.header-brand-title{h2{font-size:13px;}}.header-brand-desc{font-size:12px;}}.header-brand-addon{display:none;}}"], props => props.$theme.zIndex.appBar, props => props.$theme.palette.common.white, props => props.$theme.breakpoints.down('lg'), props => props.$theme.breakpoints.down('md'));
111
122
 
112
123
  var _default = Header;
113
124
  exports.default = _default;
@@ -13,8 +13,12 @@ var _styledComponents = _interopRequireDefault(require("styled-components"));
13
13
 
14
14
  var _Menu = _interopRequireDefault(require("@mui/icons-material/Menu"));
15
15
 
16
+ var _Close = _interopRequireDefault(require("@mui/icons-material/Close"));
17
+
16
18
  var _IconButton = _interopRequireDefault(require("@mui/material/IconButton"));
17
19
 
20
+ var _Container = _interopRequireDefault(require("@mui/material/Container"));
21
+
18
22
  var _styles = require("@mui/material/styles");
19
23
 
20
24
  var _useMediaQuery = _interopRequireDefault(require("@mui/material/useMediaQuery"));
@@ -61,14 +65,8 @@ function ResponsiveHeader(_ref) {
61
65
  const _children = typeof children === 'function' ? children({
62
66
  isMobile,
63
67
  closeMenu: () => setDrawerOpen(false)
64
- }) : children;
68
+ }) : children; // 如果 children 没有值, 则使用普通的 Header 组件渲染 (此时并没有什么内容需要在 menu 中显示)
65
69
 
66
- const {
67
- logo,
68
- brand,
69
- brandAddon,
70
- description
71
- } = rest; // 如果 children 没有值, 则使用普通的 Header 组件渲染 (此时并没有什么内容需要在 menu 中显示)
72
70
 
73
71
  if (!children) {
74
72
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_header.default, _objectSpread({
@@ -78,41 +76,38 @@ function ResponsiveHeader(_ref) {
78
76
 
79
77
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(Root, _objectSpread(_objectSpread({
80
78
  prepend: prepend || /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
81
- color: "inherit",
79
+ sx: {
80
+ color: theme.palette.grey[500]
81
+ },
82
82
  edge: "start",
83
83
  className: "header-menu",
84
- onClick: () => setDrawerOpen(true),
85
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Menu.default, {})
84
+ onClick: () => setDrawerOpen(!drawerOpen),
85
+ children: drawerOpen ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Close.default, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Menu.default, {})
86
86
  })
87
87
  }, rest), {}, {
88
- logo: isMobile ? null : logo,
89
88
  $theme: theme,
90
89
  children: [!isMobile && _children, isMobile && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Drawer.default, {
91
90
  open: drawerOpen,
92
91
  onClose: () => setDrawerOpen(false),
93
92
  ModalProps: {
94
93
  disablePortal: false,
95
- keepMounted: true
94
+ keepMounted: true,
95
+ BackdropComponent: null
96
+ },
97
+ anchor: "top",
98
+ sx: {
99
+ top: 64,
100
+ zIndex: theme.zIndex.appBar - 1
101
+ },
102
+ PaperProps: {
103
+ style: {
104
+ top: 64,
105
+ bottom: 0,
106
+ boxShadow: 'none'
107
+ }
96
108
  },
97
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(Sidebar, {
98
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
99
- className: "header-sidebar-head",
100
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
101
- className: "header-sidebar-logo",
102
- children: logo
103
- }), brand && /*#__PURE__*/(0, _jsxRuntime.jsx)("h2", {
104
- children: brand
105
- }), description && /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
106
- className: "header-sidebar-description",
107
- children: description
108
- }), brandAddon && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
109
- className: "header-sidebar-brandaddon",
110
- children: brandAddon
111
- })]
112
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
113
- className: "header-sidebar-content",
114
- children: _children
115
- })]
109
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(MenuPanel, {
110
+ children: _children
116
111
  })
117
112
  })]
118
113
  }));
@@ -128,15 +123,10 @@ ResponsiveHeader.defaultProps = _objectSpread({}, _header.default.defaultProps);
128
123
  const Root = (0, _styledComponents.default)(_header.default).withConfig({
129
124
  displayName: "responsive-header__Root",
130
125
  componentId: "sc-1dugv47-0"
131
- })([".header-menu{display:none;}", "{.header-menu{display:block;}}"], props => props.$theme.breakpoints.down('md'));
132
- /**
133
- * Sidebar
134
- */
135
-
136
- const Sidebar = _styledComponents.default.div.withConfig({
137
- displayName: "responsive-header__Sidebar",
126
+ })([".header-menu{display:none;}", "{.header-menu{display:flex;margin-right:12px;}}"], props => props.$theme.breakpoints.down('md'));
127
+ const MenuPanel = (0, _styledComponents.default)(_Container.default).withConfig({
128
+ displayName: "responsive-header__MenuPanel",
138
129
  componentId: "sc-1dugv47-1"
139
- })(["min-width:280px;font-size:14px;.header-sidebar-head{display:flex;flex-direction:column;align-items:center;padding:24px 0;border-bottom:1px solid #eee;font-size:12px;.header-sidebar-logo{min-width:44px;height:44px;font-size:44px;> *{width:auto;height:100%;}> a{display:block;}img{max-width:100%;max-height:100%;}}h2{margin-top:12px;font-size:14px;}.header-sidebar-description{margin:2px 0 0 0;}.header-sidebar-brandaddon{margin-top:8px;}}.header-sidebar-content{padding:16px 0;}"]);
140
-
130
+ })(["padding-top:8px;padding-bottom:16px;.navmenu{margin:0 -16px;.navmenu-root > .navmenu-item,.navmenu-root > .navmenu-sub{border:0;}}"]);
141
131
  var _default = ResponsiveHeader;
142
132
  exports.default = _default;
@@ -94,6 +94,7 @@ function Dashboard(_ref2) {
94
94
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactHelmet.default, {
95
95
  title: title
96
96
  }, title), /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledUxHeader, _objectSpread(_objectSpread({}, headerProps), {}, {
97
+ $theme: theme,
97
98
  children: _ref3 => {
98
99
  let {
99
100
  isMobile,
@@ -158,7 +159,7 @@ const Wrapper = _styledComponents.default.div.withConfig({
158
159
  const StyledUxHeader = (0, _styledComponents.default)(_Header.ResponsiveHeader).withConfig({
159
160
  displayName: "dashboard__StyledUxHeader",
160
161
  componentId: "sc-arvc7q-1"
161
- })([".header-container{max-width:100%;}.header-logo{display:flex;justify-content:center;width:56px;}"]); // 兼容旧版 dashboard
162
+ })([".header-container{max-width:100%;}", "{.header-logo{display:flex;justify-content:center;width:56px;}}"], props => props.$theme.breakpoints.up('md')); // 兼容旧版 dashboard
162
163
 
163
164
  function DashboardWrapper(_ref4) {
164
165
  let {
@@ -104,10 +104,14 @@ function NavMenu(_ref) {
104
104
  });
105
105
  }, [state, mode, activate, open, close]);
106
106
  (0, _react.useEffect)(() => {
107
- if (activeId) {
108
- activate(activeId);
107
+ // NavMenu#activeId 和 Item#active prop 都可以用来控制激活状态 (一般不会混用这两种方式)
108
+ // 如果未传入 NavMenu#activeId, 应该避免设置一个空值的 activeId 状态 (会与 Item#active 冲突)
109
+ if (activeId !== undefined && activeId !== null) {
110
+ setState(prev => _objectSpread(_objectSpread({}, prev), {}, {
111
+ activeId
112
+ }));
109
113
  }
110
- }, [activate, activeId]);
114
+ }, [activeId]);
111
115
  const classes = (0, _clsx.default)('navmenu', "navmenu--".concat(mode), rest.className);
112
116
 
113
117
  const renderItem = (item, index) => {
@@ -12,7 +12,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
12
12
  const NavMenuBase = _styledComponents.default.nav.withConfig({
13
13
  displayName: "style__NavMenuBase",
14
14
  componentId: "sc-2g7isz-0"
15
- })(["background-color:", ";font-size:14px;ul{list-style:none;margin:0;padding:0;}.navmenu-item,.navmenu-sub{display:flex;align-items:center;}a{color:inherit;}.navmenu-item,.navmenu-sub{color:", ";}.navmenu-item--active,.navmenu-item:hover,.navmenu-sub--opened{color:", ";}.navmenu-item{position:relative;cursor:pointer;transition:color 0.2s ease-in-out;a{text-decoration:none;white-space:nowrap;}a::before{position:absolute;top:0;right:0;bottom:0;left:0;background-color:transparent;content:'';}}.navmenu-sub{position:relative;cursor:pointer;}.navmenu-item-icon,.navmenu-sub-icon,.navmenu-sub-expand-icon{display:flex;line-height:1;}.navmenu-item-icon,.navmenu-sub-icon{margin-right:4px;}.navmenu-item-icon > *,.navmenu-sub-icon > *{width:auto;max-height:20px;font-size:1.5em;}.navmenu-sub-expand-icon{margin-left:8px;> *{width:0.8em;height:0.8em;transition:transform 0.2s ease-in-out;}}"], props => props.$bgColor, props => props.$textColor, props => props.$activeTextColor);
15
+ })(["background-color:", ";font-size:14px;ul{list-style:none;margin:0;padding:0;}.navmenu-item,.navmenu-sub{display:flex;align-items:center;}a{color:inherit;}.navmenu-item,.navmenu-sub{color:", ";}.navmenu-item--active,.navmenu-item:hover,.navmenu-sub--opened{color:", ";}.navmenu-item{position:relative;cursor:pointer;transition:color 0.2s ease-in-out;a{text-decoration:none;white-space:nowrap;}a::before{position:absolute;top:0;right:0;bottom:0;left:0;background-color:transparent;content:'';}}.navmenu-sub{position:relative;cursor:pointer;}.navmenu-item-icon,.navmenu-sub-icon,.navmenu-sub-expand-icon{display:flex;line-height:1;}.navmenu-item-icon,.navmenu-sub-icon{margin-right:4px;}.navmenu-item-icon > *,.navmenu-sub-icon > *{width:auto;height:22px;max-height:22px;font-size:1.5em;}.navmenu-sub-expand-icon{margin-left:8px;> *{width:0.8em;height:0.8em;transition:transform 0.2s ease-in-out;}}"], props => props.$bgColor, props => props.$textColor, props => props.$activeTextColor);
16
16
 
17
17
  const HorizontalStyle = (0, _styledComponents.default)(NavMenuBase).withConfig({
18
18
  displayName: "style__HorizontalStyle",
@@ -24,5 +24,5 @@ exports.HorizontalStyle = HorizontalStyle;
24
24
  const InlineStyle = (0, _styledComponents.default)(NavMenuBase).withConfig({
25
25
  displayName: "style__InlineStyle",
26
26
  componentId: "sc-2g7isz-2"
27
- })([".navmenu-root{display:flex;flex-direction:column;align-items:stretch;}.navmenu-item,.navmenu-sub{padding:0 16px;}& .navmenu-sub{flex-wrap:wrap;}.navmenu-root > .navmenu-item,.navmenu-root > .navmenu-sub{line-height:48px;border-bottom:1px solid #eee;}.navmenu-item-icon,.navmenu-sub-icon{width:32px;margin:0;}.navmenu-sub-expand-icon{margin-left:auto;}.navmenu-sub-container{display:none;flex:1 0 100%;margin:0 -16px;padding-bottom:8px;.navmenu-item,.navmenu-sub{line-height:32px;}}.navmenu-sub-list{padding-left:16px;.navmenu-item,.navmenu-sub{padding-left:32px;font-size:13px;}}.navmenu-root > .navmenu-sub{&.navmenu-sub--opened{background:#eee;}}.navmenu-sub--opened > .navmenu-sub-container{display:block;}"]);
27
+ })(["font-size:16px;.navmenu-root{display:flex;flex-direction:column;align-items:stretch;}.navmenu-item,.navmenu-sub{padding:0 16px;}& .navmenu-sub{flex-wrap:wrap;}.navmenu-root > .navmenu-item,.navmenu-root > .navmenu-sub{line-height:48px;border-bottom:1px solid #eee;}.navmenu-item-icon,.navmenu-sub-icon{width:42px;margin:0;}.navmenu-sub-expand-icon{margin-left:auto;}.navmenu-sub-container{display:none;flex:1 0 100%;margin:0 -16px;padding-bottom:8px;.navmenu-item,.navmenu-sub{line-height:32px;}}.navmenu-sub-list{padding-left:16px;.navmenu-item,.navmenu-sub{padding-left:42px;font-size:13px;}}.navmenu-sub--opened > .navmenu-sub-container{display:block;}"]);
28
28
  exports.InlineStyle = InlineStyle;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.1.34",
3
+ "version": "2.1.37",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -52,10 +52,10 @@
52
52
  "react": ">=18.1.0",
53
53
  "react-ga": "^2.7.0"
54
54
  },
55
- "gitHead": "cf0c00b60dfa2819e06e0e063614b99eeb392c79",
55
+ "gitHead": "4b1bb7cefb268cc14e165197a417bfe52ca79711",
56
56
  "dependencies": {
57
- "@arcblock/icons": "^2.1.34",
58
- "@arcblock/react-hooks": "^2.1.34",
57
+ "@arcblock/icons": "^2.1.37",
58
+ "@arcblock/react-hooks": "^2.1.37",
59
59
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
60
60
  "@emotion/react": "^11.9.0",
61
61
  "@emotion/styled": "^11.8.1",
@@ -0,0 +1,31 @@
1
+ import PropTypes from 'prop-types';
2
+ import styled from 'styled-components';
3
+ import Box from '@mui/material/Box';
4
+
5
+ /**
6
+ * 一个容器组件, 当子元素 width 超出该容器时自动隐藏子元素, 必须设置明确的 height 值
7
+ */
8
+ function AutoHidden({ height, ...rest }) {
9
+ return <Root height={height} {...rest} />;
10
+ }
11
+
12
+ AutoHidden.propTypes = {
13
+ height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
14
+ };
15
+
16
+ const Root = styled(Box)`
17
+ overflow: hidden;
18
+ &:before {
19
+ content: '';
20
+ display: inline-block;
21
+ width: 1px;
22
+ height: 100%;
23
+ float: left;
24
+ }
25
+ > * {
26
+ float: left;
27
+ white-space: nowrap;
28
+ }
29
+ `;
30
+
31
+ export default AutoHidden;
@@ -3,6 +3,7 @@ import styled from 'styled-components';
3
3
  import Box from '@mui/material/Box';
4
4
  import Container from '@mui/material/Container';
5
5
  import { useTheme } from '@mui/material/styles';
6
+ import AutoHidden from './auto-hidden';
6
7
 
7
8
  /**
8
9
  * Header 组件
@@ -15,13 +16,15 @@ function Header({ logo, brand, brandAddon, description, children, addons, prepen
15
16
  <Container className="header-container">
16
17
  {prepend}
17
18
  {logo && <div className="header-logo">{logo}</div>}
18
- <div className="header-brand">
19
- <div className="header-brand-title">
20
- <h2>{brand}</h2>
21
- <div className="header-brand-addon">{brandAddon}</div>
19
+ <AutoHidden height={44} sx={{ flexShrink: { xs: 1, md: 0 } }}>
20
+ <div className="header-brand">
21
+ <div className="header-brand-title">
22
+ <h2>{brand}</h2>
23
+ </div>
24
+ <div className="header-brand-desc">{description}</div>
22
25
  </div>
23
- <div className="header-brand-desc">{description}</div>
24
- </div>
26
+ </AutoHidden>
27
+ <div className="header-brand-addon">{brandAddon}</div>
25
28
  {children}
26
29
  <Box flexGrow={1} />
27
30
  <div className="header-addons">{addons}</div>
@@ -75,6 +78,7 @@ const Root = styled.div`
75
78
  svg {
76
79
  width: auto;
77
80
  height: 100%;
81
+ max-height: 100%;
78
82
  }
79
83
  > a {
80
84
  height: 100%;
@@ -93,8 +97,10 @@ const Root = styled.div`
93
97
  .header-brand {
94
98
  display: flex;
95
99
  flex-direction: column;
96
- flex-shrink: 0;
100
+ justify-content: center;
101
+ height: 44px;
97
102
  margin-right: 16px;
103
+ line-height: 1;
98
104
  a {
99
105
  color: inherit;
100
106
  text-decoration: none;
@@ -106,14 +112,15 @@ const Root = styled.div`
106
112
  margin: 0;
107
113
  font-size: 16px;
108
114
  }
109
- .header-brand-addon {
110
- margin-left: 8px;
111
- }
112
115
  }
113
116
  .header-brand-desc {
117
+ margin-top: 4px;
114
118
  color: #9397a1;
115
119
  }
116
120
  }
121
+ .header-brand-addon {
122
+ margin-right: 16px;
123
+ }
117
124
  .header-addons {
118
125
  display: flex;
119
126
  align-items: center;
@@ -129,9 +136,6 @@ const Root = styled.div`
129
136
  }
130
137
  }
131
138
  ${(props) => props.$theme.breakpoints.down('md')} {
132
- .header-container {
133
- height: 56px;
134
- }
135
139
  .header-menu {
136
140
  display: inline-block;
137
141
  }
@@ -139,6 +143,16 @@ const Root = styled.div`
139
143
  height: 32px;
140
144
  }
141
145
  .header-brand {
146
+ .header-brand-title {
147
+ h2 {
148
+ font-size: 13px;
149
+ }
150
+ }
151
+ .header-brand-desc {
152
+ font-size: 12px;
153
+ }
154
+ }
155
+ .header-brand-addon {
142
156
  display: none;
143
157
  }
144
158
  }
@@ -2,7 +2,9 @@ import { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import styled from 'styled-components';
4
4
  import MenuIcon from '@mui/icons-material/Menu';
5
+ import CloseIcon from '@mui/icons-material/Close';
5
6
  import Button from '@mui/material/IconButton';
7
+ import Container from '@mui/material/Container';
6
8
  import { useTheme } from '@mui/material/styles';
7
9
  import useMediaQuery from '@mui/material/useMediaQuery';
8
10
  import Drawer from '@mui/material/Drawer';
@@ -21,7 +23,6 @@ function ResponsiveHeader({ menu, prepend, children, ...rest }) {
21
23
  const [drawerOpen, setDrawerOpen] = useState(false);
22
24
  const _children =
23
25
  typeof children === 'function' ? children({ isMobile, closeMenu: () => setDrawerOpen(false) }) : children;
24
- const { logo, brand, brandAddon, description } = rest;
25
26
  // 如果 children 没有值, 则使用普通的 Header 组件渲染 (此时并没有什么内容需要在 menu 中显示)
26
27
  if (!children) {
27
28
  return <Header prepend={prepend} {...rest} />;
@@ -30,29 +31,27 @@ function ResponsiveHeader({ menu, prepend, children, ...rest }) {
30
31
  <Root
31
32
  prepend={
32
33
  prepend || (
33
- <Button color="inherit" edge="start" className="header-menu" onClick={() => setDrawerOpen(true)}>
34
- <MenuIcon />
34
+ <Button
35
+ sx={{ color: theme.palette.grey[500] }}
36
+ edge="start"
37
+ className="header-menu"
38
+ onClick={() => setDrawerOpen(!drawerOpen)}>
39
+ {drawerOpen ? <CloseIcon /> : <MenuIcon />}
35
40
  </Button>
36
41
  )
37
42
  }
38
43
  {...rest}
39
- logo={isMobile ? null : logo}
40
44
  $theme={theme}>
41
45
  {!isMobile && _children}
42
46
  {isMobile && (
43
47
  <Drawer
44
48
  open={drawerOpen}
45
49
  onClose={() => setDrawerOpen(false)}
46
- ModalProps={{ disablePortal: false, keepMounted: true }}>
47
- <Sidebar>
48
- <div className="header-sidebar-head">
49
- <div className="header-sidebar-logo">{logo}</div>
50
- {brand && <h2>{brand}</h2>}
51
- {description && <p className="header-sidebar-description">{description}</p>}
52
- {brandAddon && <div className="header-sidebar-brandaddon">{brandAddon}</div>}
53
- </div>
54
- <div className="header-sidebar-content">{_children}</div>
55
- </Sidebar>
50
+ ModalProps={{ disablePortal: false, keepMounted: true, BackdropComponent: null }}
51
+ anchor="top"
52
+ sx={{ top: 64, zIndex: theme.zIndex.appBar - 1 }}
53
+ PaperProps={{ style: { top: 64, bottom: 0, boxShadow: 'none' } }}>
54
+ <MenuPanel>{_children}</MenuPanel>
56
55
  </Drawer>
57
56
  )}
58
57
  </Root>
@@ -77,53 +76,21 @@ const Root = styled(Header)`
77
76
  }
78
77
  ${(props) => props.$theme.breakpoints.down('md')} {
79
78
  .header-menu {
80
- display: block;
79
+ display: flex;
80
+ margin-right: 12px;
81
81
  }
82
82
  }
83
83
  `;
84
84
 
85
- /**
86
- * Sidebar
87
- */
88
- const Sidebar = styled.div`
89
- min-width: 280px;
90
- font-size: 14px;
91
- .header-sidebar-head {
92
- display: flex;
93
- flex-direction: column;
94
- align-items: center;
95
- padding: 24px 0;
96
- border-bottom: 1px solid #eee;
97
- font-size: 12px;
98
- .header-sidebar-logo {
99
- min-width: 44px;
100
- height: 44px;
101
- font-size: 44px;
102
- > * {
103
- width: auto;
104
- height: 100%;
105
- }
106
- > a {
107
- display: block;
108
- }
109
- img {
110
- max-width: 100%;
111
- max-height: 100%;
112
- }
85
+ const MenuPanel = styled(Container)`
86
+ padding-top: 8px;
87
+ padding-bottom: 16px;
88
+ .navmenu {
89
+ margin: 0 -16px;
90
+ .navmenu-root > .navmenu-item,
91
+ .navmenu-root > .navmenu-sub {
92
+ border: 0;
113
93
  }
114
- h2 {
115
- margin-top: 12px;
116
- font-size: 14px;
117
- }
118
- .header-sidebar-description {
119
- margin: 2px 0 0 0;
120
- }
121
- .header-sidebar-brandaddon {
122
- margin-top: 8px;
123
- }
124
- }
125
- .header-sidebar-content {
126
- padding: 16px 0;
127
94
  }
128
95
  `;
129
96
 
@@ -42,7 +42,7 @@ function Dashboard({ children, title, headerProps, links, fullWidth, ...rest })
42
42
  <Wrapper {...rest} className={`dashboard ${rest.className}`}>
43
43
  <Helmet title={title} key={title} />
44
44
 
45
- <StyledUxHeader {...headerProps}>
45
+ <StyledUxHeader {...headerProps} $theme={theme}>
46
46
  {({ isMobile, closeMenu }) => {
47
47
  if (isMobile) {
48
48
  return (
@@ -123,11 +123,13 @@ const StyledUxHeader = styled(ResponsiveHeader)`
123
123
  .header-container {
124
124
  max-width: 100%;
125
125
  }
126
- .header-logo {
127
- display: flex;
128
- justify-content: center;
129
- /* logo 与 sidebar 中的 icon 垂直对齐, 104 - 24 * 2 = 56 */
130
- width: 56px;
126
+ ${(props) => props.$theme.breakpoints.up('md')} {
127
+ .header-logo {
128
+ display: flex;
129
+ justify-content: center;
130
+ /* logo 与 sidebar 中的 icon 垂直对齐, 104 - 24 * 2 = 56 */
131
+ width: 56px;
132
+ }
131
133
  }
132
134
  `;
133
135
 
@@ -54,10 +54,12 @@ function NavMenu({ items, mode, children, activeId, textColor, activeTextColor,
54
54
  }, [state, mode, activate, open, close]);
55
55
 
56
56
  useEffect(() => {
57
- if (activeId) {
58
- activate(activeId);
57
+ // NavMenu#activeId 和 Item#active prop 都可以用来控制激活状态 (一般不会混用这两种方式)
58
+ // 如果未传入 NavMenu#activeId, 应该避免设置一个空值的 activeId 状态 (会与 Item#active 冲突)
59
+ if (activeId !== undefined && activeId !== null) {
60
+ setState((prev) => ({ ...prev, activeId }));
59
61
  }
60
- }, [activate, activeId]);
62
+ }, [activeId]);
61
63
 
62
64
  const classes = clsx('navmenu', `navmenu--${mode}`, rest.className);
63
65
  const renderItem = (item, index) => {
@@ -64,7 +64,8 @@ const NavMenuBase = styled.nav`
64
64
  .navmenu-item-icon > *,
65
65
  .navmenu-sub-icon > * {
66
66
  width: auto;
67
- max-height: 20px;
67
+ height: 22px;
68
+ max-height: 22px;
68
69
  font-size: 1.5em;
69
70
  }
70
71
  .navmenu-sub-expand-icon {
@@ -123,6 +124,7 @@ export const HorizontalStyle = styled(NavMenuBase)`
123
124
 
124
125
  /* inline mode */
125
126
  export const InlineStyle = styled(NavMenuBase)`
127
+ font-size: 16px;
126
128
  .navmenu-root {
127
129
  display: flex;
128
130
  flex-direction: column;
@@ -144,7 +146,7 @@ export const InlineStyle = styled(NavMenuBase)`
144
146
  /* icon */
145
147
  .navmenu-item-icon,
146
148
  .navmenu-sub-icon {
147
- width: 32px;
149
+ width: 42px;
148
150
  margin: 0;
149
151
  }
150
152
  .navmenu-sub-expand-icon {
@@ -165,16 +167,11 @@ export const InlineStyle = styled(NavMenuBase)`
165
167
  padding-left: 16px;
166
168
  .navmenu-item,
167
169
  .navmenu-sub {
168
- padding-left: 32px;
170
+ padding-left: 42px;
169
171
  font-size: 13px;
170
172
  }
171
173
  }
172
174
  /* 二级 menu */
173
- .navmenu-root > .navmenu-sub {
174
- &.navmenu-sub--opened {
175
- background: #eee;
176
- }
177
- }
178
175
  .navmenu-sub--opened > .navmenu-sub-container {
179
176
  display: block;
180
177
  }