diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/alignment.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/alignment.ts index e3aed1786..ea6203e4a 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/alignment.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/alignment.ts @@ -6,6 +6,11 @@ import { } from '@blocksuite/affine-block-surface'; import { EditorChevronDown } from '@blocksuite/affine-components/toolbar'; import type { ToolbarContext } from '@blocksuite/affine-shared/services'; +import type { + Menu, + MenuItem, +} from '@blocksuite/affine-widget-edgeless-toolbar'; +import { renderMenuItems } from '@blocksuite/affine-widget-edgeless-toolbar'; import type { GfxModel } from '@blocksuite/block-std/gfx'; import { Bound } from '@blocksuite/global/gfx'; import { @@ -23,9 +28,6 @@ import { import { html } from 'lit'; import { styleMap } from 'lit/directives/style-map.js'; -import type { Menu, MenuItem } from './types'; -import { renderMenuItems } from './utils'; - enum Alignment { None, AutoArrange, diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/connector.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/connector.ts index e9df48990..2219fe787 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/connector.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/connector.ts @@ -30,6 +30,13 @@ import { getMostCommonResolvedValue, getMostCommonValue, } from '@blocksuite/affine-shared/utils'; +import type { MenuItem } from '@blocksuite/affine-widget-edgeless-toolbar'; +import { + createTextActions, + getRootBlock, + LINE_STYLE_LIST, + renderMenu, +} from '@blocksuite/affine-widget-edgeless-toolbar'; import { Bound } from '@blocksuite/global/gfx'; import { AddTextIcon, @@ -51,10 +58,6 @@ import { html } from 'lit'; import { styleMap } from 'lit/directives/style-map.js'; import { mountConnectorLabelEditor } from '../../utils/text'; -import { LINE_STYLE_LIST } from './consts'; -import { createTextActions } from './text-common'; -import type { MenuItem } from './types'; -import { getRootBlock, renderMenu } from './utils'; const FRONT_ENDPOINT_STYLE_LIST = [ { diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/edgeless-text.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/edgeless-text.ts index 14e141866..8fddbf596 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/edgeless-text.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/edgeless-text.ts @@ -1,7 +1,6 @@ import { EdgelessTextBlockModel } from '@blocksuite/affine-model'; import { type ToolbarModuleConfig } from '@blocksuite/affine-shared/services'; - -import { createTextActions } from './text-common'; +import { createTextActions } from '@blocksuite/affine-widget-edgeless-toolbar'; export const builtinEdgelessTextToolbarConfig = { // No need to adjust element bounds, which updates itself using ResizeObserver diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/group.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/group.ts index 8a96e6e39..35074e71a 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/group.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/group.ts @@ -9,11 +9,12 @@ import { } from '@blocksuite/affine-model'; import { type ToolbarModuleConfig } from '@blocksuite/affine-shared/services'; import { matchModels } from '@blocksuite/affine-shared/utils'; +import { getRootBlock } from '@blocksuite/affine-widget-edgeless-toolbar'; import { Bound } from '@blocksuite/global/gfx'; import { EditIcon, PageIcon, UngroupIcon } from '@blocksuite/icons/lit'; +import { EdgelessRootService } from '../../edgeless-root-service'; import { mountGroupTitleEditor } from '../../utils/text'; -import { getEdgelessWith, getRootBlock } from './utils'; export const builtinGroupToolbarConfig = { actions: [ @@ -84,11 +85,10 @@ export const builtinGroupToolbarConfig = { const models = ctx.getSurfaceModelsByType(GroupElementModel); if (!models.length) return; - const edgeless = getEdgelessWith(ctx); - if (!edgeless) return; + const edgelessService = ctx.std.get(EdgelessRootService); for (const model of models) { - edgeless.service.ungroup(model); + edgelessService.ungroup(model); } }, }, diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/mindmap.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/mindmap.ts index d9c7ccb09..5e7b95e29 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/mindmap.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/mindmap.ts @@ -14,11 +14,12 @@ import type { ToolbarModuleConfig, } from '@blocksuite/affine-shared/services'; import { getMostCommonValue } from '@blocksuite/affine-shared/utils'; +import { + type MenuItem, + renderMenu, +} from '@blocksuite/affine-widget-edgeless-toolbar'; import { RadiantIcon, RightLayoutIcon, StyleIcon } from '@blocksuite/icons/lit'; -import type { MenuItem } from './types'; -import { renderMenu } from './utils'; - const MINDMAP_STYLE_LIST = [ { value: MindmapStyle.ONE, diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/misc.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/misc.ts index 03d0a87e3..a58470821 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/misc.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/misc.ts @@ -1,4 +1,8 @@ -import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface'; +import { EdgelessFrameManagerIdentifier } from '@blocksuite/affine-block-frame'; +import { + EdgelessCRUDIdentifier, + getSurfaceComponent, +} from '@blocksuite/affine-block-surface'; import { ConnectorElementModel, DEFAULT_CONNECTOR_MODE, @@ -25,9 +29,9 @@ import { } from '@blocksuite/icons/lit'; import { html } from 'lit'; +import { EdgelessRootService } from '../../edgeless-root-service'; import { renderAlignmentMenu } from './alignment'; import { moreActions } from './more'; -import { getEdgelessWith } from './utils'; export const builtinMiscToolbarConfig = { actions: [ @@ -88,14 +92,16 @@ export const builtinMiscToolbarConfig = { const models = ctx.getSurfaceModels(); if (models.length < 2) return; - const edgeless = getEdgelessWith(ctx); - if (!edgeless) return; + const surface = getSurfaceComponent(ctx.std); + if (!surface) return; - const frame = edgeless.service.frame.createFrameOnSelected(); + const frameManager = ctx.std.get(EdgelessFrameManagerIdentifier); + + const frame = frameManager.createFrameOnSelected(); if (!frame) return; // TODO(@fundon): should be a command - edgeless.surface.fitToViewport(Bound.deserialize(frame.xywh)); + surface.fitToViewport(Bound.deserialize(frame.xywh)); ctx.track('CanvasElementAdded', { control: 'context-menu', @@ -131,11 +137,10 @@ export const builtinMiscToolbarConfig = { const models = ctx.getSurfaceModels(); if (models.length < 2) return; - const edgeless = getEdgelessWith(ctx); - if (!edgeless) return; + const service = ctx.std.get(EdgelessRootService); // TODO(@fundon): should be a command - edgeless.service.createGroupFromSelected(); + service.createGroupFromSelected(); }, }, { @@ -216,9 +221,6 @@ export const builtinMiscToolbarConfig = { const models = ctx.getSurfaceModels(); if (!models.length) return; - const edgeless = getEdgelessWith(ctx); - if (!edgeless) return; - // get most top selected elements(*) from tree, like in a tree below // G0 // / \ @@ -266,10 +268,8 @@ export const builtinMiscToolbarConfig = { return; } - const groupId = edgeless.service.createGroup([ - topElement, - ...otherElements, - ]); + const service = ctx.std.get(EdgelessRootService); + const groupId = service.createGroup([topElement, ...otherElements]); if (groupId) { const element = ctx.std @@ -325,9 +325,6 @@ export const builtinLockedToolbarConfig = { const models = ctx.getSurfaceModels(); if (!models.length) return; - const edgeless = getEdgelessWith(ctx); - if (!edgeless) return; - const elements = new Set( models.map(model => ctx.matchModel(model.group, MindmapElementModel) @@ -338,9 +335,11 @@ export const builtinLockedToolbarConfig = { ctx.store.captureSync(); + const service = ctx.std.get(EdgelessRootService); + for (const element of elements) { if (element instanceof GroupElementModel) { - edgeless.service.ungroup(element); + service.ungroup(element); } else { element.lockedBySelf = false; } diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/more.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/more.ts index 5b727e01a..f201ef254 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/more.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/more.ts @@ -7,7 +7,10 @@ import { } from '@blocksuite/affine-block-embed'; import { EdgelessFrameManagerIdentifier } from '@blocksuite/affine-block-frame'; import { ImageBlockComponent } from '@blocksuite/affine-block-image'; -import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface'; +import { + EdgelessCRUDIdentifier, + getSurfaceComponent, +} from '@blocksuite/affine-block-surface'; import { AttachmentBlockModel, BookmarkBlockModel, @@ -42,6 +45,7 @@ import { ResetIcon, } from '@blocksuite/icons/lit'; +import { EdgelessRootService } from '../../edgeless-root-service'; import { duplicate } from '../../utils/clipboard-utils'; import { getSortedCloneElements } from '../../utils/clone-utils'; import { moveConnectors } from '../../utils/connector'; @@ -67,10 +71,10 @@ export const moreActions = [ .createFrameOnSelected(); if (!frame) return; - const edgeless = getEdgelessWith(ctx); - if (!edgeless) return; + const surface = getSurfaceComponent(ctx.std); + if (!surface) return; - edgeless.surface.fitToViewport(Bound.deserialize(frame.xywh)); + surface.fitToViewport(Bound.deserialize(frame.xywh)); ctx.track('CanvasElementAdded', { control: 'context-menu', @@ -88,10 +92,8 @@ export const moreActions = [ return !models.some(model => ctx.matchModel(model, FrameBlockModel)); }, run(ctx) { - const edgeless = getEdgelessWith(ctx); - if (!edgeless) return; - - edgeless.service.createGroupFromSelected(); + const service = ctx.std.get(EdgelessRootService); + service.createGroupFromSelected(); }, }, ], diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/shape.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/shape.ts index 19f9c78c3..eeb2d5fdc 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/shape.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/shape.ts @@ -34,18 +34,21 @@ import type { ToolbarModuleConfig, } from '@blocksuite/affine-shared/services'; import { getMostCommonValue } from '@blocksuite/affine-shared/utils'; +import { + createTextActions, + getRootBlock, + LINE_STYLE_LIST, + renderMenu, +} from '@blocksuite/affine-widget-edgeless-toolbar'; import { Bound } from '@blocksuite/global/gfx'; import { AddTextIcon, ShapeIcon } from '@blocksuite/icons/lit'; import { html } from 'lit'; import isEqual from 'lodash-es/isEqual'; -import { LINE_STYLE_LIST } from './consts'; import { createMindmapLayoutActionMenu, createMindmapStyleActionMenu, } from './mindmap'; -import { createTextActions } from './text-common'; -import { getRootBlock, renderMenu } from './utils'; export const builtinShapeToolbarConfig = { actions: [ diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/text.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/text.ts index 7f8e7beda..28024aa8d 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/text.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/text.ts @@ -4,10 +4,9 @@ import { } from '@blocksuite/affine-block-surface'; import { TextElementModel } from '@blocksuite/affine-model'; import { type ToolbarModuleConfig } from '@blocksuite/affine-shared/services'; +import { createTextActions } from '@blocksuite/affine-widget-edgeless-toolbar'; import { Bound } from '@blocksuite/global/gfx'; -import { createTextActions } from './text-common'; - export const builtinTextToolbarConfig = { actions: createTextActions(TextElementModel, 'text', (ctx, model, props) => { // No need to adjust element bounds diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/utils.ts b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/utils.ts index f0c9705bd..54376610b 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/utils.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/utils.ts @@ -1,69 +1,6 @@ -import { EditorChevronDown } from '@blocksuite/affine-components/toolbar'; import type { ToolbarContext } from '@blocksuite/affine-shared/services'; -import type { BlockComponent } from '@blocksuite/block-std'; -import { html } from 'lit'; -import { ifDefined } from 'lit/directives/if-defined.js'; -import { repeat } from 'lit/directives/repeat.js'; import { EdgelessRootBlockComponent } from '../..'; -import type { Menu, MenuItem } from './types'; - -export function renderCurrentMenuItemWith>( - items: MenuItem[], - currentValue: T, - field: F -) { - return items.find(({ value }) => value === currentValue)?.[field]; -} - -export function renderMenu({ - label, - tooltip, - icon, - items, - currentValue, - onPick, -}: Menu) { - return html` - - ${icon ?? renderCurrentMenuItemWith(items, currentValue, 'icon')} - ${EditorChevronDown} - - `} - > - ${renderMenuItems(items, currentValue, onPick)} - - `; -} - -export function renderMenuItems( - items: MenuItem[], - currentValue: T, - onPick: (value: T) => void -) { - return repeat( - items, - item => item.value, - ({ key, value, icon, disabled }) => html` - onPick(value)} - > - ${icon} - - ` - ); -} // TODO(@fundon): it should be simple export function getEdgelessWith(ctx: ToolbarContext) { @@ -78,10 +15,3 @@ export function getEdgelessWith(ctx: ToolbarContext) { return edgeless; } - -export function getRootBlock(ctx: ToolbarContext): BlockComponent | null { - const rootModel = ctx.store.root; - if (!rootModel) return null; - - return ctx.view.getBlock(rootModel.id); -} diff --git a/blocksuite/affine/blocks/block-surface/src/index.ts b/blocksuite/affine/blocks/block-surface/src/index.ts index e26f5317d..9488c6031 100644 --- a/blocksuite/affine/blocks/block-surface/src/index.ts +++ b/blocksuite/affine/blocks/block-surface/src/index.ts @@ -88,6 +88,7 @@ export { getBgGridGap, getLastPropsKey, getSurfaceBlock, + getSurfaceComponent, normalizeWheelDeltaY, } from './utils'; export * from './utils/mindmap/style-svg'; diff --git a/blocksuite/affine/blocks/block-surface/src/utils/get-surface-block.ts b/blocksuite/affine/blocks/block-surface/src/utils/get-surface-block.ts index 676ab0eef..fd8107bcd 100644 --- a/blocksuite/affine/blocks/block-surface/src/utils/get-surface-block.ts +++ b/blocksuite/affine/blocks/block-surface/src/utils/get-surface-block.ts @@ -1,8 +1,16 @@ +import type { BlockStdScope } from '@blocksuite/block-std'; import type { Store } from '@blocksuite/store'; +import type { SurfaceBlockComponent } from '../surface-block'; import type { SurfaceBlockModel } from '../surface-model'; export function getSurfaceBlock(doc: Store) { const blocks = doc.getBlocksByFlavour('affine:surface'); return blocks.length !== 0 ? (blocks[0].model as SurfaceBlockModel) : null; } + +export function getSurfaceComponent(std: BlockStdScope) { + const surface = getSurfaceBlock(std.store); + if (!surface) return null; + return std.view.getBlock(surface.id) as SurfaceBlockComponent | null; +} diff --git a/blocksuite/affine/blocks/block-surface/src/utils/index.ts b/blocksuite/affine/blocks/block-surface/src/utils/index.ts index 17ddb8ae0..42362e0d3 100644 --- a/blocksuite/affine/blocks/block-surface/src/utils/index.ts +++ b/blocksuite/affine/blocks/block-surface/src/utils/index.ts @@ -36,5 +36,5 @@ export function normalizeWheelDeltaY(delta: number, zoom = 1) { export { addNote, addNoteAtPoint } from './add-note'; export { getBgGridGap } from './get-bg-grip-gap'; export { getLastPropsKey } from './get-last-props-key'; -export { getSurfaceBlock } from './get-surface-block'; +export * from './get-surface-block'; export * from './mindmap/style-svg.js'; diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/consts.ts b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/consts.ts similarity index 100% rename from blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/consts.ts rename to blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/consts.ts diff --git a/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/index.ts b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/index.ts new file mode 100644 index 000000000..b3c9d3372 --- /dev/null +++ b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/index.ts @@ -0,0 +1,4 @@ +export * from './consts.js'; +export * from './text-common.js'; +export * from './types.js'; +export * from './utils.js'; diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/text-common.ts b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/text-common.ts similarity index 100% rename from blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/text-common.ts rename to blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/text-common.ts diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/types.ts b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/types.ts similarity index 100% rename from blocksuite/affine/blocks/block-root/src/edgeless/configs/toolbar/types.ts rename to blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/types.ts diff --git a/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/utils.ts b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/utils.ts new file mode 100644 index 000000000..e882214bd --- /dev/null +++ b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/config/utils.ts @@ -0,0 +1,72 @@ +import { EditorChevronDown } from '@blocksuite/affine-components/toolbar'; +import type { ToolbarContext } from '@blocksuite/affine-shared/services'; +import type { BlockComponent } from '@blocksuite/block-std'; +import { html } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { repeat } from 'lit/directives/repeat.js'; + +import type { Menu, MenuItem } from './types'; + +export function renderCurrentMenuItemWith>( + items: MenuItem[], + currentValue: T, + field: F +) { + return items.find(({ value }) => value === currentValue)?.[field]; +} + +export function renderMenu({ + label, + tooltip, + icon, + items, + currentValue, + onPick, +}: Menu) { + return html` + + ${icon ?? renderCurrentMenuItemWith(items, currentValue, 'icon')} + ${EditorChevronDown} + + `} + > + ${renderMenuItems(items, currentValue, onPick)} + + `; +} + +export function renderMenuItems( + items: MenuItem[], + currentValue: T, + onPick: (value: T) => void +) { + return repeat( + items, + item => item.value, + ({ key, value, icon, disabled }) => html` + onPick(value)} + > + ${icon} + + ` + ); +} + +export function getRootBlock(ctx: ToolbarContext): BlockComponent | null { + const rootModel = ctx.store.root; + if (!rootModel) return null; + + return ctx.view.getBlock(rootModel.id); +} diff --git a/blocksuite/affine/widgets/widget-edgeless-toolbar/src/index.ts b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/index.ts index 1908c4a61..f7fe4591c 100644 --- a/blocksuite/affine/widgets/widget-edgeless-toolbar/src/index.ts +++ b/blocksuite/affine/widgets/widget-edgeless-toolbar/src/index.ts @@ -1,3 +1,4 @@ +export * from './config'; export * from './context'; export * from './create-popper'; export * from './draggable';