Skip to content

BlockSuite API Documentation / @blocksuite/affine-gfx-shape

@blocksuite/affine-gfx-shape ​

Classes ​

Extension ​

ShapeTool ​

Understanding Extensions ​

Extensions provide a way to extend the functionality of a system using dependency injection. They allow you to register services, implementations, and factories in the DI container, which can then be retrieved and used by different parts of the application.

Extensions are particularly useful for:

  • Registering different implementations for different types
  • Creating pluggable architecture where components can be added or removed
  • Managing dependencies between different parts of the application

Usage Example: Fruit Processing System ​

Let's consider a fruit processing system where different types of fruits need different processing methods. We'll show how to implement this using extensions.

Step 1: Define the interfaces ​

ts
interface FruitProcessor {
  process(fruit: Fruit): void;
}

interface Fruit {
  type: string;
  // other properties
}

Step 2: Create a service identifier ​

ts
import { createIdentifier } from '@blocksuite/global/di';

const FruitProcessorProvider = createIdentifier<FruitProcessor>('fruit-processor-provider');

Step 3: Create implementations ​

ts
class AppleProcessor implements FruitProcessor {
  process(fruit: Fruit): void {
    console.log('Slicing apple');
    // Apple-specific processing
  }
}

class BananaProcessor implements FruitProcessor {
  process(fruit: Fruit): void {
    console.log('Peeling banana');
    // Banana-specific processing
  }
}

Step 4: Create an extension factory ​

ts
const FruitProcessorExtension = (
  fruitType: string,
  implementation: new () => FruitProcessor
): ExtensionType => {
  return {
    setup: di => {
      di.addImpl(FruitProcessorProvider(fruitType), implementation);
    }
  };
};

Step 5: Create concrete extensions ​

ts
export const AppleProcessorExtension = FruitProcessorExtension('apple', AppleProcessor);
export const BananaProcessorExtension = FruitProcessorExtension('banana', BananaProcessor);

Step 6: Use the extensions ​

ts
import { Container } from '@blocksuite/global/di';

class FruitProcessingSystem {
  provider: ServiceProvider;

  constructor(extensions: ExtensionType[]) {
    const container = new Container();

    // Set up all extensions
    extensions.forEach(ext => ext.setup(container));

    // Create a provider from the container
    this.provider = container.provider();
  }

  processFruit(fruit: Fruit) {
    // Get the appropriate processor based on fruit type
    const processor = this.provider.get(FruitProcessorProvider(fruit.type));

    // Process the fruit
    processor.process(fruit);
  }
}

// Initialize the system with extensions
const system = new FruitProcessingSystem([
  AppleProcessorExtension,
  BananaProcessorExtension
]);

// Use the system
system.processFruit({ type: 'apple' });  // Output: Slicing apple
system.processFruit({ type: 'banana' }); // Output: Peeling banana

Note: We deliberately used a non-block specific example here. In BlockSuite, the extension pattern can be applied to any entity that can be configured by third parties, not just blocks. This includes different tools in the whiteboard, different column types in database blocks, and many other extensible components. The pattern remains the same regardless of what you're extending.

Extends ​
Constructors ​
Constructor ​

new ShapeTool(gfx): ShapeTool

Parameters ​
gfx ​

GfxController

Returns ​

ShapeTool

Overrides ​

BaseTool.constructor

Properties ​
toolName ​

static toolName: string = 'shape'

Overrides ​

BaseTool.toolName

Accessors ​
Methods ​
activate() ​

activate(): void

Called when the tool is activated.

Returns ​

void

Overrides ​

BaseTool.activate

clearOverlay() ​

clearOverlay(): void

Returns ​

void

click() ​

click(e): void

Parameters ​
e ​

PointerEventState

Returns ​

void

Overrides ​

BaseTool.click

createOverlay() ​

createOverlay(): void

Returns ​

void

cycleShapeName() ​

cycleShapeName(dir?): ShapeName

Parameters ​
dir? ​

"prev" | "next"

Returns ​

ShapeName

deactivate() ​

deactivate(): void

Called when the tool is deactivated.

Returns ​

void

Overrides ​

BaseTool.deactivate

dragEnd() ​

dragEnd(): void

Returns ​

void

Overrides ​

BaseTool.dragEnd

dragMove() ​

dragMove(e): void

Parameters ​
e ​

PointerEventState

Returns ​

void

Overrides ​

BaseTool.dragMove

dragStart() ​

dragStart(e): void

Parameters ​
e ​

PointerEventState

Returns ​

void

Overrides ​

BaseTool.dragStart

mounted() ​

mounted(): void

Called when the tool is registered.

Returns ​

void

Overrides ​

BaseTool.mounted

pointerMove() ​

pointerMove(e): void

Parameters ​
e ​

PointerEventState

Returns ​

void

Overrides ​

BaseTool.pointerMove

pointerOut() ​

pointerOut(e): void

Parameters ​
e ​

PointerEventState

Returns ​

void

Overrides ​

BaseTool.pointerOut

setDisableOverlay() ​

setDisableOverlay(disable): void

Parameters ​
disable ​

boolean

Returns ​

void

Other ​

EdgelessToolbarShapeDraggable ​

Extends ​
Constructors ​
Other ​
draggableController ​

draggableController: EdgelessDraggableElementController<DraggableShape>

draggingShape ​

draggingShape: ShapeName = 'roundedRect'

type ​

type: typeof ShapeTool = ShapeTool

Overrides ​

EdgelessToolbarToolMixin( SignalWatcher(LitElement) ).type

styles ​

static styles: CSSResult

Overrides ​

EdgelessToolbarToolMixin( SignalWatcher(LitElement) ).styles

crud ​
Get Signature ​

get crud(): EdgelessCRUDExtension

Returns ​

EdgelessCRUDExtension

onShapeClick ​
readyToDrop ​
shapeContainer ​
shapeShadow ​
Get Signature ​

get shapeShadow(): "0 0 7px rgba(0, 0, 0, .22)" | "0 0 5px rgba(0, 0, 0, .2)"

Returns ​

"0 0 7px rgba(0, 0, 0, .22)" | "0 0 5px rgba(0, 0, 0, .2)"

initDragController() ​

initDragController(): void

Returns ​

void

attributes ​
controllers ​
dev-mode ​
lifecycle ​
properties ​
rendering ​
render() ​

render(): TemplateResult<1>

Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's ChildPart - typically a TemplateResult. Setting properties inside this method will not trigger the element to update.

Returns ​

TemplateResult<1>

Overrides ​

EdgelessToolbarToolMixin( SignalWatcher(LitElement) ).render

styles ​
updates ​
updated() ​

updated(_changedProperties): void

Invoked whenever the element is updated. Implement to perform post-updating tasks via DOM APIs, for example, focusing an element.

Setting properties inside this method will trigger the element to update again after this update cycle completes.

Parameters ​
_changedProperties ​

Map<PropertyKey, unknown>

Map of changed properties with old values

Returns ​

void

Overrides ​

EdgelessToolbarToolMixin( SignalWatcher(LitElement) ).updated


EdgelessShapeMenu ​

Extends ​
  • LitElement<this> & DisposableClass<this>
Constructors ​
Other ​
styles ​

static styles: CSSResult

Overrides ​

SignalWatcher( WithDisposable(LitElement) ).styles

edgeless ​
onChange ​
attributes ​
controllers ​
dev-mode ​
lifecycle ​
connectedCallback() ​

connectedCallback(): void

Invoked when the component is added to the document's DOM.

In connectedCallback() you should setup tasks that should only occur when the element is connected to the document. The most common of these is adding event listeners to nodes external to the element, like a keydown event handler added to the window.

ts
connectedCallback() {
  super.connectedCallback();
  addEventListener('keydown', this._handleKeydown);
}

Typically, anything done in connectedCallback() should be undone when the element is disconnected, in disconnectedCallback().

Returns ​

void

Overrides ​

SignalWatcher( WithDisposable(LitElement) ).connectedCallback

properties ​
rendering ​
render() ​

render(): TemplateResult<1>

Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's ChildPart - typically a TemplateResult. Setting properties inside this method will not trigger the element to update.

Returns ​

TemplateResult<1>

Overrides ​

SignalWatcher( WithDisposable(LitElement) ).render

styles ​
updates ​

EdgelessShapeToolButton ​

Extends ​
Constructors ​
Other ​
type ​

type: typeof ShapeTool = ShapeTool

Overrides ​

EdgelessToolbarToolMixin( SignalWatcher(LitElement) ).type

styles ​

static styles: CSSResult

Overrides ​

EdgelessToolbarToolMixin( SignalWatcher(LitElement) ).styles

attributes ​
controllers ​
dev-mode ​
lifecycle ​
properties ​
rendering ​
render() ​

render(): TemplateResult<1>

Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's ChildPart - typically a TemplateResult. Setting properties inside this method will not trigger the element to update.

Returns ​

TemplateResult<1>

Overrides ​

EdgelessToolbarToolMixin( SignalWatcher(LitElement) ).render

styles ​
updates ​

EdgelessShapeToolElement ​

Extends ​
  • LitElement<this> & DisposableClass<this>
Constructors ​
Other ​
styles ​

static styles: CSSResult

Overrides ​

WithDisposable(LitElement).styles

crud ​
Get Signature ​

get crud(): EdgelessCRUDExtension

Returns ​

EdgelessCRUDExtension

edgeless ​
getContainerRect ​
gfx ​
Get Signature ​

get gfx(): GfxController

Returns ​

GfxController

handleClick ​
order ​
shape ​
shapeStyle ​
shapeType ​
attributes ​
controllers ​
dev-mode ​
lifecycle ​
connectedCallback() ​

connectedCallback(): void

Invoked when the component is added to the document's DOM.

In connectedCallback() you should setup tasks that should only occur when the element is connected to the document. The most common of these is adding event listeners to nodes external to the element, like a keydown event handler added to the window.

ts
connectedCallback() {
  super.connectedCallback();
  addEventListener('keydown', this._handleKeydown);
}

Typically, anything done in connectedCallback() should be undone when the element is disconnected, in disconnectedCallback().

Returns ​

void

Overrides ​

WithDisposable(LitElement).connectedCallback

properties ​
rendering ​
render() ​

render(): TemplateResult<1>

Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's ChildPart - typically a TemplateResult. Setting properties inside this method will not trigger the element to update.

Returns ​

TemplateResult<1>

Overrides ​

WithDisposable(LitElement).render

styles ​
updates ​
updated() ​

updated(changedProperties): void

Invoked whenever the element is updated. Implement to perform post-updating tasks via DOM APIs, for example, focusing an element.

Setting properties inside this method will trigger the element to update again after this update cycle completes.

Parameters ​
changedProperties ​

PropertyValueMap<EdgelessShapeToolElement>

Returns ​

void

Overrides ​

WithDisposable(LitElement).updated


ShapeElementView ​

The methods that a graphic element should implement. It is already included in the GfxCompatibleInterface interface.

Extends ​
Constructors ​
Properties ​
type ​

static type: string = 'shape'

Overrides ​

GfxElementModelView.type

Accessors ​
Methods ​
onCreated() ​

onCreated(): void

Returns ​

void

Overrides ​

GfxElementModelView.onCreated


ShapeFactory ​

Constructors ​
Constructor ​

new ShapeFactory(): ShapeFactory

Returns ​

ShapeFactory

Methods ​
createShape() ​

static createShape(xywh, type, options, shapeStyle): Shape

Parameters ​
xywh ​

XYWH

type ​

string

options ​

Options

shapeStyle ​

ShapeStyle

Returns ​

Shape


ShapeOverlay ​

An overlay is a layer covered on top of elements, can be used for rendering non-CRDT state indicators.

Extends ​
Constructors ​
Constructor ​

new ShapeOverlay(gfx, type, options, style): ShapeOverlay

Parameters ​
gfx ​

GfxController

type ​

string

options ​

Options

style ​
fillColor ​

string | { normal: string; } | { dark: string; light: string; }

shapeStyle ​

ShapeStyle

strokeColor ​

string | { normal: string; } | { dark: string; light: string; }

Returns ​

ShapeOverlay

Overrides ​

ToolOverlay.constructor

Properties ​
shape ​

shape: Shape

Methods ​
render() ​

render(ctx, rc): void

Parameters ​
ctx ​

CanvasRenderingContext2D

rc ​

RoughCanvas

Returns ​

void

Overrides ​

ToolOverlay.render


abstract Shape ​

Constructors ​
Constructor ​

new Shape(xywh, type, options, shapeStyle): Shape

Parameters ​
xywh ​

XYWH

type ​

string

options ​

Options

shapeStyle ​

ShapeStyle

Returns ​

Shape

Properties ​
options ​

options: Options

shapeStyle ​

shapeStyle: ShapeStyle

type ​

type: string

xywh ​

xywh: XYWH

Methods ​
draw() ​

abstract draw(ctx, rc): void

Parameters ​
ctx ​

CanvasRenderingContext2D

rc ​

RoughCanvas

Returns ​

void


EdgelessShapeTextEditor ​

Extends ​
Constructors ​
Other ​
crud ​
Get Signature ​

get crud(): EdgelessCRUDExtension

Returns ​

EdgelessCRUDExtension

element ​
gfx ​
Get Signature ​

get gfx(): GfxController

Returns ​

GfxController

inlineEditor ​
Get Signature ​

get inlineEditor(): AffineInlineEditor | null

Returns ​

AffineInlineEditor | null

inlineEditorContainer ​
Get Signature ​

get inlineEditorContainer(): InlineRootElement<AffineTextAttributes> | null | undefined

Returns ​

InlineRootElement<AffineTextAttributes> | null | undefined

isMindMapNode ​
Get Signature ​

get isMindMapNode(): boolean

Returns ​

boolean

richText ​
selection ​
Get Signature ​

get selection(): GfxSelectionManager

Returns ​

GfxSelectionManager

std ​
connectedCallback() ​

connectedCallback(): void

Returns ​

void

Overrides ​

WithDisposable(ShadowlessElement).connectedCallback

setKeeping() ​

setKeeping(keeping): void

Parameters ​
keeping ​

boolean

Returns ​

void

attributes ​
controllers ​
dev-mode ​
lifecycle ​
properties ​
rendering ​
render() ​

render(): TemplateResult<1> | typeof nothing

Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's ChildPart - typically a TemplateResult. Setting properties inside this method will not trigger the element to update.

Returns ​

TemplateResult<1> | typeof nothing

Overrides ​

WithDisposable(ShadowlessElement).render

styles ​
updates ​
firstUpdated() ​

firstUpdated(): void

Invoked when the element is first updated. Implement to perform one time work on the element after update.

ts
firstUpdated() {
  this.renderRoot.getElementById('my-text-area').focus();
}

Setting properties inside this method will trigger the element to update again after this update cycle completes.

Returns ​

void

Overrides ​

WithDisposable(ShadowlessElement).firstUpdated

getUpdateComplete() ​

getUpdateComplete(): Promise<boolean>

Override point for the updateComplete promise.

It is not safe to override the updateComplete getter directly due to a limitation in TypeScript which means it is not possible to call a superclass getter (e.g. super.updateComplete.then(...)) when the target language is ES5 (https://github.com/microsoft/TypeScript/issues/338). This method should be overridden instead. For example:

ts
class MyElement extends LitElement {
  override async getUpdateComplete() {
    const result = await super.getUpdateComplete();
    await this._myChild.updateComplete;
    return result;
  }
}
Returns ​

Promise<boolean>

A promise of a boolean that resolves to true if the update completed without triggering another update.

Overrides ​

WithDisposable(ShadowlessElement).getUpdateComplete

Type Aliases ​

Colors ​

Colors = object

Properties ​

color ​

color: string

fillColor ​

fillColor: string

strokeColor ​

strokeColor: string


ShapeToolOption ​

ShapeToolOption = object

Properties ​

shapeName ​

shapeName: ShapeName

Variables ​

ellipseSvg ​

const ellipseSvg: TemplateResult<1>


roundedSvg ​

const roundedSvg: TemplateResult<1>


ScribbledDiamondIcon ​

const ScribbledDiamondIcon: TemplateResult<1>


ScribbledEllipseIcon ​

const ScribbledEllipseIcon: TemplateResult<1>


ScribbledRoundedRectangleIcon ​

const ScribbledRoundedRectangleIcon: TemplateResult<1>


ScribbledSquareIcon ​

const ScribbledSquareIcon: TemplateResult<1>


ScribbledTriangleIcon ​

const ScribbledTriangleIcon: TemplateResult<1>


shape ​

const shape: ElementRenderer<ShapeElementModel>


SHAPE_OVERLAY_HEIGHT ​

const SHAPE_OVERLAY_HEIGHT: 100 = 100


SHAPE_OVERLAY_OFFSET_X ​

const SHAPE_OVERLAY_OFFSET_X: 6 = 6


SHAPE_OVERLAY_OFFSET_Y ​

const SHAPE_OVERLAY_OFFSET_Y: 6 = 6


SHAPE_OVERLAY_OPTIONS ​

const SHAPE_OVERLAY_OPTIONS: object

Type Declaration ​

fill ​

fill: string = 'transparent'

roughness ​

roughness: number = DEFAULT_ROUGHNESS

seed ​

seed: number = 666

stroke ​

stroke: string = 'black'

strokeLineDash ​

strokeLineDash: number[]

strokeStyle ​

strokeStyle: StrokeStyle = StrokeStyle.Solid

strokeWidth ​

strokeWidth: LineWidth = LineWidth.Two


SHAPE_OVERLAY_WIDTH ​

const SHAPE_OVERLAY_WIDTH: 100 = 100


ShapeComponentConfig ​

const ShapeComponentConfig: Config[]


ShapeComponentConfigMap ​

const ShapeComponentConfigMap: Record<ShapeName, Config>


ShapeElementRendererExtension ​

const ShapeElementRendererExtension: ExtensionType & object

Type Declaration ​

identifier ​

identifier: ServiceIdentifier<ElementRenderer<ShapeElementModel>>


shapeSeniorTool ​

const shapeSeniorTool: ExtensionType


shapeToMarkdownAdapterMatcher ​

const shapeToMarkdownAdapterMatcher: ExtensionType & object

Type Declaration ​

identifier ​

identifier: ServiceIdentifier<ElementToMarkdownAdapterMatcher>


shapeToolbarConfig ​

const shapeToolbarConfig: object

Type Declaration ​

actions ​

readonly actions: [{ id: "c.switch-type"; content: TemplateResult<1> | null; when: boolean; }, { id: "d.style"; when: (ctx) => boolean; content: TemplateResult<1> | null; }, { id: "e.color"; content: TemplateResult<1> | null; when: boolean; }, { icon: TemplateResult<1>; id: "f.text"; tooltip: "Add text"; run: void; when: boolean; }, ...ToolbarGenericAction[]]

when ​

readonly when: (ctx) => boolean

Parameters ​
ctx ​

ToolbarContext

Returns ​

boolean


shapeToolbarExtension ​

const shapeToolbarExtension: ExtensionType


shapeToPlainTextAdapterMatcher ​

const shapeToPlainTextAdapterMatcher: ExtensionType & object

Type Declaration ​

identifier ​

identifier: ServiceIdentifier<ElementToPlainTextAdapterMatcher>


ShapeViewInteraction ​

const ShapeViewInteraction: ExtensionType


triangleSvg ​

const triangleSvg: TemplateResult<1>

Functions ​

drawGeneralShape() ​

drawGeneralShape(ctx, shapeModel, renderer, filled, fillColor, strokeColor): void

Parameters ​

ctx ​

CanvasRenderingContext2D

shapeModel ​

ShapeElementModel | LocalShapeElementModel

renderer ​

CanvasRenderer

filled ​

boolean

fillColor ​

string

strokeColor ​

string

Returns ​

void


fitContent() ​

fitContent(shape): void

Parameters ​

shape ​

ShapeElementModel

Returns ​

void


getShapeText() ​

getShapeText(elementModel): string

Parameters ​

elementModel ​

Record<string, unknown>

Returns ​

string


getShapeType() ​

getShapeType(elementModel): string

Parameters ​

elementModel ​

Record<string, unknown>

Returns ​

string


hasGrouped() ​

hasGrouped(model): boolean

Parameters ​

model ​

ShapeElementModel

Returns ​

boolean


horizontalOffset() ​

horizontalOffset(width, textAlign, horiPadding): number

Parameters ​

width ​

number

textAlign ​

TextAlign

horiPadding ​

number

Returns ​

number


mountShapeTextEditor() ​

mountShapeTextEditor(shapeElement, edgeless): void

Parameters ​

shapeElement ​

{ id: string; } | null | undefined

edgeless ​

BlockComponent

Returns ​

void


normalizeShapeBound() ​

normalizeShapeBound(shape, bound): Bound

Parameters ​

shape ​

ShapeElementModel

bound ​

Bound

Returns ​

Bound


verticalOffset() ​

verticalOffset(lines, lineHeight, height, textVerticalAlign, verticalPadding): number

Parameters ​

lines ​

TextDelta[][]

lineHeight ​

number

height ​

number

textVerticalAlign ​

TextVerticalAlign

verticalPadding ​

number

Returns ​

number