refactor(editor): add helper function for undo notification (#11903)

### What Changes
- Refactors the `notify` function call with undo button. It is called `notifyWithUndo`, which can  associate the visibility of the `NotificationCard` with the top undo item in history stack, such as undo by shortcut `Cmd+Z`.
- change icon of the "Insert into page" button. Close [BS-3267](https://linear.app/affine-design/issue/BS-3267/frame和group的insert-into-page图标也更换一下)
This commit is contained in:
L-Sun
2025-04-23 02:43:56 +00:00
committed by L-Sun
parent 27ff9ab9f4
commit 9dbdd4b7ba
14 changed files with 136 additions and 157 deletions

View File

@@ -1,5 +1,6 @@
import { createIdentifier } from '@blocksuite/global/di';
import type { ExtensionType } from '@blocksuite/store';
import { createIdentifier, type ServiceProvider } from '@blocksuite/global/di';
import { EditorLifeCycleExtension } from '@blocksuite/std';
import { type ExtensionType, StoreIdentifier } from '@blocksuite/store';
import type { TemplateResult } from 'lit';
export interface NotificationService {
@@ -37,8 +38,16 @@ export interface NotificationService {
label: string | TemplateResult;
onClick: () => void;
}[];
onClose: () => void;
onClose?: () => void;
}): void;
/**
* Notify with undo action, it is a helper function to notify with undo action.
* And the notification card will be closed when undo action is triggered by shortcut key or other ways.
*/
notifyWithUndoAction: (
options: Parameters<NotificationService['notify']>[0]
) => void;
}
export const NotificationProvider = createIdentifier<NotificationService>(
@@ -46,11 +55,69 @@ export const NotificationProvider = createIdentifier<NotificationService>(
);
export function NotificationExtension(
notificationService: NotificationService
notificationService: Omit<NotificationService, 'notifyWithUndoAction'>
): ExtensionType {
return {
setup: di => {
di.addImpl(NotificationProvider, notificationService);
di.addImpl(NotificationProvider, provider => {
return {
...notificationService,
notifyWithUndoAction: options => {
notifyWithUndoActionImpl(
provider,
notificationService.notify,
options
);
},
};
});
},
};
}
function notifyWithUndoActionImpl(
provider: ServiceProvider,
notify: NotificationService['notify'],
options: Parameters<NotificationService['notifyWithUndoAction']>[0]
) {
const store = provider.get(StoreIdentifier);
const abortController = new AbortController();
const abort = () => {
abortController.abort();
};
options.abort?.addEventListener('abort', abort);
const clearOnClose = () => {
store.history.off('stack-item-added', addHandler);
store.history.off('stack-item-popped', popHandler);
disposable.unsubscribe();
options.abort?.removeEventListener('abort', abort);
};
const addHandler = store.history.on('stack-item-added', abort);
const popHandler = store.history.on('stack-item-popped', abort);
const disposable = provider
.get(EditorLifeCycleExtension)
.slots.unmounted.subscribe(() => abort());
notify({
...options,
actions: [
{
key: 'notification-card-undo',
label: 'Undo',
onClick: () => {
store.undo();
abortController.abort();
},
},
...(options.actions ?? []),
],
abort: abortController.signal,
onClose: () => {
options.onClose?.();
clearOnClose();
},
});
}