Integration recipes
Responding to a click and double-click, a context menu for a table cell, running an external command, and a full transport-system scenario from event to DOCX.
Examples: click, double-click, and menu
Section titled “Examples: click, double-click, and menu”How to respond to a click and double-click
Section titled “How to respond to a click and double-click”editor.interactions.on("elementActivated", async (event) => { const { gesture, target } = event;
if (gesture === "click" && target.kind === "comment") { hostSidebar.openComment(target.nodeId); }
if (gesture === "doubleClick" && target.hostData?.type === "shipment") { await hostApp.openShipment(target.hostData.id); }});Context menu for a table cell
Section titled “Context menu for a table cell”editor.contextMenu.registerProvider("transport-suite", async (ctx) => { if (ctx.target.kind !== "tableCell") return [];
return [ { id: "transport.openCargo", label: "Open cargo card", enabled: Boolean(ctx.target.hostData?.id) }, { id: "transport.bindRoute", label: "Bind to route", enabled: !ctx.readOnly }, { type: "separator" }, { id: "a4.table.insertRowBelow", label: "Insert row below", command: { type: "insert_table_row", position: "below" } } ];});Running an external command
Section titled “Running an external command”editor.commands.register("transport.bindRoute", async (ctx) => { const route = await hostUi.chooseRoute(); if (!route) return;
return ctx.session.execute({ operationId: crypto.randomUUID(), expectedRevision: ctx.revision, target: ctx.target, command: { type: "replace_target_text", text: route.displayName } });});Transport-system scenario from event to DOCX
Section titled “Transport-system scenario from event to DOCX”Step by step: a right-click on a cargo row
Section titled “Step by step: a right-click on a cargo row”-
The user right-clicks. The surface translates the click coordinates into document page coordinates and asks the core what was hit.
-
The core answers what’s under the pointer. For example, a table cell: its stable identifier, row and column numbers, enclosing elements, and the revision number in which all this is valid.
-
The editor asks your menu item providers, passing them this context — and only this context, not a reference to a markup element.
-
Your provider adds its own actions. “Open cargo card” and “Bind to route” appear alongside the permitted built-in items.
-
The user picks a route. Your interface returns its identifier; the command to change the document is assembled separately — the choice in your system and the edit in the document stay separate actions.
-
The core accepts the command or refuses it. The expected revision and the list of allowed actions prevent an edit from being applied to a stale document or to an object it wasn’t meant for.
-
The surface updates. The
contentChangedandcommandStateChangedevents bring the new revision number, and only the affected pages are redrawn, not the whole document. -
Saving and reopening confirm the result. The document is saved as a separate file or published all at once, then read back — this verifies that what landed on disk is exactly what the user saw.
What the passed context looks like
Section titled “What the passed context looks like”{ "schema": "a4.interaction-context.v1", "gesture": "contextMenu", "revision": 42, "readOnly": false, "target": { "kind": "tableCell", "nodeId": "body.block[18].row[2].cell[1]", "ancestors": [{"kind":"table","nodeId":"body.block[18]"}], "capabilities": ["read","editText","insertRow"], "hostData": {"type":"shipment","id":"SHP-009173"} }, "hit": {"pageIndex":3,"xMilliPx":412000,"yMilliPx":286000}}What arrives on a stale revision
Section titled “What arrives on a stale revision”{ "ok": false, "error": { "code": "revision_conflict", "expectedRevision": 42, "actualRevision": 43, "retry": "refresh_target_and_command_state" }}