refactor(editor): move menu context to components (#9302)

This commit is contained in:
Saul-Mirone
2024-12-25 07:34:04 +00:00
parent 62b930f336
commit 16c59d96d9
52 changed files with 235 additions and 586 deletions

View File

@@ -1,228 +0,0 @@
import {
CenterPeekIcon,
CopyIcon,
DeleteIcon,
DuplicateIcon,
OpenIcon,
RefreshIcon,
} from '@blocksuite/affine-components/icons';
import { isPeekable, peek } from '@blocksuite/affine-components/peek';
import { toast } from '@blocksuite/affine-components/toast';
import { getBlockProps } from '@blocksuite/affine-shared/utils';
import { WithDisposable } from '@blocksuite/global/utils';
import { Slice } from '@blocksuite/store';
import { css, html, LitElement, nothing } from 'lit';
import { property } from 'lit/decorators.js';
import {
isEmbedLinkedDocBlock,
isEmbedSyncedDocBlock,
} from '../../../root-block/edgeless/utils/query.js';
import type { EmbedBlockComponent } from './type.js';
export class EmbedCardMoreMenu extends WithDisposable(LitElement) {
static override styles = css`
.embed-card-more-menu {
box-sizing: border-box;
padding-bottom: 4px;
}
.embed-card-more-menu-container {
border-radius: 8px;
padding: 8px;
background: var(--affine-background-overlay-panel-color);
box-shadow: var(--affine-shadow-2);
}
.embed-card-more-menu-container > .menu-item {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
}
.embed-card-more-menu-container > .menu-item:hover {
background: var(--affine-hover-color);
}
.embed-card-more-menu-container > .menu-item:hover.delete {
background: var(--affine-background-error-color);
color: var(--affine-error-color);
}
.embed-card-more-menu-container > .menu-item:hover.delete > svg {
color: var(--affine-error-color);
}
.embed-card-more-menu-container > .menu-item svg {
margin: 0 8px;
}
.embed-card-more-menu-container > .divider {
width: 148px;
height: 1px;
margin: 8px;
background-color: var(--affine-border-color);
}
`;
private get _doc() {
return this.block.doc;
}
private get _model() {
return this.block.model;
}
get _openButtonDisabled() {
return (
isEmbedLinkedDocBlock(this._model) && this._model.pageId === this._doc.id
);
}
private get _std() {
return this.block.std;
}
private async _copyBlock() {
const slice = Slice.fromModels(this._doc, [this._model]);
await this._std.clipboard.copySlice(slice);
toast(this.block.host, 'Copied link to clipboard');
this.abortController.abort();
}
private _duplicateBlock() {
const model = this._model;
const blockProps = getBlockProps(model);
const {
width: _width,
height: _height,
xywh: _xywh,
rotate: _rotate,
zIndex: _zIndex,
...duplicateProps
} = blockProps;
const { doc } = model;
const parent = doc.getParent(model);
const index = parent?.children.indexOf(model);
doc.addBlock(
model.flavour as BlockSuite.Flavour,
duplicateProps,
parent,
index
);
this.abortController.abort();
}
private _open() {
this.block.open();
this.abortController.abort();
}
private _peek() {
peek(this.block);
}
private _peekable() {
return isPeekable(this.block);
}
private _refreshData() {
this.block.refreshData();
this.abortController.abort();
}
override render() {
return html`
<div class="embed-card-more-menu">
<div
class="embed-card-more-menu-container"
@pointerdown=${(e: MouseEvent) => e.stopPropagation()}
>
<icon-button
width="126px"
height="32px"
class="menu-item open"
text="Open"
@click=${() => this._open()}
?disabled=${this._openButtonDisabled}
>
${OpenIcon}
</icon-button>
${this._peekable()
? html`<icon-button
width="126px"
height="32px"
text="Open in center peek"
class="menu-item center-peek"
@click=${() => this._peek()}
>
${CenterPeekIcon}
</icon-button>`
: nothing}
<icon-button
width="126px"
height="32px"
class="menu-item copy"
text="Copy"
@click=${() => this._copyBlock()}
>
${CopyIcon}
</icon-button>
<icon-button
width="126px"
height="32px"
class="menu-item duplicate"
text="Duplicate"
?disabled=${this._doc.readonly}
@click=${() => this._duplicateBlock()}
>
${DuplicateIcon}
</icon-button>
${isEmbedLinkedDocBlock(this._model) ||
isEmbedSyncedDocBlock(this._model)
? nothing
: html`<icon-button
width="126px"
height="32px"
class="menu-item reload"
text="Reload"
?disabled=${this._doc.readonly}
@click=${() => this._refreshData()}
>
${RefreshIcon}
</icon-button>`}
<div class="divider"></div>
<icon-button
width="126px"
height="32px"
class="menu-item delete"
text="Delete"
?disabled=${this._doc.readonly}
@click=${() => this._doc.deleteBlock(this._model)}
>
${DeleteIcon}
</icon-button>
</div>
</div>
`;
}
@property({ attribute: false })
accessor abortController!: AbortController;
@property({ attribute: false })
accessor block!: EmbedBlockComponent;
}
declare global {
interface HTMLElementTagNameMap {
'embed-card-more-menu': EmbedCardMoreMenu;
}
}

View File

@@ -1,106 +0,0 @@
import type {
BookmarkBlockModel,
ColorScheme,
EmbedGithubModel,
EmbedLinkedDocModel,
} from '@blocksuite/affine-model';
import { WithDisposable } from '@blocksuite/global/utils';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import type { EmbedCardStyle } from '../../types.js';
import { getEmbedCardIcons } from '../../utils/url.js';
export class EmbedCardStyleMenu extends WithDisposable(LitElement) {
static override styles = css`
.embed-card-style-menu {
box-sizing: border-box;
padding-bottom: 8px;
}
.embed-card-style-menu-container {
border-radius: 8px;
padding: 8px;
gap: 8px;
display: flex;
justify-content: space-between;
align-items: center;
background: var(--affine-background-overlay-panel-color);
box-shadow: var(--affine-shadow-2);
}
.embed-card-style-menu-container > icon-button {
padding: var(--1, 0px);
}
.embed-card-style-menu-container > icon-button.selected {
border: 1px solid var(--affine-brand-color);
}
`;
private _setEmbedCardStyle(style: EmbedCardStyle) {
this.model.doc.updateBlock(this.model, { style });
this.requestUpdate();
this.abortController.abort();
}
override render() {
const { EmbedCardHorizontalIcon, EmbedCardListIcon } = getEmbedCardIcons(
this.theme
);
return html`
<div class="embed-card-style-menu">
<div
class="embed-card-style-menu-container"
@pointerdown=${(e: MouseEvent) => e.stopPropagation()}
>
<icon-button
width="76px"
height="76px"
class=${classMap({
selected: this.model.style === 'horizontal',
'card-style-button-horizontal': true,
})}
@click=${() => this._setEmbedCardStyle('horizontal')}
>
${EmbedCardHorizontalIcon}
<affine-tooltip .offset=${4}
>${'Large horizontal style'}</affine-tooltip
>
</icon-button>
<icon-button
width="76px"
height="76px"
class=${classMap({
selected: this.model.style === 'list',
'card-style-button-list': true,
})}
@click=${() => this._setEmbedCardStyle('list')}
>
${EmbedCardListIcon}
<affine-tooltip .offset=${4}
>${'Small horizontal style'}</affine-tooltip
>
</icon-button>
</div>
</div>
`;
}
@property({ attribute: false })
accessor abortController!: AbortController;
@property({ attribute: false })
accessor model!: BookmarkBlockModel | EmbedGithubModel | EmbedLinkedDocModel;
@property({ attribute: false })
accessor theme!: ColorScheme;
}
declare global {
interface HTMLElementTagNameMap {
'embed-card-style-menu': EmbedCardStyleMenu;
}
}

View File

@@ -1,4 +1,9 @@
import { toast } from '@blocksuite/affine-components/toast';
import type { EmbedCardStyle } from '@blocksuite/affine-model';
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '@blocksuite/affine-shared/consts';
import { EmbedOptionProvider } from '@blocksuite/affine-shared/services';
import type { EditorHost } from '@blocksuite/block-std';
import { ShadowlessElement } from '@blocksuite/block-std';
@@ -14,8 +19,6 @@ import { property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import type { EdgelessRootBlockComponent } from '../../../../root-block/edgeless/edgeless-root-block.js';
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH } from '../../../consts.js';
import type { EmbedCardStyle } from '../../../types.js';
import { getRootByEditorHost, isValidUrl } from '../../../utils/index.js';
import { embedCardModalStyles } from './styles.js';

View File

@@ -1 +0,0 @@
export * from '@blocksuite/affine-shared/consts';

View File

@@ -1,9 +1,8 @@
import type { BlockSnapshot, SliceSnapshot } from '@blocksuite/store';
import {
mergeToCodeModel,
transformModel,
} from '../../root-block/utils/operations/model.js';
} from '@blocksuite/affine-shared/utils';
import type { BlockSnapshot, SliceSnapshot } from '@blocksuite/store';
class DocTestUtils {
// block model operations (data layer)

View File

@@ -6,11 +6,10 @@ import type {
ParagraphBlockModel,
SurfaceRefBlockModel,
} from '@blocksuite/affine-model';
import { DEFAULT_IMAGE_PROXY_ENDPOINT } from '@blocksuite/affine-shared/consts';
import { assertExists } from '@blocksuite/global/utils';
import type { DeltaOperation, JobMiddleware } from '@blocksuite/store';
import { DEFAULT_IMAGE_PROXY_ENDPOINT } from '../consts.js';
export const replaceIdMiddleware: JobMiddleware = ({ slots, collection }) => {
const idMap = new Map<string, string>();
slots.afterImport.on(payload => {

View File

@@ -1,55 +1,8 @@
import {
DarkLoadingIcon,
EmbedCardDarkBannerIcon,
EmbedCardDarkCubeIcon,
EmbedCardDarkHorizontalIcon,
EmbedCardDarkListIcon,
EmbedCardDarkVerticalIcon,
EmbedCardLightBannerIcon,
EmbedCardLightCubeIcon,
EmbedCardLightHorizontalIcon,
EmbedCardLightListIcon,
EmbedCardLightVerticalIcon,
LightLoadingIcon,
} from '@blocksuite/affine-components/icons';
import {
ColorScheme,
type DocMode,
DocModes,
type ReferenceInfo,
} from '@blocksuite/affine-model';
import type { TemplateResult } from 'lit';
type EmbedCardIcons = {
LoadingIcon: TemplateResult<1>;
EmbedCardBannerIcon: TemplateResult<1>;
EmbedCardHorizontalIcon: TemplateResult<1>;
EmbedCardListIcon: TemplateResult<1>;
EmbedCardVerticalIcon: TemplateResult<1>;
EmbedCardCubeIcon: TemplateResult<1>;
};
export function getEmbedCardIcons(theme: ColorScheme): EmbedCardIcons {
if (theme === ColorScheme.Light) {
return {
LoadingIcon: LightLoadingIcon,
EmbedCardBannerIcon: EmbedCardLightBannerIcon,
EmbedCardHorizontalIcon: EmbedCardLightHorizontalIcon,
EmbedCardListIcon: EmbedCardLightListIcon,
EmbedCardVerticalIcon: EmbedCardLightVerticalIcon,
EmbedCardCubeIcon: EmbedCardLightCubeIcon,
};
} else {
return {
LoadingIcon: DarkLoadingIcon,
EmbedCardBannerIcon: EmbedCardDarkBannerIcon,
EmbedCardHorizontalIcon: EmbedCardDarkHorizontalIcon,
EmbedCardListIcon: EmbedCardDarkListIcon,
EmbedCardVerticalIcon: EmbedCardDarkVerticalIcon,
EmbedCardCubeIcon: EmbedCardDarkCubeIcon,
};
}
}
export function extractSearchParams(link: string) {
try {

View File

@@ -1,3 +1,4 @@
import { getEmbedCardIcons } from '@blocksuite/affine-block-embed';
import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption';
import { HoverController } from '@blocksuite/affine-components/hover';
import {
@@ -20,7 +21,6 @@ import { classMap } from 'lit/directives/class-map.js';
import { ref } from 'lit/directives/ref.js';
import { styleMap } from 'lit/directives/style-map.js';
import { getEmbedCardIcons } from '../_common/utils/url.js';
import type { AttachmentBlockService } from './attachment-service.js';
import { AttachmentOptionsTemplate } from './components/options.js';
import { AttachmentEmbedProvider } from './embed.js';

View File

@@ -1,4 +1,5 @@
import { MenuContext } from '../../root-block/configs/toolbar.js';
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import type { AttachmentBlockComponent } from '../attachment-block.js';
export class AttachmentToolbarMoreMenuContext extends MenuContext {

View File

@@ -8,6 +8,7 @@ import {
import { createLitPortal } from '@blocksuite/affine-components/portal';
import {
cloneGroups,
getMoreMenuConfig,
renderGroups,
renderToolbarSeparator,
} from '@blocksuite/affine-components/toolbar';
@@ -25,7 +26,6 @@ import { html, nothing } from 'lit';
import { join } from 'lit/directives/join.js';
import { repeat } from 'lit/directives/repeat.js';
import { getMoreMenuConfig } from '../../root-block/configs/toolbar.js';
import type { AttachmentBlockComponent } from '../attachment-block.js';
import { BUILT_IN_GROUPS } from './config.js';
import { AttachmentToolbarMoreMenuContext } from './context.js';

View File

@@ -2,7 +2,10 @@ import type {
AttachmentBlockModel,
ImageBlockProps,
} from '@blocksuite/affine-model';
import { withTempBlobData } from '@blocksuite/affine-shared/utils';
import {
transformModel,
withTempBlobData,
} from '@blocksuite/affine-shared/utils';
import type { ExtensionType } from '@blocksuite/block-std';
import { Extension } from '@blocksuite/block-std';
import type { Container } from '@blocksuite/global/di';
@@ -10,8 +13,6 @@ import { createIdentifier } from '@blocksuite/global/di';
import type { TemplateResult } from 'lit';
import { html } from 'lit';
import { transformModel } from '../root-block/utils/operations/model.js';
export type AttachmentEmbedConfig = {
name: string;
/**

View File

@@ -1,7 +1,9 @@
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '@blocksuite/affine-shared/consts';
import { css } from 'lit';
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH } from '../_common/consts.js';
export const styles = css`
.affine-attachment-card {
margin: 0 auto;

View File

@@ -1,3 +1,4 @@
import { getEmbedCardIcons } from '@blocksuite/affine-block-embed';
import { WebIcon16 } from '@blocksuite/affine-components/icons';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { getHostName } from '@blocksuite/affine-shared/utils';
@@ -8,7 +9,6 @@ import { html } from 'lit';
import { property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { getEmbedCardIcons } from '../../_common/utils/url.js';
import type { BookmarkBlockComponent } from '../bookmark-block.js';
import { styles } from '../styles.js';

View File

@@ -1,9 +1,11 @@
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '@blocksuite/affine-shared/consts';
import { unsafeCSSVar } from '@blocksuite/affine-shared/theme';
import { baseTheme } from '@toeverything/theme';
import { css, unsafeCSS } from 'lit';
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH } from '../_common/consts.js';
export const styles = css`
.affine-bookmark-card {
container: affine-bookmark-card / inline-size;

View File

@@ -1,8 +1,8 @@
import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption';
import type { DividerBlockModel } from '@blocksuite/affine-model';
import { BLOCK_CHILDREN_CONTAINER_PADDING_LEFT } from '@blocksuite/affine-shared/consts';
import { html } from 'lit';
import { BLOCK_CHILDREN_CONTAINER_PADDING_LEFT } from '../_common/consts.js';
import { dividerBlockStyles } from './styles.js';
export class DividerBlockComponent extends CaptionedBlockComponent<DividerBlockModel> {

View File

@@ -24,8 +24,6 @@ import { effects as dataViewEffects } from '@blocksuite/data-view/effects';
import { effects as inlineEffects } from '@blocksuite/inline/effects';
import type { BlockModel } from '@blocksuite/store';
import { EmbedCardMoreMenu } from './_common/components/embed-card/embed-card-more-menu-popper.js';
import { EmbedCardStyleMenu } from './_common/components/embed-card/embed-card-style-popper.js';
import { EmbedCardEditCaptionEditModal } from './_common/components/embed-card/modal/embed-card-caption-edit-modal.js';
import { EmbedCardCreateModal } from './_common/components/embed-card/modal/embed-card-create-modal.js';
import { EmbedCardEditModal } from './_common/components/embed-card/modal/embed-card-edit-modal.js';
@@ -429,9 +427,7 @@ export function effects() {
customElements.define('ai-panel-input', AIPanelInput);
customElements.define('ai-panel-generating', AIPanelGenerating);
customElements.define('edgeless-link-tool-button', EdgelessLinkToolButton);
customElements.define('embed-card-more-menu', EmbedCardMoreMenu);
customElements.define('edgeless-mindmap-menu', EdgelessMindmapMenu);
customElements.define('embed-card-style-menu', EmbedCardStyleMenu);
customElements.define('edgeless-lasso-tool-button', EdgelessLassoToolButton);
customElements.define('affine-filterable-list', FilterableListComponent);
customElements.define('ai-panel-error', AIPanelError);

View File

@@ -7,6 +7,7 @@ import type {
import {
downloadBlob,
humanFileSize,
transformModel,
withTempBlobData,
} from '@blocksuite/affine-shared/utils';
import type { EditorHost } from '@blocksuite/block-std';
@@ -14,7 +15,6 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import type { BlockModel } from '@blocksuite/store';
import { readImageSize } from '../root-block/edgeless/components/utils.js';
import { transformModel } from '../root-block/utils/operations/model.js';
import type { ImageBlockComponent } from './image-block.js';
import type { ImageEdgelessBlockComponent } from './image-edgeless-block.js';

View File

@@ -90,6 +90,7 @@ export {
type AdvancedMenuItem,
type FatMenuItems,
groupsToActions,
MenuContext,
type MenuItem,
type MenuItemGroup,
renderActions,

View File

@@ -1,16 +1,15 @@
import {
asyncSetInlineRange,
focusTextModel,
onModelTextUpdated,
} from '@blocksuite/affine-components/rich-text';
import { matchFlavours } from '@blocksuite/affine-shared/utils';
import type { Command } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store';
import { onModelTextUpdated } from '../../root-block/utils/callback.js';
import {
matchFlavours,
mergeToCodeModel,
transformModel,
} from '../../root-block/utils/operations/model.js';
} from '@blocksuite/affine-shared/utils';
import type { Command } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store';
type UpdateBlockConfig = {
flavour: BlockSuite.Flavour;
@@ -188,6 +187,9 @@ export const updateBlockType: Command<
return;
}
const newId = transformModel(model, flavour, props);
if (!newId) {
return;
}
const newModel = doc.getBlockById(newId);
if (newModel) {
newModels.push(newModel);

View File

@@ -1 +0,0 @@
export * from './toolbar.js';

View File

@@ -1,44 +0,0 @@
import type { MenuItemGroup } from '@blocksuite/affine-components/toolbar';
import type { BlockStdScope, EditorHost } from '@blocksuite/block-std';
import type { GfxModel } from '@blocksuite/block-std/gfx';
import type { BlockModel, Doc } from '@blocksuite/store';
export abstract class MenuContext {
abstract get doc(): Doc;
get firstElement(): GfxModel | null {
return null;
}
abstract get host(): EditorHost;
abstract get selectedBlockModels(): BlockModel[];
abstract get std(): BlockStdScope;
// Sometimes we need to close the menu.
close() {}
isElement() {
return false;
}
abstract isEmpty(): boolean;
abstract isMultiple(): boolean;
abstract isSingle(): boolean;
}
export interface ToolbarMoreMenuConfig {
configure: <T extends MenuContext>(
groups: MenuItemGroup<T>[]
) => MenuItemGroup<T>[];
}
export function getMoreMenuConfig(std: BlockStdScope): ToolbarMoreMenuConfig {
return {
configure: <T extends MenuContext>(groups: MenuItemGroup<T>[]) => groups,
...std.getConfig('affine:page')?.toolbarMoreMenu,
};
}

View File

@@ -11,6 +11,11 @@ import {
MAX_IMAGE_WIDTH,
ReferenceInfoSchema,
} from '@blocksuite/affine-model';
import {
CANVAS_EXPORT_IGNORE_TAGS,
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '@blocksuite/affine-shared/consts';
import {
EmbedOptionProvider,
ParseDocUrlProvider,
@@ -55,11 +60,6 @@ import {
} from '@blocksuite/store';
import DOMPurify from 'dompurify';
import {
CANVAS_EXPORT_IGNORE_TAGS,
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '../../../_common/consts.js';
import { ExportManager } from '../../../_common/export-manager/export-manager.js';
import { getRootByEditorHost } from '../../../_common/utils/query.js';
import { ClipboardAdapter } from '../../clipboard/adapter.js';

View File

@@ -25,6 +25,7 @@ import {
ShapeElementModel,
TextElementModel,
} from '@blocksuite/affine-model';
import { EMBED_CARD_HEIGHT } from '@blocksuite/affine-shared/consts';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import {
clamp,
@@ -57,7 +58,6 @@ import { state } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { styleMap } from 'lit/directives/style-map.js';
import { EMBED_CARD_HEIGHT } from '../../../../_common/consts.js';
import { isMindmapNode } from '../../../../_common/edgeless/mindmap/index.js';
import type { EdgelessTextBlockComponent } from '../../../../edgeless-text-block/edgeless-text-block.js';
import { EDGELESS_TEXT_BLOCK_MIN_WIDTH } from '../../../../edgeless-text-block/edgeless-text-block.js';

View File

@@ -1,6 +1,5 @@
export * from './adapters/markdown.js';
export * from './clipboard/index.js';
export * from './configs/index.js';
export * from './edgeless/edgeless-root-spec.js';
export * from './edgeless/index.js';
export { TemplateJob } from './edgeless/services/template.js';

View File

@@ -1,5 +1,6 @@
import type { ToolbarMoreMenuConfig } from '@blocksuite/affine-components/toolbar';
import type { DatabaseOptionsConfig } from '../database-block/config.js';
import type { ToolbarMoreMenuConfig } from './configs/index.js';
import type { DocRemoteSelectionConfig } from './widgets/doc-remote-selection/config.js';
import type { KeyboardToolbarConfig } from './widgets/keyboard-toolbar/config.js';
import type { LinkedWidgetConfig } from './widgets/linked-doc/index.js';

View File

@@ -1,31 +1,6 @@
import type { RichText } from '@blocksuite/affine-components/rich-text';
import { asyncGetRichText } from '@blocksuite/affine-components/rich-text';
import type { BlockComponent, EditorHost } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store';
export async function onModelTextUpdated(
editorHost: EditorHost,
model: BlockModel,
callback?: (text: RichText) => void
) {
const richText = await asyncGetRichText(editorHost, model.id);
if (!richText) {
console.error('RichText is not ready yet.');
return;
}
await richText.updateComplete;
const inlineEditor = richText.inlineEditor;
if (!inlineEditor) {
console.error('Inline editor is not ready yet.');
return;
}
inlineEditor.slots.renderComplete.once(() => {
if (callback) {
callback(richText);
}
});
}
// Run the callback until a model's element updated.
// Please notice that the callback will be called **once the element itself is ready**.
// The children may be not updated.

View File

@@ -1,67 +0,0 @@
import { assertExists } from '@blocksuite/global/utils';
import { type BlockModel, type Doc, Text } from '@blocksuite/store';
/**
* This file should only contain functions that are used to
* operate on block models in store, which means that this operations
* just operate on data and will not involve in something about ui like selection reset.
*/
export function mergeToCodeModel(models: BlockModel[]) {
if (models.length === 0) {
return null;
}
const doc = models[0].doc;
const parent = doc.getParent(models[0]);
if (!parent) {
return null;
}
const index = parent.children.indexOf(models[0]);
const text = models
.map(model => {
if (model.text instanceof Text) {
return model.text.toString();
}
return null;
})
.filter(Boolean)
.join('\n');
models.forEach(model => doc.deleteBlock(model));
const id = doc.addBlock(
'affine:code',
{ text: new Text(text) },
parent,
index
);
return id;
}
export function transformModel(
model: BlockModel,
flavour: BlockSuite.Flavour,
props?: Parameters<Doc['addBlock']>[1]
) {
const doc = model.doc;
const parent = doc.getParent(model);
assertExists(parent);
const blockProps: {
type?: string;
text?: Text;
children?: BlockModel[];
} = {
text: model?.text?.clone(), // should clone before `deleteBlock`
children: model.children,
...props,
};
const index = parent.children.indexOf(model);
// Sometimes the new block can not be added due to some reason, e.g. invalid schema check.
// So we need to try to add the new block first, and if it fails, we will not delete the old block.
const id = doc.addBlock(flavour, blockProps, parent, index);
doc.deleteBlock(model, {
deleteChildren: false,
});
return id;
}

View File

@@ -1,5 +1,6 @@
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import type { CodeBlockComponent } from '../../../code-block/code-block.js';
import { MenuContext } from '../../configs/toolbar.js';
export class CodeBlockToolbarContext extends MenuContext {
override close = () => {

View File

@@ -3,15 +3,17 @@ import type {
AdvancedMenuItem,
MenuItemGroup,
} from '@blocksuite/affine-components/toolbar';
import { cloneGroups } from '@blocksuite/affine-components/toolbar';
import {
cloneGroups,
getMoreMenuConfig,
} from '@blocksuite/affine-components/toolbar';
import type { CodeBlockModel } from '@blocksuite/affine-model';
import { PAGE_HEADER_HEIGHT } from '@blocksuite/affine-shared/consts';
import { WidgetComponent } from '@blocksuite/block-std';
import { limitShift, shift } from '@floating-ui/dom';
import { html } from 'lit';
import { PAGE_HEADER_HEIGHT } from '../../../_common/consts.js';
import type { CodeBlockComponent } from '../../../code-block/code-block.js';
import { getMoreMenuConfig } from '../../configs/toolbar.js';
import { MORE_GROUPS, PRIMARY_GROUPS } from './config.js';
import { CodeBlockToolbarContext } from './context.js';

View File

@@ -1,3 +1,4 @@
import { getEmbedCardIcons } from '@blocksuite/affine-block-embed';
import {
CaptionIcon,
DownloadIcon,
@@ -5,6 +6,10 @@ import {
} from '@blocksuite/affine-components/icons';
import { renderToolbarSeparator } from '@blocksuite/affine-components/toolbar';
import type { AttachmentBlockModel } from '@blocksuite/affine-model';
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '@blocksuite/affine-shared/consts';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { Bound, WithDisposable } from '@blocksuite/global/utils';
import type { TemplateResult } from 'lit';
@@ -12,12 +17,7 @@ import { html, LitElement, nothing } from 'lit';
import { property } from 'lit/decorators.js';
import { join } from 'lit/directives/join.js';
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '../../../_common/consts.js';
import type { EmbedCardStyle } from '../../../_common/types.js';
import { getEmbedCardIcons } from '../../../_common/utils/url.js';
import type { AttachmentBlockComponent } from '../../../attachment-block/index.js';
import { attachmentViewToggleMenu } from '../../../attachment-block/index.js';
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';

View File

@@ -1,4 +1,7 @@
import { getDocContentWithMaxLength } from '@blocksuite/affine-block-embed';
import {
getDocContentWithMaxLength,
getEmbedCardIcons,
} from '@blocksuite/affine-block-embed';
import {
CaptionIcon,
CenterPeekIcon,
@@ -17,6 +20,10 @@ import {
renderToolbarSeparator,
} from '@blocksuite/affine-components/toolbar';
import { type AliasInfo, BookmarkStyles } from '@blocksuite/affine-model';
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '@blocksuite/affine-shared/consts';
import {
EmbedOptionProvider,
type EmbedOptions,
@@ -42,12 +49,7 @@ import type {
EmbedModel,
} from '../../../_common/components/embed-card/type.js';
import { isInternalEmbedModel } from '../../../_common/components/embed-card/type.js';
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '../../../_common/consts.js';
import type { EmbedCardStyle } from '../../../_common/types.js';
import { getEmbedCardIcons } from '../../../_common/utils/url.js';
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
import {
isBookmarkBlock,

View File

@@ -3,6 +3,7 @@ import { ConnectorCWithArrowIcon } from '@blocksuite/affine-components/icons';
import {
cloneGroups,
darkToolbarStyles,
getMoreMenuConfig,
lightToolbarStyles,
type MenuItemGroup,
renderToolbarSeparator,
@@ -38,7 +39,6 @@ import { property, state } from 'lit/decorators.js';
import { join } from 'lit/directives/join.js';
import type { EmbedModel } from '../../../_common/components/embed-card/type.js';
import { getMoreMenuConfig } from '../../configs/toolbar.js';
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
import {
isAttachmentBlock,

View File

@@ -1,11 +1,11 @@
import type { SurfaceBlockComponent } from '@blocksuite/affine-block-surface';
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import {
GfxPrimitiveElementModel,
type GfxSelectionManager,
} from '@blocksuite/block-std/gfx';
import type { BlockModel } from '@blocksuite/store';
import { MenuContext } from '../../../configs/toolbar.js';
import type { EdgelessRootBlockComponent } from '../../../edgeless/edgeless-root-block.js';
import type { EdgelessRootService } from '../../../edgeless/edgeless-root-service.js';
import {

View File

@@ -1,5 +1,6 @@
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import type { EmbedBlockComponent } from '../../../_common/components/embed-card/type.js';
import { MenuContext } from '../../configs/toolbar.js';
export class EmbedCardToolbarContext extends MenuContext {
override close = () => {

View File

@@ -1,4 +1,7 @@
import { getDocContentWithMaxLength } from '@blocksuite/affine-block-embed';
import {
getDocContentWithMaxLength,
getEmbedCardIcons,
} from '@blocksuite/affine-block-embed';
import {
CaptionIcon,
CenterPeekIcon,
@@ -15,6 +18,7 @@ import { isPeekable, peek } from '@blocksuite/affine-components/peek';
import { toast } from '@blocksuite/affine-components/toast';
import {
cloneGroups,
getMoreMenuConfig,
type MenuItem,
type MenuItemGroup,
renderGroups,
@@ -24,6 +28,7 @@ import {
type AliasInfo,
type BookmarkBlockModel,
BookmarkStyles,
type EmbedCardStyle,
type EmbedGithubModel,
type EmbedLinkedDocModel,
type RootBlockModel,
@@ -57,9 +62,6 @@ import {
isEmbedCardBlockComponent,
isInternalEmbedModel,
} from '../../../_common/components/embed-card/type.js';
import type { EmbedCardStyle } from '../../../_common/types.js';
import { getEmbedCardIcons } from '../../../_common/utils/url.js';
import { getMoreMenuConfig } from '../../configs/toolbar.js';
import {
isBookmarkBlock,
isEmbedGithubBlock,

View File

@@ -1,4 +1,5 @@
import { MenuContext } from '../../configs/toolbar.js';
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import type { AffineFormatBarWidget } from './format-bar.js';
export class FormatBarContext extends MenuContext {

View File

@@ -3,6 +3,7 @@ import type { RichText } from '@blocksuite/affine-components/rich-text';
import { isFormatSupported } from '@blocksuite/affine-components/rich-text';
import {
cloneGroups,
getMoreMenuConfig,
type MenuItemGroup,
} from '@blocksuite/affine-components/toolbar';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
@@ -30,7 +31,6 @@ import {
import { html, nothing } from 'lit';
import { query, state } from 'lit/decorators.js';
import { getMoreMenuConfig } from '../../configs/toolbar.js';
import { ConfigRenderer } from './components/config-renderer.js';
import {
BUILT_IN_GROUPS,

View File

@@ -1,5 +1,6 @@
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import type { ImageBlockComponent } from '../../../image-block/image-block.js';
import { MenuContext } from '../../configs/toolbar.js';
export class ImageToolbarContext extends MenuContext {
override close = () => {

View File

@@ -3,15 +3,17 @@ import type {
AdvancedMenuItem,
MenuItemGroup,
} from '@blocksuite/affine-components/toolbar';
import { cloneGroups } from '@blocksuite/affine-components/toolbar';
import {
cloneGroups,
getMoreMenuConfig,
} from '@blocksuite/affine-components/toolbar';
import type { ImageBlockModel } from '@blocksuite/affine-model';
import { PAGE_HEADER_HEIGHT } from '@blocksuite/affine-shared/consts';
import { WidgetComponent } from '@blocksuite/block-std';
import { limitShift, shift } from '@floating-ui/dom';
import { html } from 'lit';
import { PAGE_HEADER_HEIGHT } from '../../../_common/consts.js';
import type { ImageBlockComponent } from '../../../image-block/image-block.js';
import { getMoreMenuConfig } from '../../configs/toolbar.js';
import { MORE_GROUPS, PRIMARY_GROUPS } from './config.js';
import { ImageToolbarContext } from './context.js';

View File

@@ -1,5 +1,6 @@
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import type { SurfaceRefBlockComponent } from '../../../surface-ref-block/surface-ref-block.js';
import { MenuContext } from '../../configs/toolbar.js';
export class SurfaceRefToolbarContext extends MenuContext {
override close = () => {

View File

@@ -10,12 +10,14 @@ import {
import { isPeekable, peek } from '@blocksuite/affine-components/peek';
import {
cloneGroups,
getMoreMenuConfig,
type MenuItem,
type MenuItemGroup,
renderGroups,
renderToolbarSeparator,
} from '@blocksuite/affine-components/toolbar';
import type { SurfaceRefBlockModel } from '@blocksuite/affine-model';
import { PAGE_HEADER_HEIGHT } from '@blocksuite/affine-shared/consts';
import { WidgetComponent } from '@blocksuite/block-std';
import { offset, shift } from '@floating-ui/dom';
import { html, nothing } from 'lit';
@@ -23,9 +25,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { join } from 'lit/directives/join.js';
import { repeat } from 'lit/directives/repeat.js';
import { PAGE_HEADER_HEIGHT } from '../../../_common/consts.js';
import type { SurfaceRefBlockComponent } from '../../../surface-ref-block/index.js';
import { getMoreMenuConfig } from '../../configs/toolbar.js';
import { BUILT_IN_GROUPS } from './config.js';
import { SurfaceRefToolbarContext } from './context.js';

View File

@@ -5,6 +5,10 @@ import {
NoteDisplayMode,
NoteShadow,
} from '@blocksuite/affine-model';
import {
EDGELESS_BLOCK_CHILD_BORDER_WIDTH,
EDGELESS_BLOCK_CHILD_PADDING,
} from '@blocksuite/affine-shared/consts';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { SpecProvider } from '@blocksuite/affine-shared/utils';
import {
@@ -20,11 +24,6 @@ import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { html } from 'lit/static-html.js';
import {
EDGELESS_BLOCK_CHILD_BORDER_WIDTH,
EDGELESS_BLOCK_CHILD_PADDING,
} from '../../_common/consts.js';
export class SurfaceRefNotePortal extends WithDisposable(ShadowlessElement) {
static override styles = css`
surface-ref-note-portal {