@arcblock/ux 2.1.40 → 2.1.43

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.
@@ -43,7 +43,7 @@ function TableSearch(_ref) {
43
43
  searchPlaceholder,
44
44
  searchAlwaysOpen
45
45
  } = options;
46
- const [inputExpand, setInputExpand] = (0, _react.useState)(searchOpen || false);
46
+ const [inputExpand, setInputExpand] = (0, _react.useState)(!!searchText || searchOpen || false);
47
47
  const [innerSearchText, setInnerSearchText] = (0, _react.useState)('');
48
48
  const inputTimer = (0, _react.useRef)(null);
49
49
  const {
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = Datatable;
7
+ exports.getDurableData = void 0;
7
8
 
8
9
  var _react = require("react");
9
10
 
@@ -31,7 +32,7 @@ var _DatatableContext = require("./DatatableContext");
31
32
 
32
33
  var _jsxRuntime = require("react/jsx-runtime");
33
34
 
34
- const _excluded = ["data", "columns", "locale", "options", "style", "customButtons", "onChange", "loading", "disabled", "stripped", "verticalKeyWidth", "hideTableHeader", "components", "emptyNode"];
35
+ const _excluded = ["data", "columns", "locale", "options", "style", "customButtons", "onChange", "loading", "disabled", "stripped", "verticalKeyWidth", "hideTableHeader", "components", "emptyNode", "durable", "durableKeys"];
35
36
 
36
37
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
37
38
 
@@ -55,6 +56,24 @@ function Datatable(_ref) {
55
56
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ReDatatable, _objectSpread({}, props))
56
57
  });
57
58
  }
