refactor(editor): edgeless attacment toolbar config extension (#10710)

This commit is contained in:
fundon
2025-03-19 00:52:22 +00:00
parent 3cce147c60
commit 251d1d8782
19 changed files with 196 additions and 114 deletions

View File

@@ -1,18 +1,13 @@
import { AttachmentBlockSchema } from '@blocksuite/affine-model'; import { AttachmentBlockSchema } from '@blocksuite/affine-model';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu'; import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
import { import { BlockViewExtension, FlavourExtension } from '@blocksuite/block-std';
BlockFlavourIdentifier,
BlockViewExtension,
FlavourExtension,
} from '@blocksuite/block-std';
import type { ExtensionType } from '@blocksuite/store'; import type { ExtensionType } from '@blocksuite/store';
import { literal } from 'lit/static-html.js'; import { literal } from 'lit/static-html.js';
import { AttachmentBlockNotionHtmlAdapterExtension } from './adapters/notion-html.js'; import { AttachmentBlockNotionHtmlAdapterExtension } from './adapters/notion-html.js';
import { AttachmentDropOption } from './attachment-service.js'; import { AttachmentDropOption } from './attachment-service.js';
import { attachmentSlashMenuConfig } from './configs/slash-menu.js'; import { attachmentSlashMenuConfig } from './configs/slash-menu.js';
import { builtinToolbarConfig } from './configs/toolbar'; import { createBuiltinToolbarConfigExtension } from './configs/toolbar';
import { import {
AttachmentEmbedConfigExtension, AttachmentEmbedConfigExtension,
AttachmentEmbedService, AttachmentEmbedService,
@@ -31,9 +26,6 @@ export const AttachmentBlockSpec: ExtensionType[] = [
AttachmentEmbedConfigExtension(), AttachmentEmbedConfigExtension(),
AttachmentEmbedService, AttachmentEmbedService,
AttachmentBlockNotionHtmlAdapterExtension, AttachmentBlockNotionHtmlAdapterExtension,
ToolbarModuleExtension({ createBuiltinToolbarConfigExtension(flavour),
id: BlockFlavourIdentifier(flavour),
config: builtinToolbarConfig,
}),
SlashMenuConfigExtension(flavour, attachmentSlashMenuConfig), SlashMenuConfigExtension(flavour, attachmentSlashMenuConfig),
]; ].flat();

View File

@@ -2,6 +2,7 @@ import { createLitPortal } from '@blocksuite/affine-components/portal';
import { import {
AttachmentBlockModel, AttachmentBlockModel,
defaultAttachmentProps, defaultAttachmentProps,
type EmbedCardStyle,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import { import {
EMBED_CARD_HEIGHT, EMBED_CARD_HEIGHT,
@@ -12,7 +13,9 @@ import {
type ToolbarAction, type ToolbarAction,
type ToolbarActionGroup, type ToolbarActionGroup,
type ToolbarModuleConfig, type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services'; } from '@blocksuite/affine-shared/services';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx'; import { Bound } from '@blocksuite/global/gfx';
import { import {
CaptionIcon, CaptionIcon,
@@ -23,6 +26,7 @@ import {
EditIcon, EditIcon,
ResetIcon, ResetIcon,
} from '@blocksuite/icons/lit'; } from '@blocksuite/icons/lit';
import type { ExtensionType } from '@blocksuite/store';
import { flip, offset } from '@floating-ui/dom'; import { flip, offset } from '@floating-ui/dom';
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import { html } from 'lit'; import { html } from 'lit';
@@ -34,9 +38,6 @@ import { AttachmentEmbedProvider } from '../embed';
import { cloneAttachmentProperties } from '../utils'; import { cloneAttachmentProperties } from '../utils';
const trackBaseProps = { const trackBaseProps = {
segment: 'doc',
page: 'doc editor',
module: 'toolbar',
category: 'attachment', category: 'attachment',
type: 'card view', type: 'card view',
}; };
@@ -54,14 +55,14 @@ export const attachmentViewDropdownMenu = {
const style = defaultAttachmentProps.style!; const style = defaultAttachmentProps.style!;
const width = EMBED_CARD_WIDTH[style]; const width = EMBED_CARD_WIDTH[style];
const height = EMBED_CARD_HEIGHT[style]; const height = EMBED_CARD_HEIGHT[style];
const bound = Bound.deserialize(model.xywh); const bounds = Bound.deserialize(model.xywh);
bound.w = width; bounds.w = width;
bound.h = height; bounds.h = height;
ctx.store.updateBlock(model, { ctx.store.updateBlock(model, {
style, style,
embed: false, embed: false,
xywh: bound.serialize(), xywh: bounds.serialize(),
}); });
}, },
}, },
@@ -72,9 +73,11 @@ export const attachmentViewDropdownMenu = {
const model = ctx.getCurrentModelByType(AttachmentBlockModel); const model = ctx.getCurrentModelByType(AttachmentBlockModel);
if (!model) return; if (!model) return;
if (!ctx.hasSelectedSurfaceModels) {
// Clears // Clears
ctx.reset(); ctx.reset();
ctx.select('note'); ctx.select('note');
}
ctx.std.get(AttachmentEmbedProvider).convertTo(model); ctx.std.get(AttachmentEmbedProvider).convertTo(model);
@@ -101,7 +104,8 @@ export const attachmentViewDropdownMenu = {
return embed ? embedAction.label : cardAction.label; return embed ? embedAction.label : cardAction.label;
}); });
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
e.stopPropagation();
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -114,16 +118,41 @@ export const attachmentViewDropdownMenu = {
return html`${keyed( return html`${keyed(
model, model,
html`<affine-view-dropdown-menu html`<affine-view-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.viewType$=${viewType$} .viewType$=${viewType$}
></affine-view-dropdown-menu>` ></affine-view-dropdown-menu>`
)}`; )}`;
}, },
} satisfies ToolbarActionGroup<ToolbarAction>; } as const satisfies ToolbarActionGroup<ToolbarAction>;
export const builtinToolbarConfig = { const downloadAction = {
id: 'c.download',
tooltip: 'Download',
icon: DownloadIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
block?.download();
},
} as const satisfies ToolbarAction;
const captionAction = {
id: 'd.caption',
tooltip: 'Caption',
icon: CaptionIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
block?.captionEditor?.show();
ctx.track('OpenedCaptionEditor', {
...trackBaseProps,
control: 'add caption',
});
},
} as const satisfies ToolbarAction;
const builtinToolbarConfig = {
actions: [ actions: [
{ {
id: 'a.rename', id: 'a.rename',
@@ -162,29 +191,8 @@ export const builtinToolbarConfig = {
}, },
}, },
attachmentViewDropdownMenu, attachmentViewDropdownMenu,
{ downloadAction,
id: 'c.download', captionAction,
tooltip: 'Download',
icon: DownloadIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
block?.download();
},
},
{
id: 'd.caption',
tooltip: 'Caption',
icon: CaptionIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
block?.captionEditor?.show();
ctx.track('OpenedCaptionEditor', {
...trackBaseProps,
control: 'add caption',
});
},
},
{ {
placement: ActionPlacement.More, placement: ActionPlacement.More,
id: 'a.clipboard', id: 'a.clipboard',
@@ -247,3 +255,96 @@ export const builtinToolbarConfig = {
}, },
], ],
} as const satisfies ToolbarModuleConfig; } as const satisfies ToolbarModuleConfig;
const builtinSurfaceToolbarConfig = {
actions: [
attachmentViewDropdownMenu,
{
id: 'c.style',
actions: [
{
id: 'horizontalThin',
label: 'Horizontal style',
},
{
id: 'cubeThick',
label: 'Vertical style',
},
],
content(ctx) {
const model = ctx.getCurrentModelByType(AttachmentBlockModel);
if (!model) return null;
const actions = this.actions.map(action => ({
...action,
run: ({ store }) => {
const style = action.id as EmbedCardStyle;
const bounds = Bound.deserialize(model.xywh);
bounds.w = EMBED_CARD_WIDTH[style];
bounds.h = EMBED_CARD_HEIGHT[style];
const xywh = bounds.serialize();
store.updateBlock(model, { style, xywh });
ctx.track('SelectedCardStyle', {
...trackBaseProps,
page: 'whiteboard editor',
control: 'select card style',
type: style,
});
},
})) satisfies ToolbarAction[];
const style$ = model.props.style$;
const onToggle = (e: CustomEvent<boolean>) => {
e.stopPropagation();
const opened = e.detail;
if (!opened) return;
ctx.track('OpenedCardStyleSelector', {
...trackBaseProps,
page: 'whiteboard editor',
control: 'switch card style',
});
};
return html`${keyed(
model,
html`<affine-card-style-dropdown-menu
@toggle=${onToggle}
.actions=${actions}
.context=${ctx}
.style$=${style$}
></affine-card-style-dropdown-menu>`
)}`;
},
} satisfies ToolbarActionGroup<ToolbarAction>,
{
...downloadAction,
id: 'd.download',
},
{
...captionAction,
id: 'e.caption',
},
],
when: ctx => ctx.getSurfaceModelsByType(AttachmentBlockModel).length === 1,
} as const satisfies ToolbarModuleConfig;
export const createBuiltinToolbarConfigExtension = (
flavour: string
): ExtensionType[] => {
const name = flavour.split(':').pop();
return [
ToolbarModuleExtension({
id: BlockFlavourIdentifier(flavour),
config: builtinToolbarConfig,
}),
ToolbarModuleExtension({
id: BlockFlavourIdentifier(`affine:surface:${name}`),
config: builtinSurfaceToolbarConfig,
}),
];
};

