diff --git a/apps/web/src/components/header/header-right-items/EditorOptionMenu.tsx b/apps/web/src/components/header/header-right-items/EditorOptionMenu.tsx index dc64ae05ce..252036f095 100644 --- a/apps/web/src/components/header/header-right-items/EditorOptionMenu.tsx +++ b/apps/web/src/components/header/header-right-items/EditorOptionMenu.tsx @@ -21,7 +21,7 @@ const PopoverContent = () => { const { editor } = useAppState(); const { toggleFavoritePage, toggleDeletePage } = usePageHelper(); const { changePageMode } = usePageHelper(); - const { confirm } = useConfirm(); + const confirm = useConfirm(store => store.confirm); const { t } = useTranslation(); const { mode = 'page', diff --git a/apps/web/src/components/header/header-right-items/TrashButtonGroup.tsx b/apps/web/src/components/header/header-right-items/TrashButtonGroup.tsx index 96156fd917..9c573b0ca0 100644 --- a/apps/web/src/components/header/header-right-items/TrashButtonGroup.tsx +++ b/apps/web/src/components/header/header-right-items/TrashButtonGroup.tsx @@ -10,7 +10,7 @@ export const TrashButtonGroup = () => { const { permanentlyDeletePage } = usePageHelper(); const { currentWorkspace } = useAppState(); const { toggleDeletePage } = usePageHelper(); - const { confirm } = useConfirm(); + const confirm = useConfirm(store => store.confirm); const router = useRouter(); const { id = '' } = useCurrentPageMeta() || {}; const { t } = useTranslation(); diff --git a/apps/web/src/components/page-list/OperationCell.tsx b/apps/web/src/components/page-list/OperationCell.tsx index 2fcc487e47..6bc7589447 100644 --- a/apps/web/src/components/page-list/OperationCell.tsx +++ b/apps/web/src/components/page-list/OperationCell.tsx @@ -19,7 +19,7 @@ export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => { const { id, favorite } = pageMeta; const { openPage } = usePageHelper(); const { toggleFavoritePage, toggleDeletePage } = usePageHelper(); - const { confirm } = useConfirm(); + const confirm = useConfirm(store => store.confirm); const { t } = useTranslation(); const OperationMenu = ( <> @@ -77,7 +77,7 @@ export const TrashOperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => { const { id } = pageMeta; const { openPage, getPageMeta } = usePageHelper(); const { toggleDeletePage, permanentlyDeletePage } = usePageHelper(); - const { confirm } = useConfirm(); + const confirm = useConfirm(store => store.confirm); const { t } = useTranslation(); return ( diff --git a/apps/web/src/components/workspace-setting/member/MembersPage.tsx b/apps/web/src/components/workspace-setting/member/MembersPage.tsx index 25b4ea5b97..84b2f9ed0f 100644 --- a/apps/web/src/components/workspace-setting/member/MembersPage.tsx +++ b/apps/web/src/components/workspace-setting/member/MembersPage.tsx @@ -33,7 +33,7 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const { members, removeMember, loaded } = useMembers(); const { triggerEnableWorkspaceModal } = useModal(); const { t } = useTranslation(); - const { confirm } = useConfirm(); + const confirm = useConfirm(store => store.confirm); if (workspace.provider === 'affine') { return ( diff --git a/apps/web/src/providers/ConfirmProvider.tsx b/apps/web/src/providers/ConfirmProvider.tsx index 933f85c7df..2e7559e9e3 100644 --- a/apps/web/src/providers/ConfirmProvider.tsx +++ b/apps/web/src/providers/ConfirmProvider.tsx @@ -1,62 +1,100 @@ -import { createContext, useContext, useState, ReactNode } from 'react'; +import { createContext, useContext, useMemo } from 'react'; import type { PropsWithChildren } from 'react'; import { Confirm, ConfirmProps } from '@affine/component'; +import { createStore, useStore } from 'zustand'; +import { combine, subscribeWithSelector } from 'zustand/middleware'; +import { UseBoundStore } from 'zustand/react'; -type ConfirmContextValue = { +type ConfirmActions = { confirm: (props: ConfirmProps) => Promise; }; -type ConfirmContextProps = PropsWithChildren>; -export const ConfirmContext = createContext({ - confirm: () => Promise.resolve(false), -}); +type ConfirmState = { + record: Record; +}; -export const useConfirm = () => useContext(ConfirmContext); - -export const ConfirmProvider = ({ - children, -}: PropsWithChildren) => { - const [confirmRecord, setConfirmRecord] = useState>( - {} - ); - return ( - { - return new Promise(resolve => { - const confirmId = String(Date.now()); - const closeHandler = () => { - delete confirmRecord[confirmId]; - setConfirmRecord({ ...confirmRecord }); - }; - setConfirmRecord(oldConfirmRecord => { - return { - ...oldConfirmRecord, - [confirmId]: ( - { - closeHandler(); - onCancel?.(); - resolve(false); - }} - onConfirm={() => { - closeHandler(); - onConfirm?.(); - resolve(true); - }} - /> - ), - }; - }); - }); +const create = () => + createStore( + subscribeWithSelector( + combine( + { + record: {}, }, - }} - > - {children} - {Object.entries(confirmRecord).map(([confirmId, confirmNode]) => { + (set, get) => ({ + confirm: ({ onCancel, onConfirm, ...props }: ConfirmProps) => { + return new Promise(resolve => { + const confirmRecord = { ...get().record }; + const confirmId = String(Date.now()); + const closeHandler = () => { + delete confirmRecord[confirmId]; + set({ record: { ...confirmRecord } }); + }; + set(({ record }) => { + return { + record: { + ...record, + [confirmId]: ( + { + closeHandler(); + onCancel?.(); + resolve(false); + }} + onConfirm={() => { + closeHandler(); + onConfirm?.(); + resolve(true); + }} + /> + ), + }, + }; + }); + }); + }, + }) + ) + ) + ); + +type Store = ReturnType; + +export const ConfirmContext = createContext(null); + +export const useConfirmApi = () => { + const api = useContext(ConfirmContext); + if (!api) { + throw new Error('cannot find confirm context'); + } + return api; +}; + +export const useConfirm: UseBoundStore = (( + selector: Parameters>[0], + equals: Parameters>[1] +) => { + const api = useConfirmApi(); + return useStore(api, selector, equals); + // eslint-disable-next-line @typescript-eslint/no-explicit-any +}) as any; + +function Records() { + const conform = useConfirm(store => store.record); + return ( + <> + {Object.entries(conform).map(([confirmId, confirmNode]) => { return
{confirmNode}
; })} + + ); +} + +export const ConfirmProvider = ({ children }: PropsWithChildren) => { + return ( + create(), [])}> + {children} + ); };