refactor(editor): edgeless bookmark toolbar config extension (#10711)
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
export * from '@blocksuite/affine-components/size-dropdown-menu';
|
||||||
@@ -32,6 +32,7 @@ import { IconButton } from '@blocksuite/affine-components/icon-button';
|
|||||||
import { effects as componentLinkPreviewEffects } from '@blocksuite/affine-components/link-preview';
|
import { effects as componentLinkPreviewEffects } from '@blocksuite/affine-components/link-preview';
|
||||||
import { effects as componentLinkedDocTitleEffects } from '@blocksuite/affine-components/linked-doc-title';
|
import { effects as componentLinkedDocTitleEffects } from '@blocksuite/affine-components/linked-doc-title';
|
||||||
import { effects as componentPortalEffects } from '@blocksuite/affine-components/portal';
|
import { effects as componentPortalEffects } from '@blocksuite/affine-components/portal';
|
||||||
|
import { effects as componentSizeDropdownMenuEffects } from '@blocksuite/affine-components/size-dropdown-menu';
|
||||||
import { SmoothCorner } from '@blocksuite/affine-components/smooth-corner';
|
import { SmoothCorner } from '@blocksuite/affine-components/smooth-corner';
|
||||||
import { effects as componentToggleButtonEffects } from '@blocksuite/affine-components/toggle-button';
|
import { effects as componentToggleButtonEffects } from '@blocksuite/affine-components/toggle-button';
|
||||||
import { ToggleSwitch } from '@blocksuite/affine-components/toggle-switch';
|
import { ToggleSwitch } from '@blocksuite/affine-components/toggle-switch';
|
||||||
@@ -147,6 +148,7 @@ export function effects() {
|
|||||||
componentHighlightDropdownMenuEffects();
|
componentHighlightDropdownMenuEffects();
|
||||||
componentViewDropdownMenuEffects();
|
componentViewDropdownMenuEffects();
|
||||||
componentTooltipContentWithShortcutEffects();
|
componentTooltipContentWithShortcutEffects();
|
||||||
|
componentSizeDropdownMenuEffects();
|
||||||
|
|
||||||
widgetScrollAnchoringEffects();
|
widgetScrollAnchoringEffects();
|
||||||
widgetFrameTitleEffects();
|
widgetFrameTitleEffects();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blocksuite/affine-block-embed": "workspace:*",
|
"@blocksuite/affine-block-embed": "workspace:*",
|
||||||
|
"@blocksuite/affine-block-surface": "workspace:*",
|
||||||
"@blocksuite/affine-components": "workspace:*",
|
"@blocksuite/affine-components": "workspace:*",
|
||||||
"@blocksuite/affine-model": "workspace:*",
|
"@blocksuite/affine-model": "workspace:*",
|
||||||
"@blocksuite/affine-shared": "workspace:*",
|
"@blocksuite/affine-shared": "workspace:*",
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { BookmarkBlockSchema } from '@blocksuite/affine-model';
|
import { BookmarkBlockSchema } from '@blocksuite/affine-model';
|
||||||
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
|
import { BlockViewExtension, FlavourExtension } from '@blocksuite/block-std';
|
||||||
import {
|
|
||||||
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 { BookmarkBlockAdapterExtensions } from './adapters/extension';
|
import { BookmarkBlockAdapterExtensions } from './adapters/extension';
|
||||||
import { BookmarkSlashMenuConfigExtension } from './configs/slash-menu';
|
import { BookmarkSlashMenuConfigExtension } from './configs/slash-menu';
|
||||||
import { builtinToolbarConfig } from './configs/toolbar';
|
import { createBuiltinToolbarConfigExtension } from './configs/toolbar';
|
||||||
|
|
||||||
const flavour = BookmarkBlockSchema.model.flavour;
|
const flavour = BookmarkBlockSchema.model.flavour;
|
||||||
|
|
||||||
@@ -22,9 +17,6 @@ export const BookmarkBlockSpec: ExtensionType[] = [
|
|||||||
: literal`affine-bookmark`;
|
: literal`affine-bookmark`;
|
||||||
}),
|
}),
|
||||||
BookmarkBlockAdapterExtensions,
|
BookmarkBlockAdapterExtensions,
|
||||||
ToolbarModuleExtension({
|
createBuiltinToolbarConfigExtension(flavour),
|
||||||
id: BlockFlavourIdentifier(flavour),
|
|
||||||
config: builtinToolbarConfig,
|
|
||||||
}),
|
|
||||||
BookmarkSlashMenuConfigExtension,
|
BookmarkSlashMenuConfigExtension,
|
||||||
].flat();
|
].flat();
|
||||||
|
|||||||
@@ -1,16 +1,29 @@
|
|||||||
import { EmbedIframeService } from '@blocksuite/affine-block-embed';
|
import { EmbedIframeService } from '@blocksuite/affine-block-embed';
|
||||||
|
import { reassociateConnectorsCommand } from '@blocksuite/affine-block-surface';
|
||||||
import { toast } from '@blocksuite/affine-components/toast';
|
import { toast } from '@blocksuite/affine-components/toast';
|
||||||
import { BookmarkBlockModel } from '@blocksuite/affine-model';
|
import {
|
||||||
|
BookmarkBlockModel,
|
||||||
|
BookmarkStyles,
|
||||||
|
type EmbedCardStyle,
|
||||||
|
} from '@blocksuite/affine-model';
|
||||||
|
import {
|
||||||
|
EMBED_CARD_HEIGHT,
|
||||||
|
EMBED_CARD_WIDTH,
|
||||||
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
EmbedOptionProvider,
|
EmbedOptionProvider,
|
||||||
FeatureFlagService,
|
FeatureFlagService,
|
||||||
|
type LinkEventType,
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
type ToolbarActionGroup,
|
type ToolbarActionGroup,
|
||||||
|
type ToolbarContext,
|
||||||
type ToolbarModuleConfig,
|
type ToolbarModuleConfig,
|
||||||
|
ToolbarModuleExtension,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { getBlockProps } from '@blocksuite/affine-shared/utils';
|
import { getBlockProps } from '@blocksuite/affine-shared/utils';
|
||||||
import { BlockSelection } from '@blocksuite/block-std';
|
import { BlockFlavourIdentifier, BlockSelection } from '@blocksuite/block-std';
|
||||||
|
import { Bound } from '@blocksuite/global/gfx';
|
||||||
import {
|
import {
|
||||||
CaptionIcon,
|
CaptionIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
@@ -18,8 +31,8 @@ import {
|
|||||||
DuplicateIcon,
|
DuplicateIcon,
|
||||||
ResetIcon,
|
ResetIcon,
|
||||||
} from '@blocksuite/icons/lit';
|
} from '@blocksuite/icons/lit';
|
||||||
import { Slice, Text } from '@blocksuite/store';
|
import { type ExtensionType, Slice, Text } from '@blocksuite/store';
|
||||||
import { signal } from '@preact/signals-core';
|
import { computed, signal } from '@preact/signals-core';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { keyed } from 'lit/directives/keyed.js';
|
import { keyed } from 'lit/directives/keyed.js';
|
||||||
import * as Y from 'yjs';
|
import * as Y from 'yjs';
|
||||||
@@ -27,26 +40,62 @@ import * as Y from 'yjs';
|
|||||||
import { BookmarkBlockComponent } from '../bookmark-block';
|
import { BookmarkBlockComponent } from '../bookmark-block';
|
||||||
|
|
||||||
const trackBaseProps = {
|
const trackBaseProps = {
|
||||||
segment: 'doc',
|
|
||||||
page: 'doc editor',
|
|
||||||
module: 'toolbar',
|
|
||||||
category: 'bookmark',
|
category: 'bookmark',
|
||||||
type: 'card view',
|
type: 'card view',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const builtinToolbarConfig = {
|
const previewAction = {
|
||||||
|
id: 'a.preview',
|
||||||
|
content(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
|
if (!model) return null;
|
||||||
|
|
||||||
|
const { url } = model.props;
|
||||||
|
|
||||||
|
return html`<affine-link-preview .url=${url}></affine-link-preview>`;
|
||||||
|
},
|
||||||
|
} satisfies ToolbarAction;
|
||||||
|
|
||||||
|
const captionAction = {
|
||||||
|
id: 'd.caption',
|
||||||
|
tooltip: 'Caption',
|
||||||
|
icon: CaptionIcon(),
|
||||||
|
run(ctx) {
|
||||||
|
const block = ctx.getCurrentBlockByType(BookmarkBlockComponent);
|
||||||
|
block?.captionEditor?.show();
|
||||||
|
|
||||||
|
ctx.track('OpenedCaptionEditor', {
|
||||||
|
...trackBaseProps,
|
||||||
|
control: 'add caption',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
} satisfies ToolbarAction;
|
||||||
|
|
||||||
|
const createOnToggleFn =
|
||||||
|
(
|
||||||
|
ctx: ToolbarContext,
|
||||||
|
name: Extract<
|
||||||
|
LinkEventType,
|
||||||
|
| 'OpenedViewSelector'
|
||||||
|
| 'OpenedCardStyleSelector'
|
||||||
|
| 'OpenedCardScaleSelector'
|
||||||
|
>,
|
||||||
|
control: string
|
||||||
|
) =>
|
||||||
|
(e: CustomEvent<boolean>) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const opened = e.detail;
|
||||||
|
if (!opened) return;
|
||||||
|
|
||||||
|
ctx.track(name, {
|
||||||
|
...trackBaseProps,
|
||||||
|
control,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const builtinToolbarConfig = {
|
||||||
actions: [
|
actions: [
|
||||||
{
|
previewAction,
|
||||||
id: 'a.preview',
|
|
||||||
content(ctx) {
|
|
||||||
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
|
||||||
if (!model) return null;
|
|
||||||
|
|
||||||
const { url } = model.props;
|
|
||||||
|
|
||||||
return html`<affine-link-preview .url=${url}></affine-link-preview>`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'b.conversions',
|
id: 'b.conversions',
|
||||||
actions: [
|
actions: [
|
||||||
@@ -181,15 +230,12 @@ 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 viewType$ = signal(actions[1].label);
|
||||||
const opened = e.detail;
|
const onToggle = createOnToggleFn(
|
||||||
if (!opened) return;
|
ctx,
|
||||||
|
'OpenedViewSelector',
|
||||||
ctx.track('OpenedViewSelector', {
|
'switch view'
|
||||||
...trackBaseProps,
|
);
|
||||||
control: 'switch view',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return html`${keyed(
|
return html`${keyed(
|
||||||
model,
|
model,
|
||||||
@@ -197,7 +243,7 @@ export const builtinToolbarConfig = {
|
|||||||
@toggle=${onToggle}
|
@toggle=${onToggle}
|
||||||
.actions=${actions}
|
.actions=${actions}
|
||||||
.context=${ctx}
|
.context=${ctx}
|
||||||
.viewType$=${signal(actions[1].label)}
|
.viewType$=${viewType$}
|
||||||
></affine-view-dropdown-menu>`
|
></affine-view-dropdown-menu>`
|
||||||
)}`;
|
)}`;
|
||||||
},
|
},
|
||||||
@@ -230,16 +276,11 @@ export const builtinToolbarConfig = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
})) satisfies ToolbarAction[];
|
})) satisfies ToolbarAction[];
|
||||||
|
const onToggle = createOnToggleFn(
|
||||||
const onToggle = (e: CustomEvent<boolean>) => {
|
ctx,
|
||||||
const opened = e.detail;
|
'OpenedCardStyleSelector',
|
||||||
if (!opened) return;
|
'switch card style'
|
||||||
|
);
|
||||||
ctx.track('OpenedCardStyleSelector', {
|
|
||||||
...trackBaseProps,
|
|
||||||
control: 'switch card style',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return html`${keyed(
|
return html`${keyed(
|
||||||
model,
|
model,
|
||||||
@@ -252,20 +293,7 @@ export const builtinToolbarConfig = {
|
|||||||
)}`;
|
)}`;
|
||||||
},
|
},
|
||||||
} satisfies ToolbarActionGroup<ToolbarAction>,
|
} satisfies ToolbarActionGroup<ToolbarAction>,
|
||||||
{
|
captionAction,
|
||||||
id: 'd.caption',
|
|
||||||
tooltip: 'Caption',
|
|
||||||
icon: CaptionIcon(),
|
|
||||||
run(ctx) {
|
|
||||||
const block = ctx.getCurrentBlockByType(BookmarkBlockComponent);
|
|
||||||
block?.captionEditor?.show();
|
|
||||||
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
|
||||||
...trackBaseProps,
|
|
||||||
control: 'add caption',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
@@ -331,3 +359,235 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as const satisfies ToolbarModuleConfig;
|
} as const satisfies ToolbarModuleConfig;
|
||||||
|
|
||||||
|
const builtinSurfaceToolbarConfig = {
|
||||||
|
actions: [
|
||||||
|
previewAction,
|
||||||
|
{
|
||||||
|
id: 'b.conversions',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
id: 'card',
|
||||||
|
label: 'Card view',
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'embed',
|
||||||
|
label: 'Embed view',
|
||||||
|
run(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
|
if (!model) return;
|
||||||
|
|
||||||
|
const { id: oldId, xywh, parent } = model;
|
||||||
|
const { url, caption } = model.props;
|
||||||
|
const options = ctx.std
|
||||||
|
.get(EmbedOptionProvider)
|
||||||
|
.getEmbedBlockOptions(url);
|
||||||
|
|
||||||
|
if (options?.viewType !== 'embed') return;
|
||||||
|
|
||||||
|
const { flavour, styles } = options;
|
||||||
|
let { style } = model.props;
|
||||||
|
|
||||||
|
if (!styles.includes(style)) {
|
||||||
|
style = styles[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const bounds = Bound.deserialize(xywh);
|
||||||
|
bounds.w = EMBED_CARD_WIDTH[style];
|
||||||
|
bounds.h = EMBED_CARD_HEIGHT[style];
|
||||||
|
|
||||||
|
const newId = ctx.store.addBlock(
|
||||||
|
flavour,
|
||||||
|
{ url, caption, style, xywh: bounds.serialize() },
|
||||||
|
parent
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.command.exec(reassociateConnectorsCommand, { oldId, newId });
|
||||||
|
|
||||||
|
ctx.store.deleteBlock(model);
|
||||||
|
|
||||||
|
// Selects new block
|
||||||
|
ctx.gfx.selection.set({ editing: false, elements: [newId] });
|
||||||
|
|
||||||
|
ctx.track('SelectedView', {
|
||||||
|
...trackBaseProps,
|
||||||
|
control: 'select view',
|
||||||
|
type: 'embed view',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
when(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
|
if (!model) return false;
|
||||||
|
|
||||||
|
const { url } = model.props;
|
||||||
|
const options = ctx.std
|
||||||
|
.get(EmbedOptionProvider)
|
||||||
|
.getEmbedBlockOptions(url);
|
||||||
|
|
||||||
|
return options?.viewType === 'embed';
|
||||||
|
},
|
||||||
|
content(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
|
if (!model) return null;
|
||||||
|
|
||||||
|
const actions = this.actions.map(action => ({ ...action }));
|
||||||
|
const viewType$ = signal('Card view');
|
||||||
|
const onToggle = createOnToggleFn(
|
||||||
|
ctx,
|
||||||
|
'OpenedViewSelector',
|
||||||
|
'switch view'
|
||||||
|
);
|
||||||
|
|
||||||
|
return html`${keyed(
|
||||||
|
model,
|
||||||
|
html`<affine-view-dropdown-menu
|
||||||
|
@toggle=${onToggle}
|
||||||
|
.actions=${actions}
|
||||||
|
.context=${ctx}
|
||||||
|
.viewType$=${viewType$}
|
||||||
|
></affine-view-dropdown-menu>`
|
||||||
|
)}`;
|
||||||
|
},
|
||||||
|
} satisfies ToolbarActionGroup<ToolbarAction>,
|
||||||
|
{
|
||||||
|
id: 'b.style',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
id: 'horizontal',
|
||||||
|
label: 'Large horizontal style',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'list',
|
||||||
|
label: 'Small horizontal style',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'vertical',
|
||||||
|
label: 'Large vertical style',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cube',
|
||||||
|
label: 'Small vertical style',
|
||||||
|
},
|
||||||
|
].filter(action => BookmarkStyles.includes(action.id as EmbedCardStyle)),
|
||||||
|
content(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
|
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,
|
||||||
|
control: 'select card style',
|
||||||
|
type: style,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
})) satisfies ToolbarAction[];
|
||||||
|
const style$ = model.props.style$;
|
||||||
|
const onToggle = createOnToggleFn(
|
||||||
|
ctx,
|
||||||
|
'OpenedCardStyleSelector',
|
||||||
|
'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>,
|
||||||
|
{
|
||||||
|
...captionAction,
|
||||||
|
id: 'c.caption',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'd.scale',
|
||||||
|
content(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
|
if (!model) return null;
|
||||||
|
|
||||||
|
const scale$ = computed(() => {
|
||||||
|
const {
|
||||||
|
xywh$: { value: xywh },
|
||||||
|
} = model;
|
||||||
|
const {
|
||||||
|
style$: { value: style },
|
||||||
|
} = model.props;
|
||||||
|
const bounds = Bound.deserialize(xywh);
|
||||||
|
const height = EMBED_CARD_HEIGHT[style];
|
||||||
|
return Math.round(100 * (bounds.h / height));
|
||||||
|
});
|
||||||
|
const onSelect = (e: CustomEvent<number>) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
const scale = e.detail / 100;
|
||||||
|
|
||||||
|
const bounds = Bound.deserialize(model.xywh);
|
||||||
|
const style = model.props.style;
|
||||||
|
bounds.w = EMBED_CARD_WIDTH[style] * scale;
|
||||||
|
bounds.h = EMBED_CARD_HEIGHT[style] * scale;
|
||||||
|
const xywh = bounds.serialize();
|
||||||
|
|
||||||
|
ctx.store.updateBlock(model, { xywh });
|
||||||
|
|
||||||
|
ctx.track('SelectedCardScale', {
|
||||||
|
...trackBaseProps,
|
||||||
|
control: 'select card scale',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const onToggle = createOnToggleFn(
|
||||||
|
ctx,
|
||||||
|
'OpenedCardScaleSelector',
|
||||||
|
'switch card scale'
|
||||||
|
);
|
||||||
|
const format = (value: number) => `${value}%`;
|
||||||
|
|
||||||
|
return html`${keyed(
|
||||||
|
model,
|
||||||
|
html`<affine-size-dropdown-menu
|
||||||
|
@select=${onSelect}
|
||||||
|
@toggle=${onToggle}
|
||||||
|
.format=${format}
|
||||||
|
.size$=${scale$}
|
||||||
|
></affine-size-dropdown-menu>`
|
||||||
|
)}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
when: ctx => ctx.getSurfaceModelsByType(BookmarkBlockModel).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,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"include": ["./src"],
|
"include": ["./src"],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../block-embed" },
|
{ "path": "../block-embed" },
|
||||||
|
{ "path": "../block-surface" },
|
||||||
{ "path": "../../components" },
|
{ "path": "../../components" },
|
||||||
{ "path": "../../model" },
|
{ "path": "../../model" },
|
||||||
{ "path": "../../shared" },
|
{ "path": "../../shared" },
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ function format(scale: number) {
|
|||||||
return `${scale}%`;
|
return `${scale}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(@fundon): remove it after refacting is completed
|
||||||
export class EdgelessScalePanel extends LitElement {
|
export class EdgelessScalePanel extends LitElement {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
:host {
|
:host {
|
||||||
@@ -28,7 +29,7 @@ export class EdgelessScalePanel extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.scale-input {
|
.scale-input {
|
||||||
display: flx;
|
display: flex;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
border: 0.5px solid var(--affine-border-color);
|
border: 0.5px solid var(--affine-border-color);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import type { ToolbarModuleConfig } from '@blocksuite/affine-shared/services';
|
|
||||||
|
|
||||||
export const builtinBookmarkToolbarConfig = {
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
id: 'a.test',
|
|
||||||
label: 'Bookmark',
|
|
||||||
run() {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
} as const satisfies ToolbarModuleConfig;
|
|
||||||
@@ -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 { builtinBookmarkToolbarConfig } from './bookmark';
|
|
||||||
import { builtinBrushToolbarConfig } from './brush';
|
import { builtinBrushToolbarConfig } from './brush';
|
||||||
import { builtinConnectorToolbarConfig } from './connector';
|
import { builtinConnectorToolbarConfig } from './connector';
|
||||||
import { builtinEmbedToolbarConfig } from './embed';
|
import { builtinEmbedToolbarConfig } from './embed';
|
||||||
@@ -16,11 +15,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:bookmark'),
|
|
||||||
config: builtinBookmarkToolbarConfig,
|
|
||||||
}),
|
|
||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
id: BlockFlavourIdentifier('affine:surface:image'),
|
id: BlockFlavourIdentifier('affine:surface:image'),
|
||||||
config: builtinImageToolbarConfig,
|
config: builtinImageToolbarConfig,
|
||||||
|
|||||||
@@ -65,7 +65,8 @@
|
|||||||
"./view-dropdown-menu": "./src/view-dropdown-menu/index.ts",
|
"./view-dropdown-menu": "./src/view-dropdown-menu/index.ts",
|
||||||
"./card-style-dropdown-menu": "./src/card-style-dropdown-menu/index.ts",
|
"./card-style-dropdown-menu": "./src/card-style-dropdown-menu/index.ts",
|
||||||
"./highlight-dropdown-menu": "./src/highlight-dropdown-menu/index.ts",
|
"./highlight-dropdown-menu": "./src/highlight-dropdown-menu/index.ts",
|
||||||
"./tooltip-content-with-shortcut": "./src/tooltip-content-with-shortcut/index.ts"
|
"./tooltip-content-with-shortcut": "./src/tooltip-content-with-shortcut/index.ts",
|
||||||
|
"./size-dropdown-menu": "./src/size-dropdown-menu/index.ts"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"src",
|
"src",
|
||||||
|
|||||||
@@ -3,11 +3,7 @@ import {
|
|||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
ToolbarContext,
|
ToolbarContext,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import { PropTypes, requiredProperties } from '@blocksuite/block-std';
|
||||||
PropTypes,
|
|
||||||
requiredProperties,
|
|
||||||
ShadowlessElement,
|
|
||||||
} from '@blocksuite/block-std';
|
|
||||||
import { SignalWatcher } from '@blocksuite/global/lit';
|
import { SignalWatcher } from '@blocksuite/global/lit';
|
||||||
import { PaletteIcon } from '@blocksuite/icons/lit';
|
import { PaletteIcon } from '@blocksuite/icons/lit';
|
||||||
import {
|
import {
|
||||||
@@ -15,6 +11,7 @@ import {
|
|||||||
type ReadonlySignal,
|
type ReadonlySignal,
|
||||||
type Signal,
|
type Signal,
|
||||||
} from '@preact/signals-core';
|
} from '@preact/signals-core';
|
||||||
|
import { LitElement } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { html, type TemplateResult } from 'lit-html';
|
import { html, type TemplateResult } from 'lit-html';
|
||||||
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
||||||
@@ -24,23 +21,29 @@ import {
|
|||||||
EmbedCardDarkCubeIcon,
|
EmbedCardDarkCubeIcon,
|
||||||
EmbedCardDarkHorizontalIcon,
|
EmbedCardDarkHorizontalIcon,
|
||||||
EmbedCardDarkListIcon,
|
EmbedCardDarkListIcon,
|
||||||
|
EmbedCardDarkVerticalIcon,
|
||||||
EmbedCardLightCubeIcon,
|
EmbedCardLightCubeIcon,
|
||||||
EmbedCardLightHorizontalIcon,
|
EmbedCardLightHorizontalIcon,
|
||||||
EmbedCardLightListIcon,
|
EmbedCardLightListIcon,
|
||||||
|
EmbedCardLightVerticalIcon,
|
||||||
} from '../icons';
|
} from '../icons';
|
||||||
|
|
||||||
const cardStyleMap: Record<ColorScheme, Record<string, TemplateResult>> = {
|
const cardStyleMap: Record<ColorScheme, Record<string, TemplateResult>> = {
|
||||||
light: {
|
light: {
|
||||||
|
cube: EmbedCardLightCubeIcon,
|
||||||
|
cubeThick: EmbedCardLightCubeIcon,
|
||||||
horizontal: EmbedCardLightHorizontalIcon,
|
horizontal: EmbedCardLightHorizontalIcon,
|
||||||
horizontalThin: EmbedCardLightListIcon,
|
horizontalThin: EmbedCardLightListIcon,
|
||||||
list: EmbedCardLightListIcon,
|
list: EmbedCardLightListIcon,
|
||||||
cubeThick: EmbedCardLightCubeIcon,
|
vertical: EmbedCardLightVerticalIcon,
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
|
cube: EmbedCardDarkCubeIcon,
|
||||||
|
cubeThick: EmbedCardDarkCubeIcon,
|
||||||
horizontal: EmbedCardDarkHorizontalIcon,
|
horizontal: EmbedCardDarkHorizontalIcon,
|
||||||
horizontalThin: EmbedCardDarkListIcon,
|
horizontalThin: EmbedCardDarkListIcon,
|
||||||
list: EmbedCardDarkListIcon,
|
list: EmbedCardDarkListIcon,
|
||||||
cubeThick: EmbedCardDarkCubeIcon,
|
vertical: EmbedCardDarkVerticalIcon,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,7 +52,7 @@ const cardStyleMap: Record<ColorScheme, Record<string, TemplateResult>> = {
|
|||||||
context: PropTypes.instanceOf(ToolbarContext),
|
context: PropTypes.instanceOf(ToolbarContext),
|
||||||
style$: PropTypes.object,
|
style$: PropTypes.object,
|
||||||
})
|
})
|
||||||
export class CardStyleDropdownMenu extends SignalWatcher(ShadowlessElement) {
|
export class CardStyleDropdownMenu extends SignalWatcher(LitElement) {
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor actions!: ToolbarAction[];
|
accessor actions!: ToolbarAction[];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
import { stopPropagation } from '@blocksuite/affine-shared/utils';
|
||||||
|
import { PropTypes, requiredProperties } from '@blocksuite/block-std';
|
||||||
|
import { SignalWatcher } from '@blocksuite/global/lit';
|
||||||
|
import { ArrowDownSmallIcon, DoneIcon } from '@blocksuite/icons/lit';
|
||||||
|
import type { ReadonlySignal, Signal } from '@preact/signals-core';
|
||||||
|
import { css, html, LitElement } from 'lit';
|
||||||
|
import { property, query } from 'lit/decorators.js';
|
||||||
|
import { repeat } from 'lit-html/directives/repeat.js';
|
||||||
|
import { when } from 'lit-html/directives/when.js';
|
||||||
|
import clamp from 'lodash-es/clamp';
|
||||||
|
|
||||||
|
import type { EditorMenuButton } from '../toolbar';
|
||||||
|
|
||||||
|
type SizeItem = { key?: string | number; value: number };
|
||||||
|
|
||||||
|
const MIN_SIZE = 0;
|
||||||
|
const MAX_SIZE = 400;
|
||||||
|
const SIZE_LIST: SizeItem[] = [
|
||||||
|
{ value: 50 },
|
||||||
|
{ value: 100 },
|
||||||
|
{ value: 200 },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
@requiredProperties({
|
||||||
|
size$: PropTypes.object,
|
||||||
|
})
|
||||||
|
export class SizeDropdownMenu extends SignalWatcher(LitElement) {
|
||||||
|
static override styles = css`
|
||||||
|
div[data-orientation] {
|
||||||
|
width: 68px;
|
||||||
|
gap: 4px;
|
||||||
|
min-width: unset;
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor-menu-action {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([data-type='check']) editor-menu-action[data-selected] {
|
||||||
|
color: var(--affine-primary-color);
|
||||||
|
background-color: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: flex;
|
||||||
|
align-self: stretch;
|
||||||
|
border: 0.5px solid var(--affine-border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
outline-color: var(--affine-primary-color);
|
||||||
|
outline-width: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder {
|
||||||
|
color: var(--affine-placeholder-color);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor sizes: readonly SizeItem[] = SIZE_LIST;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor size$!: Signal<number> | ReadonlySignal<number>;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor maxSize: number = MAX_SIZE;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor minSize: number = MIN_SIZE;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor format: ((e: number) => string) | undefined;
|
||||||
|
|
||||||
|
@property({ attribute: 'data-type' })
|
||||||
|
accessor type: 'normal' | 'check' = 'normal';
|
||||||
|
|
||||||
|
clamp(value: number, min = this.minSize, max = this.maxSize) {
|
||||||
|
return clamp(value, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
select(value: number) {
|
||||||
|
const detail = this.clamp(value);
|
||||||
|
this.dispatchEvent(new CustomEvent('select', { detail }));
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly _onKeydown = (e: KeyboardEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (e.isComposing) return;
|
||||||
|
if (e.key !== 'Enter') return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
const input = e.target as HTMLInputElement;
|
||||||
|
const value = parseInt(input.value.trim());
|
||||||
|
// Handle edge case where user enters a non-number
|
||||||
|
if (isNaN(value)) {
|
||||||
|
input.value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle edge case when user enters a number that is out of range
|
||||||
|
this.select(value);
|
||||||
|
input.value = '';
|
||||||
|
|
||||||
|
this.menuButton.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
@query('editor-menu-button')
|
||||||
|
accessor menuButton!: EditorMenuButton;
|
||||||
|
|
||||||
|
override render() {
|
||||||
|
const {
|
||||||
|
sizes,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
size$: { value: size },
|
||||||
|
} = this;
|
||||||
|
const isCheckType = type === 'check';
|
||||||
|
const placeholder = format?.(Math.trunc(size)) ?? Math.trunc(size);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<editor-menu-button
|
||||||
|
.contentPadding="${'8px'}"
|
||||||
|
.button=${html`
|
||||||
|
<editor-icon-button
|
||||||
|
aria-label="Scale"
|
||||||
|
.tooltip="${'Scale'}"
|
||||||
|
.justify="${'space-between'}"
|
||||||
|
.labelHeight="${'20px'}"
|
||||||
|
.iconContainerWidth="${'65px'}"
|
||||||
|
>
|
||||||
|
<span class="label">${format?.(size) ?? size}</span>
|
||||||
|
${ArrowDownSmallIcon()}
|
||||||
|
</editor-icon-button>
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<div data-orientation="vertical">
|
||||||
|
${repeat(
|
||||||
|
sizes,
|
||||||
|
({ key, value }) => key ?? value,
|
||||||
|
({ key, value }) => html`
|
||||||
|
<editor-menu-action
|
||||||
|
aria-label="${key}"
|
||||||
|
?data-selected="${size === value}"
|
||||||
|
@click=${() => this.select(value)}
|
||||||
|
>
|
||||||
|
${key ?? format?.(value) ?? value}
|
||||||
|
${when(isCheckType && size === value, () => DoneIcon())}
|
||||||
|
</editor-menu-action>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
inputmode="numeric"
|
||||||
|
pattern="[0-9]*"
|
||||||
|
min="${this.minSize}"
|
||||||
|
max="${this.maxSize}"
|
||||||
|
placeholder="${placeholder}"
|
||||||
|
@keydown=${this._onKeydown}
|
||||||
|
@input=${stopPropagation}
|
||||||
|
@click=${stopPropagation}
|
||||||
|
@pointerdown=${stopPropagation}
|
||||||
|
@cut=${stopPropagation}
|
||||||
|
@copy=${stopPropagation}
|
||||||
|
@paste=${stopPropagation}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</editor-menu-button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'affine-size-dropdown-menu': SizeDropdownMenu;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { SizeDropdownMenu } from './dropdown-menu';
|
||||||
|
|
||||||
|
export * from './dropdown-menu';
|
||||||
|
|
||||||
|
export function effects() {
|
||||||
|
customElements.define('affine-size-dropdown-menu', SizeDropdownMenu);
|
||||||
|
}
|
||||||
@@ -2,14 +2,11 @@ import {
|
|||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
ToolbarContext,
|
ToolbarContext,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import { PropTypes, requiredProperties } from '@blocksuite/block-std';
|
||||||
PropTypes,
|
|
||||||
requiredProperties,
|
|
||||||
ShadowlessElement,
|
|
||||||
} from '@blocksuite/block-std';
|
|
||||||
import { SignalWatcher } from '@blocksuite/global/lit';
|
import { SignalWatcher } from '@blocksuite/global/lit';
|
||||||
import { ArrowDownSmallIcon } from '@blocksuite/icons/lit';
|
import { ArrowDownSmallIcon } from '@blocksuite/icons/lit';
|
||||||
import type { ReadonlySignal, Signal } from '@preact/signals-core';
|
import type { ReadonlySignal, Signal } from '@preact/signals-core';
|
||||||
|
import { LitElement } from 'lit';
|
||||||
import { property } from 'lit/decorators.js';
|
import { property } from 'lit/decorators.js';
|
||||||
import { html } from 'lit-html';
|
import { html } from 'lit-html';
|
||||||
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
||||||
@@ -20,7 +17,7 @@ import { repeat } from 'lit-html/directives/repeat.js';
|
|||||||
context: PropTypes.instanceOf(ToolbarContext),
|
context: PropTypes.instanceOf(ToolbarContext),
|
||||||
viewType$: PropTypes.object,
|
viewType$: PropTypes.object,
|
||||||
})
|
})
|
||||||
export class ViewDropdownMenu extends SignalWatcher(ShadowlessElement) {
|
export class ViewDropdownMenu extends SignalWatcher(LitElement) {
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor actions!: ToolbarAction[];
|
accessor actions!: ToolbarAction[];
|
||||||
|
|
||||||
@@ -43,6 +40,7 @@ export class ViewDropdownMenu extends SignalWatcher(ShadowlessElement) {
|
|||||||
.button=${html`
|
.button=${html`
|
||||||
<editor-icon-button
|
<editor-icon-button
|
||||||
aria-label="Switch view"
|
aria-label="Switch view"
|
||||||
|
.tooltip="${'Switch view'}"
|
||||||
.justify="${'space-between'}"
|
.justify="${'space-between'}"
|
||||||
.labelHeight="${'20px'}"
|
.labelHeight="${'20px'}"
|
||||||
.iconContainerWidth="${'110px'}"
|
.iconContainerWidth="${'110px'}"
|
||||||
|
|||||||
@@ -425,8 +425,6 @@ function createExternalLinkableToolbarConfig(
|
|||||||
toast(ctx.host, 'Copied link to clipboard');
|
toast(ctx.host, 'Copied link to clipboard');
|
||||||
|
|
||||||
ctx.track('CopiedLink', {
|
ctx.track('CopiedLink', {
|
||||||
segment: 'doc',
|
|
||||||
page: 'doc editor',
|
|
||||||
module: 'toolbar',
|
module: 'toolbar',
|
||||||
category: matchModels(model, [BookmarkBlockModel])
|
category: matchModels(model, [BookmarkBlockModel])
|
||||||
? 'bookmark'
|
? 'bookmark'
|
||||||
@@ -464,8 +462,6 @@ function createExternalLinkableToolbarConfig(
|
|||||||
);
|
);
|
||||||
|
|
||||||
ctx.track('OpenedAliasPopup', {
|
ctx.track('OpenedAliasPopup', {
|
||||||
segment: 'doc',
|
|
||||||
page: 'doc editor',
|
|
||||||
module: 'toolbar',
|
module: 'toolbar',
|
||||||
category: matchModels(model, [BookmarkBlockModel])
|
category: matchModels(model, [BookmarkBlockModel])
|
||||||
? 'bookmark'
|
? 'bookmark'
|
||||||
@@ -986,6 +982,11 @@ export const createCustomToolbarExtension = (
|
|||||||
config: createExternalLinkableToolbarConfig(BookmarkBlockComponent),
|
config: createExternalLinkableToolbarConfig(BookmarkBlockComponent),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
ToolbarModuleExtension({
|
||||||
|
id: BlockFlavourIdentifier('custom:affine:surface:bookmark'),
|
||||||
|
config: createExternalLinkableToolbarConfig(BookmarkBlockComponent),
|
||||||
|
}),
|
||||||
|
|
||||||
ToolbarModuleExtension({
|
ToolbarModuleExtension({
|
||||||
id: BlockFlavourIdentifier('custom:affine:embed-figma'),
|
id: BlockFlavourIdentifier('custom:affine:embed-figma'),
|
||||||
config: createExternalLinkableToolbarConfig(EmbedFigmaBlockComponent),
|
config: createExternalLinkableToolbarConfig(EmbedFigmaBlockComponent),
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export const PackageList = [
|
|||||||
name: '@blocksuite/affine-block-bookmark',
|
name: '@blocksuite/affine-block-bookmark',
|
||||||
workspaceDependencies: [
|
workspaceDependencies: [
|
||||||
'blocksuite/affine/blocks/block-embed',
|
'blocksuite/affine/blocks/block-embed',
|
||||||
|
'blocksuite/affine/blocks/block-surface',
|
||||||
'blocksuite/affine/components',
|
'blocksuite/affine/components',
|
||||||
'blocksuite/affine/model',
|
'blocksuite/affine/model',
|
||||||
'blocksuite/affine/shared',
|
'blocksuite/affine/shared',
|
||||||
|
|||||||
@@ -2338,6 +2338,7 @@ __metadata:
|
|||||||
resolution: "@blocksuite/affine-block-bookmark@workspace:blocksuite/affine/blocks/block-bookmark"
|
resolution: "@blocksuite/affine-block-bookmark@workspace:blocksuite/affine/blocks/block-bookmark"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-block-embed": "workspace:*"
|
"@blocksuite/affine-block-embed": "workspace:*"
|
||||||
|
"@blocksuite/affine-block-surface": "workspace:*"
|
||||||
"@blocksuite/affine-components": "workspace:*"
|
"@blocksuite/affine-components": "workspace:*"
|
||||||
"@blocksuite/affine-model": "workspace:*"
|
"@blocksuite/affine-model": "workspace:*"
|
||||||
"@blocksuite/affine-shared": "workspace:*"
|
"@blocksuite/affine-shared": "workspace:*"
|
||||||
|
|||||||
Reference in New Issue
Block a user