View File

@@ -181,7 +181,7 @@ export const builtinToolbarConfig = {
if (!model) return null; if (!model) return null;
const actions = this.actions.map(action => ({ ...action })); const actions = this.actions.map(action => ({ ...action }));
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -194,9 +194,9 @@ export const builtinToolbarConfig = {
return html`${keyed( return html`${keyed(
model, model,
html`<affine-view-dropdown-menu html`<affine-view-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.viewType$=${signal(actions[1].label)} .viewType$=${signal(actions[1].label)}
></affine-view-dropdown-menu>` ></affine-view-dropdown-menu>`
)}`; )}`;
@@ -231,7 +231,7 @@ export const builtinToolbarConfig = {
}, },
})) satisfies ToolbarAction[]; })) satisfies ToolbarAction[];
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -244,9 +244,9 @@ export const builtinToolbarConfig = {
return html`${keyed( return html`${keyed(
model, model,
html`<affine-card-style-dropdown-menu html`<affine-card-style-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.style$=${model.props.style$} .style$=${model.props.style$}
></affine-card-style-dropdown-menu>` ></affine-card-style-dropdown-menu>`
)}`; )}`;

View File

@@ -242,8 +242,7 @@ export function createBuiltinToolbarConfigForExternal(
const viewType$ = signal( const viewType$ = signal(
`${viewType === 'card' ? 'Card' : 'Embed'} view` `${viewType === 'card' ? 'Card' : 'Embed'} view`
); );
const onToggle = (e: CustomEvent<boolean>) => {
const toggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -256,9 +255,9 @@ export function createBuiltinToolbarConfigForExternal(
return html`${keyed( return html`${keyed(
model, model,
html`<affine-view-dropdown-menu html`<affine-view-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.viewType$=${viewType$} .viewType$=${viewType$}
></affine-view-dropdown-menu>` ></affine-view-dropdown-menu>`
)}`; )}`;
@@ -293,7 +292,7 @@ export function createBuiltinToolbarConfigForExternal(
}, },
})) satisfies ToolbarAction[]; })) satisfies ToolbarAction[];
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -306,9 +305,9 @@ export function createBuiltinToolbarConfigForExternal(
return html`${keyed( return html`${keyed(
model, model,
html`<affine-card-style-dropdown-menu html`<affine-card-style-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.style$=${model.props.style$} .style$=${model.props.style$}
></affine-card-style-dropdown-menu>` ></affine-card-style-dropdown-menu>`
)}`; )}`;

View File

@@ -67,8 +67,7 @@ export const builtinToolbarConfig = {
}); });
}, },
})); }));
const onToggle = (e: CustomEvent<boolean>) => {
const toggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -81,9 +80,9 @@ export const builtinToolbarConfig = {
return html`${keyed( return html`${keyed(
model, model,
html`<affine-card-style-dropdown-menu html`<affine-card-style-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.style=${model.props.style$} .style=${model.props.style$}
></affine-card-style-dropdown-menu>` ></affine-card-style-dropdown-menu>`
)}`; )}`;

View File

@@ -119,7 +119,7 @@ export const builtinToolbarConfig = {
if (!model) return null; if (!model) return null;
const actions = this.actions.map(action => ({ ...action })); const actions = this.actions.map(action => ({ ...action }));
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -132,9 +132,9 @@ export const builtinToolbarConfig = {
return html`${keyed( return html`${keyed(
model, model,
html`<affine-view-dropdown-menu html`<affine-view-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.viewType$=${signal(actions[1].label)} .viewType$=${signal(actions[1].label)}
></affine-view-dropdown-menu>` ></affine-view-dropdown-menu>`
)}`; )}`;
@@ -168,7 +168,7 @@ export const builtinToolbarConfig = {
}); });
}, },
})) satisfies ToolbarAction[]; })) satisfies ToolbarAction[];
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -181,9 +181,9 @@ export const builtinToolbarConfig = {
return html`${keyed( return html`${keyed(
model, model,
html`<affine-card-style-dropdown-menu html`<affine-card-style-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.style$=${model.props.style$} .style$=${model.props.style$}
></affine-card-style-dropdown-menu>` ></affine-card-style-dropdown-menu>`
)}`; )}`;

View File

@@ -155,8 +155,7 @@ export const builtinToolbarConfig = {
if (!model) return null; if (!model) return null;
const actions = this.actions.map(action => ({ ...action })); const actions = this.actions.map(action => ({ ...action }));
const onToggle = (e: CustomEvent<boolean>) => {
const toggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -169,9 +168,9 @@ export const builtinToolbarConfig = {
return html`${keyed( return html`${keyed(
model, model,
html`<affine-view-dropdown-menu html`<affine-view-dropdown-menu
@toggle=${onToggle}
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle}
.viewType$=${signal(actions[2].label)} .viewType$=${signal(actions[2].label)}
></affine-view-dropdown-menu>` ></affine-view-dropdown-menu>`
)}`; )}`;

View File

@@ -1,11 +0,0 @@
import type { ToolbarModuleConfig } from '@blocksuite/affine-shared/services';
export const builtinAttachmentToolbarConfig = {
actions: [
{
id: 'a.test',
label: 'Attachment',
run() {},
},
],
} as const satisfies ToolbarModuleConfig;

View File

@@ -2,7 +2,6 @@ import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { BlockFlavourIdentifier } from '@blocksuite/block-std'; import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import type { ExtensionType } from '@blocksuite/store'; import type { ExtensionType } from '@blocksuite/store';
import { builtinAttachmentToolbarConfig } from './attachment';
import { builtinBookmarkToolbarConfig } from './bookmark'; import { builtinBookmarkToolbarConfig } from './bookmark';
import { builtinBrushToolbarConfig } from './brush'; import { builtinBrushToolbarConfig } from './brush';
import { builtinConnectorToolbarConfig } from './connector'; import { builtinConnectorToolbarConfig } from './connector';
@@ -17,11 +16,6 @@ import { builtinShapeToolbarConfig } from './shape';
import { builtinTextToolbarConfig } from './text'; import { builtinTextToolbarConfig } from './text';
export const EdgelessElementToolbarExtension: ExtensionType[] = [ export const EdgelessElementToolbarExtension: ExtensionType[] = [
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:attachment'),
config: builtinAttachmentToolbarConfig,
}),
ToolbarModuleExtension({ ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:bookmark'), id: BlockFlavourIdentifier('affine:surface:bookmark'),
config: builtinBookmarkToolbarConfig, config: builtinBookmarkToolbarConfig,

View File

@@ -21,8 +21,10 @@ import { ifDefined } from 'lit-html/directives/if-defined.js';
import { repeat } from 'lit-html/directives/repeat.js'; import { repeat } from 'lit-html/directives/repeat.js';
import { import {
EmbedCardDarkCubeIcon,
EmbedCardDarkHorizontalIcon, EmbedCardDarkHorizontalIcon,
EmbedCardDarkListIcon, EmbedCardDarkListIcon,
EmbedCardLightCubeIcon,
EmbedCardLightHorizontalIcon, EmbedCardLightHorizontalIcon,
EmbedCardLightListIcon, EmbedCardLightListIcon,
} from '../icons'; } from '../icons';
@@ -30,11 +32,15 @@ import {
const cardStyleMap: Record<ColorScheme, Record<string, TemplateResult>> = { const cardStyleMap: Record<ColorScheme, Record<string, TemplateResult>> = {
light: { light: {
horizontal: EmbedCardLightHorizontalIcon, horizontal: EmbedCardLightHorizontalIcon,
horizontalThin: EmbedCardLightListIcon,
list: EmbedCardLightListIcon, list: EmbedCardLightListIcon,
cubeThick: EmbedCardLightCubeIcon,
}, },
dark: { dark: {
horizontal: EmbedCardDarkHorizontalIcon, horizontal: EmbedCardDarkHorizontalIcon,
horizontalThin: EmbedCardDarkListIcon,
list: EmbedCardDarkListIcon, list: EmbedCardDarkListIcon,
cubeThick: EmbedCardDarkCubeIcon,
}, },
}; };
@@ -53,9 +59,6 @@ export class CardStyleDropdownMenu extends SignalWatcher(ShadowlessElement) {
@property({ attribute: false }) @property({ attribute: false })
accessor style$!: Signal<string> | ReadonlySignal<string>; accessor style$!: Signal<string> | ReadonlySignal<string>;
@property({ attribute: false })
accessor toggle: ((e: CustomEvent<boolean>) => void) | undefined;
icons$ = computed( icons$ = computed(
() => cardStyleMap[this.context.themeProvider.theme$.value] () => cardStyleMap[this.context.themeProvider.theme$.value]
); );
@@ -64,14 +67,12 @@ export class CardStyleDropdownMenu extends SignalWatcher(ShadowlessElement) {
const { const {
actions, actions,
context, context,
toggle,
style$: { value: style }, style$: { value: style },
icons$: { value: icons }, icons$: { value: icons },
} = this; } = this;
return html` return html`
<editor-menu-button <editor-menu-button
@toggle=${toggle}
.contentPadding="${'8px'}" .contentPadding="${'8px'}"
.button=${html` .button=${html`
<editor-icon-button <editor-icon-button
@@ -88,12 +89,13 @@ export class CardStyleDropdownMenu extends SignalWatcher(ShadowlessElement) {
action => action.id, action => action.id,
({ id, label, icon, disabled, run }) => html` ({ id, label, icon, disabled, run }) => html`
<editor-icon-button <editor-icon-button
aria-label="${label}" aria-label="${ifDefined(label)}"
data-testid="${id}" data-testid="${id}"
.tooltip="${label}" .tooltip="${label}"
.activeMode="${'border'}" .activeMode="${'border'}"
.iconContainerWidth="${'76px'}" .iconContainerWidth="${'76px'}"
.iconContainerHeight="${'76px'}" .iconContainerHeight="${'76px'}"
.justify="${'center'}"
?active="${id === style}" ?active="${id === style}"
?disabled="${ifDefined(disabled)}" ?disabled="${ifDefined(disabled)}"
@click=${() => run?.(context)} @click=${() => run?.(context)}

View File

@@ -30,20 +30,15 @@ export class ViewDropdownMenu extends SignalWatcher(ShadowlessElement) {
@property({ attribute: false }) @property({ attribute: false })
accessor viewType$!: Signal<string> | ReadonlySignal<string>; accessor viewType$!: Signal<string> | ReadonlySignal<string>;
@property({ attribute: false })
accessor toggle: ((e: CustomEvent<boolean>) => void) | undefined;
override render() { override render() {
const { const {
actions, actions,
context, context,
toggle,
viewType$: { value: viewType }, viewType$: { value: viewType },
} = this; } = this;
return html` return html`
<editor-menu-button <editor-menu-button
@toggle=${toggle}
.contentPadding="${'8px'}" .contentPadding="${'8px'}"
.button=${html` .button=${html`
<editor-icon-button <editor-icon-button
@@ -67,7 +62,7 @@ export class ViewDropdownMenu extends SignalWatcher(ShadowlessElement) {
action => action.id, action => action.id,
({ id, label, disabled, run }) => html` ({ id, label, disabled, run }) => html`
<editor-menu-action <editor-menu-action
aria-label="${label}" aria-label="${ifDefined(label)}"
data-testid="${`link-to-${id}`}" data-testid="${`link-to-${id}`}"
?data-selected="${label === viewType}" ?data-selected="${label === viewType}"
?disabled="${ifDefined( ?disabled="${ifDefined(

View File

@@ -260,7 +260,7 @@ export const builtinInlineLinkToolbarConfig = {
const actions = this.actions.map(action => ({ ...action })); const actions = this.actions.map(action => ({ ...action }));
const viewType$ = signal(actions[0].label); const viewType$ = signal(actions[0].label);
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -275,7 +275,7 @@ export const builtinInlineLinkToolbarConfig = {
html`<affine-view-dropdown-menu html`<affine-view-dropdown-menu
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle} .onToggle=${onToggle}
.viewType$=${viewType$} .viewType$=${viewType$}
></affine-view-dropdown-menu>` ></affine-view-dropdown-menu>`
)}`; )}`;

View File

@@ -184,7 +184,7 @@ export const builtinInlineReferenceToolbarConfig = {
const actions = this.actions.map(action => ({ ...action })); const actions = this.actions.map(action => ({ ...action }));
const viewType$ = signal(actions[0].label); const viewType$ = signal(actions[0].label);
const toggle = (e: CustomEvent<boolean>) => { const onToggle = (e: CustomEvent<boolean>) => {
const opened = e.detail; const opened = e.detail;
if (!opened) return; if (!opened) return;
@@ -199,7 +199,7 @@ export const builtinInlineReferenceToolbarConfig = {
html`<affine-view-dropdown-menu html`<affine-view-dropdown-menu
.actions=${actions} .actions=${actions}
.context=${ctx} .context=${ctx}
.toggle=${toggle} .onToggle=${onToggle}
.viewType$=${viewType$} .viewType$=${viewType$}
></affine-view-dropdown-menu>` ></affine-view-dropdown-menu>`
)}`; )}`;

View File

@@ -128,7 +128,7 @@ abstract class ToolbarContextBase {
); );
} }
getSurfaceElementsByType<M extends abstract new (...args: any) => any>( getSurfaceModelsByType<M extends abstract new (...args: any) => any>(
klass: M klass: M
) { ) {
if (this.hasSelectedSurfaceModels) { if (this.hasSelectedSurfaceModels) {
@@ -227,8 +227,14 @@ abstract class ToolbarContextBase {
return this.std.getOptional(TelemetryProvider); return this.std.getOptional(TelemetryProvider);
} }
track = (...args: Parameters<TelemetryService['track']>) => { track = (...[name, props]: Parameters<TelemetryService['track']>) => {
this.telemetryProvider?.track(...args); const segment = this.hasSelectedSurfaceModels ? 'whiteboard' : 'doc';
this.telemetryProvider?.track(name, {
segment,
page: `${segment} editor`,
module: 'toolbar',
...props,
});
}; };
} }

View File

@@ -11,6 +11,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@blocksuite/affine-block-database": "workspace:*", "@blocksuite/affine-block-database": "workspace:*",
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-block-table": "workspace:*", "@blocksuite/affine-block-table": "workspace:*",
"@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-model": "workspace:*",

View File

@@ -1,4 +1,5 @@
import { DatabaseSelection } from '@blocksuite/affine-block-database'; import { DatabaseSelection } from '@blocksuite/affine-block-database';
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface';
import { TableSelection } from '@blocksuite/affine-block-table'; import { TableSelection } from '@blocksuite/affine-block-table';
import { EditorToolbar } from '@blocksuite/affine-components/toolbar'; import { EditorToolbar } from '@blocksuite/affine-components/toolbar';
import { import {
@@ -437,7 +438,7 @@ export class AffineToolbarWidget extends WidgetComponent {
const eventOptions = { passive: false }; const eventOptions = { passive: false };
this.handleEvent('dragStart', () => { this.handleEvent('dragStart', () => {
dragStart(); dragStart();
host.addEventListener('pointerup', dragEnd, { once: true }); document.addEventListener('pointerup', dragEnd, { once: true });
}); });
this.handleEvent('nativeDrop', dragEnd); this.handleEvent('nativeDrop', dragEnd);
disposables.addFromEvent(host, 'dragenter', dragStart, eventOptions); disposables.addFromEvent(host, 'dragenter', dragStart, eventOptions);
@@ -445,7 +446,7 @@ export class AffineToolbarWidget extends WidgetComponent {
host, host,
'dragleave', 'dragleave',
throttle( throttle(
event => { (event: DragEvent) => {
const { x, y, target } = event; const { x, y, target } = event;
if (target === this) return; if (target === this) return;
const rect = host.getBoundingClientRect(); const rect = host.getBoundingClientRect();
@@ -464,7 +465,12 @@ export class AffineToolbarWidget extends WidgetComponent {
eventOptions eventOptions
); );
// Handles element when hovering // Handles elements when resizing
const edgelessSlots = std.get(EdgelessLegacySlotIdentifier);
disposables.add(edgelessSlots.elementResizeStart.subscribe(dragStart));
disposables.add(edgelessSlots.elementResizeEnd.subscribe(dragEnd));
// Handles elements when hovering
disposables.add( disposables.add(
message$.subscribe(data => { message$.subscribe(data => {
if ( if (
@@ -501,7 +507,7 @@ export class AffineToolbarWidget extends WidgetComponent {
const value = flags.value$.value; const value = flags.value$.value;
// Hides toolbar // Hides toolbar
if (value === Flag.None || flags.check(Flag.Hiding, value)) { if (Flag.None === value || flags.check(Flag.Hiding, value)) {
if (toolbar.dataset.open) delete toolbar.dataset.open; if (toolbar.dataset.open) delete toolbar.dataset.open;
return; return;
} }
@@ -530,12 +536,8 @@ export class AffineToolbarWidget extends WidgetComponent {
const value = flags.value$.value; const value = flags.value$.value;
if ( if (!context.activated) return;
!context.activated || if (Flag.None === value || flags.contains(Flag.Hiding, value)) return;
Flag.None === value ||
flags.contains(Flag.Hiding, value)
)
return;
const build = referenceElement$.value; const build = referenceElement$.value;
const referenceElement = build?.(); const referenceElement = build?.();

View File

@@ -8,6 +8,7 @@
"include": ["./src"], "include": ["./src"],
"references": [ "references": [
{ "path": "../../blocks/block-database" }, { "path": "../../blocks/block-database" },
{ "path": "../../blocks/block-surface" },
{ "path": "../../blocks/block-table" }, { "path": "../../blocks/block-table" },
{ "path": "../../components" }, { "path": "../../components" },
{ "path": "../../model" }, { "path": "../../model" },

View File

@@ -575,6 +575,7 @@ export const PackageList = [
name: '@blocksuite/affine-widget-toolbar', name: '@blocksuite/affine-widget-toolbar',
workspaceDependencies: [ workspaceDependencies: [
'blocksuite/affine/blocks/block-database', 'blocksuite/affine/blocks/block-database',
'blocksuite/affine/blocks/block-surface',
'blocksuite/affine/blocks/block-table', 'blocksuite/affine/blocks/block-table',
'blocksuite/affine/components', 'blocksuite/affine/components',
'blocksuite/affine/model', 'blocksuite/affine/model',

View File

@@ -3234,6 +3234,7 @@ __metadata:
resolution: "@blocksuite/affine-widget-toolbar@workspace:blocksuite/affine/widgets/widget-toolbar" resolution: "@blocksuite/affine-widget-toolbar@workspace:blocksuite/affine/widgets/widget-toolbar"
dependencies: dependencies:
"@blocksuite/affine-block-database": "workspace:*" "@blocksuite/affine-block-database": "workspace:*"
"@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-block-table": "workspace:*" "@blocksuite/affine-block-table": "workspace:*"
"@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-model": "workspace:*"