Diagram - Pages and layers

Place Pages and Layers independently, keep navigation in the host and edit workspace structure through shared commands.

#Usage

import { shallowRef } from 'vue';
import { Diagram } from '@primeui/vue-diagram';
import { DiagramPagesUI, DiagramLayersUI } from '@ui/diagram';

const pageId = shallowRef('page');
const layerId = shallowRef('layer');

function choosePage(id: string) {
    const snapshot = store.getSnapshot();
    const layer = snapshot.layers.find((item) => item.pageId === id);
    if (!snapshot.pages.some((item) => item.id === id) || !layer) return;
    layerId.value = layer.id;
    pageId.value = id;
}
<Diagram.Root :store="store" :page-id="pageId">
    <Diagram.WorkspaceHost :active-layer-id="layerId" @page-change="choosePage" @layer-change="layerId = $event">
        <DiagramPagesUI />
        <DiagramLayersUI />
    </Diagram.WorkspaceHost>
    <Diagram.Viewport label="Workspace" style="height: 24rem" />
</Diagram.Root>

Diagram.WorkspaceHost supplies one workspace model to both panels. The copied DiagramWorkspaceUI is the combined composition with its own host; do not nest another provider unnecessarily. Its activeLayerId, pageChange and layerChange contract is the same. These are props/emits, not named v-model contracts.

This skeleton assumes an initialized store with page page. Use First Diagram for model creation, style imports and store disposal.

Pages have independent coordinate spaces. Layers order records and control their visibility or locking within one page. The application owns the active page and insertion layer; the model stores page/layer records and saved edits.

#UI Composition

import { Diagram } from '@primeui/vue-diagram';
import { DiagramPagesUI, DiagramLayersUI } from '@/components/primeui/diagram';

Place the split controls under one Diagram.WorkspaceHost beneath the existing root. Bind its current activeLayerId; adopt pageChange and layerChange requests in the application. Keep page and insertion-layer IDs valid after history or model changes. The complete examples below show host ownership and cleanup.

#Place page navigation and layer management independently

Choose a page or insertion layer from the compact navigation row. Open Manage pages or Manage layers for a focused dialog to add, rename, reorder, hide, lock or remove. Opening or closing a manager leaves the canvas in place. Insert a card to see the chosen layer used by a real drawing command. Hidden or locked ownership can reject insertion.

Loading Demo...

Choose another page and insertion layer, then open Manage. Rename a page/layer, change visibility or lock state, and reorder layers. The management dialog keeps focus within its interaction; closing it returns focus to its Manage control. PrimeOne uses PrimeVue controls and Tailwind uses its themed HTML controls.

The panels need workspace context even without an editor shell. A custom child under the host can call useDiagramWorkspace() to read readonly refs such as pages, layers, currentPage, currentLayer and hasPending. Use its actions for changes; never mutate the snapshots or assign to a readonly ref.

Changes apply through workspace authority as each action is confirmed. Escape or Done closes the manager and returns focus to Manage; closing does not undo a saved action. Use the editor's Undo for a committed edit. Unsubmitted names stay drafts while the same page/layer and model remain current. PrimeOne uses PrimeVue Dialog; Tailwind uses its themed HTML controls and native modal dialog. Custom controls share the host's workspace model rather than recreating its transactions or availability checks.

#Keep navigation separate from saved edits

Changing root pageId disposes the outgoing session's owned transient work and subscriptions before binding the new session. Root and viewport DOM observers follow their own component lifetimes; another editor's proposals remain its own. Removing an active page does not make the Core store choose a replacement. The host must supply a surviving page. An obsolete pageId gives an unavailable scene; an empty model is supported. Multiple roots may maintain independent page choices over their owned stores.

Vue preserves mounted application child-local state across page changes. The root's session changes and internal owners rebind; no keyed viewport remount is required. This is separate from Reset, which deliberately recreates the example. Auto-fit is one-shot for the new session once its viewport has a nonzero size. Ordinary later size changes preserve navigation; offer Fit again when the user wants to reframe after a resize. Initial framing respects prior explicit navigation. Undo restores saved page/layer edits while the host still chooses which page to display.

An insertion layer is also host state. Bind it to the actual insertion operation, as the example's drawing.execute(spec, bounds) does. Selecting a layer alone does not change existing records or make every insertion tool use that layer. See Drawing and Palette for their insertion bindings.

pageChange requests a host page change. Keep the chosen layer valid for that page, including after imports or removal. The complete example reconciles its refs from store commits. activeLayerId chooses the insertion destination; it does not move existing records to that layer. Pass it separately to a palette target or drawing configuration that needs it.

Changing page replaces the root's page session, cancelling outgoing drafts and previews. Page selection is local host state outside model history. Structural edits, layer visibility and locks are saved model changes and follow current permissions, Undo and controlled-store acknowledgement.

#Edit page and layer records safely

Structure commandSaved effect / policy
page-addAdds a page and its required initial layer together.
page-updateRenames the page.
page-removeRequires explicit cascade when it contains layers or content; incoming navigation references reject removal.
layer-addAdds a layer owned by a valid page.
layer-updateChanges only name, visible or locked. Omitted flags mean visible/unlocked.
layer-orderLists every layer on that page exactly once; model order controls paint order.
layer-removeA nonempty layer needs a different same-page relocateTo destination; contents retain their geometry and ownership hierarchy.

The copied panels apply an additional UI policy: keep at least one page and layer, remove pages only after their nodes/connectors are cleared, and choose relocation for a populated layer. Their availability follows current editor policy. Removal controls appear in the management dialog; they do not silently cascade nonempty pages. Core permits more explicit host workflows through structural commands.

Unlocking a layer is allowed under its own saved lock while still respecting root read-only and explicit constraints. Unlock before other changes to a locked layer. Hidden layer records remain saved and searchable, but their entities are unavailable for ordinary visible selection/reveal in the copied explorer.

Use Page links for navigation references, Groups and containers for parent ownership and the Controlled State guide for host-owned proposals.