From d9307cd891dd532ca79ec16a37e831c0a3407e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=8F=8E=EF=B8=8F=20Yumo?= Date: Sat, 3 Aug 2024 12:03:22 +0800 Subject: [PATCH] refactor: Add ConversationsItem. fix: Item tootip experience optimization --- .dumi/preset/components-changelog-cn.json | 2 +- .dumi/preset/components-changelog-en.json | 2 +- components/conversations/Item.tsx | 78 +++++++++++++++++++ components/conversations/index.tsx | 95 ++++++++--------------- 4 files changed, 112 insertions(+), 65 deletions(-) create mode 100644 components/conversations/Item.tsx diff --git a/.dumi/preset/components-changelog-cn.json b/.dumi/preset/components-changelog-cn.json index 8d5ffe2e..53898440 100644 --- a/.dumi/preset/components-changelog-cn.json +++ b/.dumi/preset/components-changelog-cn.json @@ -1 +1 @@ -{"Conversations":[],"Bubble":[]} +{"Conversations":[],"Bubble":[]} \ No newline at end of file diff --git a/.dumi/preset/components-changelog-en.json b/.dumi/preset/components-changelog-en.json index 8d5ffe2e..53898440 100644 --- a/.dumi/preset/components-changelog-en.json +++ b/.dumi/preset/components-changelog-en.json @@ -1 +1 @@ -{"Conversations":[],"Bubble":[]} +{"Conversations":[],"Bubble":[]} \ No newline at end of file diff --git a/components/conversations/Item.tsx b/components/conversations/Item.tsx new file mode 100644 index 00000000..c6a0369f --- /dev/null +++ b/components/conversations/Item.tsx @@ -0,0 +1,78 @@ +import React from 'react'; +import { Tooltip, Typography, Dropdown } from 'antd'; +import { MoreOutlined } from '@ant-design/icons'; + +import type { MenuProps } from 'antd'; +import type { ConversationProps } from './interface'; + +interface ConversationsItemProps extends ConversationProps, React.HTMLAttributes { + classNames?: { + item?: string; + label?: string; + menu?: string; + }; + styles?: { + item?: React.CSSProperties; + }; + prefixCls?: string; + menu?: MenuProps; +} + +const ConversationsItem: React.FC = (props) => { + const { + classNames, + styles, + disabled, + onClick, + icon, + label, + key, + prefixCls, + menu, + } = props; + + const [ellipsised, setEllipsised] = React.useState(false); + + return ( + +
  • + {icon &&
    + {icon} +
    } + { + setEllipsised(v); + }, + }} + > + {label} + + {menu && !disabled && + triggerNode.parentElement ?? document.body} + > + { + event.stopPropagation(); + setEllipsised(false); + }} + disabled={disabled} + className={classNames?.menu} + /> + } +
  • +
    + ); +}; + +export default ConversationsItem; \ No newline at end of file diff --git a/components/conversations/index.tsx b/components/conversations/index.tsx index 133c07b8..1c6a1866 100644 --- a/components/conversations/index.tsx +++ b/components/conversations/index.tsx @@ -1,8 +1,8 @@ -import React, { useMemo } from 'react'; -import { Divider, Dropdown, Typography } from 'antd'; -import { MoreOutlined } from '@ant-design/icons'; +import React from 'react'; +import { Divider, Typography } from 'antd'; import classnames from 'classnames'; import useMergedState from 'rc-util/lib/hooks/useMergedState'; +import ConversationsItem from './Item'; import useStyle from './style'; import getPrefixCls from '../_util/getPrefixCls'; @@ -24,14 +24,14 @@ const Conversations: React.FC = (props) => { groupable, } = props; + const prefixCls = getPrefixCls('conversations', customizePrefixCls); + const [mergedActiveKey, setMergedActiveKey] = useMergedState(defaultActiveKey, { value: activeKey, defaultValue: defaultActiveKey, onChange: onActiveChange, }); - const prefixCls = getPrefixCls('conversations', customizePrefixCls); - const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls); const mergedCls = classnames( @@ -42,23 +42,8 @@ const Conversations: React.FC = (props) => { styles?.list, ); - const makeItemProps = (item: ConversationProps) => ({ - className: classnames( - classNames?.item, - `${prefixCls}-item`, - { [`${prefixCls}-item-active`]: item.key === mergedActiveKey && !item.disabled }, - { [`${prefixCls}-item-disabled`]: item.disabled }, - ), - style: styles?.item, - menu: typeof menu === 'function' ? menu(item) : menu, - onClick: () => setMergedActiveKey(item.key), - }); - - const mergedLabelCls = classnames(`${prefixCls}-label`, classNames?.item); - const mergedMenuCls = classnames(`${prefixCls}-menu`, classNames?.item); - const groupedMap = data.reduce((map, item) => { - const { group = 'default' } = item; + const { group = '' } = item; if (!Array.isArray(map[group])) { map[group] = []; @@ -69,44 +54,26 @@ const Conversations: React.FC = (props) => { return map; }, {} as Record); - function renderConversationItem(item: ConversationProps) { - const itemProps = makeItemProps(item); - - return ( -
  • - {item.icon &&
    - {item.icon} -
    } - - {item.label} - - {menu && !item.disabled && - triggerNode.parentElement ?? document.body} - > - { - event.stopPropagation(); - }} - disabled={item.disabled} - className={mergedMenuCls} - /> - } -
  • - ) - } - - const conversationItems = useMemo(() => Object.keys(groupedMap).reduce( + const getItemProps = React.useCallback((item: ConversationProps) => ({ + ...item, + classNames: { + item: classnames( + classNames?.item, + `${prefixCls}-item`, + { [`${prefixCls}-item-active`]: item.key === mergedActiveKey && !item.disabled }, + { [`${prefixCls}-item-disabled`]: item.disabled }, + ), + label: classnames(`${prefixCls}-label`, classNames?.item), + menu: `${prefixCls}-menu`, + }, + prefixCls, + styles: styles, + menu: typeof menu === 'function' ? menu(item) : menu, + onClick: () => setMergedActiveKey(item.key), + }), [classNames, prefixCls, mergedActiveKey, styles, menu, setMergedActiveKey]); + + // ============================ Render Items ============================ + const convItems = React.useMemo(() => Object.keys(groupedMap).reduce( (nodes, group) => { if (groupable) { @@ -129,15 +96,17 @@ const Conversations: React.FC = (props) => { return [ ...nodes, - ...groupedMap[group].map(renderConversationItem), - ] + ...groupedMap[group].map(item => React.createElement(ConversationsItem, getItemProps(item))), + ]; }, [] as ReactNode[], - ), [groupedMap, groupable]); + ), [groupedMap, groupable, getItemProps]); + + // ============================ Render ============================ return wrapCSSVar(
      - {conversationItems} + {convItems}
    , ); };