client: optimize render actions

This commit is contained in:
fantasticit 2022-05-27 21:41:03 +08:00
parent a3b2e3d97d
commit eef782f096
3 changed files with 115 additions and 67 deletions

View File

@ -1,5 +1,5 @@
import { IconMore, IconPlus, IconStar } from '@douyinfe/semi-icons';
import { Button, Dropdown, Space, Typography } from '@douyinfe/semi-ui';
import { Button, Dropdown, Popover, Space, Typography } from '@douyinfe/semi-ui';
import { DocumentCreator } from 'components/document/create';
import { DocumentDeletor } from 'components/document/delete';
import { DocumentLinkCopyer } from 'components/document/link';
@ -29,22 +29,40 @@ export const DocumentActions: React.FC<IProps> = ({
showCreateDocument,
children,
}) => {
const [visible, toggleVisible] = useToggle(false);
const [popoverVisible, togglePopoverVisible] = useToggle(false);
const [createVisible, toggleCreateVisible] = useToggle(false);
const prevent = useCallback((e) => {
e.preventDefault();
e.stopPropagation();
}, []);
const create = useCallback(() => {
togglePopoverVisible(false);
toggleCreateVisible(true);
}, [togglePopoverVisible, toggleCreateVisible]);
const wrapedOnDelete = useCallback(() => {
togglePopoverVisible(false);
onDelete && onDelete();
}, [onDelete, togglePopoverVisible]);
const wrapOnVisibleChange = useCallback(
(visible) => {
togglePopoverVisible(visible);
onVisibleChange && onVisibleChange();
},
[onVisibleChange, togglePopoverVisible]
);
return (
<>
<Dropdown
onVisibleChange={onVisibleChange}
render={
<Popover
showArrow
style={{ padding: 0 }}
trigger="click"
visible={popoverVisible}
onVisibleChange={wrapOnVisibleChange}
content={
<Dropdown.Menu>
{showCreateDocument && (
<Dropdown.Item onClick={prevent}>
<Text onClick={toggleVisible}>
<Dropdown.Item onClick={create}>
<Text>
<Space>
<IconPlus />
@ -52,15 +70,16 @@ export const DocumentActions: React.FC<IProps> = ({
</Text>
</Dropdown.Item>
)}
<Dropdown.Item onClick={prevent}>
<DocumentStar
documentId={documentId}
render={({ star, toggleStar, text }) => (
<Text
onClick={() => {
toggleStar().then(onStar);
}}
>
<DocumentStar
documentId={documentId}
render={({ star, toggleStar, text }) => (
<Dropdown.Item
onClick={() => {
toggleStar().then(onStar);
}}
>
<Text>
<Space>
<IconStar
style={{
@ -70,27 +89,40 @@ export const DocumentActions: React.FC<IProps> = ({
{text}
</Space>
</Text>
)}
/>
</Dropdown.Item>
<Dropdown.Item onClick={prevent}>
<DocumentLinkCopyer wikiId={wikiId} documentId={documentId} />
</Dropdown.Item>
</Dropdown.Item>
)}
/>
<DocumentLinkCopyer
wikiId={wikiId}
documentId={documentId}
render={({ copy, children }) => {
return <Dropdown.Item onClick={copy}>{children}</Dropdown.Item>;
}}
/>
<Dropdown.Divider />
<Dropdown.Item onClick={prevent}>
<DocumentDeletor wikiId={wikiId} documentId={documentId} onDelete={onDelete} />
</Dropdown.Item>
<DocumentDeletor
wikiId={wikiId}
documentId={documentId}
onDelete={wrapedOnDelete}
render={({ children }) => {
return <Dropdown.Item>{children}</Dropdown.Item>;
}}
/>
</Dropdown.Menu>
}
>
{children || <Button onClick={prevent} icon={<IconMore />} theme="borderless" type="tertiary" />}
</Dropdown>
{children || <Button icon={<IconMore />} theme="borderless" type="tertiary" />}
</Popover>
{showCreateDocument && (
<DocumentCreator
wikiId={wikiId}
parentDocumentId={documentId}
visible={visible}
toggleVisible={toggleVisible}
visible={createVisible}
toggleVisible={toggleCreateVisible}
onCreate={onCreate}
/>
)}

View File

@ -1,52 +1,61 @@
import { IconDelete } from '@douyinfe/semi-icons';
import { Modal, Space, Typography } from '@douyinfe/semi-ui';
import { Modal, Popconfirm, Space, Typography } from '@douyinfe/semi-ui';
import { useDeleteDocument } from 'data/document';
import { useRouterQuery } from 'hooks/use-router-query';
import Router from 'next/router';
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
interface IProps {
wikiId: string;
documentId: string;
onDelete?: () => void;
render?: (arg: { children: React.ReactNode }) => React.ReactNode;
}
const { Text } = Typography;
export const DocumentDeletor: React.FC<IProps> = ({ wikiId, documentId, onDelete }) => {
export const DocumentDeletor: React.FC<IProps> = ({ wikiId, documentId, render, onDelete }) => {
const { wikiId: currentWikiId, documentId: currentDocumentId } =
useRouterQuery<{ wikiId?: string; documentId?: string }>();
const { deleteDocument: api, loading } = useDeleteDocument(documentId);
const deleteAction = useCallback(() => {
Modal.error({
title: '确定删除吗?',
content: <Text></Text>,
onOk: () => {
api().then(() => {
const navigate = () => {
if (wikiId !== currentWikiId || documentId !== currentDocumentId) {
return;
}
Router.push({
pathname: `/wiki/${wikiId}`,
});
};
onDelete ? onDelete() : navigate();
api().then(() => {
const navigate = () => {
if (wikiId !== currentWikiId || documentId !== currentDocumentId) {
return;
}
Router.push({
pathname: `/wiki/${wikiId}`,
});
},
okButtonProps: { loading, type: 'danger' },
style: { maxWidth: '96vw' },
};
onDelete ? onDelete() : navigate();
});
}, [wikiId, documentId, api, loading, onDelete, currentWikiId, currentDocumentId]);
}, [wikiId, documentId, api, onDelete, currentWikiId, currentDocumentId]);
const content = useMemo(
() => (
<Text type="danger">
<Space>
<IconDelete />
</Space>
</Text>
),
[]
);
return (
<Text type="danger" onClick={deleteAction}>
<Space>
<IconDelete />
</Space>
</Text>
<Popconfirm
title="确定删除吗?"
content="文档删除后不可恢复!"
onConfirm={deleteAction}
okButtonProps={{ loading }}
zIndex={1070}
showArrow
>
{render ? render({ children: content }) : content}
</Popconfirm>
);
};

View File

@ -7,21 +7,28 @@ import React, { useCallback } from 'react';
interface IProps {
wikiId: string;
documentId: string;
render?: (arg: { copy: () => void; children: React.ReactNode }) => React.ReactNode;
}
const { Text } = Typography;
export const DocumentLinkCopyer: React.FC<IProps> = ({ wikiId, documentId }) => {
export const DocumentLinkCopyer: React.FC<IProps> = ({ wikiId, documentId, render }) => {
const handle = useCallback(() => {
copy(buildUrl(`/wiki/${wikiId}/document/${documentId}`));
}, [wikiId, documentId]);
return (
const content = (
<Space>
<IconLink />
</Space>
);
return render ? (
<>{render({ copy: handle, children: content })}</>
) : (
<Text onClick={handle} style={{ cursor: 'pointer' }}>
<Space>
<IconLink />
</Space>
{content}
</Text>
);
};