@arcblock/ux 2.12.2 → 2.12.4

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.
@@ -3,6 +3,7 @@ import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } f
3
3
  import { Box } from '@mui/material';
4
4
  import { styled } from '../Theme';
5
5
  import DidAddress, { HTMLDidAddressElement, IDidAddressProps } from './did-address';
6
+ import { getFontSize } from '../Util';
6
7
 
7
8
  /**
8
9
  * 根据父容器宽度自动切换 compact 模式
@@ -14,7 +15,7 @@ import DidAddress, { HTMLDidAddressElement, IDidAddressProps } from './did-addre
14
15
  * - 监听容器宽度变化, 当容器宽度变化时, 对比容器宽度和 did address full-width, => 切换 compact 模式
15
16
  */
16
17
  const ResponsiveDidAddress = forwardRef<HTMLDidAddressElement, IResponsiveDidAddressProps>(
17
- ({ style, className, component = 'span', size, ...rest }, ref) => {
18
+ ({ style, className, component = 'span', size = 0, ...rest }, ref) => {
18
19
  const [compact, setCompact] = useState(false);
19
20
  const isCompact = useLatest(compact);
20
21
  // did address 完整显示时的宽度
@@ -79,7 +80,7 @@ const ResponsiveDidAddress = forwardRef<HTMLDidAddressElement, IResponsiveDidAdd
79
80
  }, [containerWidth, addressFullWidth]);
80
81
 
81
82
  return (
82
- <Root as={component} ref={containerRef} style={style} className={className}>
83
+ <Root as={component} ref={containerRef} style={style} className={className} size={size} inline={rest.inline}>
83
84
  <StyledDidAddress
84
85
  style={{
85
86
  position: loading ? 'absolute' : 'static',
@@ -107,12 +108,17 @@ export interface IResponsiveDidAddressProps extends IDidAddressProps {
107
108
  component?: React.ElementType;
108
109
  }
109
110
 
110
- const Root = styled(Box)`
111
+ type RootProps = {
112
+ size: number;
113
+ inline?: boolean;
114
+ };
115
+
116
+ const Root = styled(Box, { shouldForwardProp: (prop) => prop !== 'size' })<RootProps>`
111
117
  display: block;
112
118
  width: 100%; /* flex & column & align-items: flex-start 时, 块级元素不会自动铺满容器 */
113
- font-size: 0;
119
+ font-size: ${({ size }) => getFontSize(size)};
114
120
  overflow: hidden;
115
- ${({ inline }: any) =>
121
+ ${({ inline }) =>
116
122
  inline &&
117
123
  `
118
124
  display: inline-block;
@@ -5,7 +5,8 @@ import { MoreHoriz as MoreHorizIcon, ExpandMore as ExpandMoreIcon, Menu as MenuI
5
5
  import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
6
6
  import { useCreation, useMemoizedFn, useReactive, useSize, useThrottleFn } from 'ahooks';
7
7
  import { NavMenuProvider, useNavMenuContext } from './nav-menu-context';
8
- import { NavMenuRoot, NavMenuList, NavMenuItem, NavMenuSub, NavMenuSubList } from './style';
8
+ import { NavMenuRoot, NavMenuItem, NavMenuSub, NavMenuSubList, NavMenuStyled } from './style';
9
+ import { SubContainer } from './sub-container';
9
10
 
10
11
  // 过滤 children 中的 Item/Sub, 忽略其它类型的 element
11
12
  function filterItems(children: React.ReactNode) {
@@ -67,7 +68,6 @@ function NavMenu({
67
68
  if (!items?.length && !children?.length) {
68
69
  throw new Error("One of 'items' or 'children' is required by NavMenu component.");
69
70
  }
70
-
71
71
  const currentState = useReactive({
72
72
  activeId,
73
73
  openedIds: [] as string[],
@@ -112,6 +112,7 @@ function NavMenu({
112
112
  const navMenuRef = useRef<HTMLUListElement | null>(null);
113
113
  const itemRefs = useRef<HTMLElement[]>([]);
114
114
  const moreIconRef = useRef<HTMLLIElement | null>(null);
115
+ const containerWidth = useRef(0);
115
116
  const isAllItemsHidden = currentState.hiddenItemCount === itemRefs.current?.length;
116
117
  const style = isAllItemsHidden ? { marginLeft: '0px' } : undefined;
117
118
 
@@ -136,7 +137,6 @@ function NavMenu({
136
137
  let totalWidthUsed = 0;
137
138
  let newHiddenCount = 0;
138
139
  let leftAllHidden = false;
139
- const containerWidth = containerSize?.width || 0;
140
140
  const moreIconWidth = moreIconRef.current
141
141
  ? moreIconRef.current.offsetWidth + parseFloat(window.getComputedStyle(moreIconRef.current).marginLeft)
142
142
  : 0;
@@ -147,7 +147,7 @@ function NavMenu({
147
147
  const marginLeft = index > 0 ? parseFloat(window.getComputedStyle(item).marginLeft) : 0;
148
148
  const currentItemWidth = item.offsetWidth + marginLeft;
149
149
 
150
- if (containerWidth - moreIconWidth >= totalWidthUsed + currentItemWidth && !leftAllHidden) {
150
+ if (containerWidth.current - moreIconWidth >= totalWidthUsed + currentItemWidth && !leftAllHidden) {
151
151
  totalWidthUsed += currentItemWidth;
152
152
  } else {
153
153
  item.style.display = 'none';
@@ -165,6 +165,7 @@ function NavMenu({
165
165
  );
166
166
 
167
167
  useLayoutEffect(() => {
168
+ containerWidth.current = containerSize?.width || navMenuRef.current?.clientWidth || 0;
168
169
  if (mode === 'horizontal') {
169
170
  checkItemsFit();
170
171
  }
@@ -195,8 +196,15 @@ function NavMenu({
195
196
 
196
197
  const classes = clsx('navmenu', `navmenu--${mode}`, rest.className);
197
198
 
198
- const renderItem = (item: ItemOptions, index: number, isTopLevel = false) => {
199
+ const renderItem = (item: ItemOptions, index: number, level = 0) => {
200
+ const isTopLevel = level === 0;
201
+
199
202
  if (item?.children) {
203
+ // 只渲染两级子菜单
204
+ if (level > 0) {
205
+ return null;
206
+ }
207
+
200
208
  // 对于 Sub 组件,如果它是顶级组件,则包含 ref
201
209
  return (
202
210
  <Sub
@@ -215,7 +223,7 @@ function NavMenu({
215
223
  {typeof item.children === 'function'
216
224
  ? item.children
217
225
  : item.children.map((childItem, childIndex: number) =>
218
- renderItem({ ...childItem, variant: 'panel' }, childIndex, false)
226
+ renderItem({ ...childItem, variant: 'panel' }, childIndex, level + 1)
219
227
  )}
220
228
  </Sub>
221
229
  );
@@ -243,21 +251,24 @@ function NavMenu({
243
251
  };
244
252
 
245
253
  const content = items
246
- ? items?.slice(-currentState.hiddenItemCount).map((item, index) => renderItem(item, index))
254
+ ? items?.slice(-currentState.hiddenItemCount).map((item, index) => renderItem(item, index, 1))
247
255
  : children?.slice(-currentState.hiddenItemCount);
248
256
 
257
+ // 当前展开的子菜单
258
+ const openedId = currentState.openedIds[0];
259
+
249
260
  return (
250
261
  <NavMenuProvider value={contextValue}>
251
- <NavMenuRoot {...rest} className={classes} $textColor={textColor} $bgColor={bgColor}>
252
- <NavMenuList className={clsx('navmenu-list', `navmenu-list--${mode}`)} ref={navMenuRef}>
253
- {items ? items.map((item, index) => renderItem(item, index, true)) : renderChildrenWithRef(children || [])}
262
+ <NavMenuStyled {...rest} className={classes} $textColor={textColor} $bgColor={bgColor}>
263
+ <NavMenuRoot className={clsx('navmenu-root', `navmenu-root--${mode}`)} ref={navMenuRef}>
264
+ {items ? items.map((item, index) => renderItem(item, index)) : renderChildrenWithRef(children || [])}
254
265
  {currentState.hiddenItemCount > 0 && (
255
266
  <Sub expandIcon={false} icon={icon} label="" ref={moreIconRef} style={style}>
256
267
  {content}
257
268
  </Sub>
258
269
  )}
259
- </NavMenuList>
260
- </NavMenuRoot>
270
+ </NavMenuRoot>
271
+ </NavMenuStyled>
261
272
  </NavMenuProvider>
262
273
  );
263
274
  }
@@ -324,7 +335,7 @@ export const Item = forwardRef<HTMLLIElement, ItemProps>(
324
335
  Item.displayName = 'NavMenu.Item';
325
336
 
326
337
  export interface SubProps extends Omit<ItemProps, 'children' | 'active'> {
327
- children?: Array<React.ReactElement> | ((props: { isOpen: boolean }) => React.ReactElement | null);
338
+ children?: Array<React.ReactElement | null> | ((props: { isOpen: boolean }) => React.ReactElement | null);
328
339
  expandIcon?: React.ReactNode | ((props: { isOpen: boolean }) => React.ReactNode);
329
340
  }
330
341
 
@@ -394,13 +405,13 @@ export const Sub = forwardRef<HTMLLIElement, SubProps>(
394
405
  {typeof expandIcon === 'function' ? expandIcon({ isOpen }) : expandIcon}
395
406
  </span>
396
407
  )}
397
- <div className="navmenu-sub__container" {...containerProps}>
408
+ <SubContainer {...containerProps}>
398
409
  {typeof children === 'function' ? (
399
410
  children({ isOpen }) // 自定义渲染
400
411
  ) : (
401
412
  <NavMenuSubList className="navmenu-sub__list">{filterItems(children)}</NavMenuSubList>
402
413
  )}
403
- </div>
414
+ </SubContainer>
404
415
  </NavMenuSub>
405
416
  );
406
417
  }
@@ -1,8 +1,7 @@
1
- import { useLayoutEffect, useRef } from 'react';
1
+ import { useRef } from 'react';
2
2
  import { Link } from 'react-router-dom';
3
3
  import { useCreation, useMemoizedFn } from 'ahooks';
4
4
  import { Box, BoxProps, Grid } from '@mui/material';
5
- import { useWindowSize } from 'react-use';
6
5
  import SubItemGroup from './sub-item-group';
7
6
  import { Item } from './nav-menu';
8
7
  import { styled } from '../Theme';
@@ -191,7 +190,6 @@ export interface ProductsProps extends BoxProps {
191
190
  export default function Products({ className, isOpen, ...rest }: ProductsProps) {
192
191
  const { mode } = useNavMenuContext();
193
192
  const wrapperRef = useRef<HTMLDivElement>(null);
194
- const { width, height } = useWindowSize();
195
193
  const { locale = 'en' } = useLocaleContext() || {};
196
194
  const t = useMemoizedFn((key, data = {}) => translate(translations, key, locale, 'en', data));
197
195
  const groups = useCreation(() => {
@@ -202,13 +200,22 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
202
200
  children: [
203
201
  [
204
202
  {
205
- label: <Link to={`https://www.nftstudio.rocks/${locale}`}>NFT Studio</Link>,
203
+ label: (
204
+ <Link to={`https://www.nftstudio.rocks/${locale}`} target="_blank" rel="noreferrer noopener">
205
+ NFT Studio
206
+ </Link>
207
+ ),
206
208
  description: t('products.nftStudio.description'),
207
209
  icon: <NftStudioSvg />,
208
210
  },
209
211
  {
210
212
  label: (
211
- <Link to={`https://www.arcblock.io/content/collections/${locale}/creator-studio`}>Creator Studio</Link>
213
+ <Link
214
+ to={`https://www.arcblock.io/content/collections/${locale}/creator-studio`}
215
+ target="_blank"
216
+ rel="noreferrer noopener">
217
+ Creator Studio
218
+ </Link>
212
219
  ),
213
220
  description: t('products.creatorStudio.description'),
214
221
  icon: <CreatorStudioSvg />,
@@ -216,12 +223,20 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
216
223
  ],
217
224
  [
218
225
  {
219
- label: <Link to={`https://www.aigne.io/${locale}`}>AIGNE</Link>,
226
+ label: (
227
+ <Link to={`https://www.aigne.io/${locale}`} target="_blank" rel="noreferrer noopener">
228
+ AIGNE
229
+ </Link>
230
+ ),
220
231
  description: t('products.aigne.description'),
221
232
  icon: <AigneSvg />,
222
233
  },
223
234
  {
224
- label: <Link to={`https://www.aistro.io/${locale}`}>Aistro</Link>,
235
+ label: (
236
+ <Link to={`https://www.aistro.io/${locale}`} target="_blank" rel="noreferrer noopener">
237
+ Aistro
238
+ </Link>
239
+ ),
225
240
  description: t('products.aistro.description'),
226
241
  icon: <AistroSvg />,
227
242
  },
@@ -234,24 +249,43 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
234
249
  children: [
235
250
  [
236
251
  {
237
- label: <Link to={`https://launcher.arcblock.io/${locale}`}>Blocklet Launcher</Link>,
252
+ label: (
253
+ <Link to={`https://launcher.arcblock.io/${locale}`} target="_blank" rel="noreferrer noopener">
254
+ Blocklet Launcher
255
+ </Link>
256
+ ),
238
257
  description: t('products.blockletLauncher.description'),
239
258
  icon: <BlockletLauncherSvg />,
240
259
  },
241
260
  {
242
- label: <Link to={`https://www.arcblock.io/content/collections/${locale}/ai-kit`}>Al Kit</Link>,
261
+ label: (
262
+ <Link
263
+ to={`https://www.arcblock.io/content/collections/${locale}/ai-kit`}
264
+ target="_blank"
265
+ rel="noreferrer noopener">
266
+ Al Kit
267
+ </Link>
268
+ ),
243
269
  description: t('products.alKit.description'),
244
270
  icon: <AIKitSvg />,
245
271
  },
246
272
  ],
247
273
  [
248
274
  {
249
- label: <Link to={`https://store.blocklet.dev/${locale}`}>Blocklet Store</Link>,
275
+ label: (
276
+ <Link to={`https://store.blocklet.dev/${locale}`} target="_blank" rel="noreferrer noopener">
277
+ Blocklet Store
278
+ </Link>
279
+ ),
250
280
  description: t('products.blockletStore.description'),
251
281
  icon: <BlockletStoreSvg />,
252
282
  },
253
283
  {
254
- label: <Link to={`https://www.web3kit.rocks/${locale}`}>Web3 Kit</Link>,
284
+ label: (
285
+ <Link to={`https://www.web3kit.rocks/${locale}`} target="_blank" rel="noreferrer noopener">
286
+ Web3 Kit
287
+ </Link>
288
+ ),
255
289
  description: t('products.web3Kit.description'),
256
290
  icon: <Web3KitSvg />,
257
291
  },
@@ -265,18 +299,31 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
265
299
  [
266
300
  {
267
301
  label: (
268
- <Link to={`https://www.arcblock.io/content/collections/${locale}/blocklet`}>Blocklet Framework</Link>
302
+ <Link
303
+ to={`https://www.arcblock.io/content/collections/${locale}/blocklet`}
304
+ target="_blank"
305
+ rel="noreferrer noopener">
306
+ Blocklet Framework
307
+ </Link>
269
308
  ),
270
309
  description: t('products.blockletFramework.description'),
271
310
  icon: <BlockletFrameworkSvg />,
272
311
  },
273
312
  {
274
- label: <Link to={`https://www.didspaces.com/${locale}`}>DID Spaces</Link>,
313
+ label: (
314
+ <Link to={`https://www.didspaces.com/${locale}`} target="_blank" rel="noreferrer noopener">
315
+ DID Spaces
316
+ </Link>
317
+ ),
275
318
  description: t('products.didSpaces.description'),
276
319
  icon: <DidSvg />,
277
320
  },
278
321
  {
279
- label: <Link to={`https://main.abtnetwork.io/${locale}`}>ABT Network</Link>,
322
+ label: (
323
+ <Link to={`https://main.abtnetwork.io/${locale}`} target="_blank" rel="noreferrer noopener">
324
+ ABT Network
325
+ </Link>
326
+ ),
280
327
  description: t('products.abtNetwork.description'),
281
328
  icon: <AbtNetworkSvg />,
282
329
  },
@@ -284,7 +331,10 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
284
331
  [
285
332
  {
286
333
  label: (
287
- <Link to={`https://www.arcblock.io/content/collections/${locale}/blocklet-server`}>
334
+ <Link
335
+ to={`https://www.arcblock.io/content/collections/${locale}/blocklet-server`}
336
+ target="_blank"
337
+ rel="noreferrer noopener">
288
338
  Blocklet Server
289
339
  </Link>
290
340
  ),
@@ -292,7 +342,14 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
292
342
  icon: <BlockletServerSvg />,
293
343
  },
294
344
  {
295
- label: <Link to={`https://www.arcblock.io/content/collections/${locale}/blockchain`}>ОСАР</Link>,
345
+ label: (
346
+ <Link
347
+ to={`https://www.arcblock.io/content/collections/${locale}/blockchain`}
348
+ target="_blank"
349
+ rel="noreferrer noopener">
350
+ ОСАР
351
+ </Link>
352
+ ),
296
353
  description: t('products.osar.description'),
297
354
  icon: <OCAPSvg />,
298
355
  },
@@ -305,29 +362,55 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
305
362
  children: [
306
363
  [
307
364
  {
308
- label: <Link to={`https://www.arcblock.io/content/collections/${locale}/did`}>DID</Link>,
365
+ label: (
366
+ <Link
367
+ to={`https://www.arcblock.io/content/collections/${locale}/did`}
368
+ target="_blank"
369
+ rel="noreferrer noopener">
370
+ DID
371
+ </Link>
372
+ ),
309
373
  description: t('products.did.description'),
310
374
  icon: <DidSvg />,
311
375
  },
312
376
  {
313
- label: <Link to={`https://www.didwallet.io/${locale}`}>DID Wallet</Link>,
377
+ label: (
378
+ <Link to={`https://www.didwallet.io/${locale}`} target="_blank" rel="noreferrer noopener">
379
+ DID Wallet
380
+ </Link>
381
+ ),
314
382
  description: t('products.didWallet.description'),
315
383
  icon: <DidWalletSvg />,
316
384
  },
317
385
  {
318
- label: <Link to={`https://www.didnames.io/${locale}`}>DID Name Service</Link>,
386
+ label: (
387
+ <Link to={`https://www.didnames.io/${locale}`} target="_blank" rel="noreferrer noopener">
388
+ DID Names
389
+ </Link>
390
+ ),
319
391
  description: t('products.didNameService.description'),
320
392
  icon: <DidNameServiceSvg />,
321
393
  },
322
394
  ],
323
395
  [
324
396
  {
325
- label: <Link to={`https://www.arcblock.io/content/collections/${locale}/verifiable-credential`}>VC</Link>,
397
+ label: (
398
+ <Link
399
+ to={`https://www.arcblock.io/content/collections/${locale}/verifiable-credential`}
400
+ target="_blank"
401
+ rel="noreferrer noopener">
402
+ VC
403
+ </Link>
404
+ ),
326
405
  description: t('products.vc.description'),
327
406
  icon: <VCSvg />,
328
407
  },
329
408
  {
330
- label: <Link to={`https://www.didconnect.io/${locale}`}>DID Connect</Link>,
409
+ label: (
410
+ <Link to={`https://www.didconnect.io/${locale}`} target="_blank" rel="noreferrer noopener">
411
+ DID Connect
412
+ </Link>
413
+ ),
331
414
  description: t('products.didConnect.description'),
332
415
  icon: <DidConnectSvg />,
333
416
  },
@@ -337,27 +420,6 @@ export default function Products({ className, isOpen, ...rest }: ProductsProps)
337
420
  ];
338
421
  }, [t, locale]);
339
422
 
340
- // 防止弹框超出 window
341
- useLayoutEffect(() => {
342
- const wrapper = wrapperRef.current;
343
- if (!wrapper) return;
344
- if (!isOpen) {
345
- wrapper.style.transform = '';
346
- return;
347
- }
348
-
349
- const rect = wrapper.getBoundingClientRect();
350
- const windowWidth = window.innerWidth;
351
- if (rect.right > windowWidth) {
352
- const offset = rect.right - windowWidth;
353
- wrapper.style.transform = `translateX(-${offset + 16}px)`;
354
- } else if (rect.left < 0) {
355
- wrapper.style.transform = `translateX(${Math.abs(rect.left) + 16}px)`;
356
- } else {
357
- wrapper.style.transform = '';
358
- }
359
- }, [width, height, isOpen]);
360
-
361
423
  return (
362
424
  <Wrapper ref={wrapperRef} className={`is-${mode} ${className}`} {...rest}>
363
425
  {groups.map((group) => (
@@ -5,11 +5,12 @@ type NavMenuProps = {
5
5
  $textColor: string;
6
6
  };
7
7
 
8
- // .navmenu-root
9
- export const NavMenuRoot = styled('nav', {
8
+ // .navmenu
9
+ export const NavMenuStyled = styled('nav', {
10
10
  shouldForwardProp: (prop) => prop !== '$bgColor' && prop !== '$textColor',
11
11
  })<NavMenuProps>(({ $bgColor, $textColor }) => ({
12
- padding: '8px 16px',
12
+ position: 'relative',
13
+ padding: '0 16px',
13
14
  minWidth: '50px',
14
15
  // FIXME: @zhanghan 这个只是临时的解决方案,会导致 header align right 不能真正的右对齐,需要修改 header 才能真正解决这个问题
15
16
  flexGrow: 100,
@@ -18,15 +19,15 @@ export const NavMenuRoot = styled('nav', {
18
19
  fontSize: '16px',
19
20
  }));
20
21
 
21
- // .navmenu-list
22
- export const NavMenuList = styled('ul')(() => ({
22
+ // .navmenu-root
23
+ export const NavMenuRoot = styled('ul')(() => ({
23
24
  listStyle: 'none',
24
25
  margin: 0,
25
26
  padding: 0,
26
27
  display: 'flex',
27
28
  alignItems: 'center',
28
29
  // inline 布局
29
- '&.navmenu-list--inline ': {
30
+ '&.navmenu-root--inline ': {
30
31
  flexDirection: 'column',
31
32
  alignItems: 'stretch',
32
33
  },
@@ -38,14 +39,16 @@ type NavMenuItemProps = {
38
39
  // 菜单项 .navmenu-item
39
40
  export const NavMenuItem = styled('li', {
40
41
  shouldForwardProp: (prop) => prop !== '$activeTextColor',
41
- })<NavMenuItemProps>(({ $activeTextColor }) => ({
42
+ })<NavMenuItemProps>(({ $activeTextColor, theme }) => ({
42
43
  display: 'flex',
43
44
  alignItems: 'center',
44
45
  position: 'relative',
45
- padding: '0 12px',
46
+ padding: '8px 12px',
46
47
  whiteSpace: 'nowrap',
47
48
  cursor: 'pointer',
48
- transition: 'color 0.2s ease-in-out',
49
+ transition: theme.transitions.create('color', {
50
+ duration: theme.transitions.duration.standard,
51
+ }),
49
52
  // 间距调整
50
53
  '&:first-of-type': {
51
54
  paddingLeft: 0,
@@ -98,7 +101,9 @@ export const NavMenuItem = styled('li', {
98
101
  marginLeft: '6px',
99
102
  fontSize: '14px',
100
103
  opacity: 0,
101
- transition: 'opacity 0.2s ease-in-out',
104
+ transition: theme.transitions.create('opacity', {
105
+ duration: theme.transitions.duration.standard,
106
+ }),
102
107
  },
103
108
  },
104
109
  '.navmenu-item__desc': {
@@ -136,13 +141,17 @@ export const NavMenuItem = styled('li', {
136
141
  },
137
142
  '&:hover': {
138
143
  background: '#f9f9fb',
139
- transition: 'background 0.2s ease-in-out',
144
+ transition: theme.transitions.create('background', {
145
+ duration: theme.transitions.duration.standard,
146
+ }),
140
147
  '.navmenu-item__label-arrow': {
141
148
  opacity: 1,
142
149
  },
143
150
  '.navmenu-item__desc': {
144
151
  color: '#26292e',
145
- transition: 'color 0.2s ease-in-out',
152
+ transition: theme.transitions.create('color', {
153
+ duration: theme.transitions.duration.standard,
154
+ }),
146
155
  },
147
156
  },
148
157
  '&.navmenu-item--active': {
@@ -160,24 +169,26 @@ export const NavMenuItem = styled('li', {
160
169
  }));
161
170
 
162
171
  // 包含子菜单的导航项 .navmenu-item .navmenu-sub
163
- export const NavMenuSub = styled(NavMenuItem)(() => ({
172
+ export const NavMenuSub = styled(NavMenuItem)(({ theme }) => ({
164
173
  '.navmenu-item': {
165
174
  marginLeft: 0,
175
+ overflow: 'hidden',
166
176
  },
167
177
  '& .navmenu-sub__container': {
168
- visibility: 'hidden',
178
+ pointerEvents: 'none',
169
179
  opacity: 0,
170
180
  position: 'absolute',
171
181
  top: '100%',
172
- left: '50%',
182
+ left: 0,
173
183
  zIndex: 1,
174
- transform: 'translateX(-50%)',
175
- paddingTop: '16px',
176
- transition: 'opacity 0.2s ease-in-out, visibility 0.2s ease-in-out',
177
184
  },
178
185
  '&.navmenu-sub--opened > .navmenu-sub__container': {
179
- visibility: 'visible',
186
+ pointerEvents: 'auto',
180
187
  opacity: 1,
188
+ transition: theme.transitions.create('opacity', {
189
+ duration: theme.transitions.duration.standard,
190
+ easing: theme.transitions.easing.easeOut,
191
+ }),
181
192
  },
182
193
  // 扩展图标
183
194
  '.navmenu-sub__expand-icon': {
@@ -188,7 +199,9 @@ export const NavMenuSub = styled(NavMenuItem)(() => ({
188
199
  '& > *': {
189
200
  width: '0.8em',
190
201
  height: '0.8em',
191
- transition: 'transform 0.2s ease-in-out',
202
+ transition: theme.transitions.create('transform', {
203
+ duration: theme.transitions.duration.standard,
204
+ }),
192
205
  },
193
206
  '.navmenu-item--inline &': {
194
207
  marginLeft: 'auto',
@@ -204,7 +217,9 @@ export const NavMenuSub = styled(NavMenuItem)(() => ({
204
217
  padding: 0,
205
218
  height: 0,
206
219
  overflow: 'hidden',
207
- transition: 'height 0.2s ease-in-out',
220
+ transition: theme.transitions.create('height', {
221
+ duration: theme.transitions.duration.standard,
222
+ }),
208
223
  },
209
224
  '&.navmenu-sub--opened > .navmenu-sub__container': {
210
225
  height: 'auto',
@@ -214,10 +229,13 @@ export const NavMenuSub = styled(NavMenuItem)(() => ({
214
229
  paddingLeft: '16px',
215
230
  boxShadow: 'none',
216
231
  },
232
+ '.navmenu-item__content': {
233
+ height: '48px',
234
+ },
217
235
  },
218
236
  }));
219
237
 
220
- // 下拉子菜单 .navmenu-sub-list
238
+ // 下拉子菜单 .navmenu-sub__list
221
239
  export const NavMenuSubList = styled('ul')(() => ({
222
240
  margin: 0,
223
241
  padding: '16px',