Skip to main content

Canvas elements

A kind of thing that can exist on the canvas.

import { function canvasElement(element: Omit<CanvasElement, "kind">): CanvasElement
Declare a new kind of element the user can place on a document canvas. Renderer-native, like `editorExtension`. The module runs in the host's own renderer and shares its `lexical` and `react` instances through a live handle rather than over RPC, so the element is a real part of the canvas rather than an embedded webview. That is the line between this and `view`/`widget`, which are sandboxed and have no Node access. The `module` must default-export a `defineCanvasElement({...})` value, and its `schema.tag` has to match the `tag` you pass here. The loader compares the two by name and refuses to register the element if they differ. Use `canvasElement` to introduce a tag. Use {@link canvasTemplate } to offer a preset of a tag that already exists.
@categoryAuthoring
canvasElement
, function defineMod<const TMod extends ModDefinition>(definition: TMod & ValidateModHooks<TMod>): Mod
The entry point of the SDK. A mod's module default-exports one `defineMod` call and nothing else. The returned value is data. It registers nothing, starts nothing, and touches no host state. The host folds it twice. At build time it runs the module in a throwaway sandbox and reads the value to derive the serializable manifest. At runtime it folds the same value again to wire your handlers into their lanes: ext-host for commands, tools, effects, and hooks; the sandboxed renderer for views and widgets. That double fold is why the module must be pure. It is re-executed to produce the manifest, so anything at the top level, a file read, a network call, a timer, a `console` line, runs during a build with no host attached. Put behavior inside handlers: `run`, `activate`, `handle`. The `ValidateModHooks` constraint makes the call fail to typecheck when a `hook.beforeAction` targets an action that is neither a known host action nor `command:` plus one of this mod's own command ids.
@example```ts export default defineMod({ metadata: { displayName: 'Review', description: 'Review helpers for the current change.', }, commands: [ command({ id: 'review.open', title: 'Review: Open', run: openPanel }), slashCommand({ id: 'review', description: 'Review this change', run: review }), ], ai: { tools: [reviewTool], }, }); ```@categoryAuthoring
defineMod
} from '@modular/sdk';
export default
defineMod<{
    readonly metadata: {
        readonly displayName: "Shapes";
        readonly description: "Canvas work";
    };
    readonly canvas: readonly [CanvasElement];
}>(definition: {
    readonly metadata: {
        readonly displayName: "Shapes";
        readonly description: "Canvas work";
    };
    readonly canvas: readonly [CanvasElement];
}): Mod
The entry point of the SDK. A mod's module default-exports one `defineMod` call and nothing else. The returned value is data. It registers nothing, starts nothing, and touches no host state. The host folds it twice. At build time it runs the module in a throwaway sandbox and reads the value to derive the serializable manifest. At runtime it folds the same value again to wire your handlers into their lanes: ext-host for commands, tools, effects, and hooks; the sandboxed renderer for views and widgets. That double fold is why the module must be pure. It is re-executed to produce the manifest, so anything at the top level, a file read, a network call, a timer, a `console` line, runs during a build with no host attached. Put behavior inside handlers: `run`, `activate`, `handle`. The `ValidateModHooks` constraint makes the call fail to typecheck when a `hook.beforeAction` targets an action that is neither a known host action nor `command:` plus one of this mod's own command ids.
@example```ts export default defineMod({ metadata: { displayName: 'Review', description: 'Review helpers for the current change.', }, commands: [ command({ id: 'review.open', title: 'Review: Open', run: openPanel }), slashCommand({ id: 'review', description: 'Review this change', run: review }), ], ai: { tools: [reviewTool], }, }); ```@categoryAuthoring
defineMod
({
metadata: {
    readonly displayName: "Shapes";
    readonly description: "Canvas work";
}
metadata
: { displayName: "Shapes"displayName: 'Shapes', description: "Canvas work"description: 'Canvas work' },
canvas: readonly [CanvasElement]canvas: [ function canvasElement(element: Omit<CanvasElement, "kind">): CanvasElement
Declare a new kind of element the user can place on a document canvas. Renderer-native, like `editorExtension`. The module runs in the host's own renderer and shares its `lexical` and `react` instances through a live handle rather than over RPC, so the element is a real part of the canvas rather than an embedded webview. That is the line between this and `view`/`widget`, which are sandboxed and have no Node access. The `module` must default-export a `defineCanvasElement({...})` value, and its `schema.tag` has to match the `tag` you pass here. The loader compares the two by name and refuses to register the element if they differ. Use `canvasElement` to introduce a tag. Use {@link canvasTemplate } to offer a preset of a tag that already exists.
@categoryAuthoring
canvasElement
({
id: stringid: 'shapes.note', name: stringname: 'Note', tag: stringtag: 'shapes-note', module: stringmodule: './canvas/note', }), ], });

tag is the custom-element name the canvas places, and module is the renderer-native module that defines it.

Members

CanvasElementid, name, description, tag, module, tool, kind.

MemberWhat it decides
tagthe element's tag on the canvas
modulewhere its implementation is loaded from
toolthe tool a person uses to place one

Like an editor extension, the implementation is named by module rather than passed as a function — canvas code loads with the canvas.

tool is what connects the element to the person: without it, the element type exists but nothing in the interface creates one.

The canvas entry point

Canvas-side types come from @modular/sdk/canvas — 41 exports. Browse them at @modular/sdk/canvas.

To ship a pre-arranged group of elements, see canvas templates.