Skip to content

Frames and ownership

Loading interactive example…Open in new tab ↗
Opening the live canvas…

The outer frame owns a nested frame and a rectangle. The nested frame owns an ellipse that extends beyond its right edge and a small sensor rectangle; clipping hides the ellipse's overflow. Both connect to the sibling rectangle.

Each frame has a single-line title above its outline. Collapsible frames automatically show a bordered toggle to the left: + expands and collapses. Frames without collapse support show only their title. The collapsed frame uses a blue fill; its contents retain their saved geometry. The control also exposes accessible Collapse and Expand actions. Pressing it and releasing outside cancels the action.

  • Move outer moves the complete tree once.
  • Receiver → Collapse receiver, after collapsing Equipment cell, shows the bundle count at both ends. Expand either frame to inspect its original shapes.
  • Collapse inner frame hides both children and bundles their two connections into one, with a 2 badge at the compact frame. Expand inner frame restores both connections to their original children. Saved geometry and bindings stay intact.
  • Resize inner frame changes its boundary to reveal or clip more of the ellipse. The ellipse's position and dimensions stay unchanged.
  • Group contents groups the equipment and receiver frames. The ellipse stays owned by the inner frame, and clipping is preserved. Ungroup selection removes the selected group while keeping its children in place.
  • Remove inner frame removes the container and transfers its child to the outer frame, preserving its geometry. The ellipse's previously clipped edge becomes visible.
  • Delete outer tree deletes the container and all its descendants.
  • Undo restores each operation, including ownership and clipping.

Selection and manual transforms use the same public commands as the buttons. Reset restores the original document with empty undo history. Grouping requires at least two elements with the same immediate owner: selecting the ellipse and the sibling rectangle cannot group them across their different owners.

Standard frames disable rotation. A host can explicitly enable rotatable on a registered frame definition; rotation then carries its descendants with it. Resizing a logical group scales its contents. Resizing a selected frame only changes its boundary, using ShapeTransformBehavior(resizesChildren: false).

dart
session.setFrameCollapsed('inner', true);
session.setFrameCollapsed('inner', false);

Collapsed frames stay movable. Expand them before resizing or editing their contents. Collapse and expand each form one undo step; save/load retains the collapse state and the expanded geometry.

The frame registration uses an external title layer in both states and a blue fill for the compact presentation. Both read the same saved title.

Bundling is opt-in on the frame through connections: CollapsedConnectionPresentation.bundled. Connections also need the same explicit bundleKey, such as equipment-telemetry in this example. Only compatible connections with the same projected endpoints, direction, appearance and routing settings combine. Connections with authored route points remain separate. The count describes original connections; bundling never deletes or rewrites them. When both endpoints attach to collapsed frames, each end shows the count. Canvas rendering, hit testing and SVG export share these badge bounds.

Select the bundled connection and open Properties to see its original connection IDs and endpoints. Property controls apply to the selected representative only; changing it can separate it from the bundle. The canvas accessibility label also announces the number of connections. Expand the frame to edit members individually.

Collapsed composition reuses the ordinary shape primitives: rows, columns, stacks, surfaces and text. Text slots must already exist in the expanded definition; collapsing changes which slots are visible, not their content. size, style, outline, and textBounds can also customize the compact frame.

Source

dart
actions: {
  'Collapse inner frame': (s) =>
      s.setFrameCollapsed('inner', true).requireAllowed(),
  'Expand inner frame': (s) =>
      s.setFrameCollapsed('inner', false).requireAllowed(),
  'Select outer': (s) => s.selectElements(['outer']),
  'Move outer': (s) =>
      s.moveElements(['outer'], const DiagramPoint(40, 0)).requireAllowed(),
  'Resize inner frame': (s) {
    final frame = s.document.shapeById('inner')!.frame;
    s.resizeElements(
      ['inner'],
      DiagramSize(frame.width == 240 ? 360 : 240, frame.height),
    ).requireAllowed();
  },
  'Group contents': (s) {
    s.selectElements(['inner', 'companion']);
    s.groupSelection().requireAllowed();
  },
  'Ungroup selection': (s) => s.ungroupSelection().requireAllowed(),
  'Remove inner frame': (s) {
    s.selectElements(['inner']);
    s.removeFrames().requireAllowed();
  },
  'Delete outer tree': (s) => s.removeElements(['outer']).requireAllowed(),
},

See Session for removal, selection and transform contracts.