Canvas
VisualMap
A working, interactive Visualli map for a .visualli document: layers, rings, connectors, peeks, term cards, Go deeper, stepping inside and the gradual-reveal bloom — on mouse and on touch.
- Provide
doc{title, layers, anchors?}— layers exactly as in the open spec (nodes,connections,containers,level,parentLayerId,parentNodeId);anchorsare thesemantic-anchorsextension's terms, underlined in summaries. Optionalheight,insets(space covered by floating chrome, so the map fits around it),source(shown on fact cards),immersion,showTrail,showControls,onLayerChange. - Interaction follows the pointer in use (
interaction="auto", the default; pin"hover"or"touch"for previews and tests):Mouse / trackpad Touch / pen Peek an idea Hover or focus → SemanticPeekbeside itFirst tap → idea is selected, SemanticPeekopens as a bottom sheetStep inside Click a ringed idea, Enter, or Step inside Second tap on the selected idea, or Step inside Go deeper Go deeper on a peek (the idea) or a term card (the term) → GoDeeperpanelSame → GoDeepersheetClose the preview Move away, Escape, click empty canvas Tap empty canvas, swipe the sheet down, ✕, Escape Move an idea ( editable)Press and drag (after 4px) · Option/Alt + arrows on a focused idea (Shift = bigger steps) Press and move (after 10px) — a still press stays a tap Defined term Click the underlined word → definition in the same card, ‹ back to the idea Same, inside the sheet - On touch the selected idea lifts, gets a heavier outline and the others dim to 60%; the canvas nudges it into the space above the sheet.
onSelect(node | null)tells the host when a sheet is up — hide competing bottom chrome (the Composer) meanwhile. touchHintshows a one-time Caveat note on touch ("tap an idea to peek · tap again to step inside") until the first tap; it's remembered per browser. Pass a string to change it,falseto hide it.- Escape/Backspace or the trail backs out a layer. Honors the five comfort attributes; the sheet slides in, or fades under Reduce motion.
- Ideas are movable (
editable, defaulttrue) so people can arrange a map their way. Connectors re-route as an idea moves (they always run between the current positions, outside the rings). A moved idea lifts and casts a deeper shadow while held; it can't leave the visible canvas. Persist each move fromonNodeMove({ layerId, nodeId, position })into the node'spositionin the.visuallifile and pass the updateddocback; Reset layout (↶ in the canvas controls) restores the file's original positions for the current layer and reports them throughonNodeMovetoo. Seteditable={false}where a map is shown rather than owned — embeds in other apps (MCP), or marketing pages on phones, where a finger should scroll the page. - Go deeper:
onGoDeeper(target)fires when someone asks (target={ kind: 'idea', node }or{ kind: 'term', node, anchor }, pluslayerId) — start generating then.facetsFor(target)returns the five facets with their current status and content; re-render as they stream.onVisualize(target, 'inside' | 'new')is Map it.deeperLayout(auto|panel|sheet|stack) andonDeeperChange(target | null, layout)let the page move its own chrome aside for the panel. - Side panels and spotlight:
aside={(layout, style) => <SourcesPanel layout={layout} style={style} … />}docks a host panel in Go deeper's slot with the same layout choice and insets (opening it closes Go deeper).highlight={ids}spotlights ideas and dims the rest — e.g. while a source passage is hovered. - Editing (
editing+onEditingChange,onEdit): browsing keeps working while editing. Click/tap selects an idea, connector or group and shows itsSelectionBar; click a selected idea (or double-click) to rename it in place; double-click empty canvas to add an idea; Delete/Backspace removes the selection (ideas with inner layers ask first); F2 renames; ⌘Z / ⇧⌘Z undo and redo; Escape steps back. TheEditBannersits top-center inside the map's top inset — reserve room for it in your chrome. Every change reachesonEdit(op, doc); persistdoc.autoEditOnMove(default false) switches to edit mode on the first drag instead of showing the invitation. - This is the reference behavior for the production Canvas 2D renderer, which shares
blobPath/drawBlob,RINGS,edgePathandusePointerMode.
Props
export interface VisualMapProps {
doc: MapDoc;
height?: number | string;
insets?: { top?: number;
right?: number;
bottom?: number;
left?: number };
immersion?: boolean;
showTrail?: boolean;
showControls?: boolean;
source?: string;
onLayerChange?: (layer: MapLayer) => void;
className?: string;
Use
import { VisualMap } from '@visualli/design-system/components';
Source: components/src/ · Guidelines: components/catalog/VisualMap/README.md
