Skip to content

Commit

Permalink
chore(navbar): update code and demo for navbar
Browse files Browse the repository at this point in the history
  • Loading branch information
04756 committed Aug 3, 2024
1 parent 002c70b commit e8b2328
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 263 deletions.
148 changes: 53 additions & 95 deletions src/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, { CSSProperties, useCallback, useMemo, useState } from 'react';
import { ChevronLeftIcon, IconFont, HomeIcon } from 'tdesign-icons-react';
import React, { CSSProperties, useCallback, useMemo } from 'react';
import { ChevronLeftIcon } from 'tdesign-icons-react';
import ClassNames from 'classnames';
import { useSpring, animated } from '@react-spring/web';
import useUnmountedRef from 'ahooks/lib/useUnmountedRef';
import useConfig from '../_util/useConfig';
import { StyledProps } from '../common';
import { TdNavbarProps } from './type';
Expand All @@ -15,130 +13,90 @@ export const Navbar: React.FC<NavbarProps> = (props) => {
visible,
title,
children,
leftIcon,
homeIcon,
titleMaxLength,
leftArrow,
left,
capsule,
right,
fixed,
animation,
rightIcon,
titleMaxLength,
onHomeClick,
style,
className,
style,
onLeftClick,
onRightClick,
} = props;
const { classPrefix } = useConfig();
const unmountRef = useUnmountedRef();

const prefix = useMemo(() => `${classPrefix}-navbar`, [classPrefix]);
const animationSuffix = useMemo(() => (animation ? '-animation' : ''), [animation]);

const cls = useCallback((name?: string) => (name ? `${prefix}__${name}` : prefix), [prefix]);

const [active, setActive] = useState(visible);

// 动画
const navbarSpring = useSpring({
opacity: visible ? 1 : 0,
onStart: () => {
setActive(true);
},
onRest: () => {
if (unmountRef.current) return;
setActive(visible);
},
});
// 左侧胶囊区域
const leftCapsuleContent = useMemo(() => {
if (!capsule) {
return null;
}
return <div className={cls('capsule')}>{capsule}</div>;
}, [capsule, cls]);