59
+
60
+ const fixCellProp = (tempObj, cellProps) => {
61
+ const cellStyle = {};
62
+
63
+ if (tempObj.align) {
64
+ cellProps.className = (0, _clsx.default)(cellProps.className, "pc-align-".concat(tempObj.align));
65
+ }
66
+
67
+ if (tempObj.verticalKeyAlign) {
68
+ cellProps.className = (0, _clsx.default)(cellProps.className, "vertical-align-".concat(tempObj.verticalKeyAlign));
69
+ }
70
+
71
+ if (tempObj.minWidth) {
72
+ cellStyle.minWidth = tempObj.minWidth;
73
+ }
74
+
75
+ cellProps.style = Object.assign({}, cellProps.style, cellStyle);
76
+ };
58
77
  /**
59
78
  * @param {Object} props.options The options of mui-datatable,detail see https://github.com/gregnb/mui-datatables/tree/b8d2eee6af4589d254b40918e5d7e70b1ee4baca
60
79
  * @param {Array} props.customButtons Custom buttons for toolbar
@@ -80,7 +99,9 @@ function ReDatatable(_ref2) {
80
99
  verticalKeyWidth,
81
100
  hideTableHeader,
82
101
  components,
83
- emptyNode
102
+ emptyNode,
103
+ durable,
104
+ durableKeys
84
105
  } = _ref2,
85
106
  rest = _objectWithoutProperties(_ref2, _excluded);
86
107
 
@@ -144,14 +165,7 @@ function ReDatatable(_ref2) {
144
165
  cellProps.width = tempObj.width;
145
166
  }
146
167
 
147
- if (tempObj.align) {
148
- cellProps.className = (0, _clsx.default)(cellProps.className, "pc-align-".concat(tempObj.align));
149
- }
150
-
151
- if (tempObj.verticalKeyAlign) {
152
- cellProps.className = (0, _clsx.default)(cellProps.className, "vertical-align-".concat(tempObj.verticalKeyAlign));
153
- }
154
-
168
+ fixCellProp(tempObj, cellProps);
155
169
  return cellProps;
156
170
  }; // Prevent memory xie caused by recursive forwarding of setCellHeaderProps functions
157
171
 
@@ -168,14 +182,7 @@ function ReDatatable(_ref2) {
168
182
  cellProps = _objectSpread(_objectSpread({}, cellProps), setCellProps(...arguments) || {});
169
183
  }
170
184
 
171
- if (tempObj.align) {
172
- cellProps.className = (0, _clsx.default)(cellProps.className, "pc-align-".concat(tempObj.align));
173
- }
174
-
175
- if (tempObj.verticalKeyAlign) {
176
- cellProps.className = (0, _clsx.default)(cellProps.className, "vertical-align-".concat(tempObj.verticalKeyAlign));
177
- }
178
-
185
+ fixCellProp(tempObj, cellProps);
179
186
  return cellProps;
180
187
  };
181
188
 
@@ -284,43 +291,55 @@ function ReDatatable(_ref2) {
284
291
  }
285
292
 
286
293
  (0, _react.useEffect)(() => setFilterLabel(textLabels.filter.title), [textLabels.filter.title]);
294
+ const durableData = getDurableData(durable);
287
295
 
288
- const opts = _objectSpread({
296
+ const opts = _objectSpread(_objectSpread(_objectSpread({
289
297
  selectableRows: 'none',
290
298
  textLabels,
291
299
  rowsPerPage: 10,
292
300
  rowsPerPageOptions: [10, 20, 50]
293
- }, options);
301
+ }, durableData), options), {}, {
302
+ // Wrap the more friendly onChange callback by listening to onTableChange,
303
+ // which will only be triggered when the table key state changes
304
+ onTableChange: (action, tableState) => {
305
+ if (action === 'propsUpdate') {
306
+ return;
307
+ }
294
308
 
295
- if (onChange) {
296
- Object.assign(opts, {
297
- serverSide: true,
298
- // Wrap the more friendly onChange callback by listening to onTableChange,
299
- // which will only be triggered when the table key state changes
300
- onTableChange: (action, tableState) => {
301
- if (action === 'propsUpdate') {
302
- return;
303
- }
309
+ const state = {
310
+ count: tableState.count,
311
+ page: tableState.page,
312
+ rowsPerPage: tableState.rowsPerPage,
313
+ searchText: tableState.searchText,
314
+ sortOrder: tableState.sortOrder,
315
+ //
316
+ filterList: tableState.filterList
317
+ };
304
318
 
305
- const state = {
306
- count: tableState.count,
307
- page: tableState.page,
308
- rowsPerPage: tableState.rowsPerPage,
309
- searchText: tableState.searchText,
310
- sortOrder: tableState.sortOrder,
311
- //
312
- filterList: tableState.filterList
313
- };
314
- const stateStr = JSON.stringify(state);
315
-
316
- if (stateStr === oldState.current) {
317
- return;
318
- }
319
+ if (durable) {
320
+ const needSaveState = {};
321
+ durableKeys.forEach(key => {
322
+ needSaveState[key] = state[key];
323
+ });
324
+ localStorage.setItem("datatable-durable-".concat(durable), JSON.stringify(needSaveState));
325
+ }
326
+
327
+ const stateStr = JSON.stringify(state);
319
328
 
320
- oldState.current = stateStr;
329
+ if (stateStr === oldState.current) {
330
+ return;
331
+ }
332
+
333
+ oldState.current = stateStr;
334
+
335
+ if (onChange) {
321
336
  onChange(state, action);
322
337
  }
323
- });
338
+ }
339
+ });
340
+
341
+ if (onChange) {
342
+ opts.serverSide = true;
324
343
  }
325
344
 
326
345
  const props = _objectSpread(_objectSpread({
@@ -361,7 +380,9 @@ ReDatatable.propTypes = {
361
380
  verticalKeyWidth: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
362
381
  hideTableHeader: _propTypes.default.bool,
363
382
  components: _propTypes.default.object,
364
- emptyNode: _propTypes.default.node
383
+ emptyNode: _propTypes.default.node,
384
+ durable: _propTypes.default.string,
385
+ durableKeys: _propTypes.default.array
365
386
  };
366
387
  ReDatatable.defaultProps = {
367
388
  options: {},
@@ -375,8 +396,27 @@ ReDatatable.defaultProps = {
375
396
  verticalKeyWidth: '',
376
397
  hideTableHeader: false,
377
398
  components: {},
378
- emptyNode: ''
399
+ emptyNode: '',
400
+ durable: '',
401
+ durableKeys: ['page', 'rowsPerPage', 'searchText', 'sortOrder']
402
+ };
403
+
404
+ const getDurableData = key => {
405
+ const durableKey = "datatable-durable-".concat(key);
406
+ let localData = localStorage[durableKey];
407
+
408
+ if (localData) {
409
+ try {
410
+ localData = JSON.parse(localData);
411
+ } catch (err) {
412
+ console.error("parse durable data error (key:".concat(key, ") => "), err);
413
+ }
414
+ }
415
+
416
+ return localData || {};
379
417
  };
418
+
419
+ exports.getDurableData = getDurableData;
380
420
  const alignCss = (0, _styledComponents.css)([".MuiTableCell-head{[class*='MUIDataTableHeadCell-toolButton']{width:100%;> [class*='MUIDataTableHeadCell-sortAction']{width:100%;}}&.pc-align-center{text-align:center;[class*='MUIDataTableHeadCell-toolButton'] > [class*='MUIDataTableHeadCell-sortAction']{justify-content:center;}}&.pc-align-right{text-align:right;[class*='MUIDataTableHeadCell-toolButton']{margin-right:0;padding-right:0;& > [class*='MUIDataTableHeadCell-sortAction']{justify-content:flex-end;}}}}.MuiTableCell-body{&.pc-align-center{text-align:center;}&.pc-align-right{text-align:right;}}"]);
381
421
 
382
422
  const TableContainer = _styledComponents.default.div.withConfig({
@@ -98,7 +98,7 @@ Header.propTypes = {
98
98
  // brand 右侧的内容区域, 可显示一个 badge 或 tag
99
99
  brandAddon: _propTypes.default.node,
100
100
  // brand 下方的描述
101
- description: _propTypes.default.string,
101
+ description: _propTypes.default.node,
102
102
  children: _propTypes.default.node,
103
103
  // 右侧区域, 可以放置 icons/actions/login 等
104
104
  addons: _propTypes.default.node,
@@ -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;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);
15
+ })(["background-color:", ";font-size:16px;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",
@@ -27,7 +27,7 @@ var _Util = require("../Util");
27
27
 
28
28
  var _jsxRuntime = require("react/jsx-runtime");
29
29
 
30
- const _excluded = ["value", "locale", "withoutSuffix", "from", "to"];
30
+ const _excluded = ["value", "locale", "withoutSuffix", "from", "to", "type"];
31
31
 
32
32
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
33
 
@@ -78,7 +78,8 @@ function RelativeTime(_ref) {
78
78
  locale,
79
79
  withoutSuffix,
80
80
  from,
81
- to
81
+ to,
82
+ type
82
83
  } = _ref,
83
84
  rest = _objectWithoutProperties(_ref, _excluded);
84
85
 
@@ -87,20 +88,29 @@ function RelativeTime(_ref) {
87
88
  }
88
89
 
89
90
  const localeOption = locale === 'zh' ? 'zh-cn' : 'zh-us';
90
- let innerContent;
91
+ let relativeString;
91
92
 
92
93
  if (from) {
93
- innerContent = (0, _dayjs.default)(value).locale(localeOption).from(from, withoutSuffix);
94
+ relativeString = (0, _dayjs.default)(value).locale(localeOption).from(from, withoutSuffix);
94
95
  } else if (to) {
95
- innerContent = (0, _dayjs.default)(value).locale(localeOption).to(to, withoutSuffix);
96
+ relativeString = (0, _dayjs.default)(value).locale(localeOption).to(to, withoutSuffix);
96
97
  } else {
97
- innerContent = (0, _dayjs.default)(value).locale(localeOption).fromNow(withoutSuffix);
98
+ relativeString = (0, _dayjs.default)(value).locale(localeOption).fromNow(withoutSuffix);
99
+ }
100
+
101
+ const absoluteString = (0, _Util.formatToDatetime)(value, {
102
+ locale: localeOption
103
+ });
104
+ let innerContent = relativeString;
105
+ let popContent = absoluteString;
106
+
107
+ if (type === 'absolute') {
108
+ innerContent = absoluteString;
109
+ popContent = relativeString;
98
110
  }
99
111
 
100
112
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
101
- title: (0, _Util.formatToDatetime)(value, {
102
- locale: localeOption
103
- }),
113
+ title: popContent,
104
114
  placement: "top-end",
105
115
  enterTouchDelay: 0,
106
116
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", _objectSpread(_objectSpread({}, rest), {}, {
@@ -114,11 +124,13 @@ RelativeTime.propTypes = {
114
124
  locale: _propTypes.default.string,
115
125
  withoutSuffix: _propTypes.default.bool,
116
126
  from: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
117
- to: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])
127
+ to: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
128
+ type: _propTypes.default.string
118
129
  };
119
130
  RelativeTime.defaultProps = {
120
131
  locale: 'en',
121
132
  withoutSuffix: false,
122
133
  from: '',
123
- to: ''
134
+ to: '',
135
+ type: 'relative'
124
136
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "2.1.40",
3
+ "version": "2.1.43",
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": "a5a95afc20fc56c089c46c81dda7e8ff4b48744a",
55
+ "gitHead": "a9cd5a9d9c5e58bba3a4adbf13069ebc37120515",
56
56
  "dependencies": {
57
- "@arcblock/icons": "^2.1.40",
58
- "@arcblock/react-hooks": "^2.1.40",
57
+ "@arcblock/icons": "^2.1.43",
58
+ "@arcblock/react-hooks": "^2.1.43",
59
59
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
60
60
  "@emotion/react": "^11.9.0",
61
61
  "@emotion/styled": "^11.8.1",
@@ -11,7 +11,7 @@ import { useDatatableContext } from './DatatableContext';
11
11
 
12
12
  export default function TableSearch({ search, options, searchText, searchTextUpdate, searchClose, onSearchOpen }) {
13
13
  const { searchOpen, searchPlaceholder, searchAlwaysOpen } = options;
14
- const [inputExpand, setInputExpand] = useState(searchOpen || false);
14
+ const [inputExpand, setInputExpand] = useState(!!searchText || searchOpen || false);
15
15
  const [innerSearchText, setInnerSearchText] = useState('');
16
16
  const inputTimer = useRef(null);
17
17
  const { loading } = useDatatableContext();
@@ -20,6 +20,24 @@ export default function Datatable({ ...props }) {
20
20
  );
21
21
  }
22
22
 
23
+ const fixCellProp = (tempObj, cellProps) => {
24
+ const cellStyle = {};
25
+
26
+ if (tempObj.align) {
27
+ cellProps.className = clsx(cellProps.className, `pc-align-${tempObj.align}`);
28
+ }
29
+
30
+ if (tempObj.verticalKeyAlign) {
31
+ cellProps.className = clsx(cellProps.className, `vertical-align-${tempObj.verticalKeyAlign}`);
32
+ }
33
+
34
+ if (tempObj.minWidth) {
35
+ cellStyle.minWidth = tempObj.minWidth;
36
+ }
37
+
38
+ cellProps.style = Object.assign({}, cellProps.style, cellStyle);
39
+ };
40
+
23
41
  /**
24
42
  * @param {Object} props.options The options of mui-datatable,detail see https://github.com/gregnb/mui-datatables/tree/b8d2eee6af4589d254b40918e5d7e70b1ee4baca
25
43
  * @param {Array} props.customButtons Custom buttons for toolbar
@@ -42,6 +60,8 @@ function ReDatatable({
42
60
  hideTableHeader,
43
61
  components,
44
62
  emptyNode,
63
+ durable,
64
+ durableKeys,
45
65
  ...rest
46
66
  }) {
47
67
  const oldState = useRef(null);
@@ -100,13 +120,7 @@ function ReDatatable({
100
120
  cellProps.width = tempObj.width;
101
121
  }
102
122
 
103
- if (tempObj.align) {
104
- cellProps.className = clsx(cellProps.className, `pc-align-${tempObj.align}`);
105
- }
106
-
107
- if (tempObj.verticalKeyAlign) {
108
- cellProps.className = clsx(cellProps.className, `vertical-align-${tempObj.verticalKeyAlign}`);
109
- }
123
+ fixCellProp(tempObj, cellProps);
110
124
 
111
125
  return cellProps;
112
126
  };
@@ -128,13 +142,7 @@ function ReDatatable({
128
142
  };
129
143
  }
130
144
 
131
- if (tempObj.align) {
132
- cellProps.className = clsx(cellProps.className, `pc-align-${tempObj.align}`);
133
- }
134
-
135
- if (tempObj.verticalKeyAlign) {
136
- cellProps.className = clsx(cellProps.className, `vertical-align-${tempObj.verticalKeyAlign}`);
137
- }
145
+ fixCellProp(tempObj, cellProps);
138
146
 
139
147
  return cellProps;
140
148
  };
@@ -216,39 +224,53 @@ function ReDatatable({
216
224
 
217
225
  useEffect(() => setFilterLabel(textLabels.filter.title), [textLabels.filter.title]);
218
226
 
227
+ const durableData = getDurableData(durable);
228
+
219
229
  const opts = {
220
230
  selectableRows: 'none',
221
231
  textLabels,
222
232
  rowsPerPage: 10,
223
233
  rowsPerPageOptions: [10, 20, 50],
234
+ ...durableData,
224
235
  ...options,
236
+ // Wrap the more friendly onChange callback by listening to onTableChange,
237
+ // which will only be triggered when the table key state changes
238
+ onTableChange: (action, tableState) => {
239
+ if (action === 'propsUpdate') {
240
+ return;
241
+ }
242
+ const state = {
243
+ count: tableState.count,
244
+ page: tableState.page,
245
+ rowsPerPage: tableState.rowsPerPage,
246
+ searchText: tableState.searchText,
247
+ sortOrder: tableState.sortOrder, //
248
+ filterList: tableState.filterList,
249
+ };
250
+
251
+ if (durable) {
252
+ const needSaveState = {};
253
+
254
+ durableKeys.forEach((key) => {
255
+ needSaveState[key] = state[key];
256
+ });
257
+
258
+ localStorage.setItem(`datatable-durable-${durable}`, JSON.stringify(needSaveState));
259
+ }
260
+
261
+ const stateStr = JSON.stringify(state);
262
+ if (stateStr === oldState.current) {
263
+ return;
264
+ }
265
+ oldState.current = stateStr;
266
+ if (onChange) {
267
+ onChange(state, action);
268
+ }
269
+ },
225
270
  };
226
271
 
227
272
  if (onChange) {
228
- Object.assign(opts, {
229
- serverSide: true,
230
- // Wrap the more friendly onChange callback by listening to onTableChange,
231
- // which will only be triggered when the table key state changes
232
- onTableChange: (action, tableState) => {
233
- if (action === 'propsUpdate') {
234
- return;
235
- }
236
- const state = {
237
- count: tableState.count,
238
- page: tableState.page,
239
- rowsPerPage: tableState.rowsPerPage,
240
- searchText: tableState.searchText,
241
- sortOrder: tableState.sortOrder, //
242
- filterList: tableState.filterList,
243
- };
244
- const stateStr = JSON.stringify(state);
245
- if (stateStr === oldState.current) {
246
- return;
247
- }
248
- oldState.current = stateStr;
249
- onChange(state, action);
250
- },
251
- });
273
+ opts.serverSide = true;
252
274
  }
253
275
 
254
276
  const props = {
@@ -290,6 +312,8 @@ ReDatatable.propTypes = {
290
312
  hideTableHeader: PropTypes.bool,
291
313
  components: PropTypes.object,
292
314
  emptyNode: PropTypes.node,
315
+ durable: PropTypes.string,
316
+ durableKeys: PropTypes.array,
293
317
  };
294
318
 
295
319
  ReDatatable.defaultProps = {
@@ -305,6 +329,21 @@ ReDatatable.defaultProps = {
305
329
  hideTableHeader: false,
306
330
  components: {},
307
331
  emptyNode: '',
332
+ durable: '',
333
+ durableKeys: ['page', 'rowsPerPage', 'searchText', 'sortOrder'],
334
+ };
335
+
336
+ export const getDurableData = (key) => {
337
+ const durableKey = `datatable-durable-${key}`;
338
+ let localData = localStorage[durableKey];
339
+ if (localData) {
340
+ try {
341
+ localData = JSON.parse(localData);
342
+ } catch (err) {
343
+ console.error(`parse durable data error (key:${key}) => `, err);
344
+ }
345
+ }
346
+ return localData || {};
308
347
  };
309
348
 
310
349
  const alignCss = css`
@@ -41,7 +41,7 @@ Header.propTypes = {
41
41
  // brand 右侧的内容区域, 可显示一个 badge 或 tag
42
42
  brandAddon: PropTypes.node,
43
43
  // brand 下方的描述
44
- description: PropTypes.string,
44
+ description: PropTypes.node,
45
45
  children: PropTypes.node,
46
46
  // 右侧区域, 可以放置 icons/actions/login 等
47
47
  addons: PropTypes.node,
@@ -2,7 +2,7 @@ import styled from 'styled-components';
2
2
 
3
3
  const NavMenuBase = styled.nav`
4
4
  background-color: ${(props) => props.$bgColor};
5
- font-size: 14px;
5
+ font-size: 16px;
6
6
  ul {
7
7
  list-style: none;
8
8
  margin: 0;
@@ -34,25 +34,35 @@ dayjs.updateLocale('zh-cn', {
34
34
  });
35
35
  setDateTool(dayjs);
36
36
 
37
- export default function RelativeTime({ value, locale, withoutSuffix, from, to, ...rest }) {
37
+ export default function RelativeTime({ value, locale, withoutSuffix, from, to, type, ...rest }) {
38
38
  if (!value) {
39
39
  return '-';
40
40
  }
41
41
 
42
42
  const localeOption = locale === 'zh' ? 'zh-cn' : 'zh-us';
43
43
 
44
- let innerContent;
44
+ let relativeString;
45
45
 
46
46
  if (from) {
47
- innerContent = dayjs(value).locale(localeOption).from(from, withoutSuffix);
47
+ relativeString = dayjs(value).locale(localeOption).from(from, withoutSuffix);
48
48
  } else if (to) {
49
- innerContent = dayjs(value).locale(localeOption).to(to, withoutSuffix);
49
+ relativeString = dayjs(value).locale(localeOption).to(to, withoutSuffix);
50
50
  } else {
51
- innerContent = dayjs(value).locale(localeOption).fromNow(withoutSuffix);
51
+ relativeString = dayjs(value).locale(localeOption).fromNow(withoutSuffix);
52
+ }
53
+
54
+ const absoluteString = formatToDatetime(value, { locale: localeOption });
55
+
56
+ let innerContent = relativeString;
57
+ let popContent = absoluteString;
58
+
59
+ if (type === 'absolute') {
60
+ innerContent = absoluteString;
61
+ popContent = relativeString;
52
62
  }
53
63
 
54
64
  return (
55
- <Tooltip title={formatToDatetime(value, { locale: localeOption })} placement="top-end" enterTouchDelay={0}>
65
+ <Tooltip title={popContent} placement="top-end" enterTouchDelay={0}>
56
66
  <span {...rest}>{innerContent}</span>
57
67
  </Tooltip>
58
68
  );
@@ -64,6 +74,7 @@ RelativeTime.propTypes = {
64
74
  withoutSuffix: PropTypes.bool,
65
75
  from: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
66
76
  to: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
77
+ type: PropTypes.string,
67
78
  };
68
79
 
69
80
  RelativeTime.defaultProps = {
@@ -71,4 +82,5 @@ RelativeTime.defaultProps = {
71
82
  withoutSuffix: false,
72
83
  from: '',
73
84
  to: '',
85
+ type: 'relative',
74
86
  };