# Designer > The mental model behind the editor - state, actions, and the Editor.* compound namespace that ties them together. Source: https://docs.docmosaic.com/docs/concepts/designer The DocMosaic editor is a **designer for printable documents** - users arrange image sections on a virtual page and export a PDF. `@docmosaic/react` exposes that designer as a small set of compound primitives that snap together; `@docmosaic/core` is the headless state machine they all read from. Same model, two surfaces. ## Mental model Think of the editor as three concentric layers: 1. **State** - a single `Document` carrying `pages`, a flat `sections` array, and metadata (`name`, `pageSize`, `orientation`). All geometry is in [PDF points](/docs/concepts/unit-system). 2. **Actions** - a stable 18-method surface (`addSection`, `updateSection`, `bringToFront`, `undo`, …) that produces the next document. The bundled reducer wraps these with a history timeline so undo/redo "just work." 3. **UI** - the `Editor.*` compound namespace. Every primitive reads its slice of state from context and dispatches actions back; nothing is prop-drilled. ```text Editor.Root ← owns Document + history + DnD provider ├─ Editor.Properties ← document name, page size, orientation ├─ Editor.Toolbar ← undo/redo, preview, download, add-section ├─ Editor.Pages ← left rail of page thumbnails ├─ Editor.Canvas ← interactive workspace (drag, resize, zoom) │ └─ Editor.Section ← one image rectangle on the canvas └─ Editor.Preview ← full-document preview dialog ``` `Editor.Root` arranges its children into the default shell automatically - `Pages` is forced to the left of `Canvas` regardless of source order - so the flat composition above works out of the box. ## Composition ```tsx import { Editor } from '@docmosaic/react'; import '@docmosaic/react/styles.css'; export function MyEditor() { return ( ); } ``` The CSS import seeds the `--editor-*` tokens documented in [Theming](/docs/theming). Drop any primitive - or build your own from `useEditor()` - and the rest of the tree keeps working. ## Selection model The editor tracks a **single selected section** at a time (`ui.selectedSectionId`). Selection drives: - The visible toolbar on `Editor.Section` (fit / layer / duplicate / delete buttons). - Keyboard nudge + delete bindings (see [Keybindings](/docs/concepts/keybindings)). - Resize handles and the focus outline. Clicking a section selects it; clicking the canvas background, hitting `Escape`, or deleting the selected section clears the selection. Multi-select is intentionally not part of the v1 surface - most flows that "want" multi-select are better expressed via layer actions on a single section. ## Drag, resize, upload The Canvas wires every section to three gestures: - **Drag** - pointer down on a section, move, pointer up. The reducer applies `UPDATE_SECTION` with the new `(x, y)`. - **Resize** - drag the right, bottom, or bottom-right handle. The Canvas captures the start size and dispatches incremental `UPDATE_SECTION` calls. - **Image upload** - drop a file onto a section (or click the empty-state). The reader produces a data URL, which becomes `section.imageUrl`. Drag-and-drop is powered by `react-dnd` with a multi-backend (HTML5 on desktop, auto-transitioning to touch on mobile). `Editor.Root` mounts a single `` for the whole tree - don't nest another. ## Headless mode When the compound shell isn't a fit (custom layout, native app, Server Components downstream), use the headless hook directly. It owns the same reducer + history: ```tsx import { createDocument } from '@docmosaic/core'; import { useDocumentState } from '@docmosaic/react'; function CustomEditor() { const { document, canUndo, canRedo, actions } = useDocumentState({ initialDocument: createDocument(), }); return (

{document.name} - {document.sections.length} sections

); } ``` `actions` is referentially stable; `document`, `canUndo`, and `canRedo` re-render on every change. Wrap the same value in `EditorProvider` if you want compound primitives to see your custom-built state. ## Controlled vs. uncontrolled `Editor.Root` works in both modes: - **Uncontrolled** (default) - omit `document`. The root owns state internally. Pass `defaultDocument` to seed it. - **Controlled** - pass `document` + `onDocumentChange`. Every mutation calls back out; the parent is responsible for re-rendering. Undo/redo are disabled because the timeline lives outside. ```tsx const [doc, setDoc] = useState(createDocument()); {/* … */} ; ``` Don't mix modes mid-render - the root warns in development if you do. ## Read-only mode `Editor.Root` accepts a `readOnly` boolean that flips the editor into viewer mode. Every mutating interaction (drag, resize, drop, file upload, page add/delete/reorder, undo/redo, keyboard nudge/delete, drawing-mode strokes) is suppressed. Mutating toolbar buttons (`Add*`, `Draw`, `Undo`, `Redo`) hide themselves; `Preview`, `Print`, and `Download` stay live so the viewer can still export. ```tsx ``` Selection (click, marquee), zoom, and pan all keep working - read-only is about mutation, not navigation. For a canvas-level override (read-only canvas inside an editable root), use `Editor.StaticCanvas`. ## See also - [Document model](/docs/concepts/document-model) - the `Document` / `Page` / `Section` hierarchy in detail - [History](/docs/concepts/history) - undo/redo and the timeline - [Unit system](/docs/concepts/unit-system) - why geometry is stored in points - [Theming](/docs/theming) - the `--editor-*` CSS-variable surface - [Keybindings](/docs/concepts/keybindings) - default shortcuts and how to override - [Layers](/docs/concepts/layers) - z-index actions for overlapping sections