// 标题
const titleChildren = useMemo(() => {
let titleNode = children || title;

if (typeof titleNode === 'string' && titleNode.length > titleMaxLength) {
titleNode = `${titleNode.slice(0, titleMaxLength)}...`;
const isStringTitle = typeof titleNode === 'string';

if (isStringTitle && !isNaN(titleMaxLength)) {
if (titleMaxLength <= 0) {
console.warn('titleMaxLength must be greater than 0');
} else if (titleNode.length > titleMaxLength) {
titleNode = `${titleNode.slice(0, titleMaxLength)}...`;
}
}

return <div className={cls('text')}>{titleNode}</div>;
return isStringTitle ? <span className={cls('center-title')}>{titleNode}</span> : titleNode;
}, [children, cls, title, titleMaxLength]);

// 返回icon点击
const onLeftClickHandle = useCallback(() => {
if (onLeftClick) {
onLeftClick();
} else {
window.history.back();
}
}, [onLeftClick]);

// 主页icon点击
const onHomeClickHandle = useCallback(() => {
if (onHomeClick) {
onHomeClick();
}
}, [onHomeClick]);

// 返回图标
const leftIconDom = useMemo(() => {
if (!leftIcon) return null;

if (React.isValidElement(leftIcon)) return leftIcon;

if (typeof leftIcon === 'string')
return <IconFont className={cls('back--arrow')} name={leftIcon} onClick={onLeftClickHandle} />;

return <ChevronLeftIcon className={cls('back--arrow')} onClick={onLeftClickHandle} />;
}, [cls, leftIcon, onLeftClickHandle]);

// 主页图标
const homeIconDom = useMemo(() => {
if (!homeIcon) return null;

if (React.isValidElement(homeIcon)) return homeIcon;

if (typeof homeIcon === 'string')
return <IconFont className={cls('back--arrow')} name={homeIcon} onClick={onHomeClickHandle} />;

return <HomeIcon className={cls('back--arrow')} onClick={onHomeClickHandle} size="21px" />;
}, [cls, homeIcon, onHomeClickHandle]);

/** 左侧icon区域 */
const leftAreaIcon = useMemo(
// 右侧icon
const rightContent = useMemo(
() =>
leftIconDom || homeIconDom ? (
<div className={cls('back')}>
{leftIconDom}
{homeIconDom}
right ? (
<div className={cls('right')} onClick={onRightClick}>
{right}
</div>
) : null,
[cls, leftIconDom, homeIconDom],
[cls, right, onRightClick],
);

/** 右侧icon */
const rightAreaIcon = useMemo(() => <div className={cls('right')}>{rightIcon}</div>, [cls, rightIcon]);
const navClass = useMemo<string>(
() =>
ClassNames(
prefix,
{ [`${prefix}--fixed`]: fixed },
visible ? `${prefix}--visible${animationSuffix}` : `${prefix}--hide${animationSuffix}`,
),
[prefix, fixed, visible, animationSuffix],
);

// 样式
const navStyle = useMemo<CSSProperties>(
() => ({
position: fixed ? 'fixed' : 'relative',
top: 0,
left: 0,
width: '100%',
...style,
}),
[fixed, style],
);

// 导航主体
const navBar = useMemo(
() =>
active ? (
<div className={ClassNames(cls(), className)} style={navStyle}>
{leftAreaIcon}
{titleChildren}
{rightAreaIcon}
return (
<div className={ClassNames(navClass, className)} style={navStyle}>
{fixed && <div className={cls('placeholder')}></div>}
<div className={cls(`content`)}>
<div className={cls(`left`)} onClick={onLeftClick}>
{leftArrow && <ChevronLeftIcon className={cls('left-arrow')} />}
{left}
{leftCapsuleContent}
</div>
) : null,
[active, className, cls, leftAreaIcon, navStyle, rightAreaIcon, titleChildren],
<div className={cls(`center`)}>{titleChildren}</div>
{rightContent}
</div>
</div>
);

return animation ? <animated.div style={navbarSpring}>{navBar}</animated.div> : navBar;
};

Navbar.defaultProps = navbarDefaultProps;
Expand Down
42 changes: 39 additions & 3 deletions src/navbar/_example/base.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
import React from 'react';
import { Navbar } from 'tdesign-mobile-react';
import { Navbar, Divider } from 'tdesign-mobile-react';
import { CloseIcon, ChevronLeftIcon, HomeIcon, EllipsisIcon } from 'tdesign-icons-react';

const BaseUsage = () => <Navbar>标题</Navbar>;
const BaseDemo = () => {
const handleClick = () => {
console.log('left-click');
};

export default BaseUsage;
return (
<>
<Navbar leftArrow fixed={false} onLeftClick={handleClick}>
标题文字
</Navbar>
<Navbar
leftArrow
fixed={false}
left={<CloseIcon size={24} />}
right={<EllipsisIcon size={24} />}
onLeftClick={handleClick}
>
标题文字
</Navbar>
<Navbar
fixed={false}
capsule={
<div className="custom-capsule">
<ChevronLeftIcon size={20} class="custom-capsule__icon" />
<Divider layout="vertical" />
<HomeIcon size={20} class="custom-capsule__icon" />
</div>
}
titleMaxLength={5}
onLeftClick={handleClick}
>
标题文字超出
</Navbar>
</>
);
};

export default BaseDemo;
21 changes: 21 additions & 0 deletions src/navbar/_example/custom-color.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { Navbar } from 'tdesign-mobile-react';
import { EllipsisIcon } from 'tdesign-icons-react';

const CustomColorDemo = () => (
<>
<Navbar
title="标题文字"
leftArrow
fixed={false}
className="custom-navbar"
right={
<>
<EllipsisIcon size={24} />
</>
}
/>
</>
);

export default CustomColorDemo;
21 changes: 0 additions & 21 deletions src/navbar/_example/event.jsx

This file was deleted.

24 changes: 0 additions & 24 deletions src/navbar/_example/icon.jsx

This file was deleted.

20 changes: 20 additions & 0 deletions src/navbar/_example/img.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { Navbar } from 'tdesign-mobile-react';
import { EllipsisIcon, HomeIcon } from 'tdesign-icons-react';

const ImgDemo = () => (
<>
<Navbar
left={<img src="https://tdesign.gtimg.com/mobile/demos/logo1.png" className="logo" />}
right={
<>
<HomeIcon size={24} />
<EllipsisIcon size={24} />
</>
}
fixed={false}
/>
</>
);

export default ImgDemo;
Loading

0 comments on commit e8b2328

Please sign in to comment.