diff --git a/blocksuite/affine/blocks/note/src/note-edgeless-block.ts b/blocksuite/affine/blocks/note/src/note-edgeless-block.ts index a75699cc9..bc2829e7a 100644 --- a/blocksuite/affine/blocks/note/src/note-edgeless-block.ts +++ b/blocksuite/affine/blocks/note/src/note-edgeless-block.ts @@ -400,7 +400,7 @@ export const EdgelessNoteInteraction = onResizeMove(context): void { const { originalBound, newBound, lockRatio, constraint } = context; - const { minWidth, minHeight } = constraint; + const { minWidth, minHeight, maxHeight, maxWidth } = constraint; let scale = initialScale; let edgelessProp = { ...model.props.edgeless }; @@ -411,8 +411,8 @@ export const EdgelessNoteInteraction = edgelessProp.scale = scale; } - newBound.w = clamp(newBound.w, minWidth, Number.MAX_SAFE_INTEGER); - newBound.h = clamp(newBound.h, minHeight, Number.MAX_SAFE_INTEGER); + newBound.w = clamp(newBound.w, minWidth * scale, maxWidth); + newBound.h = clamp(newBound.h, minHeight * scale, maxHeight); if (newBound.h > minHeight * scale) { edgelessProp.collapse = true; diff --git a/blocksuite/affine/blocks/surface/src/renderer/overlay.ts b/blocksuite/affine/blocks/surface/src/renderer/overlay.ts index cc6bc61bf..839fc8c85 100644 --- a/blocksuite/affine/blocks/surface/src/renderer/overlay.ts +++ b/blocksuite/affine/blocks/surface/src/renderer/overlay.ts @@ -35,7 +35,9 @@ export abstract class Overlay extends Extension { ]); } - clear() {} + clear() { + this.refresh(); + } dispose() {} diff --git a/blocksuite/affine/widgets/edgeless-selected-rect/src/edgeless-selected-rect.ts b/blocksuite/affine/widgets/edgeless-selected-rect/src/edgeless-selected-rect.ts index d039b4746..a2d233a05 100644 --- a/blocksuite/affine/widgets/edgeless-selected-rect/src/edgeless-selected-rect.ts +++ b/blocksuite/affine/widgets/edgeless-selected-rect/src/edgeless-selected-rect.ts @@ -28,7 +28,6 @@ import { state } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { repeat } from 'lit/directives/repeat.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { type Subscription } from 'rxjs'; import { RenderResizeHandles } from './resize-handles.js'; import { generateCursorUrl, getRotatedResizeCursor } from './utils.js'; @@ -359,21 +358,6 @@ export class EdgelessSelectedRectWidget extends WidgetComponent } `; - private readonly _initSelectedSlot = () => { - this._propDisposables.forEach(disposable => disposable.unsubscribe()); - this._propDisposables = []; - - this.selection.selectedElements.forEach(element => { - if ('flavour' in element) { - this._propDisposables.push( - element.propsUpdated.subscribe(() => { - this._updateOnElementChange(element.id); - }) - ); - } - }); - }; - private readonly _dragEndCleanup = () => { this._isWidthLimit = false; this._isHeightLimit = false; @@ -386,16 +370,15 @@ export class EdgelessSelectedRectWidget extends WidgetComponent this.frameOverlay.clear(); }; - private _propDisposables: Subscription[] = []; - private readonly _updateCursor = (options?: { type: 'resize' | 'rotate'; angle: number; handle: ResizeHandle; + pure?: boolean; }) => { if (!options) { !this._isResizing && (this.gfx.cursor$.value = 'default'); - return; + return 'default'; } const { type, angle, handle } = options; @@ -410,7 +393,11 @@ export class EdgelessSelectedRectWidget extends WidgetComponent }); } - this.gfx.cursor$.value = cursor; + if (options.pure !== true) { + this.gfx.cursor$.value = cursor; + } + + return cursor; }; private readonly _updateOnElementChange = ( @@ -423,8 +410,30 @@ export class EdgelessSelectedRectWidget extends WidgetComponent } }; + private readonly _updateHandles = () => { + const interaction = this._interaction; + const { store, selection } = this; + const elements = selection.selectedElements; + + if (interaction && !selection.editing && !store.readonly) { + const resizeHandles = interaction.getResizeHandlers({ + elements, + }); + const { rotatable } = interaction.getRotateConfig({ + elements, + }); + + this._allowedHandles = { + rotatable, + resizeHandles, + }; + } else { + this._allowedHandles = null; + } + }; + private readonly _updateOnSelectionChange = () => { - this._initSelectedSlot(); + this._updateHandles(); this._updateSelectedRect(); // Reset the cursor this._updateCursor(); @@ -554,10 +563,6 @@ export class EdgelessSelectedRectWidget extends WidgetComponent }) ); } - - _disposables.add(() => { - this._propDisposables.forEach(disposable => disposable.unsubscribe()); - }); } private get _interaction() { @@ -569,7 +574,7 @@ export class EdgelessSelectedRectWidget extends WidgetComponent } private _renderHandles() { - const { selection, gfx, block, store } = this; + const { selection, gfx, block } = this; const elements = selection.selectedElements; if (selection.inoperable) { @@ -579,23 +584,16 @@ export class EdgelessSelectedRectWidget extends WidgetComponent const handles = []; if ( + this._allowedHandles && this._interaction && - !selection.editing && - !store.readonly && !elements.some(element => element.isLocked()) ) { const interaction = this._interaction; - const resizeHandlers = interaction.getResizeHandlers({ - elements, - }); - const { rotatable } = interaction.getRotateConfig({ - elements, - }); handles.push( RenderResizeHandles( - resizeHandlers, - rotatable, + this._allowedHandles.resizeHandles, + this._allowedHandles.rotatable, (e: PointerEvent, handle: ResizeHandle) => { const isRotate = (e.target as HTMLElement).classList.contains( 'rotate' @@ -603,7 +601,7 @@ export class EdgelessSelectedRectWidget extends WidgetComponent if (isRotate) { interaction.handleElementRotate({ - elements: this.selection.selectedElements, + elements, event: e, onRotateStart: () => { this._mode = 'rotate'; @@ -622,7 +620,7 @@ export class EdgelessSelectedRectWidget extends WidgetComponent }); } else { interaction.handleElementResize({ - elements: this.selection.selectedElements, + elements, handle, event: e, onResizeStart: () => { @@ -632,12 +630,19 @@ export class EdgelessSelectedRectWidget extends WidgetComponent if (lockRatio) { this._scaleDirection = handle; this._scalePercent = `${Math.round(scaleX * 100)}%`; + this._mode = 'scale'; } if (exceed) { this._isWidthLimit = exceed.w; this._isHeightLimit = exceed.h; } + + this._updateCursor({ + type: 'resize', + angle: elements.length > 1 ? 0 : (elements[0]?.rotate ?? 0), + handle, + }); }, onResizeEnd: () => { this._mode = 'resize'; @@ -647,14 +652,11 @@ export class EdgelessSelectedRectWidget extends WidgetComponent } }, option => { - if (option) { - this._updateCursor({ - ...option, - angle: elements.length > 1 ? 0 : (elements[0]?.rotate ?? 0), - }); - } else { - this._updateCursor(); - } + return this._updateCursor({ + ...option, + angle: elements.length > 1 ? 0 : (elements[0]?.rotate ?? 0), + pure: true, + }); } ) ); @@ -784,6 +786,12 @@ export class EdgelessSelectedRectWidget extends WidgetComponent `; } + @state() + private accessor _allowedHandles: { + rotatable: boolean; + resizeHandles: ResizeHandle[]; + } | null = null; + @state() private accessor _isHeightLimit = false; diff --git a/blocksuite/affine/widgets/edgeless-selected-rect/src/resize-handles.ts b/blocksuite/affine/widgets/edgeless-selected-rect/src/resize-handles.ts index 4b417d6d6..e7c6514dd 100644 --- a/blocksuite/affine/widgets/edgeless-selected-rect/src/resize-handles.ts +++ b/blocksuite/affine/widgets/edgeless-selected-rect/src/resize-handles.ts @@ -1,6 +1,7 @@ import type { ResizeHandle } from '@blocksuite/std/gfx'; import { html, nothing } from 'lit'; import { repeat } from 'lit/directives/repeat.js'; +import { styleMap } from 'lit/directives/style-map.js'; export enum HandleDirection { Bottom = 'bottom', @@ -17,36 +18,28 @@ function ResizeHandleRenderer( handle: ResizeHandle, rotatable: boolean, onPointerDown?: (e: PointerEvent, direction: ResizeHandle) => void, - updateCursor?: (options?: { + getCursor?: (options: { type: 'resize' | 'rotate'; handle: ResizeHandle; - }) => void + }) => string ) { const handlerPointerDown = (e: PointerEvent) => { e.stopPropagation(); onPointerDown && onPointerDown(e, handle); }; - const pointerEnter = (type: 'resize' | 'rotate') => (e: PointerEvent) => { - e.stopPropagation(); - if (e.buttons === 1 || !updateCursor) return; - - updateCursor({ type, handle }); - }; - - const pointerLeave = (e: PointerEvent) => { - e.stopPropagation(); - if (e.buttons === 1 || !updateCursor) return; - - updateCursor(); - }; - const rotationTpl = handle.length > 6 && rotatable ? html`
` : nothing; @@ -58,8 +51,14 @@ function ResizeHandleRenderer( ${rotationTpl}
`; } @@ -79,17 +78,17 @@ export function RenderResizeHandles( resizeHandles: ResizeHandle[], rotatable: boolean, onPointerDown: (e: PointerEvent, direction: ResizeHandle) => void, - updateCursor?: (options?: { + getCursor?: (options: { type: 'resize' | 'rotate'; handle: ResizeHandle; - }) => void + }) => string ) { return html` ${repeat( resizeHandles, handle => handle, handle => - ResizeHandleRenderer(handle, rotatable, onPointerDown, updateCursor) + ResizeHandleRenderer(handle, rotatable, onPointerDown, getCursor) )} `; }