fix: patch service syntax (#7080)

Not sure if there is a better pattern like "macros" that can make this more generic. 🤡

also added notify impl to notification service for bs
https://github.com/toeverything/blocksuite/pull/7160
This commit is contained in:
pengx17
2024-05-30 11:46:16 +00:00
parent 622239fd41
commit da3cbc69cf

View File

@@ -1,6 +1,7 @@
import { import {
createReactComponentFromLit, createReactComponentFromLit,
type ElementOrFactory, type ElementOrFactory,
notify,
toast, toast,
type ToastOptions, type ToastOptions,
type useConfirmModal, type useConfirmModal,
@@ -12,7 +13,7 @@ import type {
RootService, RootService,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import { LitElement, type TemplateResult } from 'lit'; import { LitElement, type TemplateResult } from 'lit';
import React from 'react'; import React, { createElement, type ReactNode } from 'react';
export type ReferenceReactRenderer = ( export type ReferenceReactRenderer = (
reference: AffineReference reference: AffineReference
@@ -42,6 +43,36 @@ const TemplateWrapper = createReactComponentFromLit({
react: React, react: React,
}); });
const toReactNode = (template?: TemplateResult | string): ReactNode => {
if (!template) return null;
return typeof template === 'string'
? template
: createElement(TemplateWrapper, { template });
};
function patchSpecService<Spec extends BlockSpec>(
spec: Spec,
onMounted: (
service: Spec extends BlockSpec<any, infer BlockService>
? BlockService
: never
) => (() => void) | void
) {
const oldSetup = spec.setup;
spec.setup = (slots, disposableGroup) => {
oldSetup?.(slots, disposableGroup);
disposableGroup.add(
slots.mounted.on(({ service }) => {
const disposable = onMounted(service as any);
if (disposable) {
disposableGroup.add(disposable);
}
})
);
};
return spec;
}
/** /**
* Patch the block specs with custom renderers. * Patch the block specs with custom renderers.
*/ */
@@ -61,15 +92,15 @@ export function patchReferenceRenderer(
spec.schema.model.flavour spec.schema.model.flavour
) )
) { ) {
// todo: remove these type assertions spec = patchSpecService(
spec.service = class extends ( spec as BlockSpec<string, ParagraphBlockService>,
(spec.service as typeof ParagraphBlockService) service => {
) { service.referenceNodeConfig.setCustomContent(litRenderer);
override mounted() { return () => {
super.mounted(); service.referenceNodeConfig.setCustomContent(null);
this.referenceNodeConfig.setCustomContent(litRenderer); };
} }
}; );
} }
return spec; return spec;
@@ -82,14 +113,14 @@ export function patchNotificationService(
) { ) {
const rootSpec = specs.find( const rootSpec = specs.find(
spec => spec.schema.model.flavour === 'affine:page' spec => spec.schema.model.flavour === 'affine:page'
); ) as BlockSpec<string, RootService>;
if (!rootSpec) { if (!rootSpec) {
return specs; return specs;
} }
rootSpec.service = class extends (rootSpec.service as typeof RootService) { patchSpecService(rootSpec, service => {
override notificationService = { service.notificationService = {
confirm: async ({ confirm: async ({
title, title,
message, message,
@@ -106,12 +137,7 @@ export function patchNotificationService(
return new Promise<boolean>(resolve => { return new Promise<boolean>(resolve => {
openConfirmModal({ openConfirmModal({
title, title,
description: description: toReactNode(message),
typeof message === 'string' ? (
message
) : (
<TemplateWrapper template={message} />
),
confirmButtonOptions: { confirmButtonOptions: {
children: confirmText, children: confirmText,
type: 'primary', type: 'primary',
@@ -133,8 +159,34 @@ export function patchNotificationService(
toast: (message: string, options: ToastOptions) => { toast: (message: string, options: ToastOptions) => {
return toast(message, options); return toast(message, options);
}, },
notify: async () => {}, notify: notification => {
const accentToNotify = {
error: notify.error,
success: notify.success,
warning: notify.warning,
info: notify,
};
const fn = accentToNotify[notification.accent || 'info'];
if (!fn) {
throw new Error('Invalid notification accent');
}
const toastId = fn(
{
title: toReactNode(notification.title),
message: toReactNode(notification.message),
},
{
duration: notification.duration || 0,
}
);
notification.abort?.addEventListener('abort', () => {
notify.dismiss(toastId);
});
},
}; };
}; });
return specs; return specs;
} }