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