refactor(editor): remove assertExists (#10615)

This commit is contained in:
Saul-Mirone
2025-03-05 00:13:08 +00:00
parent a6692f70aa
commit b8ecfbdae6
106 changed files with 863 additions and 517 deletions

View File

@@ -1,5 +1,4 @@
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists } from '@blocksuite/global/utils';
import type {
BlockSnapshot,
DocSnapshot,
@@ -50,7 +49,12 @@ export class ClipboardAdapter extends BaseAdapter<string> {
): Promise<FromSliceSnapshotResult<string>> {
const snapshot = payload.snapshot;
const assets = payload.assets;
assertExists(assets);
if (!assets) {
throw new BlockSuiteError(
ErrorCode.ValueNotExists,
'ClipboardAdapter.fromSliceSnapshot: assets is not found'
);
}
const map = assets.getAssets();
const blobs: Record<string, FileSnapshot> = await encodeClipboardBlobs(map);
return {

View File

@@ -1,5 +1,4 @@
import { toast } from '@blocksuite/affine-components/toast';
import { assertExists } from '@blocksuite/global/utils';
import type { FileSnapshot } from './adapter.js';
@@ -113,12 +112,17 @@ export function decodeClipboardBlobs(
blobs: Record<string, FileSnapshot>,
map: Map<string, Blob> | undefined
) {
if (!map) {
console.error(
`Trying to decode clipboard blobs, but the map is not found.`
);
return;
}
Object.entries<FileSnapshot>(blobs).forEach(([sourceId, file]) => {
const blob = new Blob([decode(file.content)]);
const f = new File([blob], file.name, {
type: file.type,
});
assertExists(map);
map.set(sourceId, f);
});
}

View File

@@ -57,12 +57,7 @@ import {
type SerializedXYWH,
Vec,
} from '@blocksuite/global/gfx';
import {
assertExists,
assertType,
DisposableGroup,
nToLast,
} from '@blocksuite/global/utils';
import { assertType, DisposableGroup, nToLast } from '@blocksuite/global/utils';
import {
type BlockSnapshot,
BlockSnapshotSchema,
@@ -519,17 +514,19 @@ export class EdgelessClipboardController extends PageClipboard {
clipboardData: SerializedElement,
context: CreationContext,
newXYWH: SerializedXYWH
) {
): GfxPrimitiveElementModel | null {
if (clipboardData.type === GROUP) {
const yMap = new Y.Map();
const children = clipboardData.children ?? {};
for (const [key, value] of Object.entries(children)) {
const newKey = context.oldToNewIdMap.get(key);
assertExists(
newKey,
'Copy failed: cannot find the copied child in group'
);
if (!newKey) {
console.error(
`Copy failed: cannot find the copied child in group, key: ${key}`
);
return null;
}
yMap.set(newKey, value);
}
clipboardData.children = yMap;
@@ -543,17 +540,21 @@ export class EdgelessClipboardController extends PageClipboard {
const newValue = {
...oldValue,
};
assertExists(
newKey,
'Copy failed: cannot find the copied node in mind map'
);
if (!newKey) {
console.error(
`Copy failed: cannot find the copied node in mind map, key: ${oldKey}`
);
return null;
}
if (oldValue.parent) {
const newParent = context.oldToNewIdMap.get(oldValue.parent);
assertExists(
newParent,
'Copy failed: cannot find the copied node in mind map'
);
if (!newParent) {
console.error(
`Copy failed: cannot find the copied node in mind map, parent: ${oldValue.parent}`
);
return null;
}
newValue.parent = newParent;
}
@@ -603,7 +604,10 @@ export class EdgelessClipboardController extends PageClipboard {
type: clipboardData.type as string,
});
const element = this.crud.getElementById(id) as GfxPrimitiveElementModel;
assertExists(element);
if (!element) {
console.error(`Copy failed: cannot find the copied element, id: ${id}`);
return null;
}
return element;
}
@@ -898,7 +902,7 @@ export class EdgelessClipboardController extends PageClipboard {
const editorMode = isInsidePageEditor(host);
const rootComponent = getRootByEditorHost(host);
assertExists(rootComponent);
if (!rootComponent) return;
const container = rootComponent.querySelector(
'.affine-block-children-container'
@@ -1355,7 +1359,10 @@ export class EdgelessClipboardController extends PageClipboard {
bounds.push(shape.elementBound);
});
const bound = getCommonBound(bounds);
assertExists(bound, 'bound not exist');
if (!bound) {
console.error('bound not exist');
return;
}
const canvas = await this._edgelessToCanvas(
this.host,

View File

@@ -27,11 +27,7 @@ import { type BlockStdScope, stdContext } from '@blocksuite/block-std';
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
import type { Bound, IVec } from '@blocksuite/global/gfx';
import { Vec } from '@blocksuite/global/gfx';
import {
assertExists,
DisposableGroup,
WithDisposable,
} from '@blocksuite/global/utils';
import { DisposableGroup, WithDisposable } from '@blocksuite/global/utils';
import {
ArrowUpBigIcon,
PlusIcon,
@@ -194,7 +190,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
);
}
if (this._isMoving) {
assertExists(connector);
if (!connector) {
return;
}
const otherSideId = connector.source.id;
connector.target = this.connectionOverlay.renderConnector(
@@ -382,7 +380,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
);
} else {
const model = doc.getBlockById(id);
assertExists(model);
if (!model) {
return;
}
const [x, y] = service.viewport.toViewCoord(
bound.center[0],
bound.y + DEFAULT_NOTE_HEIGHT / 2

View File

@@ -7,7 +7,6 @@ import {
type PointLocation,
rotatePoints,
} from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import type { SelectableProps } from '../../utils/query.js';
import { HandleDirection, type ResizeMode } from './resize-handles.js';
@@ -113,7 +112,9 @@ export class HandleResizeManager {
const rect = this._target
.closest('.affine-edgeless-selected-rect')
?.getBoundingClientRect();
assertExists(rect);
if (!rect) {
return;
}
const { left, top, right, bottom } = rect;
const x = (left + right) / 2;
const y = (top + bottom) / 2;
@@ -207,12 +208,10 @@ export class HandleResizeManager {
_rotate,
_resizeMode,
_zoom,
_target,
_originalRect,
_currentRect,
} = this;
proportion ||= this._proportion;
assertExists(_target);
const isAll = _resizeMode === 'all';
const isCorner = _resizeMode === 'corner';

View File

@@ -11,7 +11,7 @@ import {
ShadowlessElement,
} from '@blocksuite/block-std';
import { Bound, Vec } from '@blocksuite/global/gfx';
import { assertExists, WithDisposable } from '@blocksuite/global/utils';
import { WithDisposable } from '@blocksuite/global/utils';
import { css, html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
@@ -94,12 +94,11 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
};
get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor;
}
get inlineEditorContainer() {
return this.inlineEditor.rootElement;
return this.inlineEditor?.rootElement;
}
override connectedCallback() {
@@ -116,7 +115,6 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
override firstUpdated() {
const { edgeless, connector } = this;
const { dispatcher } = edgeless;
assertExists(dispatcher);
this._resizeObserver = new ResizeObserver(() => {
this._updateLabelRect();
@@ -126,6 +124,7 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
this.updateComplete
.then(() => {
if (!this.inlineEditor) return;
this.inlineEditor.selectAll();
this.inlineEditor.slots.renderComplete.on(() => {

View File

@@ -10,7 +10,7 @@ import {
ShadowlessElement,
} from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx';
import { assertExists, WithDisposable } from '@blocksuite/global/utils';
import { WithDisposable } from '@blocksuite/global/utils';
import { cssVarV2 } from '@toeverything/theme/v2';
import { css, html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
@@ -63,7 +63,6 @@ export class EdgelessFrameTitleEditor extends WithDisposable(
override firstUpdated(): void {
const dispatcher = this.edgeless.dispatcher;
assertExists(dispatcher);
this.updateComplete
.then(() => {
if (!this.inlineEditor) return;

View File

@@ -10,7 +10,7 @@ import {
ShadowlessElement,
} from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx';
import { assertExists, WithDisposable } from '@blocksuite/global/utils';
import { WithDisposable } from '@blocksuite/global/utils';
import { html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
@@ -21,12 +21,11 @@ export class EdgelessGroupTitleEditor extends WithDisposable(
ShadowlessElement
) {
get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor;
}
get inlineEditorContainer() {
return this.inlineEditor.rootElement;
return this.inlineEditor?.rootElement;
}
private _unmount() {
@@ -47,10 +46,10 @@ export class EdgelessGroupTitleEditor extends WithDisposable(
override firstUpdated(): void {
const dispatcher = this.edgeless.dispatcher;
assertExists(dispatcher);
this.updateComplete
.then(() => {
if (!this.inlineEditor) return;
this.inlineEditor.selectAll();
this.group.showTitle = false;

View File

@@ -12,7 +12,7 @@ import {
ShadowlessElement,
} from '@blocksuite/block-std';
import { Bound, toRadian, Vec } from '@blocksuite/global/gfx';
import { assertExists, WithDisposable } from '@blocksuite/global/utils';
import { WithDisposable } from '@blocksuite/global/utils';
import { html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
@@ -32,12 +32,11 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
private _resizeObserver: ResizeObserver | null = null;
get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor;
}
get inlineEditorContainer() {
return this.inlineEditor.rootElement;
return this.inlineEditor?.rootElement;
}
get isMindMapNode() {
@@ -175,7 +174,6 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
override firstUpdated(): void {
const dispatcher = this.edgeless.dispatcher;
assertExists(dispatcher);
this.element.textDisplay = false;
@@ -202,6 +200,7 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
this.updateComplete
.then(() => {
if (!this.inlineEditor) return;
if (this.element.group instanceof MindmapElementModel) {
this.inlineEditor.selectAll();
} else {

View File

@@ -11,7 +11,7 @@ import {
ShadowlessElement,
} from '@blocksuite/block-std';
import { Bound, toRadian, Vec } from '@blocksuite/global/gfx';
import { assertExists, WithDisposable } from '@blocksuite/global/utils';
import { WithDisposable } from '@blocksuite/global/utils';
import { css, html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
@@ -144,12 +144,11 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) {
};
get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor;
}
get inlineEditorContainer() {
return this.inlineEditor.rootElement;
return this.inlineEditor?.rootElement;
}
override connectedCallback(): void {
@@ -170,10 +169,10 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) {
const edgeless = this.edgeless;
const element = this.element;
const { dispatcher } = this.edgeless;
assertExists(dispatcher);
this.updateComplete
.then(() => {
if (!this.inlineEditor) return;
this.inlineEditor.slots.renderComplete.on(() => {
this._updateRect();
this.requestUpdate();

View File

@@ -1,4 +1,4 @@
import { assertExists } from '@blocksuite/global/utils';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
// more than 100% due to the shadow
const leaveToPercent = `calc(100% + 10px)`;
@@ -28,26 +28,31 @@ export function createPopper<T extends keyof HTMLElementTagNameMap>(
onDispose?: () => void;
setProps?: (ele: HTMLElementTagNameMap[T]) => void;
}
) {
): MenuPopper<HTMLElementTagNameMap[T]> {
const duration = options?.duration ?? 230;
if (!popMap.has(reference)) popMap.set(reference, new Map());
const elMap = popMap.get(reference);
assertExists(elMap);
// if there is already a popper, cancel leave transition and apply enter transition
if (elMap.has(tagName)) {
if (elMap && elMap.has(tagName)) {
const popper = elMap.get(tagName);
assertExists(popper);
popper.cancel?.();
requestAnimationFrame(() => animateEnter(popper.element));
return popper as MenuPopper<HTMLElementTagNameMap[T]>;
if (popper) {
popper.cancel?.();
requestAnimationFrame(() => animateEnter(popper.element));
return popper as MenuPopper<HTMLElementTagNameMap[T]>;
}
}
const clipWrapper = document.createElement('div');
const menu = document.createElement(tagName);
options?.setProps?.(menu);
assertExists(reference.shadowRoot);
clipWrapper.append(menu);
if (!reference.shadowRoot) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'reference must be a shadow root'
);
}
reference.shadowRoot.append(clipWrapper);
// apply enter transition

View File

@@ -3,7 +3,6 @@ import {
ThemeProvider,
} from '@blocksuite/affine-shared/services';
import { Bound } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import {
type ReactiveController,
type ReactiveControllerHost,
@@ -200,8 +199,7 @@ export class EdgelessDraggableElementController<T>
}
const { overlay } = this;
assertExists(overlay);
if (!overlay) return;
const { x, y } = e;
const { startPos, scopeRect } = info;
const offsetX = x - startPos.x;

View File

@@ -12,7 +12,7 @@ import {
TelemetryProvider,
ThemeProvider,
} from '@blocksuite/affine-shared/services';
import { assertExists, SignalWatcher } from '@blocksuite/global/utils';
import { SignalWatcher } from '@blocksuite/global/utils';
import { css, html, LitElement, nothing } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
@@ -248,7 +248,10 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
const el = this.shapeContainer.querySelector(
`.shape.${this.draggingShape}`
) as HTMLElement;
assertExists(el, 'Edgeless toolbar Shape element not found');
if (!el) {
console.error('Edgeless toolbar Shape element not found');
return;
}
const { x, y } = service.gfx.tool.lastMousePos$.peek();
const { left, top } = this.edgeless.viewport;
const clientPos = { x: x + left, y: y + top };

View File

@@ -1,7 +1,6 @@
import type { CursorType, StandardCursor } from '@blocksuite/block-std/gfx';
import type { IVec } from '@blocksuite/global/gfx';
import { normalizeDegAngle, Vec } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { css, html } from 'lit';
export function generateCursorUrl(
@@ -89,7 +88,11 @@ export function calcAngle(target: HTMLElement, point: IVec, offset = 0) {
const rect = target
.closest('.affine-edgeless-selected-rect')
?.getBoundingClientRect();
assertExists(rect);
if (!rect) {
console.error('rect not found when calc angle');
return 0;
}
const { left, top, right, bottom } = rect;
const center = Vec.med([left, top], [right, bottom]);
return normalizeDegAngle(
@@ -104,9 +107,7 @@ export function calcAngleWithRotation(
rotate: number
) {
const handle = target.parentElement;
assertExists(handle);
const ariaLabel = handle.getAttribute('aria-label');
assertExists(ariaLabel);
const ariaLabel = handle?.getAttribute('aria-label');
const { left, top, right, bottom, width, height } = rect;
const size = Math.min(width, height);
const sx = size / width;
@@ -160,9 +161,7 @@ export function calcAngleWithRotation(
export function calcAngleEdgeWithRotation(target: HTMLElement, rotate: number) {
let angleWithEdge = 0;
const handle = target.parentElement;
assertExists(handle);
const ariaLabel = handle.getAttribute('aria-label');
assertExists(ariaLabel);
const ariaLabel = handle?.getAttribute('aria-label');
switch (ariaLabel) {
case 'top': {
angleWithEdge = 270;
@@ -187,9 +186,7 @@ export function calcAngleEdgeWithRotation(target: HTMLElement, rotate: number) {
export function getResizeLabel(target: HTMLElement) {
const handle = target.parentElement;
assertExists(handle);
const ariaLabel = handle.getAttribute('aria-label');
assertExists(ariaLabel);
const ariaLabel = handle?.getAttribute('aria-label');
return ariaLabel;
}

View File

@@ -39,8 +39,8 @@ import {
type GfxViewportElement,
} from '@blocksuite/block-std/gfx';
import { IS_WINDOWS } from '@blocksuite/global/env';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import { Bound, Point, Vec } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { effect } from '@preact/signals-core';
import { css, html } from 'lit';
import { query } from 'lit/decorators.js';
@@ -191,7 +191,12 @@ export class EdgelessRootBlockComponent extends BlockComponent<
this._viewportElement = this.host.closest(
'.affine-edgeless-viewport'
) as HTMLElement | null;
assertExists(this._viewportElement);
if (!this._viewportElement) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'EdgelessRootBlockComponent.viewportElement: viewport element is not found'
);
}
return this._viewportElement;
}

View File

@@ -17,7 +17,7 @@ import {
SurfaceSelection,
} from '@blocksuite/block-std';
import type { GfxViewportElement } from '@blocksuite/block-std/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import { css, html } from 'lit';
import { query, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
@@ -104,7 +104,12 @@ export class EdgelessRootPreviewBlockComponent
this._viewportElement = this.host.closest(
this.editorViewportSelector
) as HTMLElement | null;
assertExists(this._viewportElement);
if (!this._viewportElement) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'EdgelessRootPreviewBlockComponent.viewportElement: viewport element is not found'
);
}
return this._viewportElement;
}

View File

@@ -4,7 +4,6 @@ import { TelemetryProvider } from '@blocksuite/affine-shared/services';
import type { PointerEventState } from '@blocksuite/block-std';
import { BaseTool } from '@blocksuite/block-std/gfx';
import type { IVec } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
export class BrushTool extends BaseTool {
static BRUSH_POP_GAP = 20;
@@ -40,8 +39,10 @@ export class BrushTool extends BaseTool {
: 'vertical';
}
private _tryGetPressurePoints(e: PointerEventState) {
assertExists(this._draggingPathPressures);
private _tryGetPressurePoints(e: PointerEventState): number[][] {
if (!this._draggingPathPressures) {
return [];
}
const pressures = [...this._draggingPathPressures, e.pressure];
this._draggingPathPressures = pressures;
@@ -56,8 +57,10 @@ export class BrushTool extends BaseTool {
this._pressureSupportedPointerIds.add(pointerId);
}
assertExists(this._draggingPathPoints);
const points = this._draggingPathPoints;
if (!points) {
return [];
}
if (this._pressureSupportedPointerIds.has(pointerId)) {
return points.map(([x, y], i) => [x, y, pressures[i]]);
} else {
@@ -83,12 +86,14 @@ export class BrushTool extends BaseTool {
}
override dragMove(e: PointerEventState) {
if (!this._draggingElementId || !this._draggingElement || !this.gfx.surface)
if (
!this._draggingElementId ||
!this._draggingElement ||
!this.gfx.surface ||
!this._draggingPathPoints
)
return;
assertExists(this._draggingElementId);
assertExists(this._draggingPathPoints);
let pointX = e.point.x;
let pointY = e.point.y;
const holdingShiftKey = e.keys.shift || this.gfx.keyboard.shiftKey$.peek();

View File

@@ -1,7 +1,7 @@
import { generateElementId, sortIndex } from '@blocksuite/affine-block-surface';
import type { ConnectorElementModel } from '@blocksuite/affine-model';
import { Bound } from '@blocksuite/global/gfx';
import { assertExists, assertType } from '@blocksuite/global/utils';
import { assertType } from '@blocksuite/global/utils';
import type { BlockSnapshot, SnapshotNode } from '@blocksuite/store';
import type { SlotBlockPayload, TemplateJob } from './template.js';
@@ -154,8 +154,6 @@ export const createInsertPlaceMiddleware = (targetPlace: Bound) => {
const ignoreType = new Set(['group', 'connector']);
const changePosition = (blockJson: BlockSnapshot) => {
assertExists(templateBound);
if (blockJson.props.xywh) {
const bound = Bound.deserialize(blockJson.props['xywh'] as string);

View File

@@ -4,7 +4,7 @@ import type {
} from '@blocksuite/affine-block-surface';
import type { ConnectorElementModel } from '@blocksuite/affine-model';
import { Bound, getCommonBound } from '@blocksuite/global/gfx';
import { assertExists, assertType, Slot } from '@blocksuite/global/utils';
import { assertType, Slot } from '@blocksuite/global/utils';
import {
type BlockModel,
type BlockSnapshot,
@@ -194,7 +194,9 @@ export class TemplateJob {
return;
}
assertExists(modelData);
if (!modelData) {
return;
}
doc.addBlock(
modelData.flavour,

View File

@@ -8,7 +8,7 @@ import {
import { SpecProvider } from '@blocksuite/affine-shared/utils';
import { Container } from '@blocksuite/global/di';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists, sha } from '@blocksuite/global/utils';
import { sha } from '@blocksuite/global/utils';
import type { Schema, Store, Workspace } from '@blocksuite/store';
import { extMimeMap, Transformer } from '@blocksuite/store';
@@ -112,7 +112,12 @@ async function importMarkdownToBlock({
pageId: doc.id,
});
assertExists(snapshot, 'import markdown failed, expected to get a snapshot');
if (!snapshot) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'import markdown failed, expected to get a snapshot'
);
}
const blocks = snapshot.content.flatMap(x => x.children);

View File

@@ -16,7 +16,6 @@ import {
} from '@blocksuite/affine-shared/commands';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type { EditorHost } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
import { computePosition, flip, offset, shift } from '@floating-ui/dom';
import { html } from 'lit';
import { ref, type RefOrCallback } from 'lit/directives/ref.js';
@@ -125,8 +124,9 @@ export const HighlightButton = (formatBar: AffineFormatBarWidget) => {
formatBar.shadowRoot?.querySelector<HTMLElement>('.highlight-button');
const panel =
formatBar.shadowRoot?.querySelector<HTMLElement>('.highlight-panel');
assertExists(button);
assertExists(panel);
if (!button || !panel) {
return;
}
panel.style.display = 'flex';
computePosition(button, panel, {
placement: 'bottom',

View File

@@ -3,7 +3,6 @@ import { ArrowDownIcon } from '@blocksuite/affine-components/icons';
import { textConversionConfigs } from '@blocksuite/affine-components/rich-text';
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
import type { EditorHost } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
import { computePosition, flip, offset, shift } from '@floating-ui/dom';
import { html } from 'lit';
import { ref, type RefOrCallback } from 'lit/directives/ref.js';
@@ -85,13 +84,11 @@ export const ParagraphButton = (formatBar: AffineFormatBarWidget) => {
return;
}
const formatQuickBarElement = formatBar.formatBarElement;
const button =
formatBar.shadowRoot?.querySelector<HTMLElement>('.paragraph-button');
const panel =
formatBar.shadowRoot?.querySelector<HTMLElement>('.paragraph-panel');
assertExists(button);
assertExists(panel);
assertExists(formatQuickBarElement, 'format quick bar should exist');
if (!panel || !formatQuickBarElement) {
return;
}
panel.style.display = 'flex';
computePosition(formatQuickBarElement, panel, {
placement: 'top-start',

View File

@@ -62,7 +62,6 @@ import type {
InitCommandCtx,
} from '@blocksuite/block-std';
import { tableViewMeta } from '@blocksuite/data-view/view-presets';
import { assertExists } from '@blocksuite/global/utils';
import { MoreVerticalIcon } from '@blocksuite/icons/lit';
import { Slice, toDraftModel } from '@blocksuite/store';
import { html, type TemplateResult } from 'lit';
@@ -377,13 +376,17 @@ export const BUILT_IN_GROUPS: MenuItemGroup<FormatBarContext>[] = [
.try<{ currentSelectionPath: string }>(cmd => [
cmd.pipe(getTextSelectionCommand).pipe((ctx, next) => {
const textSelection = ctx.currentTextSelection;
assertExists(textSelection);
if (!textSelection) {
return;
}
const end = textSelection.to ?? textSelection.from;
next({ currentSelectionPath: end.blockId });
}),
cmd.pipe(getBlockSelectionsCommand).pipe((ctx, next) => {
const currentBlockSelections = ctx.currentBlockSelections;
assertExists(currentBlockSelections);
if (!currentBlockSelections) {
return;
}
const blockSelection = currentBlockSelections.at(-1);
if (!blockSelection) {
return;

View File

@@ -29,11 +29,7 @@ import {
TextSelection,
WidgetComponent,
} from '@blocksuite/block-std';
import {
assertExists,
DisposableGroup,
nextTick,
} from '@blocksuite/global/utils';
import { DisposableGroup, nextTick } from '@blocksuite/global/utils';
import type { BaseSelection } from '@blocksuite/store';
import {
autoUpdate,
@@ -239,7 +235,9 @@ export class AffineFormatBarWidget extends WidgetComponent {
private _listenFloatingElement() {
const formatQuickBarElement = this.formatBarElement;
assertExists(formatQuickBarElement, 'format quick bar should exist');
if (!formatQuickBarElement) {
return;
}
const listenFloatingElement = (
getElement: () => ReferenceElement | void
@@ -249,7 +247,10 @@ export class AffineFormatBarWidget extends WidgetComponent {
return;
}
assertExists(this._floatDisposables);
if (!this._floatDisposables) {
return;
}
HoverController.globalAbortController?.abort();
this._floatDisposables.add(
autoUpdate(
@@ -512,7 +513,9 @@ export class AffineFormatBarWidget extends WidgetComponent {
this._abortController = new AbortController();
const rootComponent = this.block;
assertExists(rootComponent);
if (!rootComponent) {
return;
}
const widgets = rootComponent.widgets;
// check if the host use the format bar widget

View File

@@ -4,7 +4,7 @@ import type {
MenuItemGroup,
} from '@blocksuite/affine-components/toolbar';
import { renderGroups } from '@blocksuite/affine-components/toolbar';
import { assertExists, noop } from '@blocksuite/global/utils';
import { noop } from '@blocksuite/global/utils';
import { MoreVerticalIcon } from '@blocksuite/icons/lit';
import { flip, offset } from '@floating-ui/dom';
import { html, LitElement } from 'lit';
@@ -57,7 +57,9 @@ export class AffineImageToolbar extends LitElement {
this._currentOpenMenu = this._popMenuAbortController;
assertExists(this._moreButton);
if (!this._moreButton) {
return;
}
createLitPortal({
template: html`

View File

@@ -4,7 +4,6 @@ import {
isInsidePageEditor,
} from '@blocksuite/affine-shared/utils';
import { BlockSelection } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
export function duplicate(
block: ImageBlockComponent,
@@ -23,7 +22,10 @@ export function duplicate(
const { doc } = model;
const parent = doc.getParent(model);
assertExists(parent, 'Parent not found');
if (!parent) {
console.error(`Parent not found for block(${model.flavour}) ${model.id}`);
return;
}
const index = parent?.children.indexOf(model);
const duplicateId = doc.addBlock(

View File

@@ -13,11 +13,7 @@ import {
isFuzzyMatch,
substringMatchScore,
} from '@blocksuite/affine-shared/utils';
import {
assertExists,
throttle,
WithDisposable,
} from '@blocksuite/global/utils';
import { throttle, WithDisposable } from '@blocksuite/global/utils';
import { autoPlacement, offset } from '@floating-ui/dom';
import { html, LitElement, nothing, type PropertyValues } from 'lit';
import { property, state } from 'lit/decorators.js';
@@ -592,7 +588,11 @@ export class InnerSlashMenu extends WithDisposable(LitElement) {
override willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has('menu') && this.menu.length !== 0) {
const firstItem = getFirstNotDividerItem(this.menu);
assertExists(firstItem);
if (!firstItem) {
console.error('No item found in slash menu');
return;
}
this._activeItem = firstItem;
// this case happen on query updated

View File

@@ -7,8 +7,8 @@ import {
GfxControllerIdentifier,
type GfxModel,
} from '@blocksuite/block-std/gfx';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import { Bound } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
export const edgelessToBlob = async (
host: EditorHost,
@@ -24,24 +24,25 @@ export const edgelessToBlob = async (
const isBlock = isTopLevelBlock(edgelessElement);
const gfx = host.std.get(GfxControllerIdentifier);
return exportManager
.edgelessToCanvas(
options.surfaceRenderer,
bound,
gfx,
isBlock ? [edgelessElement] : undefined,
isBlock ? undefined : [edgelessElement],
{ zoom: options.surfaceRenderer.viewport.zoom }
)
.then(canvas => {
assertExists(canvas);
return new Promise((resolve, reject) => {
canvas.toBlob(
blob => (blob ? resolve(blob) : reject(null)),
'image/png'
);
});
});
const canvas = await exportManager.edgelessToCanvas(
options.surfaceRenderer,
bound,
gfx,
isBlock ? [edgelessElement] : undefined,
isBlock ? undefined : [edgelessElement],
{ zoom: options.surfaceRenderer.viewport.zoom }
);
if (!canvas) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'Failed to export edgeless to canvas'
);
}
return new Promise((resolve, reject) => {
canvas.toBlob(blob => (blob ? resolve(blob) : reject(null)), 'image/png');
});
};
export const writeImageBlobToClipboard = async (blob: Blob) => {