Actions and keyboard bindings
A named action lets buttons, shape regions, and keyboard shortcuts share one edit. Configure actions on DrawingConfiguration; invoke them through session.invokeAction('id', elementId: id). Register the same actions when reopening a document: callbacks are host behavior, not serialized content.
dart
import 'package:vyuh_diagram_kit/drawing.dart';
final configuration = DrawingConfiguration(
actions: [
DrawingAction(
id: 'shape.grow',
isEnabled: (context) => context.shape != null,
execute: (context) {
context.resize(
width: context.shape!.frame.width + 40,
height: context.shape!.frame.height + 20,
);
},
),
],
keyBindings: const [
DrawingKeyBinding(
action: 'shape.grow',
key: LogicalKeyboardKey.keyG,
command: true,
shift: true,
scope: DrawingActionScope.selection,
),
],
);Use session.canInvokeAction('shape.grow', elementId: id) for button availability and session.invokeAction('shape.grow', elementId: id) on activation. Availability is checked again at invocation; unknown actions, missing targets, and locked targets are denied. Observe session changes to refresh a control's availability.
One edit, one Undo
The context exposes the current selection, target elementId, optional slotId, and an immutable document. context.shape is the targeted shape when applicable. The document reflects changes already staged by this action.
Use updateValues(patch) for declared data, resize(width: ..., height: ...) for dimensions, and updateShape(...) for the latest staged shape. Advanced edits use replace, insert, remove and select.
Edits commit together as one undo step. Exceptions or denial discard them. Contexts expire after the callback; availability predicates cannot edit.
Actions are synchronous. Fetch external data before invoking an action; do not retain a context across an await. Do not mutate the session separately from the callback: use the context so the edit remains atomic.
Publication automatically resolves and renders affected shapes. Rows and columns reflow within updated dimensions; they do not implicitly resize every container. The shape's declared textSizing policy can grow a text body automatically, or the action can explicitly replace its dimensions. No refresh method is needed.
Keyboard ownership
Bindings have three scopes:
| Scope | Eligible input owner |
|---|---|
canvas | Canvas with an empty selection |
selection | Canvas with an object selection |
text | The active diagram text editor |
Use shapeType to restrict a binding to one shape type and slotId to restrict a text binding to one named slot. A slot restriction requires scope: text. More specific matching bindings win: slot and shape, then slot, then shape, then the unrestricted scope. Duplicate scope/chord declarations are rejected.
command means Meta on macOS and Control elsewhere. Modifier matching is exact. Bindings receive initial key-down events, not repeats. A matched binding consumes its chord even when its action is disabled; an unmatched key retains the normal editor behavior. Escape, active IME composition, pointer gestures, and focused embedded controls retain their existing input ownership. Selection and canvas bindings never run in diagram text editing.
The playground offers Command+Enter on a selected UML class as an action example. It appends an ordinary text paragraph and selects it; this is free-form text, not a structured UML property. Tab retains normal editor behavior and does not add members.
Buttons and interactive regions
Any Flutter control can invoke a named action. The playground Count button uses controls.increment; Command+Shift+= invokes it on a selected controls card. Embedded controls continue to own their own focused keystrokes.
For a painted shape region, set its ShapeRegionLayerDefinition.onInteract to the action ID. A named action runs on pointer release inside the same region; cancel or release outside does not invoke it. Regions without a matching action continue to use DrawingHooks.onShapeRegionInteraction.
No repeatable-content grammar or runtime composition insertion is introduced by this API. The action decides how to change the existing canonical data.