Skip to content

Verbs ​

A verb is a named, typed edit: the one way anything changes a diagram. The property inspector, canvas overlays, toolbars, keyboard shortcuts, context menus, agents and your own code all perform the same verbs through DiagramController.perform. Every verb is admitted like any other edit (locks, the diagram's rules, other actors' leases), records one undo entry. Direct calls complete or throw on refusal; calls through controller.edits return an EditResult.

On this page ​

CategoryWhat you can do
Performing verbsPerform a verb by name, or through a typed extension.
DiscoveryList the verbs an element offers, with schemas and availability.
Who declares verbsElement, shape and part verbs, and how a shape binds its parts.
ResultsDenials, created identities and stale revisions.
PreviewsPerform verbs on an interaction lease for slider and handle drags.
SymmetryWhy every verb is two-way.
Writing verbsDeclare a verb for your shape, part or extension.
Selection, camera and toolSelection, camera, tool and options, which are not verbs.
Core verbsThe verbs every diagram offers.

Performing verbs ​

dart
EditResult perform(
  Iterable<String> ids,
  String verb, [
  Map<String, Object?> args = const {},
])

ids names the elements a verb acts on: one element for a shape's own verbs, one or more for element verbs such as move, and none for diagram verbs such as createShape.

dart
controller.edits.perform([cardId], 'setTitle', {'title': 'Orders'});
controller.edits.perform([cardId, noteId], 'setOpacity', {'opacity': .5});
controller.edits.perform([entityId], 'primary.insertRow', {'at': 2});
final created = controller.edits.perform(const [], 'createShape', {
  'type': Shapes.rectangle,
  'at': {'x': 0, 'y': 0},
});
final id = created.id!;

Arguments accept Dart values and, for agents, their JSON form: an enum or a route by name, a color as an ARGB integer, a point as {x, y}, a size as {width, height} and a rectangle as {left, top, width, height}.

The package that owns a verb also ships a typed extension on DiagramController, a thin wrapper over perform:

dart
controller.edits.setTitle(cardId, 'Orders');
controller.edits.move(const DiagramPoint(40, 0), ids: [id]);
controller.edits.insertRow(entityId, at: 2, part: 'primary');
controller.edits.setMark(elementId: id, mark: TextMark.bold, on: true);

Discovery ​

MemberReturnsMeaning
verbs([ids])List<DiagramVerbDescription>The verbs on ids: with none, the diagram verbs; with one, that element's verbs, including its parts'; with several, the element verbs they share.
verb(ids, name)DiagramVerbDescription?One verb on ids, or null when none by that name applies.
canPerform(ids, verb, [args])EditResultWhether perform would run, and why not. Nothing is published.
applyTo(element, verb, [args])DiagramElement?What a setter makes of an element outside the document, such as the next shape a tool creates.

A description carries name, label, parameters, symmetry, the bound part and availability, a result that answers for the current state without arguments. Each DiagramVerbParameter has a name, a type such as number, choice, point or story, whether it isRequired, and for scalars a schema that is the same ValueField shape values use, such as a NumberValueField with its bounds or a ChoiceValueField with its options.

dart
for (final verb in controller.verbs([id])) {
  print('${verb.name}(${verb.parameters.join(', ')}) '
      '${verb.isAvailable ? '' : '- ${verb.availability.reason}'}');
}

Who declares verbs ​

Verbs belong to the definitions that own them:

Declared byExamplesWhere
Extensions: element and diagram verbsmove, setStyle, setLocked, delete, createShape, connectDiagramExtension(verbs: [...]); core installs diagramCoreVerbs.
A shape's own verbsa card's setTitle, setTag, setDescription; an entity's showSecondarySectionShapeDefinition(verbs: [...])
Text partssetTextDiagramTextDefinition.verbs, bound to each text part
Text storiesrich text's setMark, setHeading, setList, setCheckedDiagramTextDefinition.storyVerbs, offered once by every element holding that text, including table cells (ShapeContentLayerDefinition.texts)
Content partsa table's insertRow, mergeCells, setCellText, setBordersShapeContentLayerDefinition.verbs

A shape's verb set is the element verbs that apply to it, its own verbs, and each part's verbs bound to that part. A part verb is offered as part.verb, such as title.setText, and also under its plain name when only one part offers it: a rectangle's body text is setText, while a card has title.setText, tag.setText and body.setText, and an entity has primary.insertRow and secondary.insertRow. Callers never name slots or content records; the binding carries them.

Results ​

Calls through controller.edits return an EditResult:

OutcomeResult
Performedallowed; a creating verb reports the identity in id.
Unknown verb, missing or invalid argument, such as a non-finite number, an undeclared shape value or a replacement that changes a story's identityDiagramDenialCode.unsupportedOperation with a reason.
Missing target, label or cellDiagramDenialCode.unavailableTarget.
Locked target or ownerDiagramDenialCode.locked, from admission.
Stale expectedRevision, or a stale before storyDiagramDenialCode.conflict.
A rule or another actor's previewits code and reason.

Calls through controller.edits report a denied edit in the result. Direct methods throw DiagramChangeDenied for that same denial. Both paths can also throw for misuse of the controller itself, such as calling it after dispose, performing a verb while this controller holds a gesture lease, or inserting an authored record (add, a raw transaction) that breaks the installed grammar, which is a programming error in the record. Typed wrappers that compute arguments before performing, such as createPolyline with fewer than two points, throw ArgumentError for input they cannot compute from.

Every verb accepts the argument expectedRevision: pass the document revision captured before awaiting a file, dialog or network response, and a document that changed meanwhile is denied as a conflict instead of overwritten.

dart
final revision = controller.document.revision;
final source = await pickImage();
controller.edits.perform([id], 'setImage', {
  'image': source,
  'expectedRevision': revision,
});

Inside a direct batch, a refused edit throws and rolls back all earlier changes. With controller.edits.batch, inspect the result; call requireAllowed() on a refused nested result when the entire batch must stop.

Previews ​

A continuous edit, such as a slider drag, performs the same verb on an interaction lease. Each preview starts over from the lease's baseline, so previews never drift; commit records one undo entry and cancel restores the baseline.

dart
final lease = controller.beginInteraction('Change opacity');
lease.perform([id], 'setOpacity', {'opacity': .8});
lease.perform([id], 'setOpacity', {'opacity': .4});
lease.commit();

performAll([DiagramVerbInvocation(ids, verb, args), ...], selection: ...) previews several verbs at once. A cumulative lease (beginInteraction(label, cumulative: true)), as text composition uses, adds each preview to the last instead, and yields: an unrelated edit, an undo or a new interaction commits it first. Custom tool gestures return a DiagramGesturePreview of verb invocations for each pointer sample.

Symmetry ​

Every verb is a forward-moving edit, and every verb is two-way, so an agent can always state the reverse edit. Undo is history, never a reverse verb. Each verb declares its DiagramVerbSymmetry:

SymmetryMeaningExamples
setterPerforming it with the previous value reverses it.setLocked(false), setTag(null), setImage(null), reparent(parent: null), move(-delta)
pair(counterpart)Half of a declared pair; the counterpart is itself a pair verb.insertRow/removeRow, group/ungroup, frame/unframe, addSlot/removeSlot, addConnectorLabel/removeConnectorLabel, createShape/delete
derived(reversedBy)Derives new values that the named setter expresses.align, distribute and arrangeLanes (setElementBounds), reorder (setZIndex), reroute (setRouteGeometry), clearFormatting (replaceText)

There are no toggles. A control that toggles performs the setter with the opposite of the current value, such as setMark(mark, on: !isBold) or setList(kind: isList ? ParagraphKind.paragraph : kind). Building a diagram validates every installed verb, so a one-way verb, whose counterpart or setter is missing, fails assembly.

Writing verbs ​

Performing verbs needs only the main library. Writing one uses DiagramVerb, DiagramVerbTarget, DiagramVerbSymmetry and DiagramVerbCall from package:vyuh_diagram_flutter/extension_api.dart; DiagramVerbParameter and DiagramVerbDescription stay in the main library because discovery returns them.

dart
import 'package:vyuh_diagram_flutter/extension_api.dart';
import 'package:vyuh_diagram_flutter/vyuh_diagram_flutter.dart';

final countParameter = DiagramVerbParameter.integer('count', minimum: 0);
final setCount = DiagramVerb.update<ShapeElement>(
  id: 'setCount',
  label: 'Count',
  parameters: [countParameter],
  update: (shape, call) => shape.copyWith(
    values: {...shape.values, 'count': call.read(countParameter)},
  ),
);

final counter = ShapeDefinition(
  type: 'counter',
  values: const {'count': NumberValueField(defaultValue: 0, integer: true)},
  verbs: [setCount],
);

extension CounterVerbs on DiagramController {
  EditResult setCount(String id, int count) =>
      perform([id], 'setCount', countParameter.withValue(count));
}

DiagramVerb.update declares a setter that replaces each target element. For anything else, DiagramVerb(perform: ...) receives a DiagramVerbCall with the controller, the targets ids, the decoded args, the bound part and submit(transaction), the low-level dispatch that verb implementations build on. Text extensions build on call.updateText. A verb may compose other verbs with controller.perform inside controller.batch.

DiagramVerb argumentMeaning
id, label, descriptionThe name callers perform, and how tools show it.
parametersDiagramVerbParameter.boolean, .number, .integer, .text, .choice, .color, .point, .size, .rect, .ids, .values, .motion or .value<T>.
symmetrySee symmetry.
targetDiagramVerbTarget.diagram, .element or .elements.
appliesTo(element, registry)Whether an element offers the verb.
check(call)Why the verb cannot run on its targets, without arguments; null when it can.
admitsLockedTargetsLets the verb target locked elements, as unlocking does; its edit is still admitted.

Only verb implementations construct transaction steps or call dispatch; the repository's boundary check rejects raw transactions anywhere else, including the demo app.

Selection, camera and tool ​

Selection, camera, active tool, creation styles and options are not part of the document or its history, so they are not verbs. They change through plain controller methods that are not undoable and are not admitted by the diagram's rules: setSelection, select, selectAll, clearSelection, setCamera, setTool, setShapeCreationStyle, setConnectorCreationRoute and setOptions. Select a connector label or path points with setSelection(ConnectorLabelSelection(...)) or setSelection(PathPointSelection(...)).

Core verbs ​

Element verbs, on one or more elements:

VerbArgumentsSymmetry
delete—pair add
setLocked, setVisiblelocked, visiblesetter
setOpacityopacity (0–1)setter
setZIndexzIndexsetter
setStylefill, stroke, strokeWidth, cornerRadius, strokeStyle, inkPreset (each optional)setter
setAspectLockedlocked, squaresetter
setPorts, setImage, setValues, setClipContent, setPolygonSides, setTypeports, image, values, clip, sides, typesetter
addSlot / removeSlotslot, textpair
move, resize, rotate, setElementBounds, reparent, setFrameCollapseddelta, motion; size, fromCenter, preserveAspectRatio, motion; pivot, radians; bounds, motion; parent, delta; collapsedsetter
group / ungroup, frame / unframe—pair
align, distribute, arrangeLanes, reorderalignment; distribution; direction, laneSize, gap; orderderived
duplicateoffsetpair delete
setText (text parts), setTextStory, setTextAlignment, setTextDirection, replaceTexttext; story; alignment/direction with storyId, start, end; before, aftersetter
setConnectorRoute, setConnectorStyle, setStartArrowhead, setEndArrowhead, reconnect, setRouteGeometry, setConnectorLabelroute, style, end and label partssetter
addConnectorLabel / removeConnectorLabeltext, story, fraction, offset, size; labelpair
setPathClosed, setPathHandleMode, setPathSegmentKind, movePathControlclosed; node, mode/kind/control, positionsetter
addPathPoint / removePathNodesafter, t, id; nodespair

Diagram verbs: createShape, createText, add, createConnected, connect and paste (each paired with delete and reporting id), load and applyLayout (frames, label, motion) (setters), reroute and arrangeLabels (derived).

See tables for table part verbs, rich text for rich text verbs and shapes for card and entity verbs.