feat(editor): slash menu and toolbar widget extensions (#12002)
Closes: BS-3226 Closes: BS-3227 Closes: BS-3228 Closes: BS-3229 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced new view extensions for remote selection, scroll anchoring, slash menu, and toolbar widgets, enhancing customization and integration capabilities. - **Refactor** - Updated export paths and module structure for widget-related packages to improve modularity and accessibility. - Reorganized internal dependencies and removed redundant widget imports from core block packages. - Refactored edgeless-related widgets and components to use a standardized scope interface for improved context and state management. - Centralized graphics controller access and slot management through standardized context objects. - **Chores** - Added and updated dependencies to streamline extension loading and workspace management. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -3,6 +3,10 @@ import { PresentationToolbar } from './edgeless-toolbar/presentation-toolbar';
|
||||
import { FrameBlockComponent } from './frame-block';
|
||||
import { EdgelessFrameOrderButton } from './present/frame-order-button';
|
||||
import { EdgelessFrameOrderMenu } from './present/frame-order-menu';
|
||||
import {
|
||||
EDGELESS_NAVIGATOR_BLACK_BACKGROUND_WIDGET,
|
||||
EdgelessNavigatorBlackBackgroundWidget,
|
||||
} from './present/navigator-bg-widget';
|
||||
import { EdgelessNavigatorSettingButton } from './present/navigator-setting-button';
|
||||
import { EdgelessPresentButton } from './present/present-button';
|
||||
|
||||
@@ -21,6 +25,11 @@ export function effects() {
|
||||
);
|
||||
customElements.define('edgeless-present-button', EdgelessPresentButton);
|
||||
customElements.define('presentation-toolbar', PresentationToolbar);
|
||||
// Navigation components
|
||||
customElements.define(
|
||||
EDGELESS_NAVIGATOR_BLACK_BACKGROUND_WIDGET,
|
||||
EdgelessNavigatorBlackBackgroundWidget
|
||||
);
|
||||
}
|
||||
|
||||
declare global {
|
||||
@@ -33,5 +42,6 @@ declare global {
|
||||
'edgeless-navigator-setting-button': EdgelessNavigatorSettingButton;
|
||||
'edgeless-present-button': EdgelessPresentButton;
|
||||
'presentation-toolbar': PresentationToolbar;
|
||||
'edgeless-navigator-black-background': EdgelessNavigatorBlackBackgroundWidget;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import type { FrameBlockModel, RootBlockModel } from '@blocksuite/affine-model';
|
||||
import { EditPropsStore } from '@blocksuite/affine-shared/services';
|
||||
import { Bound } from '@blocksuite/global/gfx';
|
||||
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
|
||||
import { effect } from '@preact/signals-core';
|
||||
import { css, html, nothing } from 'lit';
|
||||
import { state } from 'lit/decorators.js';
|
||||
import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
export const EDGELESS_NAVIGATOR_BLACK_BACKGROUND_WIDGET =
|
||||
'edgeless-navigator-black-background';
|
||||
export class EdgelessNavigatorBlackBackgroundWidget extends WidgetComponent<RootBlockModel> {
|
||||
static override styles = css`
|
||||
.edgeless-navigator-black-background {
|
||||
background-color: black;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
background-color: transparent;
|
||||
box-shadow: 0 0 0 5000px black;
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
|
||||
private _blackBackground = false;
|
||||
|
||||
get gfx() {
|
||||
return this.std.get(GfxControllerIdentifier);
|
||||
}
|
||||
|
||||
private get _slots() {
|
||||
return this.std.get(EdgelessLegacySlotIdentifier);
|
||||
}
|
||||
|
||||
private _tryLoadBlackBackground() {
|
||||
const value = this.std
|
||||
.get(EditPropsStore)
|
||||
.getStorage('presentBlackBackground');
|
||||
this._blackBackground = value ?? true;
|
||||
}
|
||||
|
||||
override firstUpdated() {
|
||||
const { _disposables, gfx } = this;
|
||||
_disposables.add(
|
||||
this._slots.navigatorFrameChanged.subscribe(frame => {
|
||||
this.frame = frame;
|
||||
})
|
||||
);
|
||||
|
||||
_disposables.add(
|
||||
this._slots.navigatorSettingUpdated.subscribe(({ blackBackground }) => {
|
||||
if (blackBackground !== undefined) {
|
||||
this.std
|
||||
.get(EditPropsStore)
|
||||
.setStorage('presentBlackBackground', blackBackground);
|
||||
|
||||
this._blackBackground = blackBackground;
|
||||
|
||||
this.show =
|
||||
blackBackground &&
|
||||
this.gfx.tool.currentToolOption$.peek().type === 'frameNavigator';
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
_disposables.add(
|
||||
effect(() => {
|
||||
const tool = gfx.tool.currentToolName$.value;
|
||||
|
||||
if (tool !== 'frameNavigator') {
|
||||
this.show = false;
|
||||
} else {
|
||||
this.show = this._blackBackground;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
_disposables.add(
|
||||
this._slots.fullScreenToggled.subscribe(
|
||||
() =>
|
||||
setTimeout(() => {
|
||||
this.requestUpdate();
|
||||
}, 500) // wait for full screen animation
|
||||
)
|
||||
);
|
||||
|
||||
this._tryLoadBlackBackground();
|
||||
}
|
||||
|
||||
override render() {
|
||||
const { frame, show, gfx } = this;
|
||||
|
||||
if (!show || !frame) return nothing;
|
||||
|
||||
const bound = Bound.deserialize(frame.xywh);
|
||||
const zoom = gfx.viewport.zoom;
|
||||
const width = bound.w * zoom;
|
||||
const height = bound.h * zoom;
|
||||
const [x, y] = gfx.viewport.toViewCoord(bound.x, bound.y);
|
||||
|
||||
return html` <style>
|
||||
.edgeless-navigator-black-background {
|
||||
width: ${width}px;
|
||||
height: ${height}px;
|
||||
top: ${y}px;
|
||||
left: ${x}px;
|
||||
}
|
||||
</style>
|
||||
<div class="edgeless-navigator-black-background"></div>`;
|
||||
}
|
||||
|
||||
@state()
|
||||
private accessor frame: FrameBlockModel | undefined = undefined;
|
||||
|
||||
@state()
|
||||
private accessor show = false;
|
||||
}
|
||||
|
||||
export const edgelessNavigatorBgWidget = WidgetViewExtension(
|
||||
'affine:page',
|
||||
EDGELESS_NAVIGATOR_BLACK_BACKGROUND_WIDGET,
|
||||
literal`${unsafeStatic(EDGELESS_NAVIGATOR_BLACK_BACKGROUND_WIDGET)}`
|
||||
);
|
||||
@@ -9,6 +9,7 @@ import { FrameHighlightManager } from './frame-highlight-manager';
|
||||
import { FrameBlockSpec } from './frame-spec';
|
||||
import { FrameTool } from './frame-tool';
|
||||
import { frameToolbarExtension } from './frame-toolbar';
|
||||
import { edgelessNavigatorBgWidget } from './present/navigator-bg-widget';
|
||||
import { PresentTool } from './preset-tool';
|
||||
|
||||
export class FrameViewExtension extends ViewExtensionProvider {
|
||||
@@ -28,6 +29,7 @@ export class FrameViewExtension extends ViewExtensionProvider {
|
||||
context.register(PresentTool);
|
||||
context.register(frameQuickTool);
|
||||
context.register(frameToolbarExtension);
|
||||
context.register(edgelessNavigatorBgWidget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user