@miragon/context-maps-renderer 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["svgAttr","svgCreate","OVERLAY_TYPE","DIALOG_CLASS","TITLE_ID","Diagram","CroppingConnectionDocking","ElementFactory","BaseRenderer","SelectionModule","ZoomScrollModule","MoveCanvasModule","ConnectionPreviewModule","ModelingModule","MoveModule","OutlineModule","RulesModule","RuleProvider","CommandInterceptor","PaletteModule","CreateModule","ConnectModule","LassoToolModule","DirectEditingModule","ContextPadModule","PopupMenuModule","AutoPlaceModule","OverlaysModule","kindOf","el","isCmElement","isCmContext","isCmRelationship","MARGIN","LIVE_CANVAS_ATTRIBUTES","saveSVG","source","canvas","minX","minY","maxX","maxY","elementRegistry","s","x","y","width","height","clone","attribute","viewport","MIRAGON","CD_TOKENS","LEGEND_CLOSED_UP_TO","TT_RENDER_PRIORITY","INK","INK_SOFT","FONT","PAPER","NEUTRAL_FILL","NEUTRAL_STROKE","measureContext","textWidth","fontWeight","fontSize","text","TYPE_LABEL","TEAM_ICON_GAP","TEAM_ROW_FROM_BOTTOM","teamRowLayout","estimatedTextWidth","team","left","contextWidth","textX","contextHeight","typeLabelRight","SUBDOMAIN_TYPE_SPECS","type","letterSpacing","label","contextDrawnSpan","right","context","row","contentBoundsOf","top","bottom","include","element","elements","span","point","ROOT_ID","DIAGRAM_ROOT_ID","DEFAULT_FREE_RECT_INSETS","SMALLEST_FIT_ZOOM","sizeToCss","value","CmBaseViewer","options","container","modules","name","freeArea","freeRectInsets","event","priority","callback","diagram","eventBus","importer","doc","labelEditing","warnings","parsed","parseDocumentText","serializeDocumentText","partial","root","modeling","content","insets","freeWidth","freeHeight","contentWidth","contentHeight","scale","target","foreignAttributes","foreign","foreignFields","knownKeys","CmElementFactory","elementFactory","minSize","ctx","CONTEXT_KEYS","rel","RELATIONSHIP_KEYS","size","subdomainType","CmDiagramElementFactory","attrs","newId","CmLayouter","docking","hints","connection","provisional","getMid","cmModelModule","endRoleChipLayout","roles","dx","toward","endpoint","dy","length","ux","uy","charW","chipHeight","chipWidths","role","innerWidth","a","b","dist","direction","center","ContextMapsRenderer","clear","visuals","rect","attr","create","append","line","p","shape","wp","idx","spec","w","h","box","subdomainIcon","badge","icon","peopleIcon","RELATIONSHIP_PATTERN_SPECS","dash","src","tgt","upRoles","downRoles","mx","my","cs","len","dirColor","MARK_COLORS","letter","layout","widths","chipH","innerW","cy","parent","i","fill","gap","bg","cx","darken","t","MARK_TEXT_COLOR","bgFill","border","textFill","maxWidth","lines","wrapLabel","lineHeight","available","hasTeam","maxLines","ellipsize","startY","ln","m","hex","n","f","STAR_PATH","HAND_PATH","g","c","color","rot","path","PEOPLE_PATH","kept","paragraphs","paragraph","wrapParagraph","words","fits","candidate","current","word","rest","low","high","mid","cmDrawModule","borderPoint","sx","sy","centre","CmImporter","factory","seen","reserved","reservedIdProblem","id","DOCUMENT_KEYS","unplacedRelationships","byId","waypoints","other","roots","CmExporter","meta","contexts","relationships","geom","DOCUMENT_VERSION","ioModule","Viewer","POINTER_OFFSET","EDGE_MARGIN","hoverTipFor","parts","pattern","CmHoverTooltip","place","bounds","hide","tip","cmHoverTooltipModule","NavigatedViewer","setOrDelete","obj","key","UpdatePropertiesHandler","old","properties","oldProperties","swap","oldSource","SwapEndsHandler","UpdateTitleHandler","UPDATE_PROPERTIES","SWAP_ENDS","UPDATE_TITLE","CmModeling","commandStack","graphicsFactory","gfx","relationship","description","props","isSymmetricPattern","up","r","down","tech","cmModelingModule","CmRules","canConnect","alreadyConnected","incoming","outgoing","ignore","cmRulesModule","CmFlatModelBehavior","multiMove","shapes","attached","sourceId","targetId","DRAGGING_CLS","CmDragBehavior","BEFORE_SELECTION_BEHAVIOR","cmBehaviorsModule","selection","READ_ONLY_CHANGED_EVENT","LOCK_PRIORITY","EDIT_RULES","CmReadOnly","bus","readOnly","cmReadOnlyModule","MARKERS","LABEL_INSET_X","TEAM_BAND_HEIGHT","CmLabelEditing","directEditing","newText","marker","active","edit","textbox","placeCaretAtEnd","originalEvent","zoom","bbox","containerTop","style","reserve","range","field","cmLabelEditingModule","svg","inner","STAR","HAND","subdomainGlyph","contextIconSvg","subdomainIconSvg","roleChipSvg","relationshipIconSvg","LUCIDE","lucideSvg","strokeWidth","chromeIcon","toolIcon","GROUP_TOOLS","GROUP_CONTEXTS","KEYBOARD_CREATE_OFFSET","entryHtml","draggable","sentenceCase","isKeyboardClick","CmPaletteProvider","lassoTool","config","palette","entries","ALL_SUBDOMAIN_SPECS","start","named","taken","created","viewbox","cmPaletteModule","SUBDOMAIN_MENU","PATTERN_MENU","ROLES_MENU","ACTIVE_CLASS","MENU_GAP","CUSTOMER_SUPPLIER_BLOCKERS","escapeAttribute","padEntryHtml","danger","title","placePromptBeside","anchor","cardBounds","card","CmContextPadProvider","contextPad","popupMenu","autoPlace","rules","dragging","cmModeling","scheduler","selected","position","asTRBL","DEFAULT_DISTANCE","findFreePosition","generateGetNextPosition","pad","flipX","flipY","last","previous","containerBounds","padBounds","overflowRight","overflowLeft","shiftY","overflowBottom","overflowTop","cmElements","viaClick","swallowGestureClick","disarm","appended","onCreated","entry","hint","followPad","done","cleanup","commit","changed","keyEvent","menuId","entryBounds","popup","popupBounds","menu","ALL_PATTERN_SPECS","customerSupplier","upstream","downstream","UPSTREAM_ROLES","blocker","blocked","UPSTREAM_ROLE_SPECS","existing","DOWNSTREAM_ROLES","DOWNSTREAM_ROLE_SPECS","cmContextPadModule","isTypingTarget","isCanvasTarget","ownerDocument","CmKeyboard","undoRedoKeys","onKeydown","cmd","isUndo","isRedo","sel","cmKeyboardModule","OVERLAY_TYPE$1","MARKER_SIZE","LINE_OFFSET","END_DISTANCE","markerHtml","hasError","findings","finding","tooltip","message","anchorPoint","end","side","corner","along","baseX","baseY","cmValidationModule","overlays","exporter","refresh","report","validateDocument","byAnchor","collect","group","markerX","markerY","bboxX","bboxY","tier","CmZOrder","ordered","wrapper","layer","cmZOrderModule","Modeler","CONTEXT_MAPS_NOTATION","createCollaborativeModeler","collaborative","diagramOptions","createCollaborativeViewer","contentListeners","destroyed","lastExport","MODELER_API_VERSION","editable","listener","elementInfo","boundsOf","elementIds","host","warning","state","isViewState","getBBox","isFiniteNumber","OVERLAY_TYPE","HANDLE_SIZE","HANDLE_GAP","SIDES","handlePosition","centeredLeft","centeredTop","CmConnectHandles","handle","arrow","rotationDeg","cmConnectHandlesModule","ROLES","legendGroups","renderLegend","detachers","index","separator","body","groupElement","rowElement","preview","explanation","detach","legendRow","rows","divider","legendStartsOpen","CmLegend","open","hadFocus","head","close","groups","button","cmLegendModule","JSON_EXPORT_LABEL","exportEntry","action","contextMapMenu","actions","editTitle","commandKeyLabel","platform","keyNames","percentOfActualSize","lang","viewKeys","ctrl","plus","minus","shift","editKeys","fileGroup","chrome","messages","contextMapShortcuts","view","tag","className","header","onClose","createChromeDialog","dialog","build","panel","DIALOG_CLASS$1","TITLE_ID$1","shortcutTable","section","headingId","heading","table","keys","createShortcutsDialog","DIALOG_CLASS","TITLE_ID","FIELD_ID","variant","createTitleDialog","mapTitle","form","footer","cancel"],"sources":["../src/model/di-types.ts","../src/io/saveSvg.ts","../src/theme/palette.ts","../src/theme/sizes.ts","../src/draw/styles.ts","../src/draw/textMetrics.ts","../src/draw/contextLayout.ts","../src/model/contentBounds.ts","../src/io/types.ts","../src/CmBaseViewer.ts","../src/model/CmElementFactory.ts","../src/model/CmDiagramElementFactory.ts","../src/model/CmLayouter.ts","../src/model/index.ts","../src/draw/endRoleChips.ts","../src/draw/ContextMapsRenderer.ts","../src/draw/index.ts","../src/io/CmImporter.ts","../src/io/CmExporter.ts","../src/io/index.ts","../src/Viewer.ts","../src/hover-tooltip/CmHoverTooltip.ts","../src/hover-tooltip/index.ts","../src/NavigatedViewer.ts","../src/modeling/cmd/UpdatePropertiesHandler.ts","../src/modeling/cmd/SwapEndsHandler.ts","../src/modeling/cmd/UpdateTitleHandler.ts","../src/modeling/CmModeling.ts","../src/modeling/index.ts","../src/rules/CmRules.ts","../src/rules/index.ts","../src/behaviors/CmFlatModelBehavior.ts","../src/behaviors/CmDragBehavior.ts","../src/behaviors/CmClickSelectionBehavior.ts","../src/behaviors/index.ts","../src/read-only/CmReadOnly.ts","../src/read-only/index.ts","../src/label-editing/CmLabelEditing.ts","../src/label-editing/index.ts","../src/draw/palette-icons.ts","../src/draw/lucide.ts","../src/palette/CmPaletteProvider.ts","../src/palette/index.ts","../src/context-pad/CmContextPadProvider.ts","../src/context-pad/index.ts","../src/keyboard/CmKeyboard.ts","../src/keyboard/index.ts","../src/validation/CmValidationMarkers.ts","../src/validation/index.ts","../src/zorder/CmZOrder.ts","../src/zorder/index.ts","../src/Modeler.ts","../src/collaborative/CollaborativeContextMaps.ts","../src/connect-handles/CmConnectHandles.ts","../src/connect-handles/index.ts","../src/legend/legendContent.ts","../src/legend/CmLegend.ts","../src/legend/index.ts","../src/chrome/menu.ts","../src/chrome/shortcuts.ts","../src/chrome/dialog.ts","../src/chrome/ShortcutsDialog.ts","../src/chrome/TitleDialog.ts"],"sourcesContent":["/**\n * diagram-js runtime model for the Context Maps notation.\n *\n * - `context` — a bounded context: a placed, resizable SHAPE (box) with a\n * label, optional owning team and subdomain classification.\n * - `relationship` — a context-mapping pattern: a CONNECTION (edge) between two\n * contexts, carrying a pattern plus upstream/downstream roles.\n *\n * These runtime properties are the source of truth while editing; the exporter\n * rebuilds the canonical `CmDocument` from them.\n */\n\nimport type { Connection, Shape } from \"diagram-js/lib/model/Types\";\nimport type {\n DownstreamRole,\n RelationshipPattern,\n SubdomainType,\n UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\n\nexport type CmKind = \"context\" | \"relationship\";\n\nexport interface CmContext extends Shape {\n cmKind: \"context\";\n subdomainType?: SubdomainType;\n /** Display name (separate from diagram-js `label`). */\n cmLabel?: string;\n team?: string;\n description?: string;\n fill?: string;\n stroke?: string;\n /** Keys of the document's context this version does not know, written back on export. */\n cmForeign?: Record<string, unknown>;\n}\n\nexport interface CmRelationship extends Connection {\n cmKind: \"relationship\";\n pattern: RelationshipPattern;\n upstreamRoles?: UpstreamRole[];\n downstreamRoles?: DownstreamRole[];\n cmLabel?: string;\n description?: string;\n implementationTechnology?: string;\n /** Keys of the document's relationship this version does not know, written back on export. */\n cmForeign?: Record<string, unknown>;\n}\n\nexport type CmElement = CmContext | CmRelationship;\n\nfunction kindOf(el: unknown): string | undefined {\n return typeof el === \"object\" && el !== null\n ? ((el as { cmKind?: unknown }).cmKind as string | undefined)\n : undefined;\n}\n\nexport function isCmElement(el: unknown): el is CmElement {\n return typeof kindOf(el) === \"string\";\n}\n\nexport function isCmContext(el: unknown): el is CmContext {\n return kindOf(el) === \"context\";\n}\n\nexport function isCmRelationship(el: unknown): el is CmRelationship {\n return kindOf(el) === \"relationship\";\n}\n","/**\n * Serialises the current canvas into a standalone SVG (snapshot / export),\n * fitted to the content bounds and independent of the current zoom / scroll.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport { isCmContext } from \"../model/di-types.js\";\n\nconst MARGIN = 40;\n\n/** What the live canvas <svg> carries for keyboard and screen-reader users, not for a picture. */\nconst LIVE_CANVAS_ATTRIBUTES = [\"tabindex\", \"role\", \"aria-label\"];\n\nexport function saveSVG(canvas: Canvas, elementRegistry: ElementRegistry): { svg: string } {\n // The container's own <svg> child: a chrome that moves the palette in front of it (the modeler\n // shell does) puts the palette's icon <svg>s first in the container.\n const source = canvas.getContainer().querySelector(\":scope > svg\");\n if (!source) throw new Error(\"No SVG found in the canvas container.\");\n\n // Content bounds from the context boxes (relationship lines stay within them).\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const el of elementRegistry.getAll()) {\n if (!isCmContext(el)) continue;\n const s = el as unknown as { x: number; y: number; width: number; height: number };\n minX = Math.min(minX, s.x);\n minY = Math.min(minY, s.y);\n maxX = Math.max(maxX, s.x + s.width);\n maxY = Math.max(maxY, s.y + s.height);\n }\n if (!Number.isFinite(minX)) {\n minX = 0;\n minY = 0;\n maxX = 100;\n maxY = 100;\n }\n\n const x = minX - MARGIN;\n const y = minY - MARGIN;\n const width = maxX - minX + MARGIN * 2;\n const height = maxY - minY + MARGIN * 2;\n\n const clone = source.cloneNode(true) as SVGSVGElement;\n for (const attribute of LIVE_CANVAS_ATTRIBUTES) clone.removeAttribute(attribute);\n clone.setAttribute(\"xmlns\", \"http://www.w3.org/2000/svg\");\n clone.setAttribute(\"viewBox\", `${x} ${y} ${width} ${height}`);\n clone.setAttribute(\"width\", String(Math.round(width)));\n clone.setAttribute(\"height\", String(Math.round(height)));\n\n // Neutralise pan/zoom: let the viewBox (above) drive the geometry.\n const viewport = clone.querySelector<SVGGElement>(\".viewport\");\n if (viewport) viewport.removeAttribute(\"transform\");\n\n const svg = new XMLSerializer().serializeToString(clone);\n return { svg: '<?xml version=\"1.0\" encoding=\"utf-8\"?>\\n' + svg };\n}\n","/**\n * Miragon design tokens — the single source of truth for every non-notation colour the renderer\n * draws into SVG.\n *\n * Values mirror the Miragon design system: the `miragon-brand:modeler-tool-design` skill in\n * `Miragon/corporate-identity`, whose files are vendored unchanged next to this module\n * (`cd-tokens.generated.css`, `cd-tokens.generated.json`, `cd-canvas.css`; design system 1.15.0,\n * unchanged since 1.13.0).\n * Re-copy them from the skill to update; never fork the hex values by hand. SVG attributes need\n * literal values (exports carry presentation attributes, never `var()`), so `draw/styles.ts`\n * derives its colours from `MIRAGON`; the in-canvas chrome in `assets/context-maps.css` reads the\n * `--cd-ui-*` roles directly. `test/theme.sync.test.ts` fails if a value here drifts from the\n * vendored files.\n *\n * Pure data — no DOM, no imports. The subdomain-type fills and relationship-pattern strokes are the\n * official Context Maps notation and live in `schema-model/notation.ts`; they are NOT part of this\n * brand ramp. The renderer draws light only (the modelers switch to dark together, guide §13.3).\n */\n\n/** Raw Miragon brand ramp and status layer — the `fest` values of `cd-tokens.generated.json`. */\nexport const MIRAGON = {\n /** Primary: surfaces, buttons, links, selection, backgrounds. */\n blau: \"#335DE5\",\n /** Deeper blue for links / accent text on white (WCAG AA, ~5.5:1). */\n blauLink: \"#2B50D4\",\n /** Lightened blue for accents on dark surfaces (unused here — the canvas is light-only). */\n blauHell: \"#6B8AFF\",\n /** Accent: key visual, highlights, the brand gradient. Bright — a fill, never text on white. */\n gruen: \"#00E676\",\n /** Calm neutral surface (warm off-white) — the paper surround. */\n grau: \"#F9F7F7\",\n /** Text on light; not pure black. */\n schwarz: \"#1D1D1D\",\n weiss: \"#FFFFFF\",\n /** Fixed light neutral for lines and borders on a light stage. */\n linie: \"#E6E2E2\",\n /**\n * Status layer (guide §3.3): fills, borders, icons and dots; as text on white only `danger` and\n * `info` reach AA.\n */\n success: \"#00E676\",\n warning: \"#FFB000\",\n danger: \"#CD1839\",\n info: \"#335DE5\",\n /** Signature brand gradient — brand moments only. Use verbatim. */\n gradientBrand: \"linear-gradient(120deg, #335DE5 30%, #00E676)\",\n} as const;\n\n/**\n * Every fixed `--cd-*` token this repo mirrors, mapped to the value it MUST hold in the vendored\n * files (`fest` in the JSON, `:root` in the CSS).\n */\nexport const CD_TOKENS: Record<string, string> = {\n \"--cd-blau\": MIRAGON.blau,\n \"--cd-gruen\": MIRAGON.gruen,\n \"--cd-grau\": MIRAGON.grau,\n \"--cd-schwarz\": MIRAGON.schwarz,\n \"--cd-weiss\": MIRAGON.weiss,\n \"--cd-blau-link\": MIRAGON.blauLink,\n \"--cd-blau-hell\": MIRAGON.blauHell,\n \"--cd-linie\": MIRAGON.linie,\n \"--cd-success\": MIRAGON.success,\n \"--cd-warning\": MIRAGON.warning,\n \"--cd-danger\": MIRAGON.danger,\n \"--cd-info\": MIRAGON.info,\n \"--cd-gradient-brand\": MIRAGON.gradientBrand,\n};\n","/**\n * The sizes of the design system's `shell` tokens that the renderer's own chrome needs, for hosts\n * without the modeler shell: the values of `cd-tokens.generated.json` (`test/theme.sync.test.ts`\n * fails when one drifts). Pure data — no DOM, no imports.\n */\n\n/** Guide §5.10: up to these container sizes a legend without a stored state starts closed. */\nexport const LEGEND_CLOSED_UP_TO = {\n /** `--cd-shell-sehr-schmal` */\n width: 440,\n /** `--cd-shell-niedrig` */\n height: 820,\n} as const;\n","/** Shared rendering constants (typography, accent, priorities) — Miragon corporate identity.\n * Colours are derived from the single source of truth in `theme/palette.ts` (`MIRAGON`), which\n * mirrors the vendored `--cd-*` brand tokens. */\n\nimport { MIRAGON } from \"../theme/index.js\";\n\n/** BaseRenderer default priority is 1000; 1500 wins the render.shape/connection event. */\nexport const TT_RENDER_PRIORITY = 1500;\n\n/** Selection / hover accent (Miragon blue — kept in sync with the app theme via the shared palette). */\nexport const ACCENT = MIRAGON.blau;\n\nexport const INK = MIRAGON.schwarz;\nexport const INK_SOFT = \"#5B5B5B\";\n\nexport const FONT = {\n /**\n * Set directly as the `font-family` attribute on every SVG <text> (canvas\n * labels and therefore the SVG export too) — not inherited from a CSS\n * container. Prefers the self-hosted Miragon typeface Geist (registered as\n * 'Geist Variable' by @fontsource-variable/geist, with 'Geist' as a fallback\n * name), and falls back to a system sans when the host hasn't loaded it (e.g.\n * an exported SVG opened standalone).\n */\n family:\n \"'Geist Variable', 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif\",\n label: 13.5,\n small: 11,\n} as const;\n\n/**\n * Fixed top offset (px at zoom 1) of a context's name inside its box: the\n * first line starts here, right below the subdomain-type header, so the gap\n * between header and name never varies with box size or line count.\n */\nexport const CONTEXT_NAME_TOP = 36;\n\n/** Height (px at zoom 1) reserved at the box bottom for the team caption. */\nexport const CONTEXT_TEAM_RESERVE = 18;\n\n/** Paper colour used for the label halo so text stays legible over lines. */\nexport const PAPER = MIRAGON.weiss;\n\n/** Box colours for contexts without a subdomain classification (canvas + icons). */\nexport const NEUTRAL_FILL = \"#F1F1EE\";\nexport const NEUTRAL_STROKE = \"#8A8577\";\n","import { FONT } from \"./styles.js\";\n\n/**\n * Real text measurement so the rendered wrap matches the browser's own wrap\n * in the direct-editing box (same font, same width): a shared 2D context\n * measures actual glyph widths; the character-count heuristic remains only\n * as a fallback for environments without canvas support.\n */\nlet measureContext: CanvasRenderingContext2D | null | undefined;\n\n/**\n * The advance width of `text` at zoom 1. A canvas measures it, not the SVG: Chromium lays SVG text\n * out at the scaled font size, so a width read from the drawing would change with the zoom.\n */\nexport function textWidth(text: string, fontSize: number, fontWeight: string): number {\n if (measureContext === undefined) {\n measureContext =\n typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\");\n }\n if (!measureContext) return text.length * fontSize * 0.58;\n measureContext.font = `${fontWeight} ${fontSize}px ${FONT.family}`;\n return measureContext.measureText(text).width;\n}\n","import { SUBDOMAIN_TYPE_SPECS, type SubdomainType } from \"@miragon/context-maps-schema-model\";\nimport type { CmContext } from \"../model/di-types.js\";\nimport { FONT } from \"./styles.js\";\nimport { textWidth } from \"./textMetrics.js\";\n\n/** The subdomain type's name in a context's header, right of its icon (context coordinates). */\nexport const TYPE_LABEL = { x: 28, y: 15, fontWeight: \"700\", letterSpacingEm: 0.03 } as const;\n\nexport const TEAM_ICON_SIZE = 14;\nconst TEAM_ICON_GAP = 5;\nconst TEAM_ROW_FROM_BOTTOM = 12;\n\n/** The people icon and the team's name at the bottom of a context, in context coordinates. */\nexport interface TeamRowLayout {\n /** The icon's left edge, where the row starts. */\n left: number;\n iconCenterX: number;\n textX: number;\n centerY: number;\n /** Where the team's name ends as the canvas draws it. */\n right: number;\n}\n\nexport function teamRowLayout(\n contextWidth: number,\n contextHeight: number,\n team: string,\n): TeamRowLayout {\n // Centred on an estimate of the name's width, which no font load changes, so the row stays where\n // it is drawn; only its end follows the font the canvas shows.\n const estimatedTextWidth = team.length * FONT.small * 0.55;\n const left = contextWidth / 2 - (TEAM_ICON_SIZE + TEAM_ICON_GAP + estimatedTextWidth) / 2;\n const textX = left + TEAM_ICON_SIZE + TEAM_ICON_GAP;\n return {\n left,\n iconCenterX: left + TEAM_ICON_SIZE / 2,\n textX,\n centerY: contextHeight - TEAM_ROW_FROM_BOTTOM,\n right: textX + textWidth(team, FONT.small, \"400\"),\n };\n}\n\n/** Where the subdomain type's name in the header ends, in context coordinates. */\nexport function typeLabelRight(type: SubdomainType): number {\n const { label } = SUBDOMAIN_TYPE_SPECS[type];\n const letterSpacing = TYPE_LABEL.letterSpacingEm * FONT.small;\n return (\n TYPE_LABEL.x +\n textWidth(label, FONT.small, TYPE_LABEL.fontWeight) +\n label.length * letterSpacing\n );\n}\n\n/**\n * The horizontal span a context draws, in diagram coordinates: its box, wider where the type's\n * name or the team row runs past its sides, since neither is cut to the box. Vertically both stay\n * inside, as every context is at least the notation's minimum size.\n */\nexport function contextDrawnSpan(\n context: Pick<CmContext, \"x\" | \"width\" | \"subdomainType\" | \"team\">,\n): { left: number; right: number } {\n let left = 0;\n let right = context.width;\n if (context.subdomainType && SUBDOMAIN_TYPE_SPECS[context.subdomainType]) {\n right = Math.max(right, typeLabelRight(context.subdomainType));\n }\n if (context.team) {\n const row = teamRowLayout(context.width, 0, context.team);\n left = Math.min(left, row.left);\n right = Math.max(right, row.right);\n }\n return { left: context.x + left, right: context.x + right };\n}\n","import type { ElementBounds } from \"@miragon/modeler-api\";\nimport { contextDrawnSpan } from \"../draw/contextLayout.js\";\nimport { isCmContext, isCmRelationship } from \"./di-types.js\";\n\n/**\n * The tight box around what the canvas draws of the map, in diagram coordinates, without a margin:\n * every context's box with the type's name and the team row where they run past its sides, and\n * every relationship's waypoints. The markers and role chips on a relationship sit between the\n * contexts it connects. `undefined` while there is nothing to draw.\n *\n * Read from the model, never from the SVG: Chromium measures SVG text at the scaled font size, so a\n * measured box would change with the zoom.\n */\nexport function contentBoundsOf(elements: Iterable<unknown>): ElementBounds | undefined {\n let left = Infinity;\n let top = Infinity;\n let right = -Infinity;\n let bottom = -Infinity;\n const include = (x: number, y: number, width: number, height: number): void => {\n if (![x, y, width, height].every(Number.isFinite)) return;\n left = Math.min(left, x);\n top = Math.min(top, y);\n right = Math.max(right, x + width);\n bottom = Math.max(bottom, y + height);\n };\n for (const element of elements) {\n if (isCmContext(element)) {\n const span = contextDrawnSpan(element);\n include(span.left, element.y, span.right - span.left, element.height);\n } else if (isCmRelationship(element)) {\n for (const point of element.waypoints ?? []) include(point.x, point.y, 0, 0);\n }\n }\n if (left > right || top > bottom) return undefined;\n return { x: left, y: top, width: right - left, height: bottom - top };\n}\n","import { DIAGRAM_ROOT_ID, type Relationship } from \"@miragon/context-maps-schema-model\";\n\n/** ID of the diagram-js root element holding the Context Maps diagram. */\nexport const ROOT_ID = DIAGRAM_ROOT_ID;\n\nexport interface ImportWarning {\n readonly message: string;\n readonly elementId?: string;\n}\n\n/** Diagram-level data stashed on the root element. */\nexport interface RootBusinessObject {\n title: string;\n /** Keys of the document this version does not know, written back on export. */\n foreign?: Record<string, unknown>;\n /**\n * Relationships whose ends are not both contexts of the map. The canvas cannot draw them, but\n * they stay in the document (and in the Problems view) until the text fixes them.\n */\n unplacedRelationships?: Relationship[];\n}\n","/**\n * Shared lifecycle & DI bootstrap for every Context Maps viewer. Subclasses\n * only override `_getModules()`. The renderer\n * is framework-agnostic — mount it into any element (e.g. a VS Code webview).\n */\n\nimport Diagram from \"diagram-js/lib/Diagram\";\nimport type { ModuleDeclaration } from \"didi\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type PopupMenu from \"diagram-js/lib/features/popup-menu/PopupMenu\";\nimport type { Root } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport type { ElementBounds, FreeArea } from \"@miragon/modeler-api\";\nimport { parseDocumentText, serializeDocumentText } from \"@miragon/context-maps-schema-model\";\nimport type { CmDocument } from \"@miragon/context-maps-schema-model\";\nimport { saveSVG } from \"./io/saveSvg.js\";\nimport type CmImporter from \"./io/CmImporter.js\";\nimport type CmExporter from \"./io/CmExporter.js\";\nimport type CmLabelEditing from \"./label-editing/CmLabelEditing.js\";\nimport type CmModeling from \"./modeling/CmModeling.js\";\nimport type CmReadOnly from \"./read-only/CmReadOnly.js\";\nimport { contentBoundsOf } from \"./model/contentBounds.js\";\nimport { ROOT_ID, type ImportWarning, type RootBusinessObject } from \"./io/types.js\";\n\n/** Container margins in screen px that a host's chrome covers. */\nexport interface FreeRectInsets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nexport interface CmViewerOptions {\n /** Host element. When absent, a detached <div> is created (attach later). */\n container?: HTMLElement | undefined;\n width?: number | string | undefined;\n height?: number | string | undefined;\n /** Appended to the module list (extension point). */\n additionalModules?: ModuleDeclaration[] | undefined;\n /**\n * Bind Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z and Cmd/Ctrl+Y to the canvas undo/redo (default true).\n * Pass false when the host owns the history (the VS Code document), so the keys reach it.\n */\n undoRedoKeys?: boolean | undefined;\n /**\n * The part of the container the host's chrome (palette row, zoom panel, legend) leaves free, under\n * its `@miragon/modeler-api` name: `{ insets }`, the margins the chrome covers, or `{ center }`,\n * the free rectangle's centre in diagram coordinates. An element created from the palette with\n * Enter or Space lands in that centre, and the fit after an import centres the content in what\n * the insets leave (guide §5.5, §5.9). Default: room for the renderer's own palette, which the\n * fit also keeps when only `center` is given.\n */\n freeArea?: FreeArea | undefined;\n /** @deprecated Use `freeArea: { insets }`; accepted through the 0.5 releases, ignored next to it. */\n freeRectInsets?: (() => FreeRectInsets) | undefined;\n /**\n * Fit the content into the view after every import (default true). Pass false when the host's\n * chrome fits the content itself, so the view changes once per import.\n */\n fitOnImport?: boolean | undefined;\n}\n\nexport type EventCallback<T = unknown> = (event: T) => void;\n\ntype RootWithMeta = Root & { businessObject?: RootBusinessObject };\n\n/** Margins (screen px) the renderer's own palette needs, without a host's chrome around it. */\nconst DEFAULT_FREE_RECT_INSETS: FreeRectInsets = { top: 84, right: 56, bottom: 56, left: 56 };\n\n/**\n * diagram-js reads its zoom back rounded to three decimals: a fit below 0.0005 would read back as\n * zoom 0 and a NaN viewbox.\n */\nconst SMALLEST_FIT_ZOOM = 0.001;\n\n/** Services of the Modeler that hold an edit in progress; the viewers have none of them. */\ninterface ContextPadPrompt {\n cancelPrompt(): void;\n}\n\nfunction sizeToCss(value: number | string): string {\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nexport abstract class CmBaseViewer {\n protected abstract _getModules(): ModuleDeclaration[];\n\n private _diagram: Diagram | undefined;\n private readonly _container: HTMLElement;\n private readonly _options: CmViewerOptions;\n\n constructor(options: CmViewerOptions = {}) {\n this._options = options;\n this._container = this._createContainer(options);\n }\n\n private _createContainer(options: CmViewerOptions): HTMLElement {\n const container = options.container ?? document.createElement(\"div\");\n container.classList.add(\"cm-djs-container\");\n container.style.width = sizeToCss(options.width ?? \"100%\");\n container.style.height = sizeToCss(options.height ?? (options.container ? \"100%\" : \"600px\"));\n return container;\n }\n\n private _ensureDiagram(): Diagram {\n if (!this._diagram) {\n const modules = [...this._getModules(), ...(this._options.additionalModules ?? [])];\n this._diagram = new Diagram({\n canvas: { container: this._container },\n modules,\n cmKeyboard: { undoRedoKeys: this._options.undoRedoKeys ?? true },\n cmPalette: { freeRectInsets: this.freeRectInsets, freeRectCenter: this.freeRectCenter },\n });\n }\n return this._diagram;\n }\n\n /** Resolve a diagram-js service from the didi injector. */\n get<T>(name: string): T {\n return this._ensureDiagram().get<T>(name);\n }\n\n /** The margins the host's chrome covers right now. */\n private readonly freeRectInsets = (): FreeRectInsets => {\n const { freeArea, freeRectInsets } = this._options;\n const insets = freeArea ? freeArea.insets?.() : freeRectInsets?.();\n return insets ?? DEFAULT_FREE_RECT_INSETS;\n };\n\n /** The free rectangle's centre when the host names it, else the palette derives it. */\n private readonly freeRectCenter = (): Point | undefined => this._options.freeArea?.center?.();\n\n /** A service only some of the viewers have (the Modeler's editing services), else null. */\n private _optional<T>(name: string): T | null {\n return this._ensureDiagram().get<T>(name, false);\n }\n\n on<T = unknown>(event: string, callback: EventCallback<T>, priority = 1000): void {\n this.get<EventBus>(\"eventBus\").on(event, priority, callback as EventCallback);\n }\n\n off(event: string, callback: EventCallback): void {\n this.get<EventBus>(\"eventBus\").off(event, callback);\n }\n\n /**\n * Load a document into the canvas (replaces existing content). Silent: the previous document's\n * undo history goes without a `commandStack.changed`, so a host that saves on every change does\n * not write the import back. Throws before anything changes when the document cannot be drawn.\n */\n importDocument(doc: CmDocument): { warnings: ImportWarning[] } {\n const diagram = this._ensureDiagram();\n const eventBus = diagram.get<EventBus>(\"eventBus\");\n const importer = diagram.get<CmImporter>(\"cmImporter\");\n importer.assertImportable(doc);\n const labelEditing = this._optional<CmLabelEditing>(\"cmLabelEditing\");\n // An edit in progress belongs to an element the import is about to replace: a commit after it\n // (Enter, blur) would land on a removed shape.\n labelEditing?.suspend();\n this._optional<ContextPadPrompt>(\"cmContextPadProvider\")?.cancelPrompt();\n this._optional<PopupMenu>(\"popupMenu\")?.close();\n importer.clear();\n const warnings = importer.import(doc);\n // The previous document's history would undo onto elements that are gone (or, by id\n // coincidence, onto re-imported ones). Only the editors have a command stack.\n this._optional<CommandStack>(\"commandStack\")?.clear(false);\n if (this._options.fitOnImport ?? true) this._fit();\n eventBus.fire(\"import.done\", { warnings });\n labelEditing?.resumeAfterImport();\n return { warnings };\n }\n\n /**\n * Load the text of a `.cm`/`.cm.json` file. Throws (and changes nothing) when the text is no\n * importable document.\n */\n importText(text: string): { warnings: ImportWarning[] } {\n const parsed = parseDocumentText(text);\n if (!parsed.ok) throw new Error(parsed.error);\n return this.importDocument(parsed.document);\n }\n\n /** Current canvas state as a canonical document. */\n exportDocument(): CmDocument {\n return this.get<CmExporter>(\"cmExporter\").export();\n }\n\n /** Current canvas state as the canonical file text (ends in one line break). */\n exportText(): string {\n return serializeDocumentText(this.exportDocument());\n }\n\n /**\n * Update diagram-level metadata on the root. In an editor a title change is an undoable command\n * (`cmModeling.setTitle`); a viewer has no history and writes it directly. A locked editor\n * (`cmReadOnly`) changes nothing: its host takes no edits, and the next import would silently\n * revert the title.\n */\n setMeta(partial: Partial<RootBusinessObject>): void {\n if (partial.title === undefined) return;\n if (this._optional<CmReadOnly>(\"cmReadOnly\")?.isReadOnly()) return;\n const root = this._documentRoot();\n if (!root?.businessObject || root.businessObject.title === partial.title) return;\n const modeling = this._optional<CmModeling>(\"cmModeling\");\n if (modeling) modeling.setTitle(partial.title);\n else root.businessObject = { ...root.businessObject, title: partial.title };\n }\n\n /** Read diagram-level metadata from the root; undefined before the first import. */\n getMeta(): RootBusinessObject | undefined {\n return this._documentRoot()?.businessObject;\n }\n\n /** Through the registry: asking the canvas would create an implicit root before an import. */\n private _documentRoot(): RootWithMeta | undefined {\n return this.get<ElementRegistry>(\"elementRegistry\").get(ROOT_ID) as RootWithMeta | undefined;\n }\n\n /** Standalone, self-contained SVG snapshot. */\n saveSVG(): { svg: string } {\n return saveSVG(this.get<Canvas>(\"canvas\"), this.get<ElementRegistry>(\"elementRegistry\"));\n }\n\n /**\n * The tight box around what the canvas draws of the map in diagram coordinates, with no margin\n * of its own: the box a host's chrome fits to (`@miragon/modeler-api` 1.3). It reads the live\n * canvas and ignores zoom and scroll; `undefined` while the map is empty.\n */\n contentBounds(): ElementBounds | undefined {\n // Before the first use and after destroy() there is no diagram, and asking for one would build\n // it on a detached container.\n if (!this._diagram) return undefined;\n return contentBoundsOf(this._diagram.get<ElementRegistry>(\"elementRegistry\").getAll());\n }\n\n /**\n * Centres the content box in the container minus room for the chrome, at the largest zoom that\n * shows all of it and never above 100 % (guide §5.9); an empty map shows 100 %. The same view\n * for the same document and container (the contract's fitted view after an import). Without\n * `freeArea.insets` the room is the renderer's own palette margins: `freeArea.center` names no\n * rectangle to fit into.\n */\n private _fit(): void {\n const canvas = this.get<Canvas>(\"canvas\");\n const { width, height } = canvas.getSize();\n if (!(width > 0 && height > 0)) return;\n const content = this.contentBounds();\n if (!content) {\n canvas.viewbox({ x: 0, y: 0, width, height });\n return;\n }\n const insets = this.freeRectInsets();\n const freeWidth = Math.max(width - insets.left - insets.right, 1);\n const freeHeight = Math.max(height - insets.top - insets.bottom, 1);\n const contentWidth = Math.max(content.width, 1);\n const contentHeight = Math.max(content.height, 1);\n const scale = Math.max(\n Math.min(freeWidth / contentWidth, freeHeight / contentHeight, 1),\n SMALLEST_FIT_ZOOM,\n );\n canvas.viewbox({\n x: content.x + contentWidth / 2 - (insets.left + freeWidth / 2) / scale,\n y: content.y + contentHeight / 2 - (insets.top + freeHeight / 2) / scale,\n width: width / scale,\n height: height / scale,\n });\n }\n\n /** Attach the container into `target`. */\n attachTo(target: HTMLElement): void {\n target.appendChild(this._container);\n this.get<Canvas>(\"canvas\").resized();\n }\n\n /** Detach the container from the DOM, preserving state. */\n detach(): void {\n this._container.remove();\n }\n\n clear(): void {\n this._ensureDiagram().clear();\n }\n\n destroy(): void {\n if (this._diagram) {\n this._diagram.destroy();\n this._diagram = undefined;\n }\n this._container.remove();\n }\n\n get container(): HTMLElement {\n return this._container;\n }\n}\n","/**\n * Creates diagram-js runtime elements carrying Context Maps markers: bounded\n * contexts (shapes) and relationships (connections), from canonical document\n * elements (import) or from scratch (palette / context-pad create).\n */\n\nimport type ElementFactory from \"diagram-js/lib/core/ElementFactory\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport {\n CONTEXT_KEYS,\n RELATIONSHIP_KEYS,\n SUBDOMAIN_TYPE_SPECS,\n foreignFields,\n} from \"@miragon/context-maps-schema-model\";\nimport type {\n BoundedContext,\n Relationship,\n SubdomainType,\n} from \"@miragon/context-maps-schema-model\";\nimport type { CmContext, CmRelationship } from \"./di-types.js\";\n\n/** `{ cmForeign }` when `source` carries keys this version does not know, else nothing. */\nfunction foreignAttributes(\n source: object,\n knownKeys: readonly string[],\n): { cmForeign?: Record<string, unknown> } {\n const foreign = foreignFields(source, knownKeys);\n return Object.keys(foreign).length > 0 ? { cmForeign: foreign } : {};\n}\n\nexport default class CmElementFactory {\n static $inject = [\"elementFactory\"];\n\n constructor(private readonly elementFactory: ElementFactory) {}\n\n // --- from canonical document elements (import) -------------------------\n\n createContext(ctx: BoundedContext): CmContext {\n // Boxes are fixed-size on the canvas (no resize feature) — clamp legacy or\n // hand-edited imports up to the notation minimum so the fixed name/team\n // layout always fits inside the box.\n const spec = ctx.subdomainType ? SUBDOMAIN_TYPE_SPECS[ctx.subdomainType] : undefined;\n const minSize = spec?.minSize ?? { width: 120, height: 72 };\n return this.elementFactory.createShape({\n id: ctx.id,\n x: ctx.position.x,\n y: ctx.position.y,\n width: Math.max(ctx.size.width, minSize.width),\n height: Math.max(ctx.size.height, minSize.height),\n cmKind: \"context\",\n cmLabel: ctx.label,\n ...(ctx.subdomainType ? { subdomainType: ctx.subdomainType } : {}),\n ...(ctx.team ? { team: ctx.team } : {}),\n ...(ctx.description ? { description: ctx.description } : {}),\n ...(ctx.fill ? { fill: ctx.fill } : {}),\n ...(ctx.stroke ? { stroke: ctx.stroke } : {}),\n ...foreignAttributes(ctx, CONTEXT_KEYS),\n } as Partial<CmContext>) as unknown as CmContext;\n }\n\n createRelationship(\n rel: Relationship,\n source: CmContext,\n target: CmContext,\n waypoints: Point[],\n ): CmRelationship {\n return this.elementFactory.createConnection({\n id: rel.id,\n source,\n target,\n waypoints,\n cmKind: \"relationship\",\n pattern: rel.pattern,\n ...(rel.upstreamRoles?.length ? { upstreamRoles: [...rel.upstreamRoles] } : {}),\n ...(rel.downstreamRoles?.length ? { downstreamRoles: [...rel.downstreamRoles] } : {}),\n ...(rel.label ? { cmLabel: rel.label } : {}),\n ...(rel.description ? { description: rel.description } : {}),\n ...(rel.implementationTechnology\n ? { implementationTechnology: rel.implementationTechnology }\n : {}),\n ...foreignAttributes(rel, RELATIONSHIP_KEYS),\n } as unknown as Partial<CmRelationship>) as unknown as CmRelationship;\n }\n\n // --- fresh, not-yet-placed elements (palette / context-pad create) -----\n //\n // No explicit id: the element factory (CmDiagramElementFactory) assigns a\n // collision-free model-style id (`ctx_…`).\n\n /** No type → an unclassified context (the pad's append action starts blank). */\n createNewContext(subdomainType?: SubdomainType, label?: string): CmContext {\n // Every type shares one default size; generic serves as the neutral fallback.\n const size =\n (subdomainType ? SUBDOMAIN_TYPE_SPECS[subdomainType] : undefined)?.defaultSize ??\n SUBDOMAIN_TYPE_SPECS.generic.defaultSize;\n return this.elementFactory.createShape({\n width: size.width,\n height: size.height,\n cmKind: \"context\",\n ...(subdomainType ? { subdomainType } : {}),\n cmLabel: label ?? \"New Context\",\n } as Partial<CmContext>) as unknown as CmContext;\n }\n}\n","/**\n * Element factory that assigns model-style random ids (`ctx_…`, `rel_…`) when\n * none is provided. diagram-js' stock factory numbers elements with a session\n * counter that restarts on every page load and is never advanced past ids\n * arriving via import — after a reload, drawing a connection would re-generate\n * an id already taken by an imported relationship (e.g. `connection_13`) and\n * the create command would die with \"element already exists\", silently\n * dropping the just-drawn line.\n */\n\nimport ElementFactory from \"diagram-js/lib/core/ElementFactory\";\nimport type { Connection, Label, Root, Shape } from \"diagram-js/lib/model/Types\";\nimport { newId } from \"@miragon/context-maps-schema-model\";\n\nexport default class CmDiagramElementFactory extends ElementFactory {\n override create(type: \"root\", attrs?: Partial<Root>): Root;\n override create(type: \"shape\", attrs?: Partial<Shape>): Shape;\n override create(type: \"connection\", attrs?: Partial<Connection>): Connection;\n override create(type: \"label\", attrs?: Partial<Label>): Label;\n override create(\n type: \"root\" | \"shape\" | \"connection\" | \"label\",\n attrs?: Partial<Root | Shape | Connection | Label>,\n ): Root | Shape | Connection | Label {\n if (!attrs?.id && (type === \"shape\" || type === \"connection\")) {\n attrs = { ...attrs, id: newId(type === \"shape\" ? \"ctx\" : \"rel\") };\n }\n return super.create(type as \"shape\", attrs as Partial<Shape>);\n }\n}\n","/**\n * Straight-line connection layouter that crops the waypoints to the context box\n * borders via the cropping docking. diagram-js' stock BaseLayouter only returns\n * mid(source)→mid(target), so without this the relationship line would run from\n * box centre to box centre (visibly starting inside the boxes).\n */\n\nimport { getMid } from \"diagram-js/lib/layout/LayoutUtil\";\nimport type CroppingConnectionDocking from \"diagram-js/lib/layout/CroppingConnectionDocking\";\nimport type { ConnectionLike, ShapeLike } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\n\ninterface LayoutHints {\n /**\n * diagram-js may pass a Point (drag anchor) or `false` (end did not move,\n * e.g. MoveHelper's `connectionStart: sourceMoved && anchor`) here.\n */\n connectionStart?: Point | false;\n connectionEnd?: Point | false;\n source?: ShapeLike;\n target?: ShapeLike;\n}\n\nexport default class CmLayouter {\n static $inject = [\"connectionDocking\"];\n\n constructor(private readonly docking: CroppingConnectionDocking) {}\n\n layoutConnection(connection: ConnectionLike, hints: LayoutHints = {}): Point[] {\n const source = hints.source ?? connection.source;\n const target = hints.target ?? connection.target;\n // A relationship line always aims at the CENTRE of its contexts (then gets\n // cropped to the borders below). Anchor hints are deliberately ignored when\n // the shape is known: diagram-js' move helpers pass stale/shifted anchors\n // (the box may already have been relaid out), which would detach the line.\n // Hints only matter while an end has no shape yet (connect rubber band).\n const start = source ? getMid(source) : hints.connectionStart || undefined;\n const end = target ? getMid(target) : hints.connectionEnd || undefined;\n\n const provisional: Point[] = [start, end].filter(Boolean) as Point[];\n // Give the connection a straight line so the docking can crop it to the\n // shape borders. Falls back to the raw line if either end is missing.\n connection.waypoints = provisional;\n if (source && target && provisional.length === 2) {\n return this.docking.getCroppedWaypoints(connection, source, target);\n }\n return provisional;\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CroppingConnectionDocking from \"diagram-js/lib/layout/CroppingConnectionDocking\";\nimport CmElementFactory from \"./CmElementFactory.js\";\nimport CmDiagramElementFactory from \"./CmDiagramElementFactory.js\";\n\n/**\n * Element factory with Context Maps defaults, plus the cropping docking so\n * relationship lines dock to the context box borders. The layouter itself is\n * bound in the modeling module (see there) because diagram-js' ModelingModule\n * binds a default `layouter` and loads after this one. The stock\n * `elementFactory` is replaced so every element gets a collision-free id\n * (see CmDiagramElementFactory).\n */\nexport const cmModelModule: ModuleDeclaration = {\n elementFactory: [\"type\", CmDiagramElementFactory],\n cmElementFactory: [\"type\", CmElementFactory],\n connectionDocking: [\"type\", CroppingConnectionDocking],\n};\n\nexport { default as CmElementFactory } from \"./CmElementFactory.js\";\nexport { default as CmDiagramElementFactory } from \"./CmDiagramElementFactory.js\";\nexport { default as CmLayouter } from \"./CmLayouter.js\";\nexport * from \"./di-types.js\";\n","/**\n * Geometry of the role-chip group at a relationship end (the OHS/PL/ACL/CF\n * badges next to the direction letter). Kept in one place so the renderer\n * (which draws the chips) and the validation markers (which anchor to the\n * chips' bottom-right corner) can never drift apart.\n */\n\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { FONT } from \"./styles.js\";\n\nexport interface EndRoleChipLayout {\n /** The parent box around all chips of this end. */\n box: { x: number; y: number; width: number; height: number };\n center: Point;\n chipWidths: number[];\n chipHeight: number;\n innerWidth: number;\n gap: number;\n}\n\nexport function endRoleChipLayout(\n endpoint: Point,\n toward: Point,\n direction: string,\n roles: string[],\n): EndRoleChipLayout | null {\n if (roles.length === 0) return null;\n\n const dx = toward.x - endpoint.x;\n const dy = toward.y - endpoint.y;\n const length = Math.hypot(dx, dy) || 1;\n const ux = dx / length;\n const uy = dy / length;\n const charW = FONT.small * 0.64;\n const letterDist = 11;\n\n const chipHeight = FONT.small + 6;\n const gap = 3;\n const pad = 4;\n const chipWidths = roles.map((role) => role.length * charW + 12);\n const innerWidth = chipWidths.reduce((a, b) => a + b, 0) + gap * (roles.length - 1);\n const width = innerWidth + pad * 2;\n const height = chipHeight + pad * 2;\n\n const dist = letterDist + (direction.length * charW) / 2 + 8 + width / 2;\n const center = { x: endpoint.x + ux * dist, y: endpoint.y + uy * dist };\n\n return {\n box: { x: center.x - width / 2, y: center.y - height / 2, width, height },\n center,\n chipWidths,\n chipHeight,\n innerWidth,\n gap,\n };\n}\n","/**\n * SVG rendering of the Context Maps notation (BaseRenderer subclass).\n *\n * - bounded contexts: solid fixed-size boxes, coloured by subdomain type, with\n * a wrapped name and an optional owning-team caption;\n * - relationships: lines between contexts carrying the pattern abbreviation\n * (e.g. \"SK\", \"C/S\"), U/D end markers for asymmetric patterns, and the\n * integration roles (OHS/PL upstream, ACL/CF downstream).\n *\n * Colours/labels come from the single notation source (`@miragon/context-maps-schema-model`).\n */\n\nimport BaseRenderer from \"diagram-js/lib/draw/BaseRenderer\";\nimport {\n append as svgAppend,\n create as svgCreate,\n attr as svgAttr,\n clear as svgClear,\n} from \"tiny-svg\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { ConnectionLike, ElementLike, ShapeLike } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport {\n MARK_COLORS,\n MARK_TEXT_COLOR,\n RELATIONSHIP_PATTERN_SPECS,\n SUBDOMAIN_TYPE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type { SubdomainType } from \"@miragon/context-maps-schema-model\";\nimport {\n CONTEXT_NAME_TOP,\n CONTEXT_TEAM_RESERVE,\n FONT,\n INK,\n INK_SOFT,\n NEUTRAL_FILL,\n NEUTRAL_STROKE,\n PAPER,\n TT_RENDER_PRIORITY,\n} from \"./styles.js\";\nimport { endRoleChipLayout } from \"./endRoleChips.js\";\nimport { TEAM_ICON_SIZE, TYPE_LABEL, teamRowLayout } from \"./contextLayout.js\";\nimport { textWidth } from \"./textMetrics.js\";\nimport {\n isCmContext,\n isCmElement,\n isCmRelationship,\n type CmContext,\n type CmRelationship,\n} from \"../model/di-types.js\";\n\ntype Attrs = Record<string, string | number>;\n\nexport default class ContextMapsRenderer extends BaseRenderer {\n static $inject = [\"eventBus\"];\n\n constructor(eventBus: EventBus) {\n super(eventBus, TT_RENDER_PRIORITY);\n }\n\n override canRender(element: ElementLike): boolean {\n return isCmElement(element);\n }\n\n override drawShape(visuals: SVGElement, element: ShapeLike): SVGElement {\n // diagram-js does not always clear our visual group before re-rendering on\n // update; clear it ourselves so re-draws never leave stale duplicates behind.\n svgClear(visuals);\n if (isCmContext(element)) return this.drawContext(visuals, element);\n const rect = svgAttr(svgCreate(\"rect\"), {\n width: element.width,\n height: element.height,\n fill: \"#eee\",\n });\n svgAppend(visuals, rect);\n return rect;\n }\n\n override drawConnection(visuals: SVGElement, connection: ConnectionLike): SVGElement {\n svgClear(visuals);\n if (isCmRelationship(connection)) return this.drawRelationship(visuals, connection);\n const line = svgAttr(svgCreate(\"polyline\"), {\n points: (connection.waypoints ?? []).map((p) => `${p.x},${p.y}`).join(\" \"),\n fill: \"none\",\n stroke: INK,\n });\n svgAppend(visuals, line);\n return line;\n }\n\n override getShapePath(shape: ShapeLike): string {\n const { x, y, width, height } = shape;\n return `M${x},${y}l${width},0l0,${height}l${-width},0z`;\n }\n\n override getConnectionPath(connection: ConnectionLike): string {\n const wp = (connection.waypoints ?? []) as Point[];\n if (wp.length === 0) return \"\";\n return wp.map((p, idx) => `${idx === 0 ? \"M\" : \"L\"}${p.x},${p.y}`).join(\"\");\n }\n\n // --- bounded context -----------------------------------------------------\n\n private drawContext(visuals: SVGElement, ctx: CmContext): SVGElement {\n const spec = ctx.subdomainType ? SUBDOMAIN_TYPE_SPECS[ctx.subdomainType] : undefined;\n const w = Math.max(ctx.width, 1);\n const h = Math.max(ctx.height, 1);\n const sw = 2;\n const i = sw / 2;\n const box = svgAttr(svgCreate(\"rect\"), {\n x: i,\n y: i,\n width: w - sw,\n height: h - sw,\n rx: 8,\n ry: 8,\n fill: ctx.fill ?? spec?.fill ?? NEUTRAL_FILL,\n stroke: ctx.stroke ?? spec?.stroke ?? NEUTRAL_STROKE,\n \"stroke-width\": sw,\n \"stroke-linejoin\": \"round\",\n });\n svgAppend(visuals, box);\n\n this.appendLabel(visuals, ctx.cmLabel ?? \"\", w, h, Boolean(ctx.team), {\n \"font-weight\": \"650\",\n });\n if (ctx.subdomainType && spec) {\n // Kaiser subdomain icon at the top-left corner (star / open hand / dotted\n // circle) plus the domain-type label next to it.\n svgAppend(visuals, subdomainIcon(ctx.subdomainType, 15, 15, 18, spec.stroke));\n const badge = svgAttr(svgCreate(\"text\"), {\n x: TYPE_LABEL.x,\n y: TYPE_LABEL.y,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n \"font-weight\": TYPE_LABEL.fontWeight,\n fill: spec.stroke,\n \"text-anchor\": \"start\",\n \"dominant-baseline\": \"central\",\n \"letter-spacing\": `${TYPE_LABEL.letterSpacingEm}em`,\n });\n badge.textContent = spec.label;\n svgAppend(visuals, badge);\n }\n if (ctx.team) {\n // People icon + team name, centred as a unit at the bottom of the box.\n const row = teamRowLayout(w, h, ctx.team);\n const icon = peopleIcon(row.iconCenterX, row.centerY, TEAM_ICON_SIZE, INK_SOFT);\n svgAttr(icon, { class: \"cm-team\" });\n svgAppend(visuals, icon);\n\n const team = svgAttr(svgCreate(\"text\"), {\n class: \"cm-team\",\n x: row.textX,\n y: row.centerY,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n fill: INK_SOFT,\n \"text-anchor\": \"start\",\n \"dominant-baseline\": \"central\",\n });\n team.textContent = ctx.team;\n svgAppend(visuals, team);\n }\n return box;\n }\n\n // --- relationship --------------------------------------------------------\n\n private drawRelationship(visuals: SVGElement, rel: CmRelationship): SVGElement {\n const spec =\n RELATIONSHIP_PATTERN_SPECS[rel.pattern] ?? RELATIONSHIP_PATTERN_SPECS[\"upstream-downstream\"];\n const wp = (rel.waypoints ?? []) as Point[];\n const dash = spec.dash;\n const line = svgAttr(svgCreate(\"polyline\"), {\n points: wp.map((p) => `${p.x},${p.y}`).join(\" \"),\n fill: \"none\",\n stroke: spec.stroke,\n \"stroke-width\": spec.strokeWidth,\n \"stroke-linejoin\": \"round\",\n \"stroke-linecap\": \"round\",\n ...(dash ? { \"stroke-dasharray\": dash } : {}),\n });\n svgAppend(visuals, line);\n\n if (wp.length >= 2) {\n const src = wp[0];\n const tgt = wp[wp.length - 1];\n const upRoles = rel.upstreamRoles ?? [];\n const downRoles = rel.downstreamRoles ?? [];\n\n if (spec.symmetric) {\n // No direction (SK / P / SW): a single neutral pattern chip in the MIDDLE.\n const mx = (src.x + tgt.x) / 2;\n const my = (src.y + tgt.y) / 2;\n this.chip(visuals, mx, my, spec.abbreviation, PAPER, spec.stroke, spec.stroke);\n } else {\n // Direction letter sits AT the domain as a plain letter (no box); the\n // integration roles follow as their own coloured boxes. Customer-supplier\n // uses S (supplier, upstream) and C (customer, downstream) instead of U/D.\n const cs = rel.pattern === \"customer-supplier\";\n this.endMarkers(visuals, src, tgt, cs ? \"S\" : \"U\", upRoles);\n this.endMarkers(visuals, tgt, src, cs ? \"C\" : \"D\", downRoles);\n }\n }\n return line;\n }\n\n /**\n * Draws the markers at one relationship end: the direction letter (U/D/S/C) as\n * a plain letter right at the domain (no box), then the integration roles side\n * by side inside a single axis-aligned parent box.\n */\n private endMarkers(\n visuals: SVGElement,\n endpoint: Point,\n toward: Point,\n direction: string,\n roles: string[],\n ): void {\n const dx = toward.x - endpoint.x;\n const dy = toward.y - endpoint.y;\n const len = Math.hypot(dx, dy) || 1;\n const ux = dx / len;\n const uy = dy / len;\n\n // Direction letter: plain bold letter at the domain, white halo for legibility.\n const letterDist = 11;\n const dirColor = MARK_COLORS[direction] ?? INK;\n const letter = svgAttr(svgCreate(\"text\"), {\n x: endpoint.x + ux * letterDist,\n y: endpoint.y + uy * letterDist,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small + 1,\n \"font-weight\": \"800\",\n fill: dirColor,\n stroke: PAPER,\n \"stroke-width\": 3,\n \"paint-order\": \"stroke\",\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n });\n letter.textContent = direction;\n svgAppend(visuals, letter);\n\n // Integration roles: horizontal chips inside one axis-aligned parent box\n // (geometry shared with the validation markers via endRoleChipLayout).\n const layout = endRoleChipLayout(endpoint, toward, direction, roles);\n if (!layout) return;\n const { box, center, chipWidths: widths, chipHeight: chipH, innerWidth: innerW, gap } = layout;\n const cy = center.y;\n\n const parent = svgAttr(svgCreate(\"rect\"), {\n x: box.x,\n y: box.y,\n width: box.width,\n height: box.height,\n rx: 6,\n ry: 6,\n fill: PAPER,\n \"fill-opacity\": 0.96,\n stroke: \"#d9d5cc\",\n \"stroke-width\": 1,\n });\n svgAppend(visuals, parent);\n\n let x = center.x - innerW / 2;\n roles.forEach((role, i) => {\n const w = widths[i];\n const fill = MARK_COLORS[role] ?? NEUTRAL_STROKE;\n this.miniChip(visuals, x + w / 2, cy, w, chipH, role, fill);\n x += w + gap;\n });\n }\n\n /** A fixed-size coloured sub-label (own colour + border) inside a parent box. */\n private miniChip(\n visuals: SVGElement,\n cx: number,\n cy: number,\n w: number,\n h: number,\n text: string,\n fill: string,\n ): void {\n const bg = svgAttr(svgCreate(\"rect\"), {\n x: cx - w / 2,\n y: cy - h / 2,\n width: w,\n height: h,\n rx: 3,\n ry: 3,\n fill,\n stroke: darken(fill),\n \"stroke-width\": 1,\n });\n svgAppend(visuals, bg);\n const t = svgAttr(svgCreate(\"text\"), {\n x: cx,\n y: cy,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n \"font-weight\": \"700\",\n fill: MARK_TEXT_COLOR,\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n });\n t.textContent = text;\n svgAppend(visuals, t);\n }\n\n /** A single small filled, bordered box (background, text colour, border colour). */\n private chip(\n visuals: SVGElement,\n cx: number,\n cy: number,\n text: string,\n bgFill: string,\n textFill: string,\n border: string,\n ): void {\n if (!text) return;\n const padX = 6;\n const charW = FONT.small * 0.64;\n const w = text.length * charW + padX * 2;\n const h = FONT.small + 8;\n const bg = svgAttr(svgCreate(\"rect\"), {\n x: cx - w / 2,\n y: cy - h / 2,\n width: w,\n height: h,\n rx: 4,\n ry: 4,\n fill: bgFill,\n stroke: border,\n \"stroke-width\": 1,\n ...(bgFill === PAPER ? { \"fill-opacity\": 0.95 } : {}),\n });\n svgAppend(visuals, bg);\n const t = svgAttr(svgCreate(\"text\"), {\n x: cx,\n y: cy,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n \"font-weight\": \"700\",\n fill: textFill,\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n });\n t.textContent = text;\n svgAppend(visuals, t);\n }\n\n // --- shared label rendering (wrapped, top-anchored) ----------------------\n\n /** The name starts at the FIXED offset below the type header — the gap\n * between header and name never varies with box size or line count. Lines\n * that would run past the (fixed-size) box are dropped, the last kept line\n * gets an ellipsis. */\n private appendLabel(\n visuals: SVGElement,\n text: string,\n w: number,\n h: number,\n hasTeam: boolean,\n attrs: Attrs,\n ): void {\n const fontSize =\n typeof attrs[\"font-size\"] === \"number\" ? (attrs[\"font-size\"] as number) : FONT.label;\n const fontWeight = String(attrs[\"font-weight\"] ?? \"400\");\n const maxWidth = w - 20;\n let lines = wrapLabel(text, maxWidth, fontSize, fontWeight);\n const lineHeight = fontSize * 1.2;\n const available = h - CONTEXT_NAME_TOP - (hasTeam ? CONTEXT_TEAM_RESERVE : 8);\n const maxLines = Math.max(1, Math.floor(available / lineHeight));\n if (lines.length > maxLines) {\n lines = lines.slice(0, maxLines);\n lines[maxLines - 1] = ellipsize(lines[maxLines - 1], maxWidth, fontSize, fontWeight);\n }\n const startY = CONTEXT_NAME_TOP + lineHeight / 2;\n lines.forEach((ln, idx) => {\n const t = svgAttr(svgCreate(\"text\"), {\n // `cm-name` lets the direct-editing marker hide the rendered name.\n class: \"cm-name\",\n x: w / 2,\n y: startY + idx * lineHeight,\n \"font-family\": FONT.family,\n \"font-size\": fontSize,\n fill: INK,\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n ...attrs,\n });\n t.textContent = ln;\n svgAppend(visuals, t);\n });\n }\n}\n\n// --- helpers ---------------------------------------------------------------\n\n/** Darkens a #rrggbb colour toward black by factor `f` (0..1) for chip borders. */\nfunction darken(hex: string, f = 0.7): string {\n const m = /^#([0-9a-f]{6})$/i.exec(hex);\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n const r = Math.round(((n >> 16) & 255) * f);\n const g = Math.round(((n >> 8) & 255) * f);\n const b = Math.round((n & 255) * f);\n return `rgb(${r},${g},${b})`;\n}\n\n// Material star + pan_tool (open hand) paths (Apache-2.0), 24×24 viewBox.\nconst STAR_PATH =\n \"M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14l-5-4.87 7.1-1.01z\";\nconst HAND_PATH =\n \"M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z\";\n\n/**\n * Kaiser subdomain icon centred on (cx, cy) at `size` px: a filled star for a\n * core domain, an open hand for a supporting subdomain, a dotted circle for a\n * generic subdomain.\n */\nfunction subdomainIcon(\n type: SubdomainType,\n cx: number,\n cy: number,\n size: number,\n color: string,\n): SVGElement {\n if (type === \"generic\") {\n const g = svgCreate(\"g\");\n const c = svgAttr(svgCreate(\"circle\"), {\n cx,\n cy,\n r: size / 2 - 1,\n fill: \"none\",\n stroke: color,\n \"stroke-width\": 1.6,\n \"stroke-dasharray\": \"2.2 2.2\",\n });\n svgAppend(g, c);\n return g;\n }\n const scale = size / 24;\n // The open hand is drawn upright by Material; rotate it to lie sideways.\n const rot = type === \"supporting\" ? \" rotate(90 12 12)\" : \"\";\n const g = svgCreate(\"g\");\n svgAttr(g, {\n transform: `translate(${cx - 12 * scale} ${cy - 12 * scale}) scale(${scale})${rot}`,\n });\n const path = svgAttr(svgCreate(\"path\"), {\n d: type === \"core\" ? STAR_PATH : HAND_PATH,\n fill: color,\n });\n svgAppend(g, path);\n return g;\n}\n\n// Material \"people\" icon (Apache-2.0), 24×24 viewBox.\nconst PEOPLE_PATH =\n \"M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z\";\n\n/** A people glyph centred on (cx, cy), rendered at `size` px in the given colour. */\nfunction peopleIcon(cx: number, cy: number, size: number, color: string): SVGElement {\n const scale = size / 24;\n const g = svgCreate(\"g\");\n svgAttr(g, { transform: `translate(${cx - 12 * scale} ${cy - 12 * scale}) scale(${scale})` });\n const path = svgAttr(svgCreate(\"path\"), { d: PEOPLE_PATH, fill: color });\n svgAppend(g, path);\n return g;\n}\n\nfunction ellipsize(line: string, maxWidth: number, fontSize: number, fontWeight: string): string {\n let kept = line;\n while (kept && textWidth(`${kept}…`, fontSize, fontWeight) > maxWidth) {\n kept = kept.slice(0, -1).trimEnd();\n }\n return `${kept}…`;\n}\n\n/** Greedy word-wrap into lines that fit `maxWidth` at the font size. */\n/** Explicit line breaks are the author's — wrap only within each of them. */\nfunction wrapLabel(text: string, maxWidth: number, fontSize: number, fontWeight: string): string[] {\n const paragraphs = text.split(\"\\n\");\n if (paragraphs.every((paragraph) => paragraph.trim() === \"\")) return [];\n return paragraphs.flatMap((paragraph) => {\n const lines = wrapParagraph(paragraph, maxWidth, fontSize, fontWeight);\n // An intentionally blank line keeps its vertical space.\n return lines.length ? lines : [\"\"];\n });\n}\n\nfunction wrapParagraph(\n text: string,\n maxWidth: number,\n fontSize: number,\n fontWeight: string,\n): string[] {\n const words = text.split(/\\s+/).filter(Boolean);\n if (words.length === 0) return [];\n const fits = (candidate: string) => textWidth(candidate, fontSize, fontWeight) <= maxWidth;\n const lines: string[] = [];\n let current = \"\";\n for (const word of words) {\n const candidate = current ? `${current} ${word}` : word;\n if (fits(candidate)) {\n current = candidate;\n continue;\n }\n if (current) lines.push(current);\n // A word longer than the line hard-breaks mid-word (the editor's\n // break-word behaviour), so nothing ever overflows the box.\n let rest = word;\n while (rest && !fits(rest)) {\n let low = 1;\n let high = rest.length - 1;\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n if (fits(rest.slice(0, mid))) low = mid;\n else high = mid - 1;\n }\n lines.push(rest.slice(0, low));\n rest = rest.slice(low);\n }\n current = rest;\n }\n if (current) lines.push(current);\n return lines;\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport ContextMapsRenderer from \"./ContextMapsRenderer.js\";\n\n/** SVG rendering of all Context Maps element types (BaseRenderer, priority 1500). */\nexport const cmDrawModule: ModuleDeclaration = {\n __init__: [\"cmRenderer\"],\n cmRenderer: [\"type\", ContextMapsRenderer],\n};\n\nexport { default as ContextMapsRenderer } from \"./ContextMapsRenderer.js\";\n","/**\n * Bridges the canonical `CmDocument` into the diagram-js canvas. Contexts become\n * shapes; relationships become connections whose waypoints are cropped to the\n * context box borders. Connections are added first so they sit behind the boxes.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementFactory from \"diagram-js/lib/core/ElementFactory\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { Root } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport {\n DOCUMENT_KEYS,\n foreignFields,\n reservedIdProblem,\n} from \"@miragon/context-maps-schema-model\";\nimport type { CmDocument, Relationship } from \"@miragon/context-maps-schema-model\";\nimport type CmElementFactory from \"../model/CmElementFactory.js\";\nimport type { CmContext } from \"../model/di-types.js\";\nimport { ROOT_ID, type ImportWarning, type RootBusinessObject } from \"./types.js\";\n\ntype RootWithMeta = Root & { businessObject?: RootBusinessObject };\n\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** The point where the ray from a rect's centre toward `toward` crosses its border. */\nfunction borderPoint(rect: Rect, toward: Point): Point {\n const cx = rect.x + rect.width / 2;\n const cy = rect.y + rect.height / 2;\n const dx = toward.x - cx;\n const dy = toward.y - cy;\n if (dx === 0 && dy === 0) return { x: cx, y: cy };\n const sx = dx !== 0 ? rect.width / 2 / Math.abs(dx) : Infinity;\n const sy = dy !== 0 ? rect.height / 2 / Math.abs(dy) : Infinity;\n const s = Math.min(sx, sy);\n return { x: cx + dx * s, y: cy + dy * s };\n}\n\nfunction centre(rect: Rect): Point {\n return { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };\n}\n\nexport default class CmImporter {\n static $inject = [\"canvas\", \"elementFactory\", \"cmElementFactory\", \"eventBus\", \"elementRegistry\"];\n\n constructor(\n private readonly canvas: Canvas,\n private readonly elementFactory: ElementFactory,\n private readonly factory: CmElementFactory,\n private readonly eventBus: EventBus,\n private readonly elementRegistry: ElementRegistry,\n ) {}\n\n /**\n * Throws when `doc` cannot be drawn: diagram-js keeps one element per id in a plain object, so a\n * duplicate, an id of its own roots or the name of a built-in object property would throw halfway\n * through the import, after the previous document was cleared. Checked before anything is\n * removed, so a rejected import leaves no trace.\n */\n assertImportable(doc: CmDocument): void {\n const seen = new Set<string>();\n for (const { id } of [...doc.contexts, ...doc.relationships]) {\n const reserved = reservedIdProblem(id);\n if (reserved) throw new Error(`Cannot draw the map: ${reserved}.`);\n if (seen.has(id)) throw new Error(`The id \"${id}\" is used more than once.`);\n seen.add(id);\n }\n }\n\n import(doc: CmDocument): ImportWarning[] {\n const warnings: ImportWarning[] = [];\n this.eventBus.fire(\"import.render.start\", { document: doc });\n\n const root = this.documentRoot();\n const foreign = foreignFields(doc, DOCUMENT_KEYS);\n const unplacedRelationships: Relationship[] = [];\n root.businessObject = {\n title: doc.title,\n ...(Object.keys(foreign).length > 0 ? { foreign } : {}),\n };\n\n const byId = new Map<string, CmContext>();\n for (const ctx of doc.contexts) {\n const shape = this.factory.createContext(ctx);\n byId.set(ctx.id, shape);\n }\n\n // Connections first (back), then contexts (front).\n for (const rel of doc.relationships) {\n const source = byId.get(rel.from);\n const target = byId.get(rel.to);\n if (!source || !target) {\n unplacedRelationships.push(rel);\n warnings.push({\n message: `Relationship \"${rel.id}\" references a missing context; it stays in the file but is not drawn.`,\n elementId: rel.id,\n });\n continue;\n }\n const waypoints: Point[] = [\n borderPoint(source as unknown as Rect, centre(target as unknown as Rect)),\n borderPoint(target as unknown as Rect, centre(source as unknown as Rect)),\n ];\n const connection = this.factory.createRelationship(rel, source, target, waypoints);\n this.canvas.addConnection(connection, root);\n }\n for (const shape of byId.values()) {\n this.canvas.addShape(shape, root);\n }\n if (unplacedRelationships.length > 0)\n root.businessObject.unplacedRelationships = unplacedRelationships;\n\n this.eventBus.fire(\"import.render.done\", { warnings });\n return warnings;\n }\n\n /**\n * The document root, created on the first import. Any other root goes: diagram-js creates an\n * implicit one whenever something asks for the root before the first import (an export, a\n * palette create), and it would stay in the registry next to the document's root.\n */\n private documentRoot(): RootWithMeta {\n let root = this.elementRegistry.get(ROOT_ID) as RootWithMeta | undefined;\n if (!root) {\n root = this.elementFactory.createRoot({ id: ROOT_ID }) as RootWithMeta;\n this.canvas.setRootElement(root);\n }\n for (const other of this.canvas.getRootElements()) {\n if (other !== root) this.canvas.removeRootElement(other);\n }\n return root;\n }\n\n /** Removes every element but the roots (removing a root as a shape corrupts the canvas). */\n clear(): void {\n const roots = new Set<unknown>(this.canvas.getRootElements());\n for (const el of [...this.elementRegistry.getAll()]) {\n if (roots.has(el)) continue;\n try {\n if (\"waypoints\" in el) this.canvas.removeConnection(el.id);\n else this.canvas.removeShape(el.id);\n } catch {\n // already removed — ignore\n }\n }\n }\n}\n","/**\n * Rebuilds a canonical `CmDocument` from the diagram-js runtime model. Position\n * and size truth are the live `x/y/width/height`; editable fields (label,\n * subdomain, team, pattern, roles, colours) are read from runtime properties.\n */\n\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type { Root } from \"diagram-js/lib/model/Types\";\nimport { DOCUMENT_VERSION } from \"@miragon/context-maps-schema-model\";\nimport type { BoundedContext, Relationship, CmDocument } from \"@miragon/context-maps-schema-model\";\nimport { isCmContext, isCmRelationship } from \"../model/di-types.js\";\nimport { ROOT_ID, type RootBusinessObject } from \"./types.js\";\n\nexport default class CmExporter {\n static $inject = [\"elementRegistry\"];\n\n constructor(private readonly elementRegistry: ElementRegistry) {}\n\n export(): CmDocument {\n // Through the registry: asking the canvas would create an implicit root before the first import.\n const root = this.elementRegistry.get(ROOT_ID) as\n (Root & { businessObject?: RootBusinessObject }) | undefined;\n const meta = root?.businessObject;\n\n const contexts: BoundedContext[] = [];\n const relationships: Relationship[] = [];\n\n for (const el of this.elementRegistry.getAll()) {\n if (el.id === ROOT_ID) continue;\n\n if (isCmContext(el)) {\n const geom = el as unknown as { x: number; y: number; width: number; height: number };\n contexts.push({\n id: el.id,\n label: el.cmLabel ?? \"\",\n position: { x: geom.x, y: geom.y },\n size: { width: geom.width, height: geom.height },\n ...(el.subdomainType ? { subdomainType: el.subdomainType } : {}),\n ...(el.team ? { team: el.team } : {}),\n ...(el.description ? { description: el.description } : {}),\n ...(el.fill ? { fill: el.fill } : {}),\n ...(el.stroke ? { stroke: el.stroke } : {}),\n ...el.cmForeign,\n });\n } else if (isCmRelationship(el)) {\n const source = el.source as { id?: string } | undefined;\n const target = el.target as { id?: string } | undefined;\n if (!source?.id || !target?.id) continue;\n relationships.push({\n id: el.id,\n from: source.id,\n to: target.id,\n pattern: el.pattern,\n ...(el.upstreamRoles?.length ? { upstreamRoles: [...el.upstreamRoles] } : {}),\n ...(el.downstreamRoles?.length ? { downstreamRoles: [...el.downstreamRoles] } : {}),\n ...(el.cmLabel ? { label: el.cmLabel } : {}),\n ...(el.description ? { description: el.description } : {}),\n ...(el.implementationTechnology\n ? { implementationTechnology: el.implementationTechnology }\n : {}),\n ...el.cmForeign,\n });\n }\n }\n relationships.push(...(meta?.unplacedRelationships ?? []));\n\n return {\n version: DOCUMENT_VERSION,\n title: meta?.title ?? \"Untitled context map\",\n contexts,\n relationships,\n ...meta?.foreign,\n };\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmImporter from \"./CmImporter.js\";\nimport CmExporter from \"./CmExporter.js\";\n\n/** Document <-> diagram-js bridge (import / export). */\nexport const ioModule: ModuleDeclaration = {\n cmImporter: [\"type\", CmImporter],\n cmExporter: [\"type\", CmExporter],\n};\n\nexport { default as CmImporter } from \"./CmImporter.js\";\nexport { default as CmExporter } from \"./CmExporter.js\";\nexport { saveSVG } from \"./saveSvg.js\";\nexport { ROOT_ID } from \"./types.js\";\nexport type { ImportWarning, RootBusinessObject } from \"./types.js\";\n","import type { ModuleDeclaration } from \"didi\";\nimport { CmBaseViewer } from \"./CmBaseViewer.js\";\nimport { cmModelModule } from \"./model/index.js\";\nimport { cmDrawModule } from \"./draw/index.js\";\nimport { ioModule } from \"./io/index.js\";\n\n/** Read-only renderer: draws a Context Maps diagram with no interaction. */\nexport class Viewer extends CmBaseViewer {\n protected _getModules(): ModuleDeclaration[] {\n return [cmModelModule, cmDrawModule, ioModule];\n }\n}\n","/**\n * A fast hover tooltip for the map's own data (the native SVG <title> waits about 1.5s): a\n * context's description and team, a relationship's pattern, label, description and technology.\n * What the notation itself means lives in the legend. One element inside the canvas container, so\n * it never covers the chrome around the canvas, and it follows the pointer while it rests on an\n * element.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { RELATIONSHIP_PATTERN_SPECS } from \"@miragon/context-maps-schema-model\";\nimport type { RelationshipPatternSpec } from \"@miragon/context-maps-schema-model\";\nimport { isCmContext, isCmRelationship } from \"../model/di-types.js\";\n\ninterface HoverTip {\n title: string;\n body: string;\n}\n\n/** Gap between the pointer and the tooltip, in px. */\nconst POINTER_OFFSET = { x: 14, y: 18 };\n/** Distance the tooltip keeps from the container's right edge, in px. */\nconst EDGE_MARGIN = 12;\n\nexport function hoverTipFor(element: unknown): HoverTip | null {\n if (isCmContext(element)) {\n const parts: string[] = [];\n if (element.description) parts.push(element.description);\n if (element.team) parts.push(`Team: ${element.team}`);\n if (parts.length === 0) return null;\n return { title: element.cmLabel ?? \"Bounded context\", body: parts.join(\" · \") };\n }\n if (isCmRelationship(element)) {\n const spec = RELATIONSHIP_PATTERN_SPECS[element.pattern] as RelationshipPatternSpec | undefined;\n const pattern = spec?.label ?? element.pattern;\n const parts: string[] = [];\n if (element.description) parts.push(element.description);\n if (element.implementationTechnology) parts.push(element.implementationTechnology);\n const title = element.cmLabel ? `${pattern} · ${element.cmLabel}` : pattern;\n return { title, body: parts.join(\" · \") };\n }\n return null;\n}\n\nexport default class CmHoverTooltip {\n static $inject = [\"eventBus\", \"canvas\"];\n\n private readonly tooltip: HTMLElement;\n private readonly title: HTMLElement;\n private readonly body: HTMLElement;\n\n constructor(eventBus: EventBus, canvas: Canvas) {\n const container = canvas.getContainer();\n this.tooltip = document.createElement(\"div\");\n this.tooltip.className = \"cm-hover-tooltip\";\n this.tooltip.setAttribute(\"role\", \"tooltip\");\n this.tooltip.hidden = true;\n this.title = document.createElement(\"strong\");\n this.body = document.createElement(\"span\");\n this.tooltip.append(this.title, this.body);\n container.append(this.tooltip);\n\n const place = (event: MouseEvent): void => {\n const bounds = container.getBoundingClientRect();\n const width = this.tooltip.offsetWidth;\n const left = Math.min(\n event.clientX - bounds.left + POINTER_OFFSET.x,\n bounds.width - width - EDGE_MARGIN,\n );\n this.tooltip.style.left = `${Math.max(EDGE_MARGIN, left)}px`;\n this.tooltip.style.top = `${event.clientY - bounds.top + POINTER_OFFSET.y}px`;\n };\n const hide = (): void => {\n this.tooltip.hidden = true;\n container.removeEventListener(\"mousemove\", place);\n };\n\n eventBus.on(\"element.hover\", (event: { element?: unknown; originalEvent?: MouseEvent }) => {\n const tip = hoverTipFor(event.element);\n if (!tip) {\n hide();\n return;\n }\n this.title.textContent = tip.title;\n this.body.textContent = tip.body;\n this.body.hidden = tip.body === \"\";\n this.tooltip.hidden = false;\n if (event.originalEvent) place(event.originalEvent);\n container.addEventListener(\"mousemove\", place);\n });\n eventBus.on([\"element.out\", \"drag.init\", \"canvas.viewbox.changing\", \"diagram.clear\"], hide);\n eventBus.on(\"diagram.destroy\", () => {\n hide();\n this.tooltip.remove();\n });\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmHoverTooltip from \"./CmHoverTooltip.js\";\n\n/** A fast tooltip with an element's own data (description, team, technology) on hover. */\nexport const cmHoverTooltipModule: ModuleDeclaration = {\n __init__: [\"cmHoverTooltip\"],\n cmHoverTooltip: [\"type\", CmHoverTooltip],\n};\n\nexport { default as CmHoverTooltip, hoverTipFor } from \"./CmHoverTooltip.js\";\n","import type { ModuleDeclaration } from \"didi\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport ZoomScrollModule from \"diagram-js/lib/navigation/zoomscroll\";\nimport MoveCanvasModule from \"diagram-js/lib/navigation/movecanvas\";\nimport { Viewer } from \"./Viewer.js\";\nimport { cmHoverTooltipModule } from \"./hover-tooltip/index.js\";\n\n/** Read-only + navigation: zoom (scroll), pan (drag), selection, the elements' own data on hover. */\nexport class NavigatedViewer extends Viewer {\n protected override _getModules(): ModuleDeclaration[] {\n return [\n ...super._getModules(),\n SelectionModule,\n ZoomScrollModule,\n MoveCanvasModule,\n cmHoverTooltipModule,\n ];\n }\n}\n","/**\n * Generic, undo-able command that sets arbitrary Context Maps properties\n * (cmLabel, teamType, mode, fill, stroke, description). Returns the changed\n * element so the CommandStack fires `elements.changed` → re-render.\n */\n\nimport type { ElementLike } from \"diagram-js/lib/core/Types\";\nimport type CommandHandler from \"diagram-js/lib/command/CommandHandler\";\n\nexport interface UpdatePropertiesContext {\n element: ElementLike & Record<string, unknown>;\n properties: Record<string, unknown>;\n /** set internally by the handler (for revert). */\n oldProperties?: Record<string, unknown>;\n}\n\nfunction setOrDelete(obj: Record<string, unknown>, key: string, value: unknown): void {\n if (value === undefined) delete obj[key];\n else obj[key] = value;\n}\n\nexport default class UpdatePropertiesHandler implements CommandHandler {\n execute(context: UpdatePropertiesContext): ElementLike[] {\n const { element, properties } = context;\n const target = element as unknown as Record<string, unknown>;\n const old: Record<string, unknown> = {};\n for (const key of Object.keys(properties)) {\n old[key] = target[key];\n setOrDelete(target, key, properties[key]);\n }\n context.oldProperties = old;\n return [element];\n }\n\n revert(context: UpdatePropertiesContext): ElementLike[] {\n const { element, oldProperties } = context;\n const target = element as unknown as Record<string, unknown>;\n if (oldProperties) {\n for (const key of Object.keys(oldProperties)) setOrDelete(target, key, oldProperties[key]);\n }\n return [element];\n }\n}\n","/**\n * Swaps a relationship's two ends: source ⇄ target (and reverses the waypoints).\n * This flips the direction — what was upstream/supplier becomes downstream/\n * customer and vice versa. The integration roles stay bound to their SIDE, not\n * to a context: upstreamRoles (OHS/PL) always describe whichever context is\n * upstream after the swap, downstreamRoles (ACL/CF) the downstream one — the\n * role types are side-specific, so they cannot travel with a context.\n * Undoable (revert simply swaps back).\n */\n\nimport type CommandHandler from \"diagram-js/lib/command/CommandHandler\";\nimport type { Connection, Element } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\n\nexport interface SwapEndsContext {\n connection: Connection & { source: Element; target: Element; waypoints: Point[] };\n}\n\nfunction swap(connection: SwapEndsContext[\"connection\"]): Element[] {\n const oldSource = connection.source;\n connection.source = connection.target;\n connection.target = oldSource;\n if (Array.isArray(connection.waypoints)) {\n connection.waypoints = [...connection.waypoints].reverse();\n }\n return [connection];\n}\n\nexport default class SwapEndsHandler implements CommandHandler {\n execute(context: SwapEndsContext): Element[] {\n return swap(context.connection);\n }\n\n revert(context: SwapEndsContext): Element[] {\n return swap(context.connection);\n }\n}\n","/**\n * Renames the diagram: the title lives on the root's business object, not on an element, so it\n * gets a command of its own. Through the command stack the rename is undoable and reaches every\n * `commandStack.changed` listener (a host that saves on it, the collaborative-modeler contract's\n * content events) like any element edit.\n */\n\nimport type CommandHandler from \"diagram-js/lib/command/CommandHandler\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type { Element, Root } from \"diagram-js/lib/model/Types\";\nimport { ROOT_ID, type RootBusinessObject } from \"../../io/types.js\";\n\nexport interface UpdateTitleContext {\n title: string;\n /** set by the handler (for revert). */\n oldTitle?: string;\n}\n\ntype DocumentRoot = Root & { businessObject?: RootBusinessObject };\n\nexport default class UpdateTitleHandler implements CommandHandler {\n static $inject = [\"elementRegistry\"];\n\n constructor(private readonly elementRegistry: ElementRegistry) {}\n\n private root(): DocumentRoot {\n const root = this.elementRegistry.get(ROOT_ID) as DocumentRoot | undefined;\n if (!root?.businessObject) throw new Error(\"No context map is loaded to rename.\");\n return root;\n }\n\n execute(context: UpdateTitleContext): Element[] {\n const root = this.root();\n const current = root.businessObject!;\n context.oldTitle = current.title;\n root.businessObject = { ...current, title: context.title };\n return [];\n }\n\n revert(context: UpdateTitleContext): Element[] {\n const root = this.root();\n root.businessObject = { ...root.businessObject!, title: context.oldTitle ?? \"\" };\n return [];\n }\n}\n","/**\n * High-level Context Maps mutations that go through the command stack\n * (undo/redo). Registers the generic property command handler.\n */\n\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type GraphicsFactory from \"diagram-js/lib/core/GraphicsFactory\";\nimport {\n isSymmetricPattern,\n type DownstreamRole,\n type RelationshipPattern,\n type SubdomainType,\n type UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\nimport type { CmContext, CmElement, CmRelationship } from \"../model/di-types.js\";\nimport { isCmRelationship } from \"../model/di-types.js\";\nimport UpdatePropertiesHandler from \"./cmd/UpdatePropertiesHandler.js\";\nimport SwapEndsHandler, { type SwapEndsContext } from \"./cmd/SwapEndsHandler.js\";\nimport UpdateTitleHandler, { type UpdateTitleContext } from \"./cmd/UpdateTitleHandler.js\";\n\nconst UPDATE_PROPERTIES = \"element.updateProperties\";\nconst SWAP_ENDS = \"relationship.swapEnds\";\nconst UPDATE_TITLE = \"map.updateTitle\";\n\nexport default class CmModeling {\n static $inject = [\"commandStack\", \"elementRegistry\", \"graphicsFactory\"];\n\n constructor(\n private readonly commandStack: CommandStack,\n private readonly elementRegistry: ElementRegistry,\n private readonly graphicsFactory: GraphicsFactory,\n ) {\n commandStack.registerHandler(UPDATE_PROPERTIES, UpdatePropertiesHandler);\n commandStack.registerHandler(SWAP_ENDS, SwapEndsHandler);\n commandStack.registerHandler(UPDATE_TITLE, UpdateTitleHandler);\n }\n\n /** Rename the diagram (undoable). Throws while no document is loaded. */\n setTitle(title: string): void {\n this.commandStack.execute(UPDATE_TITLE, { title } as UpdateTitleContext);\n }\n\n /**\n * Force an immediate re-render of an element's graphics. diagram-js'\n * ChangeSupport only redraws on `elements.changed` when `element.parent` is\n * set; this guarantees the visual reflects a property/swap change regardless\n * (a redundant redraw is harmless — the visual layer is cleared first).\n */\n private redraw(element: CmElement): void {\n const gfx = this.elementRegistry.getGraphics(element);\n if (!gfx) return;\n this.graphicsFactory.update(isCmRelationship(element) ? \"connection\" : \"shape\", element, gfx);\n }\n\n /** Swap the two ends of a relationship (reverse upstream/downstream). */\n swapEnds(relationship: CmRelationship): void {\n this.commandStack.execute(SWAP_ENDS, {\n connection: relationship,\n } as unknown as SwapEndsContext);\n this.redraw(relationship);\n }\n\n updateProperties(element: CmElement, properties: Record<string, unknown>): void {\n this.commandStack.execute(UPDATE_PROPERTIES, { element, properties });\n this.redraw(element);\n }\n\n /** Rename / relabel any element. */\n updateLabel(element: CmElement, label: string): void {\n this.updateProperties(element, { cmLabel: label || undefined });\n }\n\n // --- context ------------------------------------------------------------\n\n setSubdomainType(context: CmContext, subdomainType: SubdomainType | undefined): void {\n this.updateProperties(context, { subdomainType });\n }\n\n setTeam(context: CmContext, team: string | undefined): void {\n this.updateProperties(context, { team: team || undefined });\n }\n\n setDescription(element: CmElement, description: string | undefined): void {\n this.updateProperties(element, { description: description || undefined });\n }\n\n /** Set or clear per-element colour overrides (`undefined` reverts to default). */\n setColors(context: CmContext, fill: string | undefined, stroke: string | undefined): void {\n this.updateProperties(context, { fill, stroke });\n }\n\n // --- relationship -------------------------------------------------------\n\n /**\n * Switch the pattern and sanitise the roles so the result is always valid:\n * symmetric patterns carry no roles; customer-supplier drops the inapplicable\n * OHS (upstream) and CF (downstream).\n */\n setPattern(relationship: CmRelationship, pattern: RelationshipPattern): void {\n const props: Record<string, unknown> = { pattern };\n if (isSymmetricPattern(pattern)) {\n props.upstreamRoles = undefined;\n props.downstreamRoles = undefined;\n } else if (pattern === \"customer-supplier\") {\n const up = (relationship.upstreamRoles ?? []).filter((r) => r !== \"OHS\");\n const down = (relationship.downstreamRoles ?? []).filter((r) => r !== \"CF\");\n props.upstreamRoles = up.length ? up : undefined;\n props.downstreamRoles = down.length ? down : undefined;\n }\n this.updateProperties(relationship, props);\n }\n\n setUpstreamRoles(relationship: CmRelationship, roles: UpstreamRole[]): void {\n this.updateProperties(relationship, { upstreamRoles: roles.length ? roles : undefined });\n }\n\n setDownstreamRoles(relationship: CmRelationship, roles: DownstreamRole[]): void {\n this.updateProperties(relationship, { downstreamRoles: roles.length ? roles : undefined });\n }\n\n setImplementationTechnology(relationship: CmRelationship, tech: string | undefined): void {\n this.updateProperties(relationship, { implementationTechnology: tech || undefined });\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmModeling from \"./CmModeling.js\";\nimport CmLayouter from \"../model/CmLayouter.js\";\n\n/**\n * High-level Context Maps mutations + command handlers. Also (re)binds the\n * cropping `layouter`: diagram-js' ModelingModule binds a default BaseLayouter,\n * and this module loads after it, so binding here wins and relationship lines\n * dock to the context box borders.\n */\nexport const cmModelingModule: ModuleDeclaration = {\n __init__: [\"cmModeling\"],\n cmModeling: [\"type\", CmModeling],\n layouter: [\"type\", CmLayouter],\n};\n\nexport { default as CmModeling } from \"./CmModeling.js\";\n","/**\n * Allowed editing operations.\n *\n * - Contexts are free, placed, fixed-size shapes that overlap but never nest.\n * - Relationships are connections between two distinct contexts (no\n * self-loops), at most ONE per pair of contexts — a second, overlapping\n * line between the same two contexts is impossible to tell apart visually.\n */\n\nimport RuleProvider from \"diagram-js/lib/features/rules/RuleProvider\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { isCmContext } from \"../model/di-types.js\";\n\ninterface MoveContext {\n target?: { parent?: unknown } | null;\n}\n\ninterface ConnectContext {\n source?: unknown;\n target?: unknown;\n}\n\ninterface ReconnectContext {\n source?: unknown;\n target?: unknown;\n connection?: unknown;\n}\n\nexport default class CmRules extends RuleProvider {\n static override $inject = [\"eventBus\"];\n\n constructor(eventBus: EventBus) {\n super(eventBus);\n }\n\n override init(): void {\n // Don't re-parent a dragged shape into whatever it is dropped on: contexts\n // are independent and only overlap. Dropping on the root (no parent) is fine.\n this.addRule([\"shape.move\", \"elements.move\"], (context: MoveContext) =>\n context.target && context.target.parent ? null : true,\n );\n this.addRule(\"shape.create\", () => true);\n // Boxes have a fixed size — the uniform card look is part of the notation.\n this.addRule(\"shape.resize\", () => false);\n\n // A relationship connects two distinct contexts. Returning an attributes\n // object (not just `true`) makes diagram-js stamp the new connection as a\n // relationship with a default pattern, so it renders correctly.\n this.addRule(\"connection.create\", (context: ConnectContext) =>\n canConnect(context.source, context.target),\n );\n this.addRule(\"connection.reconnect\", (context: ReconnectContext) =>\n canConnect(context.source, context.target, context.connection) ? true : false,\n );\n this.addRule(\"connection.updateWaypoints\", () => true);\n }\n}\n\ninterface ConnectedElement {\n incoming?: Array<{ source?: unknown; target?: unknown }>;\n outgoing?: Array<{ source?: unknown; target?: unknown }>;\n}\n\n/** True if any relationship (other than `ignore`) already links the two contexts, either way. */\nfunction alreadyConnected(source: unknown, target: unknown, ignore?: unknown): boolean {\n const { incoming = [], outgoing = [] } = source as ConnectedElement;\n return [...incoming, ...outgoing].some(\n (connection) =>\n connection !== ignore &&\n ((connection.source === source && connection.target === target) ||\n (connection.source === target && connection.target === source)),\n );\n}\n\n/** Returns default relationship attributes if the connection is allowed, else false. */\nfunction canConnect(\n source: unknown,\n target: unknown,\n ignore?: unknown,\n): false | { cmKind: \"relationship\"; pattern: \"upstream-downstream\" } {\n if (!isCmContext(source) || !isCmContext(target)) return false;\n if (source === target) return false;\n if (alreadyConnected(source, target, ignore)) return false;\n return { cmKind: \"relationship\", pattern: \"upstream-downstream\" };\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport RulesModule from \"diagram-js/lib/features/rules\";\nimport CmRules from \"./CmRules.js\";\n\n/** Context Maps editing rules (connect, move, create — no resize). */\nexport const cmRulesModule: ModuleDeclaration = {\n __depends__: [RulesModule],\n __init__: [\"cmRules\"],\n cmRules: [\"type\", CmRules],\n};\n\nexport { default as CmRules } from \"./CmRules.js\";\n","/**\n * Two model-keeping behaviours:\n *\n * 1. Flat model — diagram-js parents a newly created shape to whatever element\n * it is dropped on, which would nest overlapping contexts and glue them\n * together. Force every created shape onto the diagram root instead.\n * (Re-parenting on *move* is prevented separately in CmRules.)\n *\n * 2. Connection relayout — when a context moves or resizes, re-crop the\n * waypoints of its attached relationships to the new box borders, so lines\n * stay docked to the edges.\n */\n\nimport CommandInterceptor from \"diagram-js/lib/command/CommandInterceptor\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type { Connection, Shape } from \"diagram-js/lib/model/Types\";\n\ninterface MovedContext {\n shape?: Shape;\n shapes?: Shape[];\n}\n\nexport default class CmFlatModelBehavior extends CommandInterceptor {\n static override $inject = [\"eventBus\", \"canvas\", \"modeling\"];\n\n constructor(eventBus: EventBus, canvas: Canvas, modeling: Modeling) {\n super(eventBus);\n\n this.preExecute(\n [\"shape.create\", \"elements.create\"],\n (context: { parent?: unknown }) => {\n context.parent = canvas.getRootElement();\n },\n true,\n );\n\n // During a multi-element move, diagram-js' MoveHelper translates every\n // fully-enclosed connection (both ends moved) by the drag delta AFTER the\n // per-shape child commands ran. Re-cropping those connections here as well\n // would apply the delta twice — and a straight line whose two ends move by\n // the same delta is already correct after the plain translation. Track the\n // moved set so relayout only touches half-attached connections.\n let multiMove: Set<string> | null = null;\n this.preExecute(\n \"elements.move\",\n (context: MovedContext) => {\n multiMove = new Set((context.shapes ?? []).map((shape) => shape.id));\n },\n true,\n );\n this.postExecuted(\n \"elements.move\",\n () => {\n multiMove = null;\n },\n true,\n );\n\n const relayout = (context: MovedContext): void => {\n const shapes = context.shapes ?? (context.shape ? [context.shape] : []);\n const seen = new Set<string>();\n for (const shape of shapes) {\n const attached: Connection[] = [\n ...((shape.incoming as Connection[]) ?? []),\n ...((shape.outgoing as Connection[]) ?? []),\n ];\n for (const connection of attached) {\n if (seen.has(connection.id)) continue;\n seen.add(connection.id);\n const sourceId = connection.source?.id;\n const targetId = connection.target?.id;\n if (sourceId && targetId && multiMove?.has(sourceId) && multiMove.has(targetId)) {\n continue;\n }\n modeling.layoutConnection(connection);\n }\n }\n };\n\n this.postExecute([\"shape.move\", \"shape.resize\"], relayout, true);\n }\n}\n","/**\n * Marks the canvas container with `cm-dragging` while any drag operation\n * (connect, move, create) is in flight. The CSS keyed on it makes the HTML\n * overlays (connect handles, validation markers, tooltips) click-transparent,\n * so releasing a drag on top of one still reaches the element underneath —\n * otherwise a connect drag dropped on a warning triangle would silently die.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\n\nconst DRAGGING_CLS = \"cm-dragging\";\n\nexport default class CmDragBehavior {\n static $inject = [\"eventBus\", \"canvas\"];\n\n constructor(eventBus: EventBus, canvas: Canvas) {\n eventBus.on(\"drag.init\", () => {\n canvas.getContainer().classList.add(DRAGGING_CLS);\n });\n eventBus.on(\"drag.cleanup\", () => {\n canvas.getContainer().classList.remove(DRAGGING_CLS);\n });\n }\n}\n","/**\n * Clicking an already-selected element KEEPS it selected. diagram-js' stock\n * SelectionBehavior toggles instead (click on selected = deselect), which\n * reads as \"the editor lost my selection\" — especially since the connect\n * handles and the inspector vanish with it. Deselecting is done by clicking\n * the empty canvas. Ctrl/Cmd-click still toggles for multi-select workflows.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport { hasPrimaryModifier } from \"diagram-js/lib/util/Mouse\";\nimport { isCmElement } from \"../model/di-types.js\";\n\n/** Above SelectionBehavior's element.click listener (default priority 500). */\nconst BEFORE_SELECTION_BEHAVIOR = 2000;\n\nexport default class CmClickSelectionBehavior {\n static $inject = [\"eventBus\", \"selection\"];\n\n constructor(eventBus: EventBus, selection: Selection) {\n eventBus.on(\n \"element.click\",\n BEFORE_SELECTION_BEHAVIOR,\n (event: { element?: unknown } & Parameters<typeof hasPrimaryModifier>[0]) => {\n const element = event.element;\n if (!isCmElement(element)) return;\n if (hasPrimaryModifier(event)) return;\n if (selection.isSelected(element)) return false;\n },\n );\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmFlatModelBehavior from \"./CmFlatModelBehavior.js\";\nimport CmDragBehavior from \"./CmDragBehavior.js\";\nimport CmClickSelectionBehavior from \"./CmClickSelectionBehavior.js\";\n\n/** Editing behaviors: keep the model flat (no nesting), drag-state CSS marker. */\nexport const cmBehaviorsModule: ModuleDeclaration = {\n __init__: [\"cmFlatModelBehavior\", \"cmDragBehavior\", \"cmClickSelectionBehavior\"],\n cmFlatModelBehavior: [\"type\", CmFlatModelBehavior],\n cmDragBehavior: [\"type\", CmDragBehavior],\n cmClickSelectionBehavior: [\"type\", CmClickSelectionBehavior],\n};\n\nexport { default as CmFlatModelBehavior } from \"./CmFlatModelBehavior.js\";\nexport { default as CmDragBehavior } from \"./CmDragBehavior.js\";\nexport { default as CmClickSelectionBehavior } from \"./CmClickSelectionBehavior.js\";\n","import RuleProvider from \"diagram-js/lib/features/rules/RuleProvider\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\n\n/** Fired with `{ readOnly }` whenever the lock changes. */\nexport const READ_ONLY_CHANGED_EVENT = \"cm.readOnly.changed\";\n\n/** Above every edit rule of the renderer and diagram-js, so the lock wins. */\nconst LOCK_PRIORITY = 5000;\n\nconst EDIT_RULES = [\n \"elements.move\",\n \"shape.move\",\n \"shape.resize\",\n \"shape.create\",\n \"elements.create\",\n \"shape.append\",\n \"connection.start\",\n \"connection.create\",\n \"connection.reconnect\",\n \"connection.updateWaypoints\",\n \"elements.delete\",\n];\n\n/**\n * Locks every edit on the canvas while the document behind it cannot be saved from the canvas\n * (an invalid file in an IDE host, guide §13.5): no move, create, connect or delete through the\n * rules, and the keyboard, context pad, connect handles and label editor consult `isReadOnly()`.\n * Selection, zoom, pan and export stay.\n */\nexport default class CmReadOnly extends RuleProvider {\n static override $inject = [\"eventBus\"];\n\n private readOnly = false;\n\n constructor(private readonly bus: EventBus) {\n super(bus);\n }\n\n override init(): void {\n this.addRule(EDIT_RULES, LOCK_PRIORITY, () => (this.readOnly ? false : undefined));\n }\n\n isReadOnly(): boolean {\n return this.readOnly;\n }\n\n setReadOnly(readOnly: boolean): void {\n if (this.readOnly === readOnly) return;\n this.readOnly = readOnly;\n this.bus.fire(READ_ONLY_CHANGED_EVENT, { readOnly });\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport RulesModule from \"diagram-js/lib/features/rules\";\nimport CmReadOnly from \"./CmReadOnly.js\";\n\n/** The canvas edit lock (an invalid file in an IDE host). */\nexport const cmReadOnlyModule: ModuleDeclaration = {\n __depends__: [RulesModule],\n __init__: [\"cmReadOnly\"],\n cmReadOnly: [\"type\", CmReadOnly],\n};\n\nexport { default as CmReadOnly, READ_ONLY_CHANGED_EVENT } from \"./CmReadOnly.js\";\n","/**\n * In-place editing via diagram-js-direct-editing (the bpmn.io mechanism):\n * double-click a context or relationship — or use the context pad's rename\n * action — and the name becomes editable directly inside the element, at the\n * spot and size it is rendered (Shift+Enter inserts a line break the renderer\n * preserves). The owning-team caption edits the same way: the pad's team\n * action (or a double-click on the caption) opens the box right over it.\n * Enter/blur commits through `cmModeling` (undoable), Escape cancels, and\n * starting a drag completes the edit. A pan or zoom keeps the box open and\n * moves it with its element. The edited text is hidden behind an element\n * marker while the box is open so nothing doubles up. Neither an import nor\n * a view change commits an open edit: an import takes it down before and\n * reopens it on the element with the same id afterwards, with the text typed\n * so far.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { Element, ShapeLike } from \"diagram-js/lib/model/Types\";\nimport { CONTEXT_NAME_TOP, CONTEXT_TEAM_RESERVE, FONT } from \"../draw/styles.js\";\nimport { isCmContext, isCmElement, type CmContext, type CmElement } from \"../model/di-types.js\";\nimport type CmModeling from \"../modeling/CmModeling.js\";\nimport { READ_ONLY_CHANGED_EVENT, type CmReadOnly } from \"../read-only/index.js\";\n\ntype EditMode = \"name\" | \"team\";\n\n/** Hide the rendered text being edited: `.cm-name` resp. `.cm-team` (CSS). */\nconst MARKERS: Record<EditMode, string> = {\n name: \"cm-direct-editing\",\n team: \"cm-direct-editing-team\",\n};\n\n/** Mirrors the renderer: label wrap inset (10px each side). */\nconst LABEL_INSET_X = 10;\n/** The team caption band at the bottom of the box (renderer: centre at h-12). */\nconst TEAM_BAND_HEIGHT = 20;\nconst TEAM_BAND_BOTTOM_GAP = 2;\n\n// The service surface of the (untyped, plain-JS) diagram-js-direct-editing\n// package — typed locally so nothing untyped leaks into the published d.ts.\ninterface DirectEditingContext {\n bounds: { x: number; y: number; width: number; height: number };\n text: string;\n style?: Record<string, string | number>;\n options?: { centerVertically?: boolean; autoResize?: boolean; resizable?: boolean };\n}\n\ninterface DirectEditingService {\n registerProvider(provider: {\n activate(element: Element): DirectEditingContext | undefined;\n update(element: Element, newText: string): void;\n }): void;\n activate(element: Element): boolean;\n isActive(element?: Element): boolean;\n cancel(): void;\n complete(): void;\n getValue(): string;\n /** The text box's parent element of the edit open right now. */\n $textbox?: HTMLElement;\n}\n\n/** An open edit taken down for an import: its element, what it edits, the text typed so far. */\ninterface SuspendedEdit {\n elementId: string;\n mode: EditMode;\n text: string;\n}\n\nexport default class CmLabelEditing {\n static $inject = [\n \"eventBus\",\n \"canvas\",\n \"directEditing\",\n \"cmModeling\",\n \"elementRegistry\",\n \"cmReadOnly\",\n ];\n\n /** Which property the CURRENT activation edits (set right before activate). */\n private mode: EditMode = \"name\";\n private activeMarker?: { element: Element; marker: string };\n private suspended?: SuspendedEdit;\n private resumeTimer?: ReturnType<typeof setTimeout>;\n\n constructor(\n eventBus: EventBus,\n private readonly canvas: Canvas,\n private readonly directEditing: DirectEditingService,\n private readonly modeling: CmModeling,\n private readonly elementRegistry: ElementRegistry,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n // Registered as a plain object: the provider contract claims the method\n // name `activate` for context creation, while this service keeps\n // `activate(element)` as the public \"start editing\" API.\n directEditing.registerProvider({\n activate: (element) => this.activationContext(element),\n update: (element, newText) => this.commit(element, newText),\n });\n\n eventBus.on(\n \"element.dblclick\",\n (event: { element?: unknown; originalEvent?: { clientY?: number } }) => {\n const element = event.element;\n if (!isCmElement(element)) return;\n // A double-click on the team caption band edits the team, not the name.\n this.mode =\n isCmContext(element) && element.team && this.isInTeamBand(element, event.originalEvent)\n ? \"team\"\n : \"name\";\n directEditing.activate(element as Element);\n },\n );\n\n // Only the user's own gestures commit (Enter, blur, a drag): diagram-js cannot tell a wheel\n // zoom from a host's setViewState or fit, and a commit there would write half-typed text into\n // the document every peer shares.\n eventBus.on(\"drag.init\", () => directEditing.complete());\n eventBus.on(\"canvas.viewbox.changed\", () => this.placeOpenEdit());\n\n eventBus.on(\"directEditing.activate\", (event: { active?: { element?: Element } }) => {\n const element = event.active?.element;\n if (!element) return;\n const marker = MARKERS[this.mode];\n canvas.addMarker(element as unknown as ShapeLike, marker);\n this.activeMarker = { element, marker };\n });\n eventBus.on([\"directEditing.complete\", \"directEditing.cancel\"], () => {\n const active = this.activeMarker;\n if (active) canvas.removeMarker(active.element as unknown as ShapeLike, active.marker);\n this.activeMarker = undefined;\n });\n eventBus.on(\"diagram.destroy\", () => {\n clearTimeout(this.resumeTimer);\n this.suspended = undefined;\n });\n // A read-only canvas has no label editor (guide §13.5), also not on a double-click.\n eventBus.on(\"directEditing.activate.allowed\", 2000, () =>\n this.readOnly.isReadOnly() ? false : undefined,\n );\n eventBus.on(READ_ONLY_CHANGED_EVENT, (event: { readOnly?: boolean }) => {\n if (event.readOnly) directEditing.cancel();\n });\n }\n\n /**\n * Takes an open edit down WITHOUT committing it, for an import that replaces the elements: a\n * later commit (Enter, blur) would land on a removed shape and be wiped with the history.\n * `resumeAfterImport` brings the editor back with the typed text.\n */\n suspend(): void {\n clearTimeout(this.resumeTimer);\n const element = this.activeMarker?.element;\n if (!this.directEditing.isActive() || !element) return;\n this.suspended = {\n elementId: element.id,\n mode: this.mode,\n text: this.directEditing.getValue(),\n };\n this.directEditing.cancel();\n }\n\n /**\n * Reopens a suspended edit on the element with the same id, if the imported document still has\n * it. Deferred to the next task, after the host has restored its viewbox and selection around the\n * import, so the editor opens where the element ends up.\n */\n resumeAfterImport(): void {\n clearTimeout(this.resumeTimer);\n if (!this.suspended) return;\n this.resumeTimer = setTimeout(() => {\n const edit = this.suspended;\n this.suspended = undefined;\n if (edit && !this.directEditing.isActive()) this.resume(edit);\n }, 0);\n }\n\n /** The edit open right now (its element and the uncommitted text), for hosts and tests. */\n openEdit(): { elementId: string; text: string } | undefined {\n const element = this.activeMarker?.element;\n if (!this.directEditing.isActive() || !element) return undefined;\n return { elementId: element.id, text: this.directEditing.getValue() };\n }\n\n /** The open box follows its element through a pan or zoom: same text, caret and focus. */\n private placeOpenEdit(): void {\n const element = this.activeMarker?.element;\n const textbox = this.directEditing.$textbox;\n if (!this.directEditing.isActive() || !element || !textbox) return;\n const context = this.activationContext(element);\n if (!context) return;\n const { x, y, width, height } = context.bounds;\n Object.assign(textbox.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${width}px`,\n height: `${height}px`,\n });\n const content = textbox.querySelector<HTMLElement>(\"[contenteditable]\");\n const fontSize = context.style?.fontSize;\n if (content && fontSize !== undefined) content.style.fontSize = String(fontSize);\n }\n\n private resume(edit: SuspendedEdit): void {\n const element = this.elementRegistry.get(edit.elementId);\n if (!isCmElement(element)) return;\n if (edit.mode === \"team\" && !isCmContext(element)) return;\n this.mode = edit.mode;\n if (!this.directEditing.activate(element as Element)) return;\n const content = this.directEditing.$textbox?.querySelector<HTMLElement>(\"[contenteditable]\");\n if (!content) return;\n content.innerText = edit.text;\n placeCaretAtEnd(content);\n }\n\n /** Start in-place editing of the element's name (context pad, hosts). */\n activate(element: CmElement): void {\n this.mode = \"name\";\n this.directEditing.activate(element as Element);\n }\n\n /** Start in-place editing of the owning-team caption at the box bottom. */\n activateTeam(context: CmContext): void {\n this.mode = \"team\";\n this.directEditing.activate(context as unknown as Element);\n }\n\n cancel(): void {\n this.directEditing.cancel();\n }\n\n private isInTeamBand(context: CmContext, originalEvent?: { clientY?: number }): boolean {\n if (typeof originalEvent?.clientY !== \"number\") return false;\n const zoom = this.canvas.zoom();\n const bbox = this.canvas.getAbsoluteBBox(context as unknown as ShapeLike);\n const containerTop = this.canvas.getContainer().getBoundingClientRect().top;\n const y = originalEvent.clientY - containerTop;\n return y >= bbox.y + bbox.height - (TEAM_BAND_HEIGHT + TEAM_BAND_BOTTOM_GAP) * zoom;\n }\n\n private activationContext(element: Element): DirectEditingContext | undefined {\n if (!isCmElement(element)) return undefined;\n if (this.mode === \"team\" && !isCmContext(element)) this.mode = \"name\";\n const zoom = this.canvas.zoom();\n const bbox = this.canvas.getAbsoluteBBox(element as unknown as ShapeLike);\n\n if (this.mode === \"team\") {\n const context = element as CmContext;\n // Right over the caption at the box bottom, in the caption's type size.\n return {\n bounds: {\n x: bbox.x + LABEL_INSET_X * zoom,\n y: bbox.y + bbox.height - (TEAM_BAND_HEIGHT + TEAM_BAND_BOTTOM_GAP) * zoom,\n width: bbox.width - 2 * LABEL_INSET_X * zoom,\n height: TEAM_BAND_HEIGHT * zoom,\n },\n text: context.team ?? \"\",\n style: {\n fontFamily: FONT.family,\n fontSize: `${FONT.small * zoom}px`,\n fontWeight: 400,\n lineHeight: 1.2,\n backgroundColor: \"transparent\",\n border: \"1px dashed var(--cd-ui-interaktion)\",\n textAlign: \"center\",\n },\n options: { centerVertically: true },\n };\n }\n\n const style: Record<string, string | number> = {\n fontFamily: FONT.family,\n fontSize: `${FONT.label * zoom}px`,\n fontWeight: 650,\n lineHeight: 1.2,\n // In-place illusion: the element's own fill stays visible, a dashed\n // accent frame signals the edit state (the rendered name is hidden).\n backgroundColor: \"transparent\",\n border: \"1px dashed var(--cd-ui-interaktion)\",\n textAlign: \"center\",\n };\n\n if (isCmContext(element)) {\n // The renderer anchors the name at the fixed top offset below the type\n // header — mirror that band exactly so the text does not jump. The 1px\n // dashed border (box-sizing: border-box) pushes the text down — offset\n // the box up by it.\n const reserve = element.team ? CONTEXT_TEAM_RESERVE * zoom : 0;\n return {\n bounds: {\n x: bbox.x + LABEL_INSET_X * zoom,\n y: bbox.y + CONTEXT_NAME_TOP * zoom - 1,\n width: bbox.width - 2 * LABEL_INSET_X * zoom,\n height: bbox.height - CONTEXT_NAME_TOP * zoom - reserve,\n },\n text: element.cmLabel ?? \"\",\n style,\n };\n }\n\n // Relationship: a compact box centred on the line (the canvas shows the\n // label only in the hover tooltip, so the box needs its own paper).\n const width = 160 * zoom;\n const height = 44 * zoom;\n return {\n bounds: {\n x: bbox.x + bbox.width / 2 - width / 2,\n y: bbox.y + bbox.height / 2 - height / 2,\n width,\n height,\n },\n text: (element as CmElement).cmLabel ?? \"\",\n style: { ...style, backgroundColor: \"var(--cd-ui-flaeche-hoch)\" },\n options: { centerVertically: true },\n };\n }\n\n private commit(element: Element, newText: string): void {\n const value = newText.trim();\n // DirectEditing also calls update() on pure bounds jitter — don't push a\n // no-op command (an empty undo step) when nothing changed.\n if (this.mode === \"team\") {\n const context = element as unknown as CmContext;\n if (value === (context.team ?? \"\")) return;\n this.modeling.setTeam(context, value || undefined);\n return;\n }\n if (value === ((element as CmElement).cmLabel ?? \"\")) return;\n this.modeling.updateLabel(element as CmElement, value);\n }\n}\n\nfunction placeCaretAtEnd(field: HTMLElement): void {\n const range = document.createRange();\n range.selectNodeContents(field);\n range.collapse(false);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport DirectEditingModule from \"diagram-js-direct-editing\";\nimport { cmModelingModule } from \"../modeling/index.js\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmLabelEditing from \"./CmLabelEditing.js\";\n\n/** In-place name editing (double-click / context pad), bpmn.io style. */\nexport const cmLabelEditingModule: ModuleDeclaration = {\n __depends__: [DirectEditingModule, cmModelingModule, cmReadOnlyModule],\n __init__: [\"cmLabelEditing\"],\n cmLabelEditing: [\"type\", CmLabelEditing],\n};\n\nexport { default as CmLabelEditing } from \"./CmLabelEditing.js\";\n","/**\n * Tiny inline-SVG glyphs for the palette / legend — the same shapes the canvas\n * draws (contexts coloured by subdomain, plus a relationship line). Returned as\n * HTML strings for diagram-js palette `html`.\n */\n\nimport {\n MARK_COLORS,\n MARK_TEXT_COLOR,\n RELATIONSHIP_PATTERN_SPECS,\n SUBDOMAIN_TYPE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type {\n DownstreamRole,\n RelationshipPattern,\n SubdomainType,\n SubdomainTypeSpec,\n UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\nimport { FONT, NEUTRAL_FILL, NEUTRAL_STROKE } from \"./styles.js\";\n\nfunction svg(inner: string, size = 24): string {\n return `<svg class=\"cm-palette-svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 26 26\" aria-hidden=\"true\">${inner}</svg>`;\n}\n\n// Kaiser subdomain glyphs (Material star / pan_tool), 24×24 viewBox.\nconst STAR = \"M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14l-5-4.87 7.1-1.01z\";\nconst HAND =\n \"M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z\";\n\n/** The subdomain glyph centred at (cx, cy) at `size` px: star / hand / dotted circle. */\nfunction subdomainGlyph(\n type: SubdomainType,\n cx: number,\n cy: number,\n size: number,\n color: string,\n): string {\n if (type === \"generic\") {\n return `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${size / 2 - 0.5}\" fill=\"none\" stroke=\"${color}\" stroke-width=\"1.4\" stroke-dasharray=\"1.8 1.8\"/>`;\n }\n const scale = size / 24;\n const rot = type === \"supporting\" ? ` rotate(90 12 12)` : \"\";\n const t = `translate(${cx - 12 * scale} ${cy - 12 * scale}) scale(${scale})${rot}`;\n return `<path d=\"${type === \"core\" ? STAR : HAND}\" fill=\"${color}\" transform=\"${t}\"/>`;\n}\n\n/** No (or unknown) type → the neutral box an unclassified context gets on the canvas. */\nexport function contextIconSvg(type?: SubdomainType): string {\n const s = type ? SUBDOMAIN_TYPE_SPECS[type] : undefined;\n if (!type || !s) {\n return svg(\n `<rect x=\"2\" y=\"4\" width=\"22\" height=\"18\" rx=\"3.5\" fill=\"${NEUTRAL_FILL}\" stroke=\"${NEUTRAL_STROKE}\" stroke-width=\"1.5\"/>`,\n );\n }\n return svg(\n `<rect x=\"2\" y=\"4\" width=\"22\" height=\"18\" rx=\"3.5\" fill=\"${s.fill}\" stroke=\"${s.stroke}\" stroke-width=\"1.5\"/>` +\n subdomainGlyph(type, 13, 13, 12, s.stroke),\n );\n}\n\n/** The bare subdomain glyph (star / hand / dotted circle) without the box — legend rows. */\nexport function subdomainIconSvg(type: SubdomainType, size = 18): string {\n const s = SUBDOMAIN_TYPE_SPECS[type] as SubdomainTypeSpec | undefined;\n const color = s?.stroke ?? NEUTRAL_STROKE;\n const inner =\n !s || type === \"generic\"\n ? `<circle cx=\"12\" cy=\"12\" r=\"9\" fill=\"none\" stroke=\"${color}\" stroke-width=\"1.8\" stroke-dasharray=\"2.4 2.4\"/>`\n : `<path d=\"${type === \"core\" ? STAR : HAND}\" fill=\"${color}\"/>`;\n return `<svg class=\"cm-palette-svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">${inner}</svg>`;\n}\n\n/** The same coloured role chip (OHS/PL/ACL/CF) the canvas draws at relationship ends. */\nexport function roleChipSvg(role: UpstreamRole | DownstreamRole): string {\n return svg(\n `<rect x=\"1\" y=\"6.5\" width=\"24\" height=\"13\" rx=\"3\" fill=\"${MARK_COLORS[role] ?? NEUTRAL_STROKE}\"/>` +\n `<text x=\"13\" y=\"16.4\" text-anchor=\"middle\" font-size=\"9.5\" font-weight=\"700\" fill=\"${MARK_TEXT_COLOR}\" font-family=\"${FONT.family}\">${role}</text>`,\n );\n}\n\nexport function relationshipIconSvg(\n pattern: RelationshipPattern = \"upstream-downstream\",\n size = 24,\n): string {\n const s =\n RELATIONSHIP_PATTERN_SPECS[pattern] ?? RELATIONSHIP_PATTERN_SPECS[\"upstream-downstream\"];\n const dash = s.dash ? ` stroke-dasharray=\"${s.dash}\"` : \"\";\n const w = Math.min(s.strokeWidth, 2.6);\n return svg(\n `<g stroke=\"${s.stroke}\" stroke-width=\"${w}\" stroke-linecap=\"round\">` +\n `<circle cx=\"5\" cy=\"13\" r=\"2.5\" fill=\"${s.stroke}\" stroke=\"none\"/>` +\n `<line x1=\"7\" y1=\"13\" x2=\"19\" y2=\"13\"${dash}/>` +\n `<circle cx=\"21\" cy=\"13\" r=\"2.5\" fill=\"${s.stroke}\" stroke=\"none\"/></g>`,\n size,\n );\n}\n","/**\n * The Lucide icons of the in-canvas chrome (context pad, connect handles, the lasso tool, the\n * shortcuts dialog), inlined so the renderer has no icon runtime dependency. Copied unchanged from\n * lucide-static 1.59.0 (`icon-nodes.json`; ISC, © Lucide Icons and Contributors; `arrow-right`,\n * `circle-x`, `trash`, `triangle-alert` and `x` derive from Feather, MIT, © Cole Bemis).\n */\nexport const LUCIDE = {\n \"arrow-left-right\":\n '<path d=\"M8 3 4 7l4 4\"/><path d=\"M4 7h16\"/><path d=\"m16 21 4-4-4-4\"/><path d=\"M20 17H4\"/>',\n \"arrow-right\": '<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>',\n \"circle-x\": '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m15 9-6 6\"/><path d=\"m9 9 6 6\"/>',\n pencil:\n '<path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\"/><path d=\"m15 5 4 4\"/>',\n \"sliders-horizontal\":\n '<path d=\"M10 5H3\"/><path d=\"M12 19H3\"/><path d=\"M14 3v4\"/><path d=\"M16 17v4\"/><path d=\"M21 12h-9\"/><path d=\"M21 19h-5\"/><path d=\"M21 5h-7\"/><path d=\"M8 10v4\"/><path d=\"M8 12H3\"/>',\n \"square-dashed-mouse-pointer\":\n '<path d=\"M12.034 12.681a.498.498 0 0 1 .647-.647l9 3.5a.5.5 0 0 1-.033.943l-3.444 1.068a1 1 0 0 0-.66.66l-1.067 3.443a.5.5 0 0 1-.943.033z\"/><path d=\"M5 3a2 2 0 0 0-2 2\"/><path d=\"M19 3a2 2 0 0 1 2 2\"/><path d=\"M5 21a2 2 0 0 1-2-2\"/><path d=\"M9 3h1\"/><path d=\"M9 21h2\"/><path d=\"M14 3h1\"/><path d=\"M3 9v1\"/><path d=\"M21 9v2\"/><path d=\"M3 14v1\"/>',\n \"square-plus\":\n '<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/><path d=\"M8 12h8\"/><path d=\"M12 8v8\"/>',\n \"text-align-start\": '<path d=\"M21 5H3\"/><path d=\"M15 12H3\"/><path d=\"M17 19H3\"/>',\n \"triangle-alert\":\n '<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>',\n trash:\n '<path d=\"M10 11v6\"/><path d=\"M14 11v6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\"/><path d=\"M3 6h18\"/><path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/>',\n users:\n '<path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\"/><path d=\"M16 3.128a4 4 0 0 1 0 7.744\"/><path d=\"M22 21v-2a4 4 0 0 0-3-3.87\"/><circle cx=\"9\" cy=\"7\" r=\"4\"/>',\n x: '<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>',\n} as const;\n\nexport type LucideIconName = keyof typeof LUCIDE;\n\nfunction lucideSvg(name: LucideIconName, size: number, strokeWidth: number): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"${strokeWidth}\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">${LUCIDE[name]}</svg>`;\n}\n\n/**\n * A chrome icon (guide §5.14, §11): 16px with stroke 2.5 on the 24 grid, so the stroke matches the\n * shell's chrome icons; `currentColor`, so the surrounding role decides the colour.\n */\nexport function chromeIcon(name: LucideIconName): string {\n return lucideSvg(name, 16, 2.5);\n}\n\n/** A palette tool icon (guide §5.5): 20px with stroke 2, the same 1.67px line as the chrome. */\nexport function toolIcon(name: LucideIconName): string {\n return lucideSvg(name, 20, 2);\n}\n","/**\n * The tool palette: the lasso tool first, then the three subdomain types of bounded context.\n * Relationships are drawn via the context pad's connect arrow, not from the palette. A pointer\n * drags or clicks a context onto the canvas; Enter or Space on an entry (a click without a\n * pointer, `detail === 0`, as the Miragon modeler shell sends it) places it in the centre of the\n * free rectangle instead, selected and with its name editor open (guide §5.5).\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type Create from \"diagram-js/lib/features/create/Create\";\nimport type LassoTool from \"diagram-js/lib/features/lasso-tool/LassoTool\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type Palette from \"diagram-js/lib/features/palette/Palette\";\nimport type {\n PaletteEntries,\n default as PaletteProvider,\n} from \"diagram-js/lib/features/palette/PaletteProvider\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type { Element, Shape } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { ALL_SUBDOMAIN_SPECS } from \"@miragon/context-maps-schema-model\";\nimport type { FreeRectInsets } from \"../CmBaseViewer.js\";\nimport { contextIconSvg } from \"../draw/palette-icons.js\";\nimport { toolIcon } from \"../draw/lucide.js\";\nimport type CmLabelEditing from \"../label-editing/CmLabelEditing.js\";\nimport type CmElementFactory from \"../model/CmElementFactory.js\";\nimport { isCmContext, type CmContext } from \"../model/di-types.js\";\nimport type { CmReadOnly } from \"../read-only/index.js\";\n\n/** diagram-js highlights tools only inside the group named exactly `tools`. */\nconst GROUP_TOOLS = \"tools\";\nconst GROUP_CONTEXTS = \"cm-1-contexts\";\n\n/** Guide §5.5: a keyboard-created element lands this far down-right of one already centred there. */\nconst KEYBOARD_CREATE_OFFSET = 24;\n\nexport interface CmPaletteConfig {\n freeRectInsets?: (() => FreeRectInsets) | undefined;\n /** The free rectangle's centre in diagram coordinates, when the host knows it better. */\n freeRectCenter?: (() => Point | undefined) | undefined;\n}\n\nfunction entryHtml(icon: string, draggable: boolean): string {\n const drag = draggable ? ` draggable=\"true\"` : \"\";\n return `<div class=\"entry cm-palette-entry\"${drag}>${icon}</div>`;\n}\n\n/** \"Supporting Subdomain\" → \"Supporting subdomain\": tooltips are in sentence case (guide §5.6). */\nfunction sentenceCase(label: string): string {\n return label.charAt(0) + label.slice(1).toLowerCase();\n}\n\n/** A click the shell synthesises for Enter or Space on a palette entry (no pointer, detail 0). */\nfunction isKeyboardClick(event: Event): boolean {\n return event.type === \"click\" && (event as MouseEvent).detail === 0;\n}\n\nexport default class CmPaletteProvider implements PaletteProvider {\n static $inject = [\n \"palette\",\n \"create\",\n \"lassoTool\",\n \"cmElementFactory\",\n \"canvas\",\n \"modeling\",\n \"selection\",\n \"elementRegistry\",\n \"cmLabelEditing\",\n \"cmReadOnly\",\n \"config.cmPalette\",\n ];\n\n constructor(\n palette: Palette,\n private readonly create: Create,\n private readonly lassoTool: LassoTool,\n private readonly factory: CmElementFactory,\n private readonly canvas: Canvas,\n private readonly modeling: Modeling,\n private readonly selection: Selection,\n private readonly elementRegistry: ElementRegistry,\n private readonly labelEditing: CmLabelEditing,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n private readonly config: CmPaletteConfig | undefined,\n ) {\n palette.registerProvider(this);\n }\n\n getPaletteEntries(): PaletteEntries {\n const entries: PaletteEntries = {};\n\n // Entry keys must end in `-tool` (\"lasso-tool\" ↔ tool \"lasso\") for diagram-js'\n // tool-manager highlight to find them; Esc cancels any tool.\n entries[\"lasso-tool\"] = {\n group: GROUP_TOOLS,\n title: \"Lasso\",\n html: entryHtml(toolIcon(\"square-dashed-mouse-pointer\"), false),\n action: {\n click: (event: Event) => this.lassoTool.activateSelection(event as MouseEvent),\n },\n };\n\n for (const spec of ALL_SUBDOMAIN_SPECS) {\n const start = (event: Event) => {\n const shape = this.factory.createNewContext(spec.type, spec.label);\n if (isKeyboardClick(event)) this.placeInFreeRect(shape);\n else this.create.start(event as MouseEvent, shape as unknown as Element);\n };\n entries[`context.${spec.type}`] = {\n group: GROUP_CONTEXTS,\n title: sentenceCase(spec.label),\n html: entryHtml(contextIconSvg(spec.type), true),\n action: { dragstart: start, click: start },\n };\n }\n\n return entries;\n }\n\n /**\n * Enter or Space on a creating entry (guide §5.5): a create that follows the pointer never ends\n * without one, so the context goes straight to the centre of the free rectangle (24px down-right\n * while that spot is taken), selected, with the canvas focused and its name editor open.\n */\n private placeInFreeRect(shape: CmContext): void {\n if (this.readOnly.isReadOnly()) return;\n const named = this.config?.freeRectCenter?.();\n const centre = named ? { x: named.x, y: named.y } : this.freeRectCentre();\n const taken = (point: Point): boolean =>\n this.elementRegistry\n .filter((element) => isCmContext(element))\n .some((element) => {\n const box = element as unknown as { x: number; y: number; width: number; height: number };\n return (\n Math.abs(box.x + box.width / 2 - point.x) < 1 &&\n Math.abs(box.y + box.height / 2 - point.y) < 1\n );\n });\n while (taken(centre)) {\n centre.x += KEYBOARD_CREATE_OFFSET;\n centre.y += KEYBOARD_CREATE_OFFSET;\n }\n const created = this.modeling.createShape(\n shape as unknown as Shape,\n centre,\n this.canvas.getRootElement() as Shape,\n );\n this.selection.select(created);\n this.canvas.focus();\n this.labelEditing.activate(created as unknown as CmContext);\n }\n\n /** The centre of the container minus the host's chrome, in diagram coordinates. */\n private freeRectCentre(): Point {\n const viewbox = this.canvas.viewbox();\n const insets = this.config?.freeRectInsets?.() ?? { top: 0, right: 0, bottom: 0, left: 0 };\n const freeWidth = Math.max(0, viewbox.outer.width - insets.left - insets.right);\n const freeHeight = Math.max(0, viewbox.outer.height - insets.top - insets.bottom);\n return {\n x: viewbox.x + (insets.left + freeWidth / 2) / viewbox.scale,\n y: viewbox.y + (insets.top + freeHeight / 2) / viewbox.scale,\n };\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport PaletteModule from \"diagram-js/lib/features/palette\";\nimport CreateModule from \"diagram-js/lib/features/create\";\nimport ConnectModule from \"diagram-js/lib/features/connect\";\nimport LassoToolModule from \"diagram-js/lib/features/lasso-tool\";\nimport ModelingModule from \"diagram-js/lib/features/modeling\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport { cmLabelEditingModule } from \"../label-editing/index.js\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmPaletteProvider from \"./CmPaletteProvider.js\";\n\n/** Tool palette: lasso tool + create contexts (drag, click or Enter/Space). */\nexport const cmPaletteModule: ModuleDeclaration = {\n __depends__: [\n PaletteModule,\n CreateModule,\n ConnectModule,\n LassoToolModule,\n ModelingModule,\n SelectionModule,\n cmLabelEditingModule,\n cmReadOnlyModule,\n ],\n __init__: [\"cmPaletteProvider\"],\n cmPaletteProvider: [\"type\", CmPaletteProvider],\n};\n\nexport { default as CmPaletteProvider } from \"./CmPaletteProvider.js\";\nexport type { CmPaletteConfig } from \"./CmPaletteProvider.js\";\n","/**\n * Per-element quick actions (diagram-js context pad + popup menus), so every\n * embedder of the Modeler gets element-level editing out of the box — not just\n * hosts that build their own inspector.\n *\n * - Bounded context: append a connected context, connect, subdomain type\n * (menu), owning team (in-place over its caption), rename (in-place direct\n * editing), description (anchored prompt), delete.\n * - Relationship: pattern (menu); integration roles (menu) and swap ends\n * while the pattern is asymmetric; rename, description, delete.\n * - Multi-selection: delete.\n *\n * Every mutation goes through `cmModeling`/`modeling`, so it is undoable and\n * lands in `exportDocument()`. Role/pattern constraints mirror the reference\n * inspector: upstream roles combine, downstream roles exclude each other, and\n * customer-supplier blocks OHS (upstream) and CF (downstream).\n */\n\nimport type ContextPad from \"diagram-js/lib/features/context-pad/ContextPad\";\nimport type {\n ContextPadEntries,\n ContextPadEntry,\n default as ContextPadProvider,\n} from \"diagram-js/lib/features/context-pad/ContextPadProvider\";\nimport type PopupMenu from \"diagram-js/lib/features/popup-menu/PopupMenu\";\nimport type { PopupMenuTarget } from \"diagram-js/lib/features/popup-menu/PopupMenu\";\nimport type { PopupMenuEntries } from \"diagram-js/lib/features/popup-menu/PopupMenuProvider\";\nimport type Connect from \"diagram-js/lib/features/connect/Connect\";\nimport type Create from \"diagram-js/lib/features/create/Create\";\nimport type AutoPlace from \"diagram-js/lib/features/auto-place/AutoPlace\";\nimport type Dragging from \"diagram-js/lib/features/dragging/Dragging\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type Rules from \"diagram-js/lib/features/rules/Rules\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type Scheduler from \"diagram-js/lib/features/scheduler/Scheduler\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { Element, Shape } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { asTRBL, getMid } from \"diagram-js/lib/layout/LayoutUtil\";\nimport {\n DEFAULT_DISTANCE,\n findFreePosition,\n generateGetNextPosition,\n} from \"diagram-js/lib/features/auto-place/AutoPlaceUtil\";\nimport {\n ALL_PATTERN_SPECS,\n ALL_SUBDOMAIN_SPECS,\n DOWNSTREAM_ROLES,\n DOWNSTREAM_ROLE_SPECS,\n RELATIONSHIP_PATTERN_SPECS,\n SUBDOMAIN_TYPE_SPECS,\n UPSTREAM_ROLES,\n UPSTREAM_ROLE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type {\n DownstreamRole,\n RelationshipPatternSpec,\n UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\nimport {\n isCmContext,\n isCmElement,\n isCmRelationship,\n type CmContext,\n type CmElement,\n type CmRelationship,\n} from \"../model/di-types.js\";\nimport type CmModeling from \"../modeling/CmModeling.js\";\nimport type CmLabelEditing from \"../label-editing/CmLabelEditing.js\";\nimport type CmElementFactory from \"../model/CmElementFactory.js\";\nimport { READ_ONLY_CHANGED_EVENT, type CmReadOnly } from \"../read-only/index.js\";\nimport { contextIconSvg, relationshipIconSvg, roleChipSvg } from \"../draw/palette-icons.js\";\nimport { chromeIcon } from \"../draw/lucide.js\";\n\nconst SUBDOMAIN_MENU = \"cm-subdomain-menu\";\nconst PATTERN_MENU = \"cm-pattern-menu\";\nconst ROLES_MENU = \"cm-roles-menu\";\n\n/** Marks the entry matching the element's current state (check + accent, CSS). */\nconst ACTIVE_CLASS = \"cm-popup-active\";\nconst MENU_GAP = 8;\n\n/** Why OHS / CF are unavailable while the pattern is customer-supplier. */\nconst CUSTOMER_SUPPLIER_BLOCKERS: Partial<Record<UpstreamRole | DownstreamRole, string>> = {\n OHS: \"Open Host Service is one-size-fits-all and not applicable in a customer-supplier relationship.\",\n CF: \"Conformist is not applicable in a customer-supplier relationship — a customer can negotiate.\",\n};\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction padEntryHtml(\n icon: string,\n title: string,\n options: { draggable?: boolean; danger?: boolean } = {},\n): string {\n const draggable = options.draggable ? ` draggable=\"true\"` : \"\";\n const danger = options.danger ? \" cm-pad-entry--danger\" : \"\";\n const label = escapeAttribute(title);\n return `<div class=\"entry cm-pad-entry${danger}\"${draggable} title=\"${label}\" aria-label=\"${label}\">${icon}</div>`;\n}\n\n/**\n * Beside the pad entry that opened the card, kept on screen when the entry sits at a viewport\n * edge: no room on the right → flip to the entry's left, bottom → shift up.\n */\nfunction placePromptBeside(card: HTMLElement, anchor: HTMLElement): void {\n const bounds = anchor.getBoundingClientRect();\n card.style.left = `${bounds.right + MENU_GAP}px`;\n card.style.top = `${bounds.top}px`;\n const cardBounds = card.getBoundingClientRect();\n const margin = 8;\n if (cardBounds.right > window.innerWidth - margin) {\n card.style.left = `${Math.max(margin, bounds.left - cardBounds.width - MENU_GAP)}px`;\n }\n if (cardBounds.bottom > window.innerHeight - margin) {\n card.style.top = `${Math.max(margin, window.innerHeight - margin - cardBounds.height)}px`;\n }\n}\n\nexport default class CmContextPadProvider implements ContextPadProvider {\n static $inject = [\n \"contextPad\",\n \"popupMenu\",\n \"eventBus\",\n \"connect\",\n \"create\",\n \"autoPlace\",\n \"rules\",\n \"dragging\",\n \"modeling\",\n \"cmModeling\",\n \"cmLabelEditing\",\n \"cmElementFactory\",\n \"selection\",\n \"canvas\",\n \"scheduler\",\n \"cmReadOnly\",\n ];\n\n /** The last pad-opened menu, so a roles toggle can re-open it in place. */\n private currentMenu?: { element: CmElement; menuId: string; title: string; position: Point };\n\n constructor(\n private readonly contextPad: ContextPad,\n private readonly popupMenu: PopupMenu,\n private readonly eventBus: EventBus,\n connect: Connect,\n private readonly create: Create,\n private readonly autoPlace: AutoPlace,\n private readonly rules: Rules,\n private readonly dragging: Dragging,\n private readonly modeling: Modeling,\n private readonly cmModeling: CmModeling,\n private readonly labelEditing: CmLabelEditing,\n private readonly elementFactory: CmElementFactory,\n private readonly selection: Selection,\n private readonly canvas: Canvas,\n private readonly scheduler: Scheduler,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n // Injecting Connect instantiates it so its connect.* drag handlers exist\n // (same reason as CmConnectHandles — the module does not eagerly init it).\n void connect;\n contextPad.registerProvider(this);\n // A read-only canvas has no context pad (guide §13.5): nothing it offers may change the map.\n eventBus.on(\"contextPad.open.allowed\", 2000, () =>\n this.readOnly.isReadOnly() ? false : undefined,\n );\n eventBus.on(READ_ONLY_CHANGED_EVENT, (event: { readOnly?: boolean }) => {\n if (event.readOnly) {\n this.cancelPrompt();\n popupMenu.close();\n contextPad.close();\n return;\n }\n // Unlocked with an element still selected: its pad comes back, as a fresh selection would.\n const selected = selection.get() as Element[];\n if (selected.length === 1) contextPad.open(selected[0]!, true);\n else if (selected.length > 1) contextPad.open(selected, true);\n });\n popupMenu.registerProvider(SUBDOMAIN_MENU, {\n getPopupMenuEntries: (target: PopupMenuTarget) => this.subdomainMenuEntries(target),\n });\n popupMenu.registerProvider(PATTERN_MENU, {\n getPopupMenuEntries: (target: PopupMenuTarget) => this.patternMenuEntries(target),\n });\n popupMenu.registerProvider(ROLES_MENU, {\n getPopupMenuEntries: (target: PopupMenuTarget) => this.rolesMenuEntries(target),\n });\n // Deconflict auto-placed appends: diagram-js' stock position (right of the\n // source) ignores occupied slots — step downwards until the slot is free.\n // Registered at default priority, beating the stock low-priority listener.\n eventBus.on(\"autoPlace\", (event: { source: Shape; shape: Shape }) => {\n const { source, shape } = event;\n const position = {\n x: asTRBL(source).right + DEFAULT_DISTANCE + shape.width / 2,\n y: getMid(source).y,\n };\n return findFreePosition(\n source,\n shape,\n position,\n generateGetNextPosition({ y: { margin: 30, minDistance: 30 } }),\n );\n });\n // The pad's placement is corrected purely via CSS classes: connections\n // flip it away from the target context their last segment points into.\n eventBus.on(\"contextPad.create\", (event: { target?: unknown; pad?: HTMLElement }) => {\n const { pad, target } = event;\n if (!pad) return;\n let flipX = false;\n let flipY = false;\n if (isCmRelationship(target)) {\n const waypoints = (target.waypoints ?? []) as Point[];\n const last = waypoints[waypoints.length - 1];\n const previous = waypoints[waypoints.length - 2];\n if (last && previous) {\n const dx = last.x - previous.x;\n const dy = last.y - previous.y;\n flipX = Math.abs(dx) >= Math.abs(dy) && dx > 0;\n flipY = Math.abs(dy) > Math.abs(dx) && dy > 0;\n }\n }\n pad.classList.toggle(\"cm-pad-flip-x\", flipX);\n pad.classList.toggle(\"cm-pad-flip-y\", flipY);\n });\n // diagram-js positions the pad without any viewport clamping, and the\n // canvas container clips (overflow: hidden) — pull an overflowing pad back\n // in so its actions stay reachable for shapes at the canvas edge. Runs\n // after diagram-js' own scheduled position update (lower listener priority\n // → later schedule() call → later task).\n eventBus.on([\"contextPad.open\", \"contextPad.show\", \"canvas.viewbox.changed\"], 250, () =>\n this.clampPadIntoView(),\n );\n }\n\n private clampPadIntoView(): void {\n void this.scheduler.schedule(() => {\n const container = this.canvas.getContainer();\n const pad = container.querySelector<HTMLElement>(\".djs-context-pad.open\");\n if (!pad) return;\n const containerBounds = container.getBoundingClientRect();\n const padBounds = pad.getBoundingClientRect();\n const margin = 4;\n const overflowRight = padBounds.right - (containerBounds.right - margin);\n if (overflowRight > 0) {\n pad.style.left = `${parseFloat(pad.style.left || \"0\") - overflowRight}px`;\n }\n // The cm-pad-flip-x transform can carry a connection's pad past the\n // LEFT border (its anchor is the unclamped last waypoint).\n const overflowLeft = containerBounds.left + margin - padBounds.left;\n if (overflowLeft > 0) {\n pad.style.left = `${parseFloat(pad.style.left || \"0\") + overflowLeft}px`;\n }\n // Vertically pull an overflowing pad up — but never past the top\n // border: when the stack is taller than the canvas, the top actions\n // stay reachable rather than none of them.\n let shiftY = 0;\n const overflowBottom = padBounds.bottom - (containerBounds.bottom - margin);\n if (overflowBottom > 0) shiftY = -overflowBottom;\n const overflowTop = containerBounds.top + margin - (padBounds.top + shiftY);\n if (overflowTop > 0) shiftY += overflowTop;\n if (shiftY !== 0) {\n pad.style.top = `${parseFloat(pad.style.top || \"0\") + shiftY}px`;\n }\n }, \"cmContextPad#clampIntoView\");\n }\n\n getContextPadEntries(element: Element): ContextPadEntries {\n if (this.readOnly.isReadOnly()) return {};\n if (isCmContext(element)) return this.contextEntries(element);\n if (isCmRelationship(element)) return this.relationshipEntries(element);\n return {};\n }\n\n getMultiElementContextPadEntries(elements: Element[]): ContextPadEntries {\n if (this.readOnly.isReadOnly()) return {};\n const cmElements = elements.filter(isCmElement);\n if (cmElements.length !== elements.length) return {};\n return { delete: this.deleteEntry(cmElements, \"Delete selection\") };\n }\n\n // --- bounded context ------------------------------------------------------\n\n private contextEntries(context: CmContext): ContextPadEntries {\n const spec = context.subdomainType ? SUBDOMAIN_TYPE_SPECS[context.subdomainType] : undefined;\n return {\n \"append-context\": {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"square-plus\"),\n \"Append a connected context — click to place automatically, drag to position\",\n { draggable: true },\n ),\n action: {\n click: () => this.appendContext(context),\n dragstart: (event: Event) => this.startAppend(event, context),\n },\n },\n connect: {\n group: \"edit\",\n html: padEntryHtml(chromeIcon(\"arrow-right\"), \"Connect to another context\", {\n draggable: true,\n }),\n action: {\n click: (event: Event) => this.startConnect(event, context, true),\n dragstart: (event: Event) => this.startConnect(event, context, false),\n },\n },\n \"subdomain-type\": {\n group: \"edit\",\n html: padEntryHtml(\n contextIconSvg(context.subdomainType),\n `Change subdomain type — currently ${spec?.label ?? \"unclassified\"}`,\n ),\n action: {\n click: (event: Event) => this.openMenu(event, context, SUBDOMAIN_MENU, \"Subdomain type\"),\n },\n },\n team: {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"users\"),\n `Set owning team — currently ${context.team ?? \"none\"}`,\n ),\n action: { click: () => this.labelEditing.activateTeam(context) },\n },\n \"edit-label\": this.editLabelEntry(context, \"Rename context\"),\n description: this.descriptionEntry(context, \"Purpose, ubiquitous language, notes…\"),\n delete: this.deleteEntry([context], \"Delete context\"),\n };\n }\n\n /**\n * Same payload as Connect#start, mirroring CmConnectHandles, but with\n * diagram-js' ghost-click trap OFF for both variants: the trap relies on the\n * gesture-ending canvas click, which Chromium suppresses whenever the\n * mousedown target was re-rendered by the connect command — the unconsumed\n * trap would then swallow the user's NEXT click. The click variant instead\n * blocks exactly one immediately-following element.click itself (when it\n * does fire, it must not re-select the target over the fresh relationship).\n */\n private startConnect(event: Event, source: CmContext, viaClick: boolean): void {\n this.dragging.init(event as MouseEvent, \"connect\", {\n autoActivate: viaClick,\n trapClick: false,\n data: {\n shape: source,\n context: { start: source, connectionStart: getMid(source) },\n },\n });\n if (viaClick) {\n const swallowGestureClick = () => false;\n this.eventBus.once(\"connect.cleanup\", 250, () => {\n this.eventBus.once(\"element.click\", 10000, swallowGestureClick);\n const disarm = (): void => this.eventBus.off(\"element.click\", swallowGestureClick);\n // Dragging binds endDrag to mousedown AND mouseup — the gesture already\n // ends in the *mousedown* of the finishing click, whose click event is\n // only delivered after the following mouseup. Hold the blocker until\n // then: the capture-mouseup runs before the click, the 0ms task after.\n document.addEventListener(\"mouseup\", () => setTimeout(disarm, 0), {\n capture: true,\n once: true,\n });\n // Safety net (same window as diagram-js' ClickTrap): if the click never\n // arrives, the blocker must not eat a later real one.\n setTimeout(disarm, 400);\n });\n }\n // The drag lifecycle clears the selection; the user is still \"at\" the source.\n this.eventBus.once(\"connect.cleanup\", 250, () => {\n if (this.selection.get().length === 0) this.selection.select(source);\n });\n }\n\n /**\n * Append a fresh, unclassified context connected to the source. The click\n * variant auto-places it (diagram-js auto-place, which also selects it), the\n * drag variant hands placement to the create tool with a `source` hint —\n * both stamp the connection through the `connection.create` rule. After\n * placement the subdomain-type menu opens so classifying is one click away.\n */\n private appendContext(source: CmContext): void {\n const shape = this.elementFactory.createNewContext();\n // CmRules returns the relationship attrs (cmKind + default pattern), not\n // just a boolean — pass them on so the connection is stamped correctly.\n const connection = this.rules.allowed(\"connection.create\", {\n source,\n target: shape,\n }) as unknown as false | null | Record<string, unknown>;\n const appended = this.autoPlace.append(\n source,\n shape,\n connection && typeof connection === \"object\" ? { connection } : {},\n ) as unknown as CmContext;\n this.openTypeMenu(appended);\n }\n\n private startAppend(event: Event, source: CmContext): void {\n const shape = this.elementFactory.createNewContext();\n const onCreated = () => this.openTypeMenu(shape);\n this.eventBus.once(\"create.end\", 250, onCreated);\n // A cancelled create must not leave the armed listener behind — it would\n // fire on the next palette create otherwise.\n this.eventBus.once(\"create.cleanup\", () => this.eventBus.off(\"create.end\", onCreated));\n this.create.start(event as MouseEvent, shape, { source });\n }\n\n /** Open the subdomain-type menu for a freshly appended context, anchored to\n * its pad entry — deferred one task so the pad has been positioned first. */\n private openTypeMenu(context: CmContext): void {\n void this.scheduler.schedule(() => {\n if (!this.contextPad.isOpen(context)) return;\n const entry = this.canvas\n .getContainer()\n .querySelector<HTMLElement>('.djs-context-pad.open [data-action=\"subdomain-type\"]');\n if (!entry) return;\n this.openMenuBeside(entry.getBoundingClientRect(), context, SUBDOMAIN_MENU, \"Subdomain type\");\n }, \"cmContextPad#openTypeMenu\");\n }\n\n // --- relationship ---------------------------------------------------------\n\n private relationshipEntries(relationship: CmRelationship): ContextPadEntries {\n // Tolerate unknown patterns (unvalidated imports), like the renderer does:\n // the pad must still open so the pattern menu can repair the element.\n const spec = RELATIONSHIP_PATTERN_SPECS[relationship.pattern] as\n RelationshipPatternSpec | undefined;\n const entries: ContextPadEntries = {\n pattern: {\n group: \"edit\",\n html: padEntryHtml(\n relationshipIconSvg(spec?.pattern),\n `Change pattern — currently ${spec?.label ?? relationship.pattern}`,\n ),\n action: {\n click: (event: Event) =>\n this.openMenu(event, relationship, PATTERN_MENU, \"Relationship pattern\"),\n },\n },\n };\n if (spec && !spec.symmetric) {\n entries.roles = {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"sliders-horizontal\"),\n \"Edit integration roles — OHS/PL upstream, ACL/CF downstream\",\n ),\n action: {\n click: (event: Event) =>\n this.openMenu(event, relationship, ROLES_MENU, \"Integration roles\"),\n },\n };\n entries[\"swap-ends\"] = {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"arrow-left-right\"),\n \"Swap ends — reverse upstream/downstream\",\n ),\n action: { click: () => this.cmModeling.swapEnds(relationship) },\n };\n }\n entries[\"edit-label\"] = this.editLabelEntry(relationship, \"Edit label\");\n entries.description = this.descriptionEntry(relationship, \"What flows here, contracts, notes…\");\n entries.delete = this.deleteEntry([relationship], \"Delete relationship\");\n return entries;\n }\n\n // --- shared entries -------------------------------------------------------\n\n private editLabelEntry(element: CmElement, title: string): ContextPadEntry {\n return {\n group: \"edit\",\n html: padEntryHtml(chromeIcon(\"pencil\"), `${title} — edit the name in place`),\n action: { click: () => this.labelEditing.activate(element) },\n };\n }\n\n private descriptionEntry(element: CmElement, placeholder: string): ContextPadEntry {\n return {\n group: \"edit\",\n html: padEntryHtml(chromeIcon(\"text-align-start\"), \"Edit description\"),\n action: {\n click: (event: Event) =>\n this.openPrompt(event, {\n value: element.description ?? \"\",\n placeholder,\n label: \"Description\",\n multiline: true,\n onCommit: (value) => this.cmModeling.setDescription(element, value || undefined),\n }),\n },\n };\n }\n\n /**\n * A small input card anchored beside the clicked pad entry (like the popup\n * menus — below would cover the rest of the vertical stack) — for the\n * free-text properties, which should not open centred over the element.\n * Enter (Ctrl/Cmd+Enter in the multiline variant) and blur commit, Escape\n * cancels.\n */\n private activePrompt?: { cancel(): void };\n\n /** Closes an open description prompt without saving it (an import replaces its element). */\n cancelPrompt(): void {\n this.activePrompt?.cancel();\n }\n\n private openPrompt(\n event: Event,\n config: {\n value: string;\n placeholder: string;\n label: string;\n multiline?: boolean;\n onCommit(value: string): void;\n },\n ): void {\n this.activePrompt?.cancel();\n const anchor = ((event as { delegateTarget?: EventTarget }).delegateTarget ??\n event.target) as HTMLElement;\n\n const card = document.createElement(\"div\");\n card.className = \"cm-pad-prompt\";\n\n const field = document.createElement(config.multiline ? \"textarea\" : \"input\") as\n HTMLInputElement | HTMLTextAreaElement;\n field.className = \"cm-pad-prompt__field\";\n field.value = config.value;\n field.placeholder = config.placeholder;\n field.setAttribute(\"aria-label\", config.label);\n if (field instanceof HTMLTextAreaElement) field.rows = 4;\n card.appendChild(field);\n\n if (config.multiline) {\n const hint = document.createElement(\"div\");\n hint.className = \"cm-pad-prompt__hint\";\n hint.textContent = \"Esc to cancel · ⌘/Ctrl+Enter to save\";\n card.appendChild(hint);\n }\n\n this.canvas.getContainer().appendChild(card);\n placePromptBeside(card, anchor);\n field.focus();\n if (field instanceof HTMLTextAreaElement) {\n // Select-all in a filled textarea makes the first keystroke wipe the\n // text — park the caret at the end instead.\n field.setSelectionRange(field.value.length, field.value.length);\n } else {\n field.select();\n }\n\n // A pan or zoom moves the pad, also one the host makes (setViewState, a fit): the card follows\n // its entry and keeps the typed text instead of committing it (mirrors the label editor).\n // After the pad's own position update and clamp, which are scheduled at a higher priority.\n const followPad = (): void => {\n void this.scheduler.schedule(() => {\n if (anchor.isConnected) placePromptBeside(card, anchor);\n }, \"cmContextPad#placePrompt\");\n };\n this.eventBus.on(\"canvas.viewbox.changed\", 200, followPad);\n\n let done = false;\n const cleanup = (): void => {\n if (done) return;\n done = true;\n this.eventBus.off(\"canvas.viewbox.changed\", followPad);\n this.scheduler.cancel(\"cmContextPad#placePrompt\");\n card.remove();\n this.activePrompt = undefined;\n (this.canvas as { restoreFocus?: () => void }).restoreFocus?.();\n };\n const commit = (): void => {\n if (done) return;\n const value = field.value.trim();\n const changed = value !== config.value.trim();\n cleanup();\n if (changed) config.onCommit(value);\n };\n field.addEventListener(\"keydown\", (event: Event) => {\n const keyEvent = event as KeyboardEvent;\n if (keyEvent.key === \"Escape\") {\n keyEvent.preventDefault();\n keyEvent.stopPropagation();\n cleanup();\n } else if (\n keyEvent.key === \"Enter\" &&\n (!config.multiline || keyEvent.ctrlKey || keyEvent.metaKey)\n ) {\n keyEvent.preventDefault();\n commit();\n }\n });\n field.addEventListener(\"blur\", commit);\n this.activePrompt = { cancel: cleanup };\n }\n\n private deleteEntry(elements: CmElement[], title: string): ContextPadEntry {\n return {\n group: \"delete\",\n html: padEntryHtml(chromeIcon(\"trash\"), title, { danger: true }),\n action: { click: () => this.modeling.removeElements(elements as Element[]) },\n };\n }\n\n private openMenu(event: Event, element: CmElement, menuId: string, title: string): void {\n const anchor = ((event as { delegateTarget?: EventTarget }).delegateTarget ??\n event.target) as HTMLElement;\n this.openMenuBeside(anchor.getBoundingClientRect(), element, menuId, title);\n }\n\n /**\n * Menus open beside the clicked entry — beneath it they would cover the\n * rest of the vertical stack. At the viewport's right edge PopupMenu flips\n * an overflowing menu back across its anchor (and the whole pad column), so\n * a flipped menu is pushed fully left of the pad instead; the popup applies\n * its initial position only once, so the correction sticks (and is saved\n * for `reopenMenu`).\n */\n private openMenuBeside(\n entryBounds: DOMRect,\n element: CmElement,\n menuId: string,\n title: string,\n ): void {\n const position = { x: entryBounds.right + MENU_GAP, y: entryBounds.top };\n this.popupMenu.open(element, menuId, position, { title });\n const popup = document.querySelector<HTMLElement>(\".djs-popup\");\n const popupBounds = popup?.getBoundingClientRect();\n if (popup && popupBounds && popupBounds.left < entryBounds.right) {\n position.x = Math.max(MENU_GAP, entryBounds.left - MENU_GAP - popupBounds.width);\n popup.style.left = `${position.x}px`;\n }\n this.currentMenu = { element, menuId, title, position };\n }\n\n /**\n * Re-open a menu after a command: the command stack's `commandStack.changed`\n * auto-closes any popup, but a multi-select menu (integration roles) should\n * survive a toggle so combinations don't require re-opening the pad entry.\n */\n private reopenMenu(element: CmElement, menuId: string): void {\n const menu = this.currentMenu;\n if (!menu || menu.menuId !== menuId || menu.element !== element) return;\n this.popupMenu.open(element, menuId, menu.position, { title: menu.title });\n }\n\n // --- popup menus ----------------------------------------------------------\n\n private subdomainMenuEntries(target: PopupMenuTarget): PopupMenuEntries {\n if (!isCmContext(target)) return {};\n const current = target.subdomainType;\n const entries: PopupMenuEntries = {};\n for (const spec of ALL_SUBDOMAIN_SPECS) {\n entries[`type-${spec.type}`] = {\n label: spec.label,\n description: spec.description,\n imageHtml: contextIconSvg(spec.type),\n ...(spec.type === current ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (spec.type !== current) this.cmModeling.setSubdomainType(target, spec.type);\n },\n };\n }\n entries[\"type-none\"] = {\n label: \"Unclassified\",\n description: \"No subdomain classification.\",\n imageHtml: contextIconSvg(),\n ...(current === undefined ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (current !== undefined) this.cmModeling.setSubdomainType(target, undefined);\n },\n };\n return entries;\n }\n\n private patternMenuEntries(target: PopupMenuTarget): PopupMenuEntries {\n if (!isCmRelationship(target)) return {};\n const current = target.pattern;\n const entries: PopupMenuEntries = {};\n for (const spec of ALL_PATTERN_SPECS) {\n entries[`pattern-${spec.pattern}`] = {\n label: spec.label,\n description: spec.description,\n imageHtml: relationshipIconSvg(spec.pattern),\n ...(spec.pattern === current ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (spec.pattern !== current) this.cmModeling.setPattern(target, spec.pattern);\n },\n };\n }\n return entries;\n }\n\n private rolesMenuEntries(target: PopupMenuTarget): PopupMenuEntries {\n if (!isCmRelationship(target)) return {};\n const spec = RELATIONSHIP_PATTERN_SPECS[target.pattern] as RelationshipPatternSpec | undefined;\n if (!spec || spec.symmetric) return {};\n const customerSupplier = target.pattern === \"customer-supplier\";\n const upstream = target.upstreamRoles ?? [];\n const downstream = target.downstreamRoles ?? [];\n const entries: PopupMenuEntries = {};\n\n for (const role of UPSTREAM_ROLES) {\n const active = upstream.includes(role);\n const blocker = customerSupplier ? CUSTOMER_SUPPLIER_BLOCKERS[role] : undefined;\n // A blocked role that is already set (unvalidated import, CML) stays\n // clickable — deselecting it is the repair, not the violation.\n const blocked = blocker !== undefined && !active;\n entries[`upstream-${role}`] = {\n label: UPSTREAM_ROLE_SPECS[role].label,\n description: blocker\n ? active\n ? `${blocker} Click to remove it.`\n : blocker\n : UPSTREAM_ROLE_SPECS[role].description,\n imageHtml: roleChipSvg(role),\n group: { id: \"upstream\", name: \"Upstream (from) — OHS and/or PL\" },\n ...(blocked ? { disabled: true } : {}),\n ...(active ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (blocked) return;\n this.cmModeling.setUpstreamRoles(\n target,\n active ? upstream.filter((existing) => existing !== role) : [...upstream, role],\n );\n this.reopenMenu(target, ROLES_MENU);\n },\n };\n }\n for (const role of DOWNSTREAM_ROLES) {\n const active = downstream.includes(role);\n const blocker = customerSupplier ? CUSTOMER_SUPPLIER_BLOCKERS[role] : undefined;\n const blocked = blocker !== undefined && !active;\n entries[`downstream-${role}`] = {\n label: DOWNSTREAM_ROLE_SPECS[role].label,\n description: blocker\n ? active\n ? `${blocker} Click to remove it.`\n : blocker\n : DOWNSTREAM_ROLE_SPECS[role].description,\n imageHtml: roleChipSvg(role),\n group: { id: \"downstream\", name: \"Downstream (to) — ACL or CF, not both\" },\n ...(blocked ? { disabled: true } : {}),\n ...(active ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (blocked) return;\n this.cmModeling.setDownstreamRoles(target, active ? [] : [role]);\n this.reopenMenu(target, ROLES_MENU);\n },\n };\n }\n return entries;\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport ContextPadModule from \"diagram-js/lib/features/context-pad\";\nimport PopupMenuModule from \"diagram-js/lib/features/popup-menu\";\nimport ConnectModule from \"diagram-js/lib/features/connect\";\nimport CreateModule from \"diagram-js/lib/features/create\";\nimport AutoPlaceModule from \"diagram-js/lib/features/auto-place\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport ModelingModule from \"diagram-js/lib/features/modeling\";\nimport { cmModelingModule } from \"../modeling/index.js\";\nimport { cmRulesModule } from \"../rules/index.js\";\nimport { cmLabelEditingModule } from \"../label-editing/index.js\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmContextPadProvider from \"./CmContextPadProvider.js\";\n\nexport const cmContextPadModule: ModuleDeclaration = {\n __depends__: [\n ContextPadModule,\n PopupMenuModule,\n ConnectModule,\n CreateModule,\n AutoPlaceModule,\n SelectionModule,\n ModelingModule,\n cmModelingModule,\n // The connect action needs CmRules: only its connection.create rule stamps\n // the new connection as a relationship (cmKind + default pattern).\n cmRulesModule,\n cmLabelEditingModule,\n cmReadOnlyModule,\n ],\n __init__: [\"cmContextPadProvider\"],\n cmContextPadProvider: [\"type\", CmContextPadProvider],\n};\n\nexport { default as CmContextPadProvider } from \"./CmContextPadProvider.js\";\n","/**\n * Keyboard shortcuts: select all, undo / redo, delete-selection. Bound to the document so they\n * work without first clicking (focusing) the canvas, but only for keys aimed at the canvas: keys\n * from outside its container (a host's chrome) and keys someone closer to the target already\n * handled (`defaultPrevented`) are left alone, and typing inside form fields is never\n * intercepted. No container `tabindex`, so the canvas adds no tab stop of its own.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type { Element } from \"diagram-js/lib/model/Types\";\nimport { isCmElement } from \"../model/di-types.js\";\nimport type CmReadOnly from \"../read-only/CmReadOnly.js\";\n\nexport interface CmKeyboardConfig {\n /**\n * Bind Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z and Cmd/Ctrl+Y to the canvas command stack (default true).\n * A host that owns the history (the VS Code document) passes false, so the keys reach it.\n */\n undoRedoKeys?: boolean | undefined;\n}\n\nfunction isTypingTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null;\n if (!el) return false;\n return (\n el.tagName === \"INPUT\" ||\n el.tagName === \"TEXTAREA\" ||\n el.tagName === \"SELECT\" ||\n el.isContentEditable\n );\n}\n\n/**\n * A key aimed at the canvas: from inside its container, or with nothing focused at all. The\n * palette lives in the container too, but a key on a focused palette entry is the palette's: Delete\n * there must not remove the selected elements.\n */\nfunction isCanvasTarget(target: EventTarget | null, container: HTMLElement): boolean {\n if (!(target instanceof Node)) return false;\n if (target instanceof Element && target.closest(\".djs-palette\")) return false;\n const ownerDocument = container.ownerDocument;\n return (\n container.contains(target) ||\n target === ownerDocument.body ||\n target === ownerDocument.documentElement\n );\n}\n\nexport default class CmKeyboard {\n static $inject = [\n \"config.cmKeyboard\",\n \"canvas\",\n \"commandStack\",\n \"selection\",\n \"modeling\",\n \"elementRegistry\",\n \"eventBus\",\n \"cmReadOnly\",\n ];\n\n constructor(\n config: CmKeyboardConfig | undefined,\n canvas: Canvas,\n commandStack: CommandStack,\n selection: Selection,\n modeling: Modeling,\n elementRegistry: ElementRegistry,\n eventBus: EventBus,\n readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n const container = canvas.getContainer();\n const doc = container.ownerDocument ?? document;\n const undoRedoKeys = config?.undoRedoKeys ?? true;\n\n const onKeydown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented) return;\n if (!isCanvasTarget(e.target, container)) return;\n if (isTypingTarget(e.target)) return;\n const cmd = e.ctrlKey || e.metaKey;\n const key = e.key.toLowerCase();\n\n // Select all reads the map, so it stays under the read-only lock; without it the host\n // (VS Code) would run its own Select All over the chrome's text.\n if (cmd && key === \"a\" && !e.shiftKey && !e.altKey) {\n e.preventDefault();\n selection.select(elementRegistry.filter((element) => isCmElement(element)) as Element[]);\n return;\n }\n if (readOnly.isReadOnly()) return;\n\n const isUndo = cmd && key === \"z\" && !e.shiftKey;\n const isRedo = (cmd && key === \"z\" && e.shiftKey) || (cmd && key === \"y\" && !e.shiftKey);\n if (isUndo || isRedo) {\n if (!undoRedoKeys) return;\n e.preventDefault();\n if (isUndo && commandStack.canUndo()) commandStack.undo();\n if (isRedo && commandStack.canRedo()) commandStack.redo();\n } else if (key === \"delete\" || key === \"backspace\") {\n const sel = selection.get() as Element[];\n if (sel.length) {\n e.preventDefault();\n modeling.removeElements([...sel]);\n }\n }\n };\n\n doc.addEventListener(\"keydown\", onKeydown);\n eventBus.on(\"diagram.destroy\", () => doc.removeEventListener(\"keydown\", onKeydown));\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmKeyboard from \"./CmKeyboard.js\";\n\n/** Select all, undo/redo and delete-selection for keys aimed at the canvas. */\nexport const cmKeyboardModule: ModuleDeclaration = {\n __depends__: [cmReadOnlyModule],\n __init__: [\"cmKeyboard\"],\n cmKeyboard: [\"type\", CmKeyboard],\n};\n\nexport { default as CmKeyboard } from \"./CmKeyboard.js\";\nexport type { CmKeyboardConfig } from \"./CmKeyboard.js\";\n","/**\n * Live semantic-rule markers on the canvas: a relationship with validation\n * findings gets a small marker next to the issue — the problem pill's icons in\n * the status roles: `triangle-alert` for warnings, `circle-x` if any finding is\n * an error. Sided findings (e.g. an ACL issue\n * is a downstream concern) anchor at the BOTTOM-RIGHT corner of that end's\n * role-chip box (geometry shared with the renderer via endRoleChipLayout);\n * findings about the relationship as a whole sit at the middle of the line.\n * Hovering shows the message(s) instantly via a CSS tooltip (a native `title`\n * would only appear after the OS hover delay). Implemented as diagram-js\n * overlays (HTML above the SVG), so hover is not swallowed by the connection\n * hit layer and the marker follows its element. Recomputed on every change.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type Overlays from \"diagram-js/lib/features/overlays/Overlays\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { validateDocument, type SemanticFinding } from \"@miragon/context-maps-schema-model\";\nimport type CmExporter from \"../io/CmExporter.js\";\nimport { isCmRelationship, type CmRelationship } from \"../model/di-types.js\";\nimport { endRoleChipLayout } from \"../draw/endRoleChips.js\";\nimport { chromeIcon } from \"../draw/lucide.js\";\n\nconst OVERLAY_TYPE = \"cm-validation\";\nconst MARKER_SIZE = 22;\nconst LINE_OFFSET = 16;\n/** Fallback distance from the endpoint when the end has no role chips. */\nconst END_DISTANCE = 44;\n\ntype MarkerSide = \"upstream\" | \"downstream\" | \"middle\";\n\ninterface RankedFinding extends SemanticFinding {\n kind: \"error\" | \"warning\";\n}\n\nfunction markerHtml(findings: RankedFinding[]): HTMLElement {\n const hasError = findings.some((finding) => finding.kind === \"error\");\n const marker = document.createElement(\"div\");\n marker.className = \"cm-validation-marker\";\n marker.dataset.severity = hasError ? \"error\" : \"warning\";\n marker.innerHTML = chromeIcon(hasError ? \"circle-x\" : \"triangle-alert\");\n\n const tooltip = document.createElement(\"div\");\n tooltip.className = \"cm-validation-tooltip\";\n for (const finding of findings) {\n const message = document.createElement(\"div\");\n message.className = \"cm-validation-tooltip__message\";\n message.textContent = finding.message;\n tooltip.appendChild(message);\n }\n marker.appendChild(tooltip);\n return marker;\n}\n\n/**\n * Where the marker sits. Sided findings anchor at the bottom-right corner of\n * the role-chip box of that end (that is where the offending OHS/PL/ACL/CF\n * badge is drawn); without chips they fall back to a point near the endpoint.\n * Whole-relationship findings sit at the middle of the line, nudged off it.\n */\nfunction anchorPoint(relationship: CmRelationship, waypoints: Point[], side: MarkerSide): Point {\n const start = waypoints[0];\n const end = waypoints[waypoints.length - 1];\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const length = Math.hypot(dx, dy) || 1;\n const ux = dx / length;\n const uy = dy / length;\n\n if (side === \"middle\") {\n return {\n x: (start.x + end.x) / 2 + -uy * LINE_OFFSET,\n y: (start.y + end.y) / 2 + ux * LINE_OFFSET,\n };\n }\n\n const customerSupplier = relationship.pattern === \"customer-supplier\";\n const layout =\n side === \"upstream\"\n ? endRoleChipLayout(\n start,\n end,\n customerSupplier ? \"S\" : \"U\",\n relationship.upstreamRoles ?? [],\n )\n : endRoleChipLayout(\n end,\n start,\n customerSupplier ? \"C\" : \"D\",\n relationship.downstreamRoles ?? [],\n );\n if (layout) {\n // Centred (almost) on the chip box corner: the triangle's visible body is\n // bottom-heavy, so half the marker overlapping the corner reads as sitting\n // right AT the corner instead of floating next to it.\n const corner = { x: layout.box.x + layout.box.width, y: layout.box.y + layout.box.height };\n return { x: corner.x + 1, y: corner.y + 1 };\n }\n\n const along = Math.min(END_DISTANCE, length * 0.35);\n const baseX = side === \"upstream\" ? start.x + ux * along : end.x - ux * along;\n const baseY = side === \"upstream\" ? start.y + uy * along : end.y - uy * along;\n return { x: baseX + -uy * LINE_OFFSET, y: baseY + ux * LINE_OFFSET };\n}\n\nexport default class CmValidationMarkers {\n static $inject = [\"eventBus\", \"elementRegistry\", \"overlays\", \"cmExporter\"];\n\n constructor(\n eventBus: EventBus,\n private readonly elementRegistry: ElementRegistry,\n private readonly overlays: Overlays,\n private readonly exporter: CmExporter,\n ) {\n const refresh = (): void => this.refresh();\n eventBus.on(\"import.render.done\", refresh);\n eventBus.on(\"commandStack.changed\", refresh);\n }\n\n private refresh(): void {\n this.overlays.remove({ type: OVERLAY_TYPE });\n\n const report = validateDocument(this.exporter.export());\n // One marker per relationship END the findings point at (or the middle for\n // whole-relationship findings), so the triangle sits next to the issue.\n const byAnchor = new Map<string, { relationshipId: string; findings: RankedFinding[] }>();\n const collect = (findings: SemanticFinding[], kind: RankedFinding[\"kind\"]): void => {\n for (const finding of findings) {\n if (!finding.relationshipId) continue;\n const key = `${finding.relationshipId} ${finding.side ?? \"middle\"}`;\n const group = byAnchor.get(key) ?? { relationshipId: finding.relationshipId, findings: [] };\n group.findings.push({ ...finding, kind });\n byAnchor.set(key, group);\n }\n };\n collect(report.errors, \"error\");\n collect(report.warnings, \"warning\");\n\n for (const [key, group] of byAnchor) {\n const element = this.elementRegistry.get(group.relationshipId);\n if (!isCmRelationship(element)) continue;\n const waypoints = (element.waypoints ?? []) as Point[];\n if (waypoints.length < 2) continue;\n const side = key.split(\" \")[1] as MarkerSide;\n const { x: markerX, y: markerY } = anchorPoint(element, waypoints, side);\n\n // Overlay positions on a connection are relative to its waypoint bbox.\n const bboxX = Math.min(...waypoints.map((p) => p.x));\n const bboxY = Math.min(...waypoints.map((p) => p.y));\n this.overlays.add(element, OVERLAY_TYPE, {\n position: {\n left: markerX - bboxX - MARKER_SIZE / 2,\n top: markerY - bboxY - MARKER_SIZE / 2,\n },\n html: markerHtml(group.findings),\n });\n }\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport OverlaysModule from \"diagram-js/lib/features/overlays\";\nimport CmValidationMarkers from \"./CmValidationMarkers.js\";\n\n/** Live semantic-rule markers (warning triangles with tooltips) on the canvas. */\nexport const cmValidationModule: ModuleDeclaration = {\n __depends__: [OverlaysModule],\n __init__: [\"cmValidationMarkers\"],\n cmValidationMarkers: [\"type\", CmValidationMarkers],\n};\n\nexport { default as CmValidationMarkers } from \"./CmValidationMarkers.js\";\n","/**\n * Enforces a fixed stacking order regardless of creation order, by reordering\n * the element graphics within the canvas layer. Back → front:\n *\n * relationships < contexts\n *\n * So the relationship lines always read behind the context boxes and appear to\n * dock to the box borders (the segment inside a box is covered by the box).\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { isCmElement, isCmRelationship, type CmElement } from \"../model/di-types.js\";\n\n/** Lower = further back. */\nfunction tier(el: CmElement): number {\n return isCmRelationship(el) ? 0 : 1;\n}\n\nexport default class CmZOrder {\n static $inject = [\"eventBus\", \"canvas\", \"elementRegistry\"];\n\n private importing = false;\n\n constructor(\n eventBus: EventBus,\n private readonly canvas: Canvas,\n private readonly elementRegistry: ElementRegistry,\n ) {\n eventBus.on(\"import.render.start\", () => {\n this.importing = true;\n });\n eventBus.on(\"import.render.done\", () => {\n this.importing = false;\n this.reorder();\n });\n eventBus.on(\"commandStack.changed\", () => {\n if (!this.importing) this.reorder();\n });\n }\n\n /** Re-append each element's graphics group in ascending tier order (back → front). */\n reorder(): void {\n const ordered = (this.elementRegistry.getAll().filter(isCmElement) as CmElement[]).sort(\n (a, b) => tier(a) - tier(b),\n );\n for (const el of ordered) {\n const gfx = this.canvas.getGraphics(el) as SVGElement | undefined;\n const wrapper = gfx?.parentNode as (Node & ChildNode) | null;\n const layer = wrapper?.parentNode as (Node & { appendChild(n: Node): Node }) | null;\n if (wrapper && layer) layer.appendChild(wrapper);\n }\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmZOrder from \"./CmZOrder.js\";\n\n/** Keeps the fixed stacking order (interactions on top, base teams at the back). */\nexport const cmZOrderModule: ModuleDeclaration = {\n __init__: [\"cmZOrder\"],\n cmZOrder: [\"type\", CmZOrder],\n};\n\nexport { default as CmZOrder } from \"./CmZOrder.js\";\n","import type { ModuleDeclaration } from \"didi\";\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\n\nimport ConnectionPreviewModule from \"diagram-js/lib/features/connection-preview\";\nimport ModelingModule from \"diagram-js/lib/features/modeling\";\nimport MoveModule from \"diagram-js/lib/features/move\";\nimport OutlineModule from \"diagram-js/lib/features/outline\";\n\nimport { NavigatedViewer } from \"./NavigatedViewer.js\";\nimport { cmModelingModule } from \"./modeling/index.js\";\nimport { cmRulesModule } from \"./rules/index.js\";\nimport { cmBehaviorsModule } from \"./behaviors/index.js\";\nimport { cmPaletteModule } from \"./palette/index.js\";\nimport { cmContextPadModule } from \"./context-pad/index.js\";\nimport { cmLabelEditingModule } from \"./label-editing/index.js\";\nimport { cmKeyboardModule } from \"./keyboard/index.js\";\nimport { cmValidationModule } from \"./validation/index.js\";\nimport { cmZOrderModule } from \"./zorder/index.js\";\nimport { cmReadOnlyModule } from \"./read-only/index.js\";\n\n/**\n * Full Context Maps editor: palette/create, move, connect with rules,\n * context pad, inline label editing, undo/redo, and the edit lock for a\n * document the host cannot take edits for (`cmReadOnly`). Boxes are\n * fixed-size — no resize feature.\n */\nexport class Modeler extends NavigatedViewer {\n protected override _getModules(): ModuleDeclaration[] {\n return [\n ...super._getModules(),\n // diagram-js stock\n ConnectionPreviewModule,\n ModelingModule,\n MoveModule,\n OutlineModule,\n // Context Maps editor\n cmReadOnlyModule,\n cmModelingModule,\n cmRulesModule,\n cmBehaviorsModule,\n cmPaletteModule,\n cmContextPadModule,\n cmLabelEditingModule,\n cmKeyboardModule,\n cmValidationModule,\n cmZOrderModule,\n ];\n }\n\n undo(): void {\n this.get<CommandStack>(\"commandStack\").undo();\n }\n\n redo(): void {\n this.get<CommandStack>(\"commandStack\").redo();\n }\n\n canUndo(): boolean {\n return this.get<CommandStack>(\"commandStack\").canUndo();\n }\n\n canRedo(): boolean {\n return this.get<CommandStack>(\"commandStack\").canRedo();\n }\n}\n","import {\n MODELER_API_VERSION,\n type CollaborativeModeler,\n type CollaborativeModelerOptions,\n type ElementBounds,\n type ElementInfo,\n type ElementsSurface,\n type ImportResult,\n type ModelerMeta,\n} from \"@miragon/modeler-api\";\nimport type { ModuleDeclaration } from \"didi\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type { Element } from \"diagram-js/lib/model/Types\";\nimport { getBBox } from \"diagram-js/lib/util/Elements\";\nimport type { CmViewerOptions, FreeRectInsets } from \"../CmBaseViewer.js\";\nimport { Modeler } from \"../Modeler.js\";\nimport { NavigatedViewer } from \"../NavigatedViewer.js\";\nimport { isCmElement, type CmElement } from \"../model/di-types.js\";\n\n/** Stable notation id in `meta.notation` of the collaborative-modeler contract. */\nexport const CONTEXT_MAPS_NOTATION = \"context-maps\";\n\n/**\n * The contract's factory options (`freeArea`, `fitOnImport`, `undoRedoKeys`, see\n * `CmViewerOptions`) and the renderer's own. The viewer ignores `undoRedoKeys`.\n */\nexport interface CollaborativeContextMapsOptions extends CollaborativeModelerOptions {\n /** Appended to the renderer's own modules (e.g. a host's chrome module). */\n additionalModules?: ModuleDeclaration[] | undefined;\n /** @deprecated Use `freeArea: { insets }`; accepted through the 0.5 releases, ignored next to it. */\n freeRectInsets?: (() => FreeRectInsets) | undefined;\n}\n\n/** The contract surface plus the wrapped diagram for host-specific wiring. */\nexport interface CollaborativeContextMapsModeler extends CollaborativeModeler {\n readonly elements: ElementsSurface & { bounds(id: string): ElementBounds | undefined };\n contentBounds(): ElementBounds | undefined;\n readonly diagram: Modeler | NavigatedViewer;\n}\n\ninterface ViewState {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * The editing mount (`meta.editable: true`) of the collaborative-modeler contract: the text lane\n * is the canonical JSON of a `.cm`/`.cm.json` file (`serializeDocumentText`).\n */\nexport function createCollaborativeModeler(\n options: CollaborativeContextMapsOptions = {},\n): CollaborativeContextMapsModeler {\n return collaborative(\n new Modeler({ ...diagramOptions(options), undoRedoKeys: options.undoRedoKeys ?? true }),\n true,\n );\n}\n\n/** The read-only mount (`meta.editable: false`): imports, exports and reveals, never edits. */\nexport function createCollaborativeViewer(\n options: CollaborativeContextMapsOptions = {},\n): CollaborativeContextMapsModeler {\n return collaborative(new NavigatedViewer(diagramOptions(options)), false);\n}\n\nfunction diagramOptions(options: CollaborativeContextMapsOptions): CmViewerOptions {\n return {\n width: \"100%\",\n height: \"100%\",\n additionalModules: options.additionalModules ?? [],\n freeArea: options.freeArea,\n freeRectInsets: options.freeRectInsets,\n fitOnImport: options.fitOnImport,\n };\n}\n\nfunction collaborative(\n diagram: Modeler | NavigatedViewer,\n editable: boolean,\n): CollaborativeContextMapsModeler {\n const eventBus = diagram.get<EventBus>(\"eventBus\");\n const canvas = diagram.get<Canvas>(\"canvas\");\n const elementRegistry = diagram.get<ElementRegistry>(\"elementRegistry\");\n const selection = diagram.get<Selection>(\"selection\");\n const contentListeners = new Set<() => void>();\n let destroyed = false;\n let lastExport = \"\";\n\n const meta: ModelerMeta = {\n notation: CONTEXT_MAPS_NOTATION,\n apiVersion: MODELER_API_VERSION,\n editable,\n };\n\n // An import never touches the command stack (it erases the history without an event), so every\n // `commandStack.changed` is a user-visible change: element commands, the title, undo and redo.\n if (editable) {\n eventBus.on(\"commandStack.changed\", () => {\n for (const listener of [...contentListeners]) listener();\n });\n }\n\n const elements: CollaborativeContextMapsModeler[\"elements\"] = {\n list: () =>\n destroyed ? [] : (elementRegistry.getAll() as unknown[]).filter(isCmElement).map(elementInfo),\n bounds(id) {\n if (destroyed) return undefined;\n const element = elementRegistry.get(id);\n return isCmElement(element) ? boundsOf(element) : undefined;\n },\n reveal(id) {\n if (destroyed) return false;\n const element = elementRegistry.get(id);\n if (!isCmElement(element)) return false;\n selection.select(element as Element);\n canvas.scrollToElement(element as Element);\n return true;\n },\n selection: () => (destroyed ? [] : elementIds(selection.get())),\n onSelection(callback) {\n const listener = (event: unknown) =>\n callback(elementIds((event as { newSelection?: unknown[] }).newSelection ?? []));\n eventBus.on(\"selection.changed\", listener);\n return () => eventBus.off(\"selection.changed\", listener);\n },\n };\n\n return {\n meta,\n elements,\n diagram,\n attachTo(host) {\n diagram.attachTo(host as HTMLElement);\n },\n async importText(text): Promise<ImportResult> {\n if (destroyed) throw new Error(\"The modeler was destroyed.\");\n const { warnings } = diagram.importText(text);\n return { warnings: warnings.map((warning) => warning.message) };\n },\n exportText() {\n // Asking a destroyed diagram would build a new one on the detached container.\n if (destroyed) return lastExport;\n return diagram.exportText();\n },\n onContentChanged(callback) {\n if (!editable) return () => undefined;\n contentListeners.add(callback);\n return () => contentListeners.delete(callback);\n },\n getViewState(): ViewState | undefined {\n if (destroyed) return undefined;\n try {\n const { x, y, width, height } = canvas.viewbox();\n const state = { x, y, width, height };\n return isViewState(state) ? state : undefined;\n } catch {\n return undefined;\n }\n },\n setViewState(state) {\n if (destroyed || !isViewState(state)) return;\n canvas.viewbox({ x: state.x, y: state.y, width: state.width, height: state.height });\n },\n contentBounds: () => (destroyed ? undefined : diagram.contentBounds()),\n destroy() {\n if (destroyed) return;\n try {\n lastExport = diagram.exportText();\n } catch {\n lastExport = \"\";\n }\n destroyed = true;\n contentListeners.clear();\n diagram.destroy();\n },\n };\n}\n\nfunction elementIds(elements: readonly unknown[]): string[] {\n return elements.filter(isCmElement).map((element) => element.id);\n}\n\n/** The shape's box, or the box around a relationship's waypoints, in diagram coordinates. */\nfunction boundsOf(element: CmElement): ElementBounds {\n const { x, y, width, height } = getBBox(element as unknown as Element);\n return { x, y, width, height };\n}\n\nfunction elementInfo(element: CmElement): ElementInfo {\n return element.cmLabel ? { id: element.id, name: element.cmLabel } : { id: element.id };\n}\n\nfunction isViewState(state: unknown): state is ViewState {\n if (typeof state !== \"object\" || state === null) return false;\n const { x, y, width, height } = state as Record<string, unknown>;\n return (\n isFiniteNumber(x) &&\n isFiniteNumber(y) &&\n isFiniteNumber(width) &&\n isFiniteNumber(height) &&\n width > 0 &&\n height > 0\n );\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n","/**\n * Four connect handles around a selected bounded context — one arrow at the\n * middle of each side (top, right, bottom, left), each pointing outward.\n * Press a handle, drag, release over another context to draw the relationship\n * (press-drag-release ONLY: a click listener would restart the tool after the\n * mouseup and leave the preview line chasing the cursor). Implemented as\n * diagram-js overlays so the handles float outside the shape, follow it, and\n * never collide with the resize handles on the selection outline.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Overlays from \"diagram-js/lib/features/overlays/Overlays\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type Connect from \"diagram-js/lib/features/connect/Connect\";\nimport type Dragging from \"diagram-js/lib/features/dragging/Dragging\";\nimport type { Element } from \"diagram-js/lib/model/Types\";\nimport { getMid } from \"diagram-js/lib/layout/LayoutUtil\";\nimport { isCmContext } from \"../model/di-types.js\";\nimport { chromeIcon } from \"../draw/lucide.js\";\nimport { READ_ONLY_CHANGED_EVENT, type CmReadOnly } from \"../read-only/index.js\";\n\nconst OVERLAY_TYPE = \"cm-connect-handle\";\nconst HANDLE_SIZE = 28;\n/** Clear of the selection outline and its mid-side resize handles. */\nconst HANDLE_GAP = 12;\n\nconst SIDES = [\n { side: \"top\", rotationDeg: -90 },\n { side: \"right\", rotationDeg: 0 },\n { side: \"bottom\", rotationDeg: 90 },\n { side: \"left\", rotationDeg: 180 },\n] as const;\n\ntype Side = (typeof SIDES)[number][\"side\"];\n\nfunction handlePosition(\n side: Side,\n shape: { width: number; height: number },\n): { top: number; left: number } {\n const centeredLeft = shape.width / 2 - HANDLE_SIZE / 2;\n const centeredTop = shape.height / 2 - HANDLE_SIZE / 2;\n const outside = HANDLE_SIZE + HANDLE_GAP;\n switch (side) {\n case \"top\":\n return { top: -outside, left: centeredLeft };\n case \"bottom\":\n return { top: shape.height + HANDLE_GAP, left: centeredLeft };\n case \"left\":\n return { top: centeredTop, left: -outside };\n case \"right\":\n return { top: centeredTop, left: shape.width + HANDLE_GAP };\n }\n}\n\nexport default class CmConnectHandles {\n static $inject = [\"eventBus\", \"selection\", \"overlays\", \"connect\", \"dragging\", \"cmReadOnly\"];\n\n constructor(\n private readonly eventBus: EventBus,\n private readonly selection: Selection,\n private readonly overlays: Overlays,\n connect: Connect,\n private readonly dragging: Dragging,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n // Not used to start the drag, but injecting Connect instantiates it so its\n // connect.* event handlers (hover/end → modeling.connect) are registered —\n // the connect module does not eagerly initialize it.\n void connect;\n const refresh = (): void => this.refresh();\n eventBus.on(\"selection.changed\", refresh);\n // Re-anchor after resize/undo/redo (handle offsets depend on width/height).\n eventBus.on(\"commandStack.changed\", refresh);\n eventBus.on(READ_ONLY_CHANGED_EVENT, refresh);\n }\n\n private refresh(): void {\n this.overlays.remove({ type: OVERLAY_TYPE });\n\n if (this.readOnly.isReadOnly()) return;\n const selected = this.selection.get() as Element[];\n if (selected.length !== 1) return;\n const element = selected[0];\n if (!isCmContext(element)) return;\n const shape = element as unknown as { width: number; height: number };\n\n for (const { side, rotationDeg } of SIDES) {\n const handle = document.createElement(\"div\");\n handle.className = \"cm-connect-handle\";\n handle.dataset.side = side;\n handle.title = \"Connect to another context\";\n handle.setAttribute(\"aria-label\", \"Connect to another context\");\n const arrow = document.createElement(\"span\");\n arrow.className = \"cm-connect-handle__arrow\";\n arrow.style.transform = `rotate(${rotationDeg}deg)`;\n arrow.innerHTML = chromeIcon(\"arrow-right\");\n handle.append(arrow);\n handle.addEventListener(\"mousedown\", (event: MouseEvent) => {\n if (event.button !== 0) return;\n event.preventDefault();\n event.stopPropagation();\n // Same payload as Connect#start, but with trapClick OFF: the ghost-\n // click trap Dragging arms after a drag is only consumed by a click\n // that reaches the canvas — a drag started on this HTML handle never\n // produces one, so the trap would instead swallow the user's NEXT\n // click on a context (no selection, seemingly broken editor).\n this.dragging.init(event, \"connect\", {\n autoActivate: false,\n trapClick: false,\n data: {\n shape: element,\n context: { start: element, connectionStart: getMid(element) },\n },\n });\n // Keep the source context marked after the drag: the drag lifecycle\n // clears the selection, but the user is still \"at\" this context. Low\n // priority so this runs after the stock cleanup listeners.\n this.eventBus.once(\"connect.cleanup\", 250, () => {\n if (this.selection.get().length === 0) this.selection.select(element);\n });\n });\n\n this.overlays.add(element, OVERLAY_TYPE, {\n position: handlePosition(side, shape),\n html: handle,\n });\n }\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport ConnectModule from \"diagram-js/lib/features/connect\";\nimport OverlaysModule from \"diagram-js/lib/features/overlays\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmConnectHandles from \"./CmConnectHandles.js\";\n\n/** Four outward connect arrows around a selected context (top/right/bottom/left). */\nexport const cmConnectHandlesModule: ModuleDeclaration = {\n __depends__: [ConnectModule, OverlaysModule, SelectionModule, cmReadOnlyModule],\n __init__: [\"cmConnectHandles\"],\n cmConnectHandles: [\"type\", CmConnectHandles],\n};\n\nexport { default as CmConnectHandles } from \"./CmConnectHandles.js\";\n","/**\n * The notation legend's content — subdomain types, integration roles and relationship patterns —\n * driven entirely by the notation spec, so it can never drift from what the canvas draws. The\n * Miragon modeler shell renders it into its legend card (`legend.render`); the rows use the\n * shell's row classes, so they look like every other modeler's legend.\n */\n\nimport {\n ALL_PATTERN_SPECS,\n ALL_SUBDOMAIN_SPECS,\n DOWNSTREAM_ROLE_SPECS,\n UPSTREAM_ROLE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type { DownstreamRole, UpstreamRole } from \"@miragon/context-maps-schema-model\";\nimport { contextIconSvg, relationshipIconSvg, roleChipSvg } from \"../draw/palette-icons.js\";\n\nexport interface LegendRow {\n /** The 24px notation preview, as SVG markup (the palette's and the context pad's). */\n readonly preview: string;\n readonly label: string;\n /** What the notation means, for the row's tooltip. */\n readonly explanation: string;\n}\n\nexport interface LegendGroup {\n readonly label: string;\n readonly rows: readonly LegendRow[];\n}\n\nconst ROLES: ReadonlyArray<{\n token: UpstreamRole | DownstreamRole;\n label: string;\n description: string;\n}> = [\n { token: \"OHS\", ...UPSTREAM_ROLE_SPECS.OHS },\n { token: \"PL\", ...UPSTREAM_ROLE_SPECS.PL },\n { token: \"ACL\", ...DOWNSTREAM_ROLE_SPECS.ACL },\n { token: \"CF\", ...DOWNSTREAM_ROLE_SPECS.CF },\n];\n\n/** The legend's groups and rows, in reading order. */\nexport function legendGroups(): LegendGroup[] {\n return [\n {\n label: \"Subdomain types\",\n rows: ALL_SUBDOMAIN_SPECS.map((spec) => ({\n preview: contextIconSvg(spec.type),\n label: spec.label,\n explanation: spec.description,\n })),\n },\n {\n label: \"Integration roles\",\n rows: ROLES.map((role) => ({\n preview: roleChipSvg(role.token),\n label: `${role.token} · ${role.label}`,\n explanation: role.description,\n })),\n },\n {\n label: \"Relationship patterns\",\n rows: ALL_PATTERN_SPECS.map((spec) => ({\n preview: relationshipIconSvg(spec.pattern),\n label: `${spec.abbreviation} · ${spec.label}`,\n explanation: spec.description,\n })),\n },\n ];\n}\n\n/**\n * The chrome tooltip of the host (the shell's `shell.tooltip`): shown after the hover delay, on\n * the chrome's tooltip layer above the legend, so a glass card's backdrop filter cannot clip it.\n */\nexport interface LegendTooltip {\n attach(control: HTMLElement, content: { label: string }): () => void;\n}\n\nexport interface LegendRenderOptions {\n /** Explains each row on hover; without it the explanation is the row's hidden description. */\n readonly tooltip?: LegendTooltip | undefined;\n}\n\n/**\n * Renders the legend's rows into `body` (the shell's `legend.render`) and returns the function\n * that detaches their tooltips again.\n */\nexport function renderLegend(body: HTMLElement, options: LegendRenderOptions = {}): () => void {\n const detachers: Array<() => void> = [];\n legendGroups().forEach((group, index) => {\n if (index > 0) {\n const separator = document.createElement(\"div\");\n separator.className = \"cd-shell-legend-separator\";\n separator.setAttribute(\"role\", \"separator\");\n body.append(separator);\n }\n const groupElement = document.createElement(\"div\");\n groupElement.className = \"cm-legend-group\";\n groupElement.setAttribute(\"role\", \"group\");\n groupElement.setAttribute(\"aria-label\", group.label);\n for (const row of group.rows) {\n const rowElement = document.createElement(\"div\");\n rowElement.className = \"cd-shell-legend-row cm-legend-row\";\n const preview = document.createElement(\"span\");\n preview.className = \"cd-shell-legend-preview\";\n preview.innerHTML = row.preview;\n const label = document.createElement(\"span\");\n label.textContent = row.label;\n rowElement.append(preview, label);\n if (options.tooltip) {\n detachers.push(options.tooltip.attach(rowElement, { label: row.explanation }));\n } else {\n const explanation = document.createElement(\"span\");\n explanation.className = \"cm-visually-hidden\";\n explanation.textContent = `: ${row.explanation}`;\n rowElement.append(explanation);\n }\n groupElement.append(rowElement);\n }\n body.append(groupElement);\n });\n return () => {\n for (const detach of detachers.splice(0)) detach();\n };\n}\n","/**\n * The notation legend as a card of its own, for hosts without the Miragon\n * modeler shell (opt-in: `additionalModules: [cmLegendModule]`; the shell\n * renders `renderLegend` into its own legend instead). A collapsible card\n * (bottom-left of the canvas): subdomain types, integration roles (OHS/PL/ACL/CF) and the\n * relationship patterns — driven entirely by the notation spec, so it can\n * never drift from what the canvas draws. Shipped by the renderer so every\n * embedder gets it, replacing the per-host copies the reference apps carried.\n * Hovering a row shows the spelled-out explanation instantly (custom CSS\n * tooltip — a native `title` only appears after the OS hover delay).\n * Collapsed it shrinks to a button in the same corner, never disappearing. It starts open, or\n * closed on a small canvas (`legendStartsOpen`).\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { chromeIcon } from \"../draw/lucide.js\";\nimport { LEGEND_CLOSED_UP_TO } from \"../theme/index.js\";\nimport { legendGroups, type LegendRow } from \"./legendContent.js\";\n\nfunction legendRow(row: LegendRow): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"cm-legend__row cm-legend-item\";\n const icon = document.createElement(\"span\");\n icon.className = \"cm-legend__icon\";\n icon.innerHTML = row.preview;\n const text = document.createElement(\"span\");\n text.textContent = row.label;\n const tip = document.createElement(\"span\");\n tip.className = \"cm-legend-tip\";\n tip.textContent = row.explanation;\n // The tip is position: fixed (anchored here) so it escapes the card's\n // scroll clipping when a small canvas forces the legend body to scroll.\n element.addEventListener(\"mouseenter\", () => {\n const bounds = element.getBoundingClientRect();\n tip.style.left = `${bounds.right + 10}px`;\n tip.style.top = `${bounds.top + bounds.height / 2}px`;\n });\n element.append(icon, text, tip);\n return element;\n}\n\nfunction group(label: string, rows: HTMLElement[]): HTMLElement {\n const el = document.createElement(\"div\");\n el.className = \"cm-legend__group\";\n el.setAttribute(\"role\", \"group\");\n el.setAttribute(\"aria-label\", label);\n el.append(...rows);\n return el;\n}\n\nfunction divider(): HTMLElement {\n const el = document.createElement(\"div\");\n el.className = \"cm-legend__divider\";\n return el;\n}\n\n/**\n * Guide §5.10: without a stored state the legend starts open, but closed in a container at most\n * `--cd-shell-sehr-schmal` wide or `--cd-shell-niedrig` high, where the open card would cover the\n * diagram.\n */\nfunction legendStartsOpen(width: number, height: number): boolean {\n return width > LEGEND_CLOSED_UP_TO.width && height > LEGEND_CLOSED_UP_TO.height;\n}\n\nexport default class CmLegend {\n static $inject = [\"canvas\", \"eventBus\"];\n\n private openState = false;\n /** Set once the container had a size to start from, or the host chose a state. */\n private started = false;\n private readonly host: HTMLElement;\n\n constructor(\n private readonly canvas: Canvas,\n eventBus: EventBus,\n ) {\n this.host = document.createElement(\"div\");\n canvas.getContainer().appendChild(this.host);\n this.startFromContainerSize();\n this.render();\n // A container attached later has no size yet: the start state waits for the first one.\n eventBus.on([\"canvas.resized\", \"import.done\"], () => {\n if (this.startFromContainerSize()) this.render();\n });\n eventBus.on(\"diagram.destroy\", () => this.host.remove());\n }\n\n isOpen(): boolean {\n return this.openState;\n }\n\n setOpen(open: boolean): void {\n this.started = true;\n if (this.openState === open) return;\n this.openState = open;\n this.render();\n }\n\n private startFromContainerSize(): boolean {\n if (this.started) return false;\n const { width, height } = this.canvas.getSize();\n if (!(width > 0 && height > 0)) return false;\n this.started = true;\n const open = legendStartsOpen(width, height);\n if (open === this.openState) return false;\n this.openState = open;\n return true;\n }\n\n toggle(): void {\n this.setOpen(!this.openState);\n }\n\n private render(): void {\n // The activated toggle removes itself with the re-render — hand the focus\n // to its counterpart so the keyboard path survives, but only when the\n // focus actually was inside (the initial render must not steal it).\n const hadFocus = this.host.contains(this.host.ownerDocument.activeElement);\n this.host.replaceChildren(this.openState ? this.panel() : this.collapsedButton());\n if (hadFocus) {\n this.host.querySelector<HTMLButtonElement>(\".cm-legend__close, .cm-legend-toggle\")?.focus();\n }\n }\n\n private panel(): HTMLElement {\n const box = document.createElement(\"div\");\n box.className = \"cm-legend\";\n box.setAttribute(\"aria-label\", \"Legend\");\n\n const head = document.createElement(\"div\");\n head.className = \"cm-legend__head\";\n const title = document.createElement(\"strong\");\n title.textContent = \"Legend\";\n const close = document.createElement(\"button\");\n close.type = \"button\";\n close.className = \"cm-legend__close\";\n close.setAttribute(\"aria-expanded\", \"true\");\n close.setAttribute(\"aria-label\", \"Close legend\");\n close.innerHTML = chromeIcon(\"x\");\n close.addEventListener(\"click\", () => this.toggle());\n head.append(title, close);\n\n const groups = legendGroups().map((entry) => group(entry.label, entry.rows.map(legendRow)));\n // Groups live in a scrollable body so a small canvas never clips the head\n // (and with it the collapse button) away.\n const body = document.createElement(\"div\");\n body.className = \"cm-legend__body\";\n groups.forEach((element, index) => body.append(...(index > 0 ? [divider()] : []), element));\n box.append(head, body);\n return box;\n }\n\n private collapsedButton(): HTMLElement {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = \"cm-legend-toggle\";\n button.setAttribute(\"aria-expanded\", \"false\");\n button.setAttribute(\"aria-label\", \"Show legend\");\n button.textContent = \"Legend\";\n button.addEventListener(\"click\", () => this.toggle());\n return button;\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmLegend from \"./CmLegend.js\";\n\n/**\n * The legend as a card on the canvas, for hosts without the Miragon modeler shell; with the shell,\n * render `renderLegend` into its legend instead.\n */\nexport const cmLegendModule: ModuleDeclaration = {\n __init__: [\"cmLegend\"],\n cmLegend: [\"type\", CmLegend],\n};\n\nexport { default as CmLegend } from \"./CmLegend.js\";\nexport { legendGroups, renderLegend } from \"./legendContent.js\";\nexport type {\n LegendGroup,\n LegendRenderOptions,\n LegendRow,\n LegendTooltip,\n} from \"./legendContent.js\";\n","/*\n * The context map's entries of the chrome menu (guide §5.4), the same in every host. The types\n * mirror the menu groups of `@miragon/modeler-shell` structurally, so an app hands the result to\n * the shell as it is while the renderer never imports the shell. The Model group's \"Legend\"\n * checkbox is the shell's own, added with its legend.\n */\n\n/** The icons the guide gives these entries (guide §5.14, the shell's common set). */\nexport type MapMenuIcon = \"file-image\" | \"file-code-corner\" | \"keyboard\";\n\ninterface MapMenuItem {\n readonly id: string;\n readonly label: string;\n readonly icon?: MapMenuIcon;\n readonly keepEnabledWhenReadOnly?: boolean;\n}\n\nexport interface MapMenuAction extends MapMenuItem {\n readonly kind: \"action\";\n readonly shortcut?: string;\n onSelect(): void;\n}\n\nexport interface MapMenuDialog extends MapMenuItem {\n readonly kind: \"dialog\";\n onSelect(): void;\n}\n\nexport type MapMenuEntry = MapMenuAction | MapMenuDialog;\n\nexport interface MapMenu {\n readonly model: readonly MapMenuEntry[];\n readonly export: readonly MapMenuEntry[];\n readonly help: readonly MapMenuEntry[];\n}\n\nexport interface MapExport {\n onSelect(): void;\n /** The chip of an app key that runs the same export, e.g. \"⌘S\". */\n readonly shortcut?: string | undefined;\n}\n\n/**\n * The exports a host offers, in the guide's order: PNG first (the more frequent target), then\n * SVG, then the map's own JSON and Context Mapper's CML.\n */\nexport interface MapExports {\n readonly png: MapExport;\n readonly svg: MapExport;\n readonly json: MapExport;\n readonly cml: MapExport;\n}\n\nexport interface MapMenuActions {\n readonly exports: MapExports;\n showKeyboardShortcuts(): void;\n /** Opens the dialog that renames the map; without it the Model group has no title entry. */\n editTitle?: (() => void) | undefined;\n}\n\n/** The map's native file in the Export group and in the shortcuts dialog. */\nexport const JSON_EXPORT_LABEL = \"Export as JSON\";\n\nfunction exportEntry(\n id: string,\n label: string,\n action: MapExport,\n icon?: MapMenuIcon,\n): MapMenuAction {\n return {\n kind: \"action\",\n id,\n label,\n ...(icon ? { icon } : {}),\n ...(action.shortcut ? { shortcut: action.shortcut } : {}),\n onSelect: () => action.onSelect(),\n };\n}\n\n/** The menu groups of the context map (guide §5.4): Model, Export with PNG first, Help. */\nexport function contextMapMenu(actions: MapMenuActions): MapMenu {\n const { editTitle } = actions;\n return {\n model: editTitle\n ? [{ kind: \"dialog\", id: \"map-title\", label: \"Map title…\", onSelect: () => editTitle() }]\n : [],\n export: [\n exportEntry(\"export-png\", \"Export as PNG\", actions.exports.png, \"file-image\"),\n exportEntry(\"export-svg\", \"Export as SVG\", actions.exports.svg, \"file-code-corner\"),\n exportEntry(\"export-json\", JSON_EXPORT_LABEL, actions.exports.json),\n exportEntry(\"export-cml\", \"Export as CML\", actions.exports.cml),\n ],\n help: [\n {\n kind: \"dialog\",\n id: \"keyboard-shortcuts\",\n label: \"Keyboard shortcuts…\",\n icon: \"keyboard\",\n onSelect: () => actions.showKeyboardShortcuts(),\n },\n ],\n };\n}\n","import { JSON_EXPORT_LABEL } from \"./menu.js\";\n\n/*\n * Every shortcut of the context map for the \"Keyboard shortcuts…\" dialog (guide §5.4): one table\n * per group, the keys as chips like the chrome tooltip's (guide §5.6). The chrome's texts and key\n * names come in structurally (a `@miragon/modeler-shell` handle fits), so the View rows say what\n * the zoom panel's tooltips say.\n */\n\nexport type ShortcutPlatform = \"mac\" | \"other\";\n\nexport interface ShortcutKeyNames {\n readonly ctrl: string;\n readonly shift: string;\n readonly plus: string;\n readonly minus: string;\n}\n\n/** What the shortcuts need of the chrome around the map. */\nexport interface ShortcutsChrome {\n readonly platform: ShortcutPlatform;\n /** The tool's UI language, for the percentage in \"Zoom to 100%\". */\n readonly lang: string;\n readonly messages: {\n readonly zoomIn: string;\n readonly zoomOut: string;\n zoomToActual(percent: string): string;\n readonly fit: string;\n /** The File group's \"Open…\" (the shell's `messages.openFile`); default \"Open…\". */\n readonly openFile?: string | undefined;\n readonly keyNames: ShortcutKeyNames;\n };\n}\n\nexport interface ShortcutRow {\n readonly action: string;\n /** Alternative key combinations, each shown as its own chip. */\n readonly keys: readonly string[];\n}\n\nexport interface ShortcutGroup {\n readonly title: string;\n readonly rows: readonly ShortcutRow[];\n}\n\nexport interface ContextMapShortcutOptions {\n /** The web app's file keys: Cmd/Ctrl+O opens a file, Cmd/Ctrl+S exports the map as JSON. */\n readonly fileKeys?: boolean | undefined;\n}\n\n/** \"⌘O\" on macOS, \"Ctrl+O\" elsewhere: the chip of a Cmd/Ctrl key the app binds itself. */\nfunction commandKeyLabel(\n key: string,\n platform: ShortcutPlatform,\n keyNames: Pick<ShortcutKeyNames, \"ctrl\">,\n): string {\n return platform === \"mac\" ? `⌘${key}` : `${keyNames.ctrl}+${key}`;\n}\n\nfunction percentOfActualSize(lang: string): string {\n try {\n return new Intl.NumberFormat(lang, { style: \"percent\" }).format(1);\n } catch {\n return new Intl.NumberFormat(\"en\", { style: \"percent\" }).format(1);\n }\n}\n\n/** The chrome's zoom and fit keys as its tooltips name them (guide §5.8). */\nfunction viewKeys(platform: ShortcutPlatform, keyNames: ShortcutKeyNames) {\n if (platform === \"mac\") {\n return { zoomIn: \"⌘+\", zoomOut: \"⌘−\", zoomToActual: \"⌘0\", fit: \"⇧1\" };\n }\n const { ctrl, shift, plus, minus } = keyNames;\n return {\n zoomIn: `${ctrl}+${plus}`,\n zoomOut: `${ctrl}+${minus}`,\n zoomToActual: `${ctrl}+0`,\n fit: `${shift}+1`,\n };\n}\n\nfunction editKeys(platform: ShortcutPlatform, keyNames: ShortcutKeyNames) {\n if (platform === \"mac\") {\n return {\n undo: [\"⌘Z\"],\n redo: [\"⌘⇧Z\"],\n selectAll: [\"⌘A\"],\n remove: [\"⌫\"],\n lineBreak: [\"⇧Enter\"],\n lassoDrag: [\"⇧ Drag\"],\n };\n }\n const { ctrl, shift } = keyNames;\n return {\n undo: [`${ctrl}+Z`],\n redo: [`${ctrl}+${shift}+Z`, `${ctrl}+Y`],\n selectAll: [`${ctrl}+A`],\n remove: [\"Del\", \"Backspace\"],\n lineBreak: [`${shift}+Enter`],\n lassoDrag: [`${shift}+Drag`],\n };\n}\n\nfunction fileGroup(chrome: ShortcutsChrome): ShortcutGroup {\n const { platform, messages } = chrome;\n return {\n title: \"File\",\n rows: [\n {\n action: messages.openFile ?? \"Open…\",\n keys: [commandKeyLabel(\"O\", platform, messages.keyNames)],\n },\n { action: JSON_EXPORT_LABEL, keys: [commandKeyLabel(\"S\", platform, messages.keyNames)] },\n ],\n };\n}\n\n/**\n * Every shortcut of the map, grouped as guide §5.4 asks (View, Edit, Tools), after the web app's\n * File keys where it binds them.\n */\nexport function contextMapShortcuts(\n chrome: ShortcutsChrome,\n options: ContextMapShortcutOptions = {},\n): ShortcutGroup[] {\n const { platform, messages } = chrome;\n const view = viewKeys(platform, messages.keyNames);\n const edit = editKeys(platform, messages.keyNames);\n return [\n ...(options.fileKeys ? [fileGroup(chrome)] : []),\n {\n title: \"View\",\n rows: [\n { action: messages.zoomIn, keys: [view.zoomIn] },\n { action: messages.zoomOut, keys: [view.zoomOut] },\n {\n action: messages.zoomToActual(percentOfActualSize(chrome.lang)),\n keys: [view.zoomToActual],\n },\n { action: messages.fit, keys: [view.fit] },\n ],\n },\n {\n title: \"Edit\",\n rows: [\n { action: \"Undo\", keys: edit.undo },\n { action: \"Redo\", keys: edit.redo },\n { action: \"Select all\", keys: edit.selectAll },\n { action: \"Delete\", keys: edit.remove },\n { action: \"Rename\", keys: [\"Double-click\"] },\n { action: \"Save a name\", keys: [\"Enter\"] },\n { action: \"Line break in a name\", keys: edit.lineBreak },\n { action: \"Discard a name\", keys: [\"Esc\"] },\n ],\n },\n {\n title: \"Tools\",\n rows: [\n { action: \"Create a context from the palette\", keys: [\"Enter\", \"Space\"] },\n { action: \"Lasso by dragging\", keys: edit.lassoDrag },\n ],\n },\n ];\n}\n","import { chromeIcon } from \"../draw/lucide.js\";\n\n/** What a dialog needs of the chrome around the map; a `@miragon/modeler-shell` handle fits. */\nexport interface DialogChrome {\n /** Where the dialog lives (the shell root), so it shares the chrome's mode and fonts. */\n readonly root: HTMLElement;\n readonly messages: { readonly close: string };\n /** The control the focus returns to once the dialog closes. */\n readonly menu: { readonly trigger: HTMLElement };\n}\n\nexport interface ChromeDialog {\n open(): void;\n isOpen(): boolean;\n close(): void;\n destroy(): void;\n}\n\nexport interface ChromeDialogSpec {\n /** Class of the `<dialog>` next to `cm-dialog`, for the dialog's own rules. */\n readonly className: string;\n readonly titleId: string;\n readonly title: string;\n /** The parts below the header, built once on the first open. */\n content(close: () => void): Node[];\n /** Runs before every open, while the dialog is still closed. */\n beforeOpen?(): void;\n /** Runs after every open, once the dialog shows and holds the focus. */\n afterOpen?(): void;\n}\n\nexport function element<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n className: string,\n text?: string,\n): HTMLElementTagNameMap[K] {\n const created = document.createElement(tag);\n created.className = className;\n if (text !== undefined) created.textContent = text;\n return created;\n}\n\nfunction header(chrome: DialogChrome, spec: ChromeDialogSpec, onClose: () => void): HTMLElement {\n const head = element(\"header\", \"cm-dialog-header\");\n const title = element(\"h3\", \"cm-dialog-title\", spec.title);\n title.id = spec.titleId;\n const close = element(\"button\", \"cm-dialog-close\");\n close.type = \"button\";\n close.setAttribute(\"aria-label\", chrome.messages.close);\n close.innerHTML = chromeIcon(\"x\");\n close.addEventListener(\"click\", onClose);\n head.append(title, close);\n return head;\n}\n\n/**\n * A dialog of the map's chrome (guide §8, \"Modeler dialogs\" of the shell's API): a native modal\n * <dialog> inside the chrome's root, so the browser keeps the focus inside it and closes it on\n * Escape. Built on the first open and kept (closed) afterwards; `destroy()` removes it. The host\n * calls it with the diagram's teardown, since the chrome removes only what it added itself.\n */\nexport function createChromeDialog(chrome: DialogChrome, spec: ChromeDialogSpec): ChromeDialog {\n let dialog: HTMLDialogElement | undefined;\n\n function build(): HTMLDialogElement {\n const created = element(\"dialog\", `cm-dialog ${spec.className}`);\n created.setAttribute(\"aria-labelledby\", spec.titleId);\n const close = (): void => created.close();\n const panel = element(\"div\", \"cm-dialog-panel\");\n panel.append(header(chrome, spec, close), ...spec.content(close));\n created.append(panel);\n // A click on the backdrop targets the <dialog> itself; the panel covers all of its own box.\n created.addEventListener(\"click\", (event) => {\n if (event.target === created) created.close();\n });\n created.addEventListener(\"close\", () => {\n if (!chrome.menu.trigger.hidden) chrome.menu.trigger.focus({ preventScroll: true });\n });\n chrome.root.append(created);\n return created;\n }\n\n return {\n open() {\n dialog ??= build();\n if (dialog.open) return;\n spec.beforeOpen?.();\n dialog.showModal();\n spec.afterOpen?.();\n },\n close() {\n dialog?.close();\n },\n isOpen: () => dialog?.open === true,\n destroy() {\n dialog?.remove();\n dialog = undefined;\n },\n };\n}\n","import { createChromeDialog, element, type ChromeDialog, type DialogChrome } from \"./dialog.js\";\nimport {\n contextMapShortcuts,\n type ContextMapShortcutOptions,\n type ShortcutGroup,\n type ShortcutsChrome,\n} from \"./shortcuts.js\";\n\nconst DIALOG_CLASS = \"cm-shortcuts\";\nconst TITLE_ID = \"cm-shortcuts-title\";\n\n/** What the dialog needs of the chrome around the map; a `@miragon/modeler-shell` handle fits. */\nexport interface ShortcutsDialogChrome extends ShortcutsChrome, DialogChrome {\n readonly messages: ShortcutsChrome[\"messages\"] & DialogChrome[\"messages\"];\n}\n\nexport type ShortcutsDialog = ChromeDialog;\n\nfunction shortcutTable(group: ShortcutGroup, index: number): HTMLElement {\n const section = element(\"section\", `${DIALOG_CLASS}-group`);\n const headingId = `${TITLE_ID}-group-${index}`;\n const heading = element(\"h4\", `${DIALOG_CLASS}-group-title`, group.title);\n heading.id = headingId;\n const table = element(\"table\", `${DIALOG_CLASS}-table`);\n table.setAttribute(\"aria-labelledby\", headingId);\n const body = table.createTBody();\n for (const row of group.rows) {\n const line = body.insertRow();\n const action = element(\"th\", `${DIALOG_CLASS}-action`, row.action);\n action.scope = \"row\";\n const keys = element(\"td\", `${DIALOG_CLASS}-keys`);\n for (const key of row.keys) keys.append(element(\"kbd\", `${DIALOG_CLASS}-key`, key));\n line.append(action, keys);\n }\n section.append(heading, table);\n return section;\n}\n\n/**\n * The \"Keyboard shortcuts…\" dialog of the Help group (guide §5.4, §8): one table per group, the\n * keys as chips like the chrome tooltip's.\n */\nexport function createShortcutsDialog(\n chrome: ShortcutsDialogChrome,\n options: ContextMapShortcutOptions = {},\n): ShortcutsDialog {\n return createChromeDialog(chrome, {\n className: DIALOG_CLASS,\n titleId: TITLE_ID,\n title: \"Keyboard shortcuts\",\n content() {\n const body = element(\"div\", \"cm-dialog-body cm-shortcuts-body\");\n body.append(...contextMapShortcuts(chrome, options).map(shortcutTable));\n return [body];\n },\n });\n}\n","import { createChromeDialog, element, type ChromeDialog, type DialogChrome } from \"./dialog.js\";\n\nconst DIALOG_CLASS = \"cm-title-dialog\";\nconst TITLE_ID = \"cm-title-dialog-title\";\nconst FIELD_ID = \"cm-title-dialog-field\";\n\n/** The map's title, read when the dialog opens and written when it applies. */\nexport interface MapTitle {\n title(): string;\n setTitle(title: string): void;\n}\n\nexport type TitleDialogChrome = DialogChrome;\nexport type TitleDialog = ChromeDialog;\n\nfunction button(label: string, variant: \"primary\" | \"secondary\"): HTMLButtonElement {\n const created = element(\"button\", \"cm-dialog-button\", label);\n created.type = variant === \"primary\" ? \"submit\" : \"button\";\n created.dataset.variant = variant;\n return created;\n}\n\n/**\n * The \"Map title…\" dialog of the Model group: guide §5.4 keeps form fields out of the menu, so the\n * entry opens a dialog (§8) with the title field, Cancel and Apply. Enter applies, Escape cancels;\n * an unchanged title writes nothing, so the map's history gets no empty step.\n */\nexport function createTitleDialog(chrome: TitleDialogChrome, mapTitle: MapTitle): TitleDialog {\n const field = element(\"input\", \"cm-dialog-input\");\n field.id = FIELD_ID;\n field.type = \"text\";\n field.autocomplete = \"off\";\n field.spellcheck = false;\n // showModal() focuses the first focusable element, which would be the header's Close button.\n field.autofocus = true;\n\n return createChromeDialog(chrome, {\n className: DIALOG_CLASS,\n titleId: TITLE_ID,\n title: \"Map title\",\n beforeOpen() {\n field.value = mapTitle.title();\n },\n afterOpen() {\n field.select();\n },\n content(close) {\n const form = element(\"form\", \"cm-dialog-form\");\n form.noValidate = true;\n const body = element(\"div\", \"cm-dialog-body\");\n const label = element(\"label\", \"cm-dialog-label\", \"Title\");\n label.htmlFor = FIELD_ID;\n body.append(label, field);\n const footer = element(\"div\", \"cm-dialog-footer\");\n const cancel = button(\"Cancel\", \"secondary\");\n cancel.addEventListener(\"click\", close);\n footer.append(cancel, button(\"Apply\", \"primary\"));\n form.append(body, footer);\n form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n const title = field.value.trim();\n close();\n if (title !== mapTitle.title()) mapTitle.setTitle(title);\n });\n return [form];\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["svgAttr","svgCreate","OVERLAY_TYPE","DIALOG_CLASS","TITLE_ID","Diagram","CroppingConnectionDocking","ElementFactory","BaseRenderer","SelectionModule","ZoomScrollModule","MoveCanvasModule","ConnectionPreviewModule","ModelingModule","MoveModule","OutlineModule","RulesModule","RuleProvider","CommandInterceptor","PaletteModule","CreateModule","ConnectModule","LassoToolModule","DirectEditingModule","ContextPadModule","PopupMenuModule","AutoPlaceModule","OverlaysModule","kindOf","el","isCmElement","isCmContext","isCmRelationship","MARGIN","LIVE_CANVAS_ATTRIBUTES","saveSVG","source","canvas","minX","minY","maxX","maxY","elementRegistry","s","x","y","width","height","clone","attribute","viewport","MIRAGON","CD_TOKENS","TT_RENDER_PRIORITY","INK","INK_SOFT","FONT","PAPER","NEUTRAL_FILL","NEUTRAL_STROKE","measureContext","textWidth","fontWeight","fontSize","text","TYPE_LABEL","TEAM_ICON_GAP","TEAM_ROW_FROM_BOTTOM","teamRowLayout","estimatedTextWidth","team","left","contextWidth","textX","contextHeight","typeLabelRight","SUBDOMAIN_TYPE_SPECS","type","letterSpacing","label","contextDrawnSpan","right","context","row","contentBoundsOf","top","bottom","include","element","elements","span","point","ROOT_ID","DIAGRAM_ROOT_ID","DEFAULT_FREE_RECT_INSETS","SMALLEST_FIT_ZOOM","sizeToCss","value","CmBaseViewer","options","container","modules","name","freeArea","freeRectInsets","event","priority","callback","diagram","eventBus","importer","doc","labelEditing","warnings","parsed","parseDocumentText","serializeDocumentText","partial","root","modeling","content","insets","freeWidth","freeHeight","contentWidth","contentHeight","scale","target","foreignAttributes","foreign","foreignFields","knownKeys","CmElementFactory","elementFactory","minSize","ctx","CONTEXT_KEYS","rel","RELATIONSHIP_KEYS","size","subdomainType","CmDiagramElementFactory","attrs","newId","CmLayouter","docking","hints","connection","provisional","getMid","cmModelModule","endRoleChipLayout","roles","dx","toward","endpoint","dy","length","ux","uy","charW","chipHeight","chipWidths","role","innerWidth","a","b","dist","direction","center","ContextMapsRenderer","clear","visuals","rect","attr","create","append","line","p","shape","wp","idx","spec","w","h","box","subdomainIcon","badge","icon","peopleIcon","RELATIONSHIP_PATTERN_SPECS","dash","src","tgt","upRoles","downRoles","mx","my","cs","len","dirColor","MARK_COLORS","letter","layout","widths","chipH","innerW","cy","parent","i","fill","gap","bg","cx","darken","t","MARK_TEXT_COLOR","bgFill","border","textFill","maxWidth","lines","wrapLabel","lineHeight","available","hasTeam","maxLines","ellipsize","startY","ln","m","hex","n","f","STAR_PATH","HAND_PATH","g","c","color","rot","path","PEOPLE_PATH","kept","paragraphs","paragraph","wrapParagraph","words","fits","candidate","current","word","rest","low","high","mid","cmDrawModule","borderPoint","sx","sy","centre","CmImporter","factory","seen","reserved","reservedIdProblem","id","DOCUMENT_KEYS","unplacedRelationships","byId","waypoints","other","roots","CmExporter","meta","contexts","relationships","geom","DOCUMENT_VERSION","ioModule","Viewer","POINTER_OFFSET","EDGE_MARGIN","hoverTipFor","parts","pattern","CmHoverTooltip","place","bounds","hide","tip","cmHoverTooltipModule","NavigatedViewer","setOrDelete","obj","key","UpdatePropertiesHandler","old","properties","oldProperties","swap","oldSource","SwapEndsHandler","UpdateTitleHandler","UPDATE_PROPERTIES","SWAP_ENDS","UPDATE_TITLE","CmModeling","commandStack","graphicsFactory","gfx","relationship","description","props","isSymmetricPattern","up","r","down","tech","cmModelingModule","CmRules","canConnect","alreadyConnected","incoming","outgoing","ignore","cmRulesModule","CmFlatModelBehavior","multiMove","shapes","attached","sourceId","targetId","DRAGGING_CLS","CmDragBehavior","BEFORE_SELECTION_BEHAVIOR","cmBehaviorsModule","selection","READ_ONLY_CHANGED_EVENT","LOCK_PRIORITY","EDIT_RULES","CmReadOnly","bus","readOnly","cmReadOnlyModule","MARKERS","LABEL_INSET_X","TEAM_BAND_HEIGHT","CmLabelEditing","directEditing","newText","marker","active","edit","textbox","placeCaretAtEnd","originalEvent","zoom","bbox","containerTop","style","reserve","range","field","cmLabelEditingModule","svg","inner","STAR","HAND","subdomainGlyph","contextIconSvg","subdomainIconSvg","roleChipSvg","relationshipIconSvg","LUCIDE","lucideSvg","strokeWidth","chromeIcon","toolIcon","GROUP_TOOLS","GROUP_CONTEXTS","KEYBOARD_CREATE_OFFSET","entryHtml","draggable","sentenceCase","isKeyboardClick","CmPaletteProvider","lassoTool","config","palette","entries","ALL_SUBDOMAIN_SPECS","start","named","taken","created","viewbox","cmPaletteModule","SUBDOMAIN_MENU","PATTERN_MENU","ROLES_MENU","ACTIVE_CLASS","MENU_GAP","CUSTOMER_SUPPLIER_BLOCKERS","escapeAttribute","padEntryHtml","danger","title","placePromptBeside","anchor","cardBounds","card","CmContextPadProvider","contextPad","popupMenu","autoPlace","rules","dragging","cmModeling","scheduler","selected","position","asTRBL","DEFAULT_DISTANCE","findFreePosition","generateGetNextPosition","pad","flipX","flipY","last","previous","containerBounds","padBounds","overflowRight","overflowLeft","shiftY","overflowBottom","overflowTop","cmElements","viaClick","swallowGestureClick","disarm","appended","onCreated","entry","hint","followPad","done","cleanup","commit","changed","keyEvent","menuId","entryBounds","popup","popupBounds","menu","ALL_PATTERN_SPECS","customerSupplier","upstream","downstream","UPSTREAM_ROLES","blocker","blocked","UPSTREAM_ROLE_SPECS","existing","DOWNSTREAM_ROLES","DOWNSTREAM_ROLE_SPECS","cmContextPadModule","isTypingTarget","isCanvasTarget","ownerDocument","CmKeyboard","undoRedoKeys","onKeydown","cmd","isUndo","isRedo","sel","cmKeyboardModule","OVERLAY_TYPE$1","MARKER_SIZE","LINE_OFFSET","END_DISTANCE","markerHtml","hasError","findings","finding","tooltip","message","anchorPoint","end","side","corner","along","baseX","baseY","cmValidationModule","overlays","exporter","refresh","report","validateDocument","byAnchor","collect","group","markerX","markerY","bboxX","bboxY","tier","CmZOrder","ordered","wrapper","layer","cmZOrderModule","Modeler","CONTEXT_MAPS_NOTATION","createCollaborativeModeler","collaborative","diagramOptions","createCollaborativeViewer","contentListeners","destroyed","lastExport","MODELER_API_VERSION","editable","listener","elementInfo","boundsOf","elementIds","host","warning","state","isViewState","getBBox","isFiniteNumber","OVERLAY_TYPE","HANDLE_SIZE","HANDLE_GAP","SIDES","handlePosition","centeredLeft","centeredTop","CmConnectHandles","handle","arrow","rotationDeg","cmConnectHandlesModule","ROLES","legendGroups","renderLegend","detachers","index","separator","body","groupElement","rowElement","preview","explanation","detach","legendRow","rows","divider","CmLegend","open","hadFocus","head","close","groups","button","cmLegendModule","JSON_EXPORT_LABEL","exportEntry","action","contextMapMenu","actions","editTitle","commandKeyLabel","platform","keyNames","percentOfActualSize","lang","viewKeys","ctrl","plus","minus","shift","editKeys","fileGroup","chrome","messages","contextMapShortcuts","view","tag","className","header","onClose","createChromeDialog","dialog","build","panel","DIALOG_CLASS$1","TITLE_ID$1","shortcutTable","section","headingId","heading","table","keys","createShortcutsDialog","DIALOG_CLASS","TITLE_ID","FIELD_ID","variant","createTitleDialog","mapTitle","form","footer","cancel"],"sources":["../src/model/di-types.ts","../src/io/saveSvg.ts","../src/theme/palette.ts","../src/draw/styles.ts","../src/draw/textMetrics.ts","../src/draw/contextLayout.ts","../src/model/contentBounds.ts","../src/io/types.ts","../src/CmBaseViewer.ts","../src/model/CmElementFactory.ts","../src/model/CmDiagramElementFactory.ts","../src/model/CmLayouter.ts","../src/model/index.ts","../src/draw/endRoleChips.ts","../src/draw/ContextMapsRenderer.ts","../src/draw/index.ts","../src/io/CmImporter.ts","../src/io/CmExporter.ts","../src/io/index.ts","../src/Viewer.ts","../src/hover-tooltip/CmHoverTooltip.ts","../src/hover-tooltip/index.ts","../src/NavigatedViewer.ts","../src/modeling/cmd/UpdatePropertiesHandler.ts","../src/modeling/cmd/SwapEndsHandler.ts","../src/modeling/cmd/UpdateTitleHandler.ts","../src/modeling/CmModeling.ts","../src/modeling/index.ts","../src/rules/CmRules.ts","../src/rules/index.ts","../src/behaviors/CmFlatModelBehavior.ts","../src/behaviors/CmDragBehavior.ts","../src/behaviors/CmClickSelectionBehavior.ts","../src/behaviors/index.ts","../src/read-only/CmReadOnly.ts","../src/read-only/index.ts","../src/label-editing/CmLabelEditing.ts","../src/label-editing/index.ts","../src/draw/palette-icons.ts","../src/draw/lucide.ts","../src/palette/CmPaletteProvider.ts","../src/palette/index.ts","../src/context-pad/CmContextPadProvider.ts","../src/context-pad/index.ts","../src/keyboard/CmKeyboard.ts","../src/keyboard/index.ts","../src/validation/CmValidationMarkers.ts","../src/validation/index.ts","../src/zorder/CmZOrder.ts","../src/zorder/index.ts","../src/Modeler.ts","../src/collaborative/CollaborativeContextMaps.ts","../src/connect-handles/CmConnectHandles.ts","../src/connect-handles/index.ts","../src/legend/legendContent.ts","../src/legend/CmLegend.ts","../src/legend/index.ts","../src/chrome/menu.ts","../src/chrome/shortcuts.ts","../src/chrome/dialog.ts","../src/chrome/ShortcutsDialog.ts","../src/chrome/TitleDialog.ts"],"sourcesContent":["/**\n * diagram-js runtime model for the Context Maps notation.\n *\n * - `context` — a bounded context: a placed, resizable SHAPE (box) with a\n * label, optional owning team and subdomain classification.\n * - `relationship` — a context-mapping pattern: a CONNECTION (edge) between two\n * contexts, carrying a pattern plus upstream/downstream roles.\n *\n * These runtime properties are the source of truth while editing; the exporter\n * rebuilds the canonical `CmDocument` from them.\n */\n\nimport type { Connection, Shape } from \"diagram-js/lib/model/Types\";\nimport type {\n DownstreamRole,\n RelationshipPattern,\n SubdomainType,\n UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\n\nexport type CmKind = \"context\" | \"relationship\";\n\nexport interface CmContext extends Shape {\n cmKind: \"context\";\n subdomainType?: SubdomainType;\n /** Display name (separate from diagram-js `label`). */\n cmLabel?: string;\n team?: string;\n description?: string;\n fill?: string;\n stroke?: string;\n /** Keys of the document's context this version does not know, written back on export. */\n cmForeign?: Record<string, unknown>;\n}\n\nexport interface CmRelationship extends Connection {\n cmKind: \"relationship\";\n pattern: RelationshipPattern;\n upstreamRoles?: UpstreamRole[];\n downstreamRoles?: DownstreamRole[];\n cmLabel?: string;\n description?: string;\n implementationTechnology?: string;\n /** Keys of the document's relationship this version does not know, written back on export. */\n cmForeign?: Record<string, unknown>;\n}\n\nexport type CmElement = CmContext | CmRelationship;\n\nfunction kindOf(el: unknown): string | undefined {\n return typeof el === \"object\" && el !== null\n ? ((el as { cmKind?: unknown }).cmKind as string | undefined)\n : undefined;\n}\n\nexport function isCmElement(el: unknown): el is CmElement {\n return typeof kindOf(el) === \"string\";\n}\n\nexport function isCmContext(el: unknown): el is CmContext {\n return kindOf(el) === \"context\";\n}\n\nexport function isCmRelationship(el: unknown): el is CmRelationship {\n return kindOf(el) === \"relationship\";\n}\n","/**\n * Serialises the current canvas into a standalone SVG (snapshot / export),\n * fitted to the content bounds and independent of the current zoom / scroll.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport { isCmContext } from \"../model/di-types.js\";\n\nconst MARGIN = 40;\n\n/** What the live canvas <svg> carries for keyboard and screen-reader users, not for a picture. */\nconst LIVE_CANVAS_ATTRIBUTES = [\"tabindex\", \"role\", \"aria-label\"];\n\nexport function saveSVG(canvas: Canvas, elementRegistry: ElementRegistry): { svg: string } {\n // The container's own <svg> child: a chrome that moves the palette in front of it (the modeler\n // shell does) puts the palette's icon <svg>s first in the container.\n const source = canvas.getContainer().querySelector(\":scope > svg\");\n if (!source) throw new Error(\"No SVG found in the canvas container.\");\n\n // Content bounds from the context boxes (relationship lines stay within them).\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const el of elementRegistry.getAll()) {\n if (!isCmContext(el)) continue;\n const s = el as unknown as { x: number; y: number; width: number; height: number };\n minX = Math.min(minX, s.x);\n minY = Math.min(minY, s.y);\n maxX = Math.max(maxX, s.x + s.width);\n maxY = Math.max(maxY, s.y + s.height);\n }\n if (!Number.isFinite(minX)) {\n minX = 0;\n minY = 0;\n maxX = 100;\n maxY = 100;\n }\n\n const x = minX - MARGIN;\n const y = minY - MARGIN;\n const width = maxX - minX + MARGIN * 2;\n const height = maxY - minY + MARGIN * 2;\n\n const clone = source.cloneNode(true) as SVGSVGElement;\n for (const attribute of LIVE_CANVAS_ATTRIBUTES) clone.removeAttribute(attribute);\n clone.setAttribute(\"xmlns\", \"http://www.w3.org/2000/svg\");\n clone.setAttribute(\"viewBox\", `${x} ${y} ${width} ${height}`);\n clone.setAttribute(\"width\", String(Math.round(width)));\n clone.setAttribute(\"height\", String(Math.round(height)));\n\n // Neutralise pan/zoom: let the viewBox (above) drive the geometry.\n const viewport = clone.querySelector<SVGGElement>(\".viewport\");\n if (viewport) viewport.removeAttribute(\"transform\");\n\n const svg = new XMLSerializer().serializeToString(clone);\n return { svg: '<?xml version=\"1.0\" encoding=\"utf-8\"?>\\n' + svg };\n}\n","/**\n * Miragon design tokens — the single source of truth for every non-notation colour the renderer\n * draws into SVG.\n *\n * Values mirror the Miragon design system: the `miragon-brand:modeler-tool-design` skill in\n * `Miragon/corporate-identity`, whose files are vendored unchanged next to this module\n * (`cd-tokens.generated.css`, `cd-tokens.generated.json`, `cd-canvas.css`; design system 1.15.0,\n * unchanged since 1.13.0).\n * Re-copy them from the skill to update; never fork the hex values by hand. SVG attributes need\n * literal values (exports carry presentation attributes, never `var()`), so `draw/styles.ts`\n * derives its colours from `MIRAGON`; the in-canvas chrome in `assets/context-maps.css` reads the\n * `--cd-ui-*` roles directly. `test/theme.sync.test.ts` fails if a value here drifts from the\n * vendored files.\n *\n * Pure data — no DOM, no imports. The subdomain-type fills and relationship-pattern strokes are the\n * official Context Maps notation and live in `schema-model/notation.ts`; they are NOT part of this\n * brand ramp. The renderer draws light only (the modelers switch to dark together, guide §13.3).\n */\n\n/** Raw Miragon brand ramp and status layer — the `fest` values of `cd-tokens.generated.json`. */\nexport const MIRAGON = {\n /** Primary: surfaces, buttons, links, selection, backgrounds. */\n blau: \"#335DE5\",\n /** Deeper blue for links / accent text on white (WCAG AA, ~5.5:1). */\n blauLink: \"#2B50D4\",\n /** Lightened blue for accents on dark surfaces (unused here — the canvas is light-only). */\n blauHell: \"#6B8AFF\",\n /** Accent: key visual, highlights, the brand gradient. Bright — a fill, never text on white. */\n gruen: \"#00E676\",\n /** Calm neutral surface (warm off-white) — the paper surround. */\n grau: \"#F9F7F7\",\n /** Text on light; not pure black. */\n schwarz: \"#1D1D1D\",\n weiss: \"#FFFFFF\",\n /** Fixed light neutral for lines and borders on a light stage. */\n linie: \"#E6E2E2\",\n /**\n * Status layer (guide §3.3): fills, borders, icons and dots; as text on white only `danger` and\n * `info` reach AA.\n */\n success: \"#00E676\",\n warning: \"#FFB000\",\n danger: \"#CD1839\",\n info: \"#335DE5\",\n /** Signature brand gradient — brand moments only. Use verbatim. */\n gradientBrand: \"linear-gradient(120deg, #335DE5 30%, #00E676)\",\n} as const;\n\n/**\n * Every fixed `--cd-*` token this repo mirrors, mapped to the value it MUST hold in the vendored\n * files (`fest` in the JSON, `:root` in the CSS).\n */\nexport const CD_TOKENS: Record<string, string> = {\n \"--cd-blau\": MIRAGON.blau,\n \"--cd-gruen\": MIRAGON.gruen,\n \"--cd-grau\": MIRAGON.grau,\n \"--cd-schwarz\": MIRAGON.schwarz,\n \"--cd-weiss\": MIRAGON.weiss,\n \"--cd-blau-link\": MIRAGON.blauLink,\n \"--cd-blau-hell\": MIRAGON.blauHell,\n \"--cd-linie\": MIRAGON.linie,\n \"--cd-success\": MIRAGON.success,\n \"--cd-warning\": MIRAGON.warning,\n \"--cd-danger\": MIRAGON.danger,\n \"--cd-info\": MIRAGON.info,\n \"--cd-gradient-brand\": MIRAGON.gradientBrand,\n};\n","/** Shared rendering constants (typography, accent, priorities) — Miragon corporate identity.\n * Colours are derived from the single source of truth in `theme/palette.ts` (`MIRAGON`), which\n * mirrors the vendored `--cd-*` brand tokens. */\n\nimport { MIRAGON } from \"../theme/index.js\";\n\n/** BaseRenderer default priority is 1000; 1500 wins the render.shape/connection event. */\nexport const TT_RENDER_PRIORITY = 1500;\n\n/** Selection / hover accent (Miragon blue — kept in sync with the app theme via the shared palette). */\nexport const ACCENT = MIRAGON.blau;\n\nexport const INK = MIRAGON.schwarz;\nexport const INK_SOFT = \"#5B5B5B\";\n\nexport const FONT = {\n /**\n * Set directly as the `font-family` attribute on every SVG <text> (canvas\n * labels and therefore the SVG export too) — not inherited from a CSS\n * container. Prefers the self-hosted Miragon typeface Geist (registered as\n * 'Geist Variable' by @fontsource-variable/geist, with 'Geist' as a fallback\n * name), and falls back to a system sans when the host hasn't loaded it (e.g.\n * an exported SVG opened standalone).\n */\n family:\n \"'Geist Variable', 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif\",\n label: 13.5,\n small: 11,\n} as const;\n\n/**\n * Fixed top offset (px at zoom 1) of a context's name inside its box: the\n * first line starts here, right below the subdomain-type header, so the gap\n * between header and name never varies with box size or line count.\n */\nexport const CONTEXT_NAME_TOP = 36;\n\n/** Height (px at zoom 1) reserved at the box bottom for the team caption. */\nexport const CONTEXT_TEAM_RESERVE = 18;\n\n/** Paper colour used for the label halo so text stays legible over lines. */\nexport const PAPER = MIRAGON.weiss;\n\n/** Box colours for contexts without a subdomain classification (canvas + icons). */\nexport const NEUTRAL_FILL = \"#F1F1EE\";\nexport const NEUTRAL_STROKE = \"#8A8577\";\n","import { FONT } from \"./styles.js\";\n\n/**\n * Real text measurement so the rendered wrap matches the browser's own wrap\n * in the direct-editing box (same font, same width): a shared 2D context\n * measures actual glyph widths; the character-count heuristic remains only\n * as a fallback for environments without canvas support.\n */\nlet measureContext: CanvasRenderingContext2D | null | undefined;\n\n/**\n * The advance width of `text` at zoom 1. A canvas measures it, not the SVG: Chromium lays SVG text\n * out at the scaled font size, so a width read from the drawing would change with the zoom.\n */\nexport function textWidth(text: string, fontSize: number, fontWeight: string): number {\n if (measureContext === undefined) {\n measureContext =\n typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\");\n }\n if (!measureContext) return text.length * fontSize * 0.58;\n measureContext.font = `${fontWeight} ${fontSize}px ${FONT.family}`;\n return measureContext.measureText(text).width;\n}\n","import { SUBDOMAIN_TYPE_SPECS, type SubdomainType } from \"@miragon/context-maps-schema-model\";\nimport type { CmContext } from \"../model/di-types.js\";\nimport { FONT } from \"./styles.js\";\nimport { textWidth } from \"./textMetrics.js\";\n\n/** The subdomain type's name in a context's header, right of its icon (context coordinates). */\nexport const TYPE_LABEL = { x: 28, y: 15, fontWeight: \"700\", letterSpacingEm: 0.03 } as const;\n\nexport const TEAM_ICON_SIZE = 14;\nconst TEAM_ICON_GAP = 5;\nconst TEAM_ROW_FROM_BOTTOM = 12;\n\n/** The people icon and the team's name at the bottom of a context, in context coordinates. */\nexport interface TeamRowLayout {\n /** The icon's left edge, where the row starts. */\n left: number;\n iconCenterX: number;\n textX: number;\n centerY: number;\n /** Where the team's name ends as the canvas draws it. */\n right: number;\n}\n\nexport function teamRowLayout(\n contextWidth: number,\n contextHeight: number,\n team: string,\n): TeamRowLayout {\n // Centred on an estimate of the name's width, which no font load changes, so the row stays where\n // it is drawn; only its end follows the font the canvas shows.\n const estimatedTextWidth = team.length * FONT.small * 0.55;\n const left = contextWidth / 2 - (TEAM_ICON_SIZE + TEAM_ICON_GAP + estimatedTextWidth) / 2;\n const textX = left + TEAM_ICON_SIZE + TEAM_ICON_GAP;\n return {\n left,\n iconCenterX: left + TEAM_ICON_SIZE / 2,\n textX,\n centerY: contextHeight - TEAM_ROW_FROM_BOTTOM,\n right: textX + textWidth(team, FONT.small, \"400\"),\n };\n}\n\n/** Where the subdomain type's name in the header ends, in context coordinates. */\nexport function typeLabelRight(type: SubdomainType): number {\n const { label } = SUBDOMAIN_TYPE_SPECS[type];\n const letterSpacing = TYPE_LABEL.letterSpacingEm * FONT.small;\n return (\n TYPE_LABEL.x +\n textWidth(label, FONT.small, TYPE_LABEL.fontWeight) +\n label.length * letterSpacing\n );\n}\n\n/**\n * The horizontal span a context draws, in diagram coordinates: its box, wider where the type's\n * name or the team row runs past its sides, since neither is cut to the box. Vertically both stay\n * inside, as every context is at least the notation's minimum size.\n */\nexport function contextDrawnSpan(\n context: Pick<CmContext, \"x\" | \"width\" | \"subdomainType\" | \"team\">,\n): { left: number; right: number } {\n let left = 0;\n let right = context.width;\n if (context.subdomainType && SUBDOMAIN_TYPE_SPECS[context.subdomainType]) {\n right = Math.max(right, typeLabelRight(context.subdomainType));\n }\n if (context.team) {\n const row = teamRowLayout(context.width, 0, context.team);\n left = Math.min(left, row.left);\n right = Math.max(right, row.right);\n }\n return { left: context.x + left, right: context.x + right };\n}\n","import type { ElementBounds } from \"@miragon/modeler-api\";\nimport { contextDrawnSpan } from \"../draw/contextLayout.js\";\nimport { isCmContext, isCmRelationship } from \"./di-types.js\";\n\n/**\n * The tight box around what the canvas draws of the map, in diagram coordinates, without a margin:\n * every context's box with the type's name and the team row where they run past its sides, and\n * every relationship's waypoints. The markers and role chips on a relationship sit between the\n * contexts it connects. `undefined` while there is nothing to draw.\n *\n * Read from the model, never from the SVG: Chromium measures SVG text at the scaled font size, so a\n * measured box would change with the zoom.\n */\nexport function contentBoundsOf(elements: Iterable<unknown>): ElementBounds | undefined {\n let left = Infinity;\n let top = Infinity;\n let right = -Infinity;\n let bottom = -Infinity;\n const include = (x: number, y: number, width: number, height: number): void => {\n if (![x, y, width, height].every(Number.isFinite)) return;\n left = Math.min(left, x);\n top = Math.min(top, y);\n right = Math.max(right, x + width);\n bottom = Math.max(bottom, y + height);\n };\n for (const element of elements) {\n if (isCmContext(element)) {\n const span = contextDrawnSpan(element);\n include(span.left, element.y, span.right - span.left, element.height);\n } else if (isCmRelationship(element)) {\n for (const point of element.waypoints ?? []) include(point.x, point.y, 0, 0);\n }\n }\n if (left > right || top > bottom) return undefined;\n return { x: left, y: top, width: right - left, height: bottom - top };\n}\n","import { DIAGRAM_ROOT_ID, type Relationship } from \"@miragon/context-maps-schema-model\";\n\n/** ID of the diagram-js root element holding the Context Maps diagram. */\nexport const ROOT_ID = DIAGRAM_ROOT_ID;\n\nexport interface ImportWarning {\n readonly message: string;\n readonly elementId?: string;\n}\n\n/** Diagram-level data stashed on the root element. */\nexport interface RootBusinessObject {\n title: string;\n /** Keys of the document this version does not know, written back on export. */\n foreign?: Record<string, unknown>;\n /**\n * Relationships whose ends are not both contexts of the map. The canvas cannot draw them, but\n * they stay in the document (and in the Problems view) until the text fixes them.\n */\n unplacedRelationships?: Relationship[];\n}\n","/**\n * Shared lifecycle & DI bootstrap for every Context Maps viewer. Subclasses\n * only override `_getModules()`. The renderer\n * is framework-agnostic — mount it into any element (e.g. a VS Code webview).\n */\n\nimport Diagram from \"diagram-js/lib/Diagram\";\nimport type { ModuleDeclaration } from \"didi\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type PopupMenu from \"diagram-js/lib/features/popup-menu/PopupMenu\";\nimport type { Root } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport type { ElementBounds, FreeArea } from \"@miragon/modeler-api\";\nimport { parseDocumentText, serializeDocumentText } from \"@miragon/context-maps-schema-model\";\nimport type { CmDocument } from \"@miragon/context-maps-schema-model\";\nimport { saveSVG } from \"./io/saveSvg.js\";\nimport type CmImporter from \"./io/CmImporter.js\";\nimport type CmExporter from \"./io/CmExporter.js\";\nimport type CmLabelEditing from \"./label-editing/CmLabelEditing.js\";\nimport type CmModeling from \"./modeling/CmModeling.js\";\nimport type CmReadOnly from \"./read-only/CmReadOnly.js\";\nimport { contentBoundsOf } from \"./model/contentBounds.js\";\nimport { ROOT_ID, type ImportWarning, type RootBusinessObject } from \"./io/types.js\";\n\n/** Container margins in screen px that a host's chrome covers. */\nexport interface FreeRectInsets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nexport interface CmViewerOptions {\n /** Host element. When absent, a detached <div> is created (attach later). */\n container?: HTMLElement | undefined;\n width?: number | string | undefined;\n height?: number | string | undefined;\n /** Appended to the module list (extension point). */\n additionalModules?: ModuleDeclaration[] | undefined;\n /**\n * Bind Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z and Cmd/Ctrl+Y to the canvas undo/redo (default true).\n * Pass false when the host owns the history (the VS Code document), so the keys reach it.\n */\n undoRedoKeys?: boolean | undefined;\n /**\n * The part of the container the host's chrome (palette row, zoom panel, legend) leaves free, under\n * its `@miragon/modeler-api` name: `{ insets }`, the margins the chrome covers, or `{ center }`,\n * the free rectangle's centre in diagram coordinates. An element created from the palette with\n * Enter or Space lands in that centre, and the fit after an import centres the content in what\n * the insets leave (guide §5.5, §5.9). Default: room for the renderer's own palette, which the\n * fit also keeps when only `center` is given.\n */\n freeArea?: FreeArea | undefined;\n /** @deprecated Use `freeArea: { insets }`; accepted through the 0.5 releases, ignored next to it. */\n freeRectInsets?: (() => FreeRectInsets) | undefined;\n /**\n * Fit the content into the view after every import (default true). Pass false when the host's\n * chrome fits the content itself, so the view changes once per import.\n */\n fitOnImport?: boolean | undefined;\n}\n\nexport type EventCallback<T = unknown> = (event: T) => void;\n\ntype RootWithMeta = Root & { businessObject?: RootBusinessObject };\n\n/** Margins (screen px) the renderer's own palette needs, without a host's chrome around it. */\nconst DEFAULT_FREE_RECT_INSETS: FreeRectInsets = { top: 84, right: 56, bottom: 56, left: 56 };\n\n/**\n * diagram-js reads its zoom back rounded to three decimals: a fit below 0.0005 would read back as\n * zoom 0 and a NaN viewbox.\n */\nconst SMALLEST_FIT_ZOOM = 0.001;\n\n/** Services of the Modeler that hold an edit in progress; the viewers have none of them. */\ninterface ContextPadPrompt {\n cancelPrompt(): void;\n}\n\nfunction sizeToCss(value: number | string): string {\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nexport abstract class CmBaseViewer {\n protected abstract _getModules(): ModuleDeclaration[];\n\n private _diagram: Diagram | undefined;\n private readonly _container: HTMLElement;\n private readonly _options: CmViewerOptions;\n\n constructor(options: CmViewerOptions = {}) {\n this._options = options;\n this._container = this._createContainer(options);\n }\n\n private _createContainer(options: CmViewerOptions): HTMLElement {\n const container = options.container ?? document.createElement(\"div\");\n container.classList.add(\"cm-djs-container\");\n container.style.width = sizeToCss(options.width ?? \"100%\");\n container.style.height = sizeToCss(options.height ?? (options.container ? \"100%\" : \"600px\"));\n return container;\n }\n\n private _ensureDiagram(): Diagram {\n if (!this._diagram) {\n const modules = [...this._getModules(), ...(this._options.additionalModules ?? [])];\n this._diagram = new Diagram({\n canvas: { container: this._container },\n modules,\n cmKeyboard: { undoRedoKeys: this._options.undoRedoKeys ?? true },\n cmPalette: { freeRectInsets: this.freeRectInsets, freeRectCenter: this.freeRectCenter },\n });\n }\n return this._diagram;\n }\n\n /** Resolve a diagram-js service from the didi injector. */\n get<T>(name: string): T {\n return this._ensureDiagram().get<T>(name);\n }\n\n /** The margins the host's chrome covers right now. */\n private readonly freeRectInsets = (): FreeRectInsets => {\n const { freeArea, freeRectInsets } = this._options;\n const insets = freeArea ? freeArea.insets?.() : freeRectInsets?.();\n return insets ?? DEFAULT_FREE_RECT_INSETS;\n };\n\n /** The free rectangle's centre when the host names it, else the palette derives it. */\n private readonly freeRectCenter = (): Point | undefined => this._options.freeArea?.center?.();\n\n /** A service only some of the viewers have (the Modeler's editing services), else null. */\n private _optional<T>(name: string): T | null {\n return this._ensureDiagram().get<T>(name, false);\n }\n\n on<T = unknown>(event: string, callback: EventCallback<T>, priority = 1000): void {\n this.get<EventBus>(\"eventBus\").on(event, priority, callback as EventCallback);\n }\n\n off(event: string, callback: EventCallback): void {\n this.get<EventBus>(\"eventBus\").off(event, callback);\n }\n\n /**\n * Load a document into the canvas (replaces existing content). Silent: the previous document's\n * undo history goes without a `commandStack.changed`, so a host that saves on every change does\n * not write the import back. Throws before anything changes when the document cannot be drawn.\n */\n importDocument(doc: CmDocument): { warnings: ImportWarning[] } {\n const diagram = this._ensureDiagram();\n const eventBus = diagram.get<EventBus>(\"eventBus\");\n const importer = diagram.get<CmImporter>(\"cmImporter\");\n importer.assertImportable(doc);\n const labelEditing = this._optional<CmLabelEditing>(\"cmLabelEditing\");\n // An edit in progress belongs to an element the import is about to replace: a commit after it\n // (Enter, blur) would land on a removed shape.\n labelEditing?.suspend();\n this._optional<ContextPadPrompt>(\"cmContextPadProvider\")?.cancelPrompt();\n this._optional<PopupMenu>(\"popupMenu\")?.close();\n importer.clear();\n const warnings = importer.import(doc);\n // The previous document's history would undo onto elements that are gone (or, by id\n // coincidence, onto re-imported ones). Only the editors have a command stack.\n this._optional<CommandStack>(\"commandStack\")?.clear(false);\n if (this._options.fitOnImport ?? true) this._fit();\n eventBus.fire(\"import.done\", { warnings });\n labelEditing?.resumeAfterImport();\n return { warnings };\n }\n\n /**\n * Load the text of a `.cm`/`.cm.json` file. Throws (and changes nothing) when the text is no\n * importable document.\n */\n importText(text: string): { warnings: ImportWarning[] } {\n const parsed = parseDocumentText(text);\n if (!parsed.ok) throw new Error(parsed.error);\n return this.importDocument(parsed.document);\n }\n\n /** Current canvas state as a canonical document. */\n exportDocument(): CmDocument {\n return this.get<CmExporter>(\"cmExporter\").export();\n }\n\n /** Current canvas state as the canonical file text (ends in one line break). */\n exportText(): string {\n return serializeDocumentText(this.exportDocument());\n }\n\n /**\n * Update diagram-level metadata on the root. In an editor a title change is an undoable command\n * (`cmModeling.setTitle`); a viewer has no history and writes it directly. A locked editor\n * (`cmReadOnly`) changes nothing: its host takes no edits, and the next import would silently\n * revert the title.\n */\n setMeta(partial: Partial<RootBusinessObject>): void {\n if (partial.title === undefined) return;\n if (this._optional<CmReadOnly>(\"cmReadOnly\")?.isReadOnly()) return;\n const root = this._documentRoot();\n if (!root?.businessObject || root.businessObject.title === partial.title) return;\n const modeling = this._optional<CmModeling>(\"cmModeling\");\n if (modeling) modeling.setTitle(partial.title);\n else root.businessObject = { ...root.businessObject, title: partial.title };\n }\n\n /** Read diagram-level metadata from the root; undefined before the first import. */\n getMeta(): RootBusinessObject | undefined {\n return this._documentRoot()?.businessObject;\n }\n\n /** Through the registry: asking the canvas would create an implicit root before an import. */\n private _documentRoot(): RootWithMeta | undefined {\n return this.get<ElementRegistry>(\"elementRegistry\").get(ROOT_ID) as RootWithMeta | undefined;\n }\n\n /** Standalone, self-contained SVG snapshot. */\n saveSVG(): { svg: string } {\n return saveSVG(this.get<Canvas>(\"canvas\"), this.get<ElementRegistry>(\"elementRegistry\"));\n }\n\n /**\n * The tight box around what the canvas draws of the map in diagram coordinates, with no margin\n * of its own: the box a host's chrome fits to (`@miragon/modeler-api` 1.3). It reads the live\n * canvas and ignores zoom and scroll; `undefined` while the map is empty.\n */\n contentBounds(): ElementBounds | undefined {\n // Before the first use and after destroy() there is no diagram, and asking for one would build\n // it on a detached container.\n if (!this._diagram) return undefined;\n return contentBoundsOf(this._diagram.get<ElementRegistry>(\"elementRegistry\").getAll());\n }\n\n /**\n * Centres the content box in the container minus room for the chrome, at the largest zoom that\n * shows all of it and never above 100 % (guide §5.9); an empty map shows 100 %. The same view\n * for the same document and container (the contract's fitted view after an import). Without\n * `freeArea.insets` the room is the renderer's own palette margins: `freeArea.center` names no\n * rectangle to fit into.\n */\n private _fit(): void {\n const canvas = this.get<Canvas>(\"canvas\");\n const { width, height } = canvas.getSize();\n if (!(width > 0 && height > 0)) return;\n const content = this.contentBounds();\n if (!content) {\n canvas.viewbox({ x: 0, y: 0, width, height });\n return;\n }\n const insets = this.freeRectInsets();\n const freeWidth = Math.max(width - insets.left - insets.right, 1);\n const freeHeight = Math.max(height - insets.top - insets.bottom, 1);\n const contentWidth = Math.max(content.width, 1);\n const contentHeight = Math.max(content.height, 1);\n const scale = Math.max(\n Math.min(freeWidth / contentWidth, freeHeight / contentHeight, 1),\n SMALLEST_FIT_ZOOM,\n );\n canvas.viewbox({\n x: content.x + contentWidth / 2 - (insets.left + freeWidth / 2) / scale,\n y: content.y + contentHeight / 2 - (insets.top + freeHeight / 2) / scale,\n width: width / scale,\n height: height / scale,\n });\n }\n\n /** Attach the container into `target`. */\n attachTo(target: HTMLElement): void {\n target.appendChild(this._container);\n this.get<Canvas>(\"canvas\").resized();\n }\n\n /** Detach the container from the DOM, preserving state. */\n detach(): void {\n this._container.remove();\n }\n\n clear(): void {\n this._ensureDiagram().clear();\n }\n\n destroy(): void {\n if (this._diagram) {\n this._diagram.destroy();\n this._diagram = undefined;\n }\n this._container.remove();\n }\n\n get container(): HTMLElement {\n return this._container;\n }\n}\n","/**\n * Creates diagram-js runtime elements carrying Context Maps markers: bounded\n * contexts (shapes) and relationships (connections), from canonical document\n * elements (import) or from scratch (palette / context-pad create).\n */\n\nimport type ElementFactory from \"diagram-js/lib/core/ElementFactory\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport {\n CONTEXT_KEYS,\n RELATIONSHIP_KEYS,\n SUBDOMAIN_TYPE_SPECS,\n foreignFields,\n} from \"@miragon/context-maps-schema-model\";\nimport type {\n BoundedContext,\n Relationship,\n SubdomainType,\n} from \"@miragon/context-maps-schema-model\";\nimport type { CmContext, CmRelationship } from \"./di-types.js\";\n\n/** `{ cmForeign }` when `source` carries keys this version does not know, else nothing. */\nfunction foreignAttributes(\n source: object,\n knownKeys: readonly string[],\n): { cmForeign?: Record<string, unknown> } {\n const foreign = foreignFields(source, knownKeys);\n return Object.keys(foreign).length > 0 ? { cmForeign: foreign } : {};\n}\n\nexport default class CmElementFactory {\n static $inject = [\"elementFactory\"];\n\n constructor(private readonly elementFactory: ElementFactory) {}\n\n // --- from canonical document elements (import) -------------------------\n\n createContext(ctx: BoundedContext): CmContext {\n // Boxes are fixed-size on the canvas (no resize feature) — clamp legacy or\n // hand-edited imports up to the notation minimum so the fixed name/team\n // layout always fits inside the box.\n const spec = ctx.subdomainType ? SUBDOMAIN_TYPE_SPECS[ctx.subdomainType] : undefined;\n const minSize = spec?.minSize ?? { width: 120, height: 72 };\n return this.elementFactory.createShape({\n id: ctx.id,\n x: ctx.position.x,\n y: ctx.position.y,\n width: Math.max(ctx.size.width, minSize.width),\n height: Math.max(ctx.size.height, minSize.height),\n cmKind: \"context\",\n cmLabel: ctx.label,\n ...(ctx.subdomainType ? { subdomainType: ctx.subdomainType } : {}),\n ...(ctx.team ? { team: ctx.team } : {}),\n ...(ctx.description ? { description: ctx.description } : {}),\n ...(ctx.fill ? { fill: ctx.fill } : {}),\n ...(ctx.stroke ? { stroke: ctx.stroke } : {}),\n ...foreignAttributes(ctx, CONTEXT_KEYS),\n } as Partial<CmContext>) as unknown as CmContext;\n }\n\n createRelationship(\n rel: Relationship,\n source: CmContext,\n target: CmContext,\n waypoints: Point[],\n ): CmRelationship {\n return this.elementFactory.createConnection({\n id: rel.id,\n source,\n target,\n waypoints,\n cmKind: \"relationship\",\n pattern: rel.pattern,\n ...(rel.upstreamRoles?.length ? { upstreamRoles: [...rel.upstreamRoles] } : {}),\n ...(rel.downstreamRoles?.length ? { downstreamRoles: [...rel.downstreamRoles] } : {}),\n ...(rel.label ? { cmLabel: rel.label } : {}),\n ...(rel.description ? { description: rel.description } : {}),\n ...(rel.implementationTechnology\n ? { implementationTechnology: rel.implementationTechnology }\n : {}),\n ...foreignAttributes(rel, RELATIONSHIP_KEYS),\n } as unknown as Partial<CmRelationship>) as unknown as CmRelationship;\n }\n\n // --- fresh, not-yet-placed elements (palette / context-pad create) -----\n //\n // No explicit id: the element factory (CmDiagramElementFactory) assigns a\n // collision-free model-style id (`ctx_…`).\n\n /** No type → an unclassified context (the pad's append action starts blank). */\n createNewContext(subdomainType?: SubdomainType, label?: string): CmContext {\n // Every type shares one default size; generic serves as the neutral fallback.\n const size =\n (subdomainType ? SUBDOMAIN_TYPE_SPECS[subdomainType] : undefined)?.defaultSize ??\n SUBDOMAIN_TYPE_SPECS.generic.defaultSize;\n return this.elementFactory.createShape({\n width: size.width,\n height: size.height,\n cmKind: \"context\",\n ...(subdomainType ? { subdomainType } : {}),\n cmLabel: label ?? \"New Context\",\n } as Partial<CmContext>) as unknown as CmContext;\n }\n}\n","/**\n * Element factory that assigns model-style random ids (`ctx_…`, `rel_…`) when\n * none is provided. diagram-js' stock factory numbers elements with a session\n * counter that restarts on every page load and is never advanced past ids\n * arriving via import — after a reload, drawing a connection would re-generate\n * an id already taken by an imported relationship (e.g. `connection_13`) and\n * the create command would die with \"element already exists\", silently\n * dropping the just-drawn line.\n */\n\nimport ElementFactory from \"diagram-js/lib/core/ElementFactory\";\nimport type { Connection, Label, Root, Shape } from \"diagram-js/lib/model/Types\";\nimport { newId } from \"@miragon/context-maps-schema-model\";\n\nexport default class CmDiagramElementFactory extends ElementFactory {\n override create(type: \"root\", attrs?: Partial<Root>): Root;\n override create(type: \"shape\", attrs?: Partial<Shape>): Shape;\n override create(type: \"connection\", attrs?: Partial<Connection>): Connection;\n override create(type: \"label\", attrs?: Partial<Label>): Label;\n override create(\n type: \"root\" | \"shape\" | \"connection\" | \"label\",\n attrs?: Partial<Root | Shape | Connection | Label>,\n ): Root | Shape | Connection | Label {\n if (!attrs?.id && (type === \"shape\" || type === \"connection\")) {\n attrs = { ...attrs, id: newId(type === \"shape\" ? \"ctx\" : \"rel\") };\n }\n return super.create(type as \"shape\", attrs as Partial<Shape>);\n }\n}\n","/**\n * Straight-line connection layouter that crops the waypoints to the context box\n * borders via the cropping docking. diagram-js' stock BaseLayouter only returns\n * mid(source)→mid(target), so without this the relationship line would run from\n * box centre to box centre (visibly starting inside the boxes).\n */\n\nimport { getMid } from \"diagram-js/lib/layout/LayoutUtil\";\nimport type CroppingConnectionDocking from \"diagram-js/lib/layout/CroppingConnectionDocking\";\nimport type { ConnectionLike, ShapeLike } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\n\ninterface LayoutHints {\n /**\n * diagram-js may pass a Point (drag anchor) or `false` (end did not move,\n * e.g. MoveHelper's `connectionStart: sourceMoved && anchor`) here.\n */\n connectionStart?: Point | false;\n connectionEnd?: Point | false;\n source?: ShapeLike;\n target?: ShapeLike;\n}\n\nexport default class CmLayouter {\n static $inject = [\"connectionDocking\"];\n\n constructor(private readonly docking: CroppingConnectionDocking) {}\n\n layoutConnection(connection: ConnectionLike, hints: LayoutHints = {}): Point[] {\n const source = hints.source ?? connection.source;\n const target = hints.target ?? connection.target;\n // A relationship line always aims at the CENTRE of its contexts (then gets\n // cropped to the borders below). Anchor hints are deliberately ignored when\n // the shape is known: diagram-js' move helpers pass stale/shifted anchors\n // (the box may already have been relaid out), which would detach the line.\n // Hints only matter while an end has no shape yet (connect rubber band).\n const start = source ? getMid(source) : hints.connectionStart || undefined;\n const end = target ? getMid(target) : hints.connectionEnd || undefined;\n\n const provisional: Point[] = [start, end].filter(Boolean) as Point[];\n // Give the connection a straight line so the docking can crop it to the\n // shape borders. Falls back to the raw line if either end is missing.\n connection.waypoints = provisional;\n if (source && target && provisional.length === 2) {\n return this.docking.getCroppedWaypoints(connection, source, target);\n }\n return provisional;\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CroppingConnectionDocking from \"diagram-js/lib/layout/CroppingConnectionDocking\";\nimport CmElementFactory from \"./CmElementFactory.js\";\nimport CmDiagramElementFactory from \"./CmDiagramElementFactory.js\";\n\n/**\n * Element factory with Context Maps defaults, plus the cropping docking so\n * relationship lines dock to the context box borders. The layouter itself is\n * bound in the modeling module (see there) because diagram-js' ModelingModule\n * binds a default `layouter` and loads after this one. The stock\n * `elementFactory` is replaced so every element gets a collision-free id\n * (see CmDiagramElementFactory).\n */\nexport const cmModelModule: ModuleDeclaration = {\n elementFactory: [\"type\", CmDiagramElementFactory],\n cmElementFactory: [\"type\", CmElementFactory],\n connectionDocking: [\"type\", CroppingConnectionDocking],\n};\n\nexport { default as CmElementFactory } from \"./CmElementFactory.js\";\nexport { default as CmDiagramElementFactory } from \"./CmDiagramElementFactory.js\";\nexport { default as CmLayouter } from \"./CmLayouter.js\";\nexport * from \"./di-types.js\";\n","/**\n * Geometry of the role-chip group at a relationship end (the OHS/PL/ACL/CF\n * badges next to the direction letter). Kept in one place so the renderer\n * (which draws the chips) and the validation markers (which anchor to the\n * chips' bottom-right corner) can never drift apart.\n */\n\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { FONT } from \"./styles.js\";\n\nexport interface EndRoleChipLayout {\n /** The parent box around all chips of this end. */\n box: { x: number; y: number; width: number; height: number };\n center: Point;\n chipWidths: number[];\n chipHeight: number;\n innerWidth: number;\n gap: number;\n}\n\nexport function endRoleChipLayout(\n endpoint: Point,\n toward: Point,\n direction: string,\n roles: string[],\n): EndRoleChipLayout | null {\n if (roles.length === 0) return null;\n\n const dx = toward.x - endpoint.x;\n const dy = toward.y - endpoint.y;\n const length = Math.hypot(dx, dy) || 1;\n const ux = dx / length;\n const uy = dy / length;\n const charW = FONT.small * 0.64;\n const letterDist = 11;\n\n const chipHeight = FONT.small + 6;\n const gap = 3;\n const pad = 4;\n const chipWidths = roles.map((role) => role.length * charW + 12);\n const innerWidth = chipWidths.reduce((a, b) => a + b, 0) + gap * (roles.length - 1);\n const width = innerWidth + pad * 2;\n const height = chipHeight + pad * 2;\n\n const dist = letterDist + (direction.length * charW) / 2 + 8 + width / 2;\n const center = { x: endpoint.x + ux * dist, y: endpoint.y + uy * dist };\n\n return {\n box: { x: center.x - width / 2, y: center.y - height / 2, width, height },\n center,\n chipWidths,\n chipHeight,\n innerWidth,\n gap,\n };\n}\n","/**\n * SVG rendering of the Context Maps notation (BaseRenderer subclass).\n *\n * - bounded contexts: solid fixed-size boxes, coloured by subdomain type, with\n * a wrapped name and an optional owning-team caption;\n * - relationships: lines between contexts carrying the pattern abbreviation\n * (e.g. \"SK\", \"C/S\"), U/D end markers for asymmetric patterns, and the\n * integration roles (OHS/PL upstream, ACL/CF downstream).\n *\n * Colours/labels come from the single notation source (`@miragon/context-maps-schema-model`).\n */\n\nimport BaseRenderer from \"diagram-js/lib/draw/BaseRenderer\";\nimport {\n append as svgAppend,\n create as svgCreate,\n attr as svgAttr,\n clear as svgClear,\n} from \"tiny-svg\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { ConnectionLike, ElementLike, ShapeLike } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport {\n MARK_COLORS,\n MARK_TEXT_COLOR,\n RELATIONSHIP_PATTERN_SPECS,\n SUBDOMAIN_TYPE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type { SubdomainType } from \"@miragon/context-maps-schema-model\";\nimport {\n CONTEXT_NAME_TOP,\n CONTEXT_TEAM_RESERVE,\n FONT,\n INK,\n INK_SOFT,\n NEUTRAL_FILL,\n NEUTRAL_STROKE,\n PAPER,\n TT_RENDER_PRIORITY,\n} from \"./styles.js\";\nimport { endRoleChipLayout } from \"./endRoleChips.js\";\nimport { TEAM_ICON_SIZE, TYPE_LABEL, teamRowLayout } from \"./contextLayout.js\";\nimport { textWidth } from \"./textMetrics.js\";\nimport {\n isCmContext,\n isCmElement,\n isCmRelationship,\n type CmContext,\n type CmRelationship,\n} from \"../model/di-types.js\";\n\ntype Attrs = Record<string, string | number>;\n\nexport default class ContextMapsRenderer extends BaseRenderer {\n static $inject = [\"eventBus\"];\n\n constructor(eventBus: EventBus) {\n super(eventBus, TT_RENDER_PRIORITY);\n }\n\n override canRender(element: ElementLike): boolean {\n return isCmElement(element);\n }\n\n override drawShape(visuals: SVGElement, element: ShapeLike): SVGElement {\n // diagram-js does not always clear our visual group before re-rendering on\n // update; clear it ourselves so re-draws never leave stale duplicates behind.\n svgClear(visuals);\n if (isCmContext(element)) return this.drawContext(visuals, element);\n const rect = svgAttr(svgCreate(\"rect\"), {\n width: element.width,\n height: element.height,\n fill: \"#eee\",\n });\n svgAppend(visuals, rect);\n return rect;\n }\n\n override drawConnection(visuals: SVGElement, connection: ConnectionLike): SVGElement {\n svgClear(visuals);\n if (isCmRelationship(connection)) return this.drawRelationship(visuals, connection);\n const line = svgAttr(svgCreate(\"polyline\"), {\n points: (connection.waypoints ?? []).map((p) => `${p.x},${p.y}`).join(\" \"),\n fill: \"none\",\n stroke: INK,\n });\n svgAppend(visuals, line);\n return line;\n }\n\n override getShapePath(shape: ShapeLike): string {\n const { x, y, width, height } = shape;\n return `M${x},${y}l${width},0l0,${height}l${-width},0z`;\n }\n\n override getConnectionPath(connection: ConnectionLike): string {\n const wp = (connection.waypoints ?? []) as Point[];\n if (wp.length === 0) return \"\";\n return wp.map((p, idx) => `${idx === 0 ? \"M\" : \"L\"}${p.x},${p.y}`).join(\"\");\n }\n\n // --- bounded context -----------------------------------------------------\n\n private drawContext(visuals: SVGElement, ctx: CmContext): SVGElement {\n const spec = ctx.subdomainType ? SUBDOMAIN_TYPE_SPECS[ctx.subdomainType] : undefined;\n const w = Math.max(ctx.width, 1);\n const h = Math.max(ctx.height, 1);\n const sw = 2;\n const i = sw / 2;\n const box = svgAttr(svgCreate(\"rect\"), {\n x: i,\n y: i,\n width: w - sw,\n height: h - sw,\n rx: 8,\n ry: 8,\n fill: ctx.fill ?? spec?.fill ?? NEUTRAL_FILL,\n stroke: ctx.stroke ?? spec?.stroke ?? NEUTRAL_STROKE,\n \"stroke-width\": sw,\n \"stroke-linejoin\": \"round\",\n });\n svgAppend(visuals, box);\n\n this.appendLabel(visuals, ctx.cmLabel ?? \"\", w, h, Boolean(ctx.team), {\n \"font-weight\": \"650\",\n });\n if (ctx.subdomainType && spec) {\n // Kaiser subdomain icon at the top-left corner (star / open hand / dotted\n // circle) plus the domain-type label next to it.\n svgAppend(visuals, subdomainIcon(ctx.subdomainType, 15, 15, 18, spec.stroke));\n const badge = svgAttr(svgCreate(\"text\"), {\n x: TYPE_LABEL.x,\n y: TYPE_LABEL.y,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n \"font-weight\": TYPE_LABEL.fontWeight,\n fill: spec.stroke,\n \"text-anchor\": \"start\",\n \"dominant-baseline\": \"central\",\n \"letter-spacing\": `${TYPE_LABEL.letterSpacingEm}em`,\n });\n badge.textContent = spec.label;\n svgAppend(visuals, badge);\n }\n if (ctx.team) {\n // People icon + team name, centred as a unit at the bottom of the box.\n const row = teamRowLayout(w, h, ctx.team);\n const icon = peopleIcon(row.iconCenterX, row.centerY, TEAM_ICON_SIZE, INK_SOFT);\n svgAttr(icon, { class: \"cm-team\" });\n svgAppend(visuals, icon);\n\n const team = svgAttr(svgCreate(\"text\"), {\n class: \"cm-team\",\n x: row.textX,\n y: row.centerY,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n fill: INK_SOFT,\n \"text-anchor\": \"start\",\n \"dominant-baseline\": \"central\",\n });\n team.textContent = ctx.team;\n svgAppend(visuals, team);\n }\n return box;\n }\n\n // --- relationship --------------------------------------------------------\n\n private drawRelationship(visuals: SVGElement, rel: CmRelationship): SVGElement {\n const spec =\n RELATIONSHIP_PATTERN_SPECS[rel.pattern] ?? RELATIONSHIP_PATTERN_SPECS[\"upstream-downstream\"];\n const wp = (rel.waypoints ?? []) as Point[];\n const dash = spec.dash;\n const line = svgAttr(svgCreate(\"polyline\"), {\n points: wp.map((p) => `${p.x},${p.y}`).join(\" \"),\n fill: \"none\",\n stroke: spec.stroke,\n \"stroke-width\": spec.strokeWidth,\n \"stroke-linejoin\": \"round\",\n \"stroke-linecap\": \"round\",\n ...(dash ? { \"stroke-dasharray\": dash } : {}),\n });\n svgAppend(visuals, line);\n\n if (wp.length >= 2) {\n const src = wp[0];\n const tgt = wp[wp.length - 1];\n const upRoles = rel.upstreamRoles ?? [];\n const downRoles = rel.downstreamRoles ?? [];\n\n if (spec.symmetric) {\n // No direction (SK / P / SW): a single neutral pattern chip in the MIDDLE.\n const mx = (src.x + tgt.x) / 2;\n const my = (src.y + tgt.y) / 2;\n this.chip(visuals, mx, my, spec.abbreviation, PAPER, spec.stroke, spec.stroke);\n } else {\n // Direction letter sits AT the domain as a plain letter (no box); the\n // integration roles follow as their own coloured boxes. Customer-supplier\n // uses S (supplier, upstream) and C (customer, downstream) instead of U/D.\n const cs = rel.pattern === \"customer-supplier\";\n this.endMarkers(visuals, src, tgt, cs ? \"S\" : \"U\", upRoles);\n this.endMarkers(visuals, tgt, src, cs ? \"C\" : \"D\", downRoles);\n }\n }\n return line;\n }\n\n /**\n * Draws the markers at one relationship end: the direction letter (U/D/S/C) as\n * a plain letter right at the domain (no box), then the integration roles side\n * by side inside a single axis-aligned parent box.\n */\n private endMarkers(\n visuals: SVGElement,\n endpoint: Point,\n toward: Point,\n direction: string,\n roles: string[],\n ): void {\n const dx = toward.x - endpoint.x;\n const dy = toward.y - endpoint.y;\n const len = Math.hypot(dx, dy) || 1;\n const ux = dx / len;\n const uy = dy / len;\n\n // Direction letter: plain bold letter at the domain, white halo for legibility.\n const letterDist = 11;\n const dirColor = MARK_COLORS[direction] ?? INK;\n const letter = svgAttr(svgCreate(\"text\"), {\n x: endpoint.x + ux * letterDist,\n y: endpoint.y + uy * letterDist,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small + 1,\n \"font-weight\": \"800\",\n fill: dirColor,\n stroke: PAPER,\n \"stroke-width\": 3,\n \"paint-order\": \"stroke\",\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n });\n letter.textContent = direction;\n svgAppend(visuals, letter);\n\n // Integration roles: horizontal chips inside one axis-aligned parent box\n // (geometry shared with the validation markers via endRoleChipLayout).\n const layout = endRoleChipLayout(endpoint, toward, direction, roles);\n if (!layout) return;\n const { box, center, chipWidths: widths, chipHeight: chipH, innerWidth: innerW, gap } = layout;\n const cy = center.y;\n\n const parent = svgAttr(svgCreate(\"rect\"), {\n x: box.x,\n y: box.y,\n width: box.width,\n height: box.height,\n rx: 6,\n ry: 6,\n fill: PAPER,\n \"fill-opacity\": 0.96,\n stroke: \"#d9d5cc\",\n \"stroke-width\": 1,\n });\n svgAppend(visuals, parent);\n\n let x = center.x - innerW / 2;\n roles.forEach((role, i) => {\n const w = widths[i];\n const fill = MARK_COLORS[role] ?? NEUTRAL_STROKE;\n this.miniChip(visuals, x + w / 2, cy, w, chipH, role, fill);\n x += w + gap;\n });\n }\n\n /** A fixed-size coloured sub-label (own colour + border) inside a parent box. */\n private miniChip(\n visuals: SVGElement,\n cx: number,\n cy: number,\n w: number,\n h: number,\n text: string,\n fill: string,\n ): void {\n const bg = svgAttr(svgCreate(\"rect\"), {\n x: cx - w / 2,\n y: cy - h / 2,\n width: w,\n height: h,\n rx: 3,\n ry: 3,\n fill,\n stroke: darken(fill),\n \"stroke-width\": 1,\n });\n svgAppend(visuals, bg);\n const t = svgAttr(svgCreate(\"text\"), {\n x: cx,\n y: cy,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n \"font-weight\": \"700\",\n fill: MARK_TEXT_COLOR,\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n });\n t.textContent = text;\n svgAppend(visuals, t);\n }\n\n /** A single small filled, bordered box (background, text colour, border colour). */\n private chip(\n visuals: SVGElement,\n cx: number,\n cy: number,\n text: string,\n bgFill: string,\n textFill: string,\n border: string,\n ): void {\n if (!text) return;\n const padX = 6;\n const charW = FONT.small * 0.64;\n const w = text.length * charW + padX * 2;\n const h = FONT.small + 8;\n const bg = svgAttr(svgCreate(\"rect\"), {\n x: cx - w / 2,\n y: cy - h / 2,\n width: w,\n height: h,\n rx: 4,\n ry: 4,\n fill: bgFill,\n stroke: border,\n \"stroke-width\": 1,\n ...(bgFill === PAPER ? { \"fill-opacity\": 0.95 } : {}),\n });\n svgAppend(visuals, bg);\n const t = svgAttr(svgCreate(\"text\"), {\n x: cx,\n y: cy,\n \"font-family\": FONT.family,\n \"font-size\": FONT.small,\n \"font-weight\": \"700\",\n fill: textFill,\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n });\n t.textContent = text;\n svgAppend(visuals, t);\n }\n\n // --- shared label rendering (wrapped, top-anchored) ----------------------\n\n /** The name starts at the FIXED offset below the type header — the gap\n * between header and name never varies with box size or line count. Lines\n * that would run past the (fixed-size) box are dropped, the last kept line\n * gets an ellipsis. */\n private appendLabel(\n visuals: SVGElement,\n text: string,\n w: number,\n h: number,\n hasTeam: boolean,\n attrs: Attrs,\n ): void {\n const fontSize =\n typeof attrs[\"font-size\"] === \"number\" ? (attrs[\"font-size\"] as number) : FONT.label;\n const fontWeight = String(attrs[\"font-weight\"] ?? \"400\");\n const maxWidth = w - 20;\n let lines = wrapLabel(text, maxWidth, fontSize, fontWeight);\n const lineHeight = fontSize * 1.2;\n const available = h - CONTEXT_NAME_TOP - (hasTeam ? CONTEXT_TEAM_RESERVE : 8);\n const maxLines = Math.max(1, Math.floor(available / lineHeight));\n if (lines.length > maxLines) {\n lines = lines.slice(0, maxLines);\n lines[maxLines - 1] = ellipsize(lines[maxLines - 1], maxWidth, fontSize, fontWeight);\n }\n const startY = CONTEXT_NAME_TOP + lineHeight / 2;\n lines.forEach((ln, idx) => {\n const t = svgAttr(svgCreate(\"text\"), {\n // `cm-name` lets the direct-editing marker hide the rendered name.\n class: \"cm-name\",\n x: w / 2,\n y: startY + idx * lineHeight,\n \"font-family\": FONT.family,\n \"font-size\": fontSize,\n fill: INK,\n \"text-anchor\": \"middle\",\n \"dominant-baseline\": \"central\",\n ...attrs,\n });\n t.textContent = ln;\n svgAppend(visuals, t);\n });\n }\n}\n\n// --- helpers ---------------------------------------------------------------\n\n/** Darkens a #rrggbb colour toward black by factor `f` (0..1) for chip borders. */\nfunction darken(hex: string, f = 0.7): string {\n const m = /^#([0-9a-f]{6})$/i.exec(hex);\n if (!m) return hex;\n const n = parseInt(m[1], 16);\n const r = Math.round(((n >> 16) & 255) * f);\n const g = Math.round(((n >> 8) & 255) * f);\n const b = Math.round((n & 255) * f);\n return `rgb(${r},${g},${b})`;\n}\n\n// Material star + pan_tool (open hand) paths (Apache-2.0), 24×24 viewBox.\nconst STAR_PATH =\n \"M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14l-5-4.87 7.1-1.01z\";\nconst HAND_PATH =\n \"M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z\";\n\n/**\n * Kaiser subdomain icon centred on (cx, cy) at `size` px: a filled star for a\n * core domain, an open hand for a supporting subdomain, a dotted circle for a\n * generic subdomain.\n */\nfunction subdomainIcon(\n type: SubdomainType,\n cx: number,\n cy: number,\n size: number,\n color: string,\n): SVGElement {\n if (type === \"generic\") {\n const g = svgCreate(\"g\");\n const c = svgAttr(svgCreate(\"circle\"), {\n cx,\n cy,\n r: size / 2 - 1,\n fill: \"none\",\n stroke: color,\n \"stroke-width\": 1.6,\n \"stroke-dasharray\": \"2.2 2.2\",\n });\n svgAppend(g, c);\n return g;\n }\n const scale = size / 24;\n // The open hand is drawn upright by Material; rotate it to lie sideways.\n const rot = type === \"supporting\" ? \" rotate(90 12 12)\" : \"\";\n const g = svgCreate(\"g\");\n svgAttr(g, {\n transform: `translate(${cx - 12 * scale} ${cy - 12 * scale}) scale(${scale})${rot}`,\n });\n const path = svgAttr(svgCreate(\"path\"), {\n d: type === \"core\" ? STAR_PATH : HAND_PATH,\n fill: color,\n });\n svgAppend(g, path);\n return g;\n}\n\n// Material \"people\" icon (Apache-2.0), 24×24 viewBox.\nconst PEOPLE_PATH =\n \"M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z\";\n\n/** A people glyph centred on (cx, cy), rendered at `size` px in the given colour. */\nfunction peopleIcon(cx: number, cy: number, size: number, color: string): SVGElement {\n const scale = size / 24;\n const g = svgCreate(\"g\");\n svgAttr(g, { transform: `translate(${cx - 12 * scale} ${cy - 12 * scale}) scale(${scale})` });\n const path = svgAttr(svgCreate(\"path\"), { d: PEOPLE_PATH, fill: color });\n svgAppend(g, path);\n return g;\n}\n\nfunction ellipsize(line: string, maxWidth: number, fontSize: number, fontWeight: string): string {\n let kept = line;\n while (kept && textWidth(`${kept}…`, fontSize, fontWeight) > maxWidth) {\n kept = kept.slice(0, -1).trimEnd();\n }\n return `${kept}…`;\n}\n\n/** Greedy word-wrap into lines that fit `maxWidth` at the font size. */\n/** Explicit line breaks are the author's — wrap only within each of them. */\nfunction wrapLabel(text: string, maxWidth: number, fontSize: number, fontWeight: string): string[] {\n const paragraphs = text.split(\"\\n\");\n if (paragraphs.every((paragraph) => paragraph.trim() === \"\")) return [];\n return paragraphs.flatMap((paragraph) => {\n const lines = wrapParagraph(paragraph, maxWidth, fontSize, fontWeight);\n // An intentionally blank line keeps its vertical space.\n return lines.length ? lines : [\"\"];\n });\n}\n\nfunction wrapParagraph(\n text: string,\n maxWidth: number,\n fontSize: number,\n fontWeight: string,\n): string[] {\n const words = text.split(/\\s+/).filter(Boolean);\n if (words.length === 0) return [];\n const fits = (candidate: string) => textWidth(candidate, fontSize, fontWeight) <= maxWidth;\n const lines: string[] = [];\n let current = \"\";\n for (const word of words) {\n const candidate = current ? `${current} ${word}` : word;\n if (fits(candidate)) {\n current = candidate;\n continue;\n }\n if (current) lines.push(current);\n // A word longer than the line hard-breaks mid-word (the editor's\n // break-word behaviour), so nothing ever overflows the box.\n let rest = word;\n while (rest && !fits(rest)) {\n let low = 1;\n let high = rest.length - 1;\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n if (fits(rest.slice(0, mid))) low = mid;\n else high = mid - 1;\n }\n lines.push(rest.slice(0, low));\n rest = rest.slice(low);\n }\n current = rest;\n }\n if (current) lines.push(current);\n return lines;\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport ContextMapsRenderer from \"./ContextMapsRenderer.js\";\n\n/** SVG rendering of all Context Maps element types (BaseRenderer, priority 1500). */\nexport const cmDrawModule: ModuleDeclaration = {\n __init__: [\"cmRenderer\"],\n cmRenderer: [\"type\", ContextMapsRenderer],\n};\n\nexport { default as ContextMapsRenderer } from \"./ContextMapsRenderer.js\";\n","/**\n * Bridges the canonical `CmDocument` into the diagram-js canvas. Contexts become\n * shapes; relationships become connections whose waypoints are cropped to the\n * context box borders. Connections are added first so they sit behind the boxes.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementFactory from \"diagram-js/lib/core/ElementFactory\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { Root } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport {\n DOCUMENT_KEYS,\n foreignFields,\n reservedIdProblem,\n} from \"@miragon/context-maps-schema-model\";\nimport type { CmDocument, Relationship } from \"@miragon/context-maps-schema-model\";\nimport type CmElementFactory from \"../model/CmElementFactory.js\";\nimport type { CmContext } from \"../model/di-types.js\";\nimport { ROOT_ID, type ImportWarning, type RootBusinessObject } from \"./types.js\";\n\ntype RootWithMeta = Root & { businessObject?: RootBusinessObject };\n\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** The point where the ray from a rect's centre toward `toward` crosses its border. */\nfunction borderPoint(rect: Rect, toward: Point): Point {\n const cx = rect.x + rect.width / 2;\n const cy = rect.y + rect.height / 2;\n const dx = toward.x - cx;\n const dy = toward.y - cy;\n if (dx === 0 && dy === 0) return { x: cx, y: cy };\n const sx = dx !== 0 ? rect.width / 2 / Math.abs(dx) : Infinity;\n const sy = dy !== 0 ? rect.height / 2 / Math.abs(dy) : Infinity;\n const s = Math.min(sx, sy);\n return { x: cx + dx * s, y: cy + dy * s };\n}\n\nfunction centre(rect: Rect): Point {\n return { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };\n}\n\nexport default class CmImporter {\n static $inject = [\"canvas\", \"elementFactory\", \"cmElementFactory\", \"eventBus\", \"elementRegistry\"];\n\n constructor(\n private readonly canvas: Canvas,\n private readonly elementFactory: ElementFactory,\n private readonly factory: CmElementFactory,\n private readonly eventBus: EventBus,\n private readonly elementRegistry: ElementRegistry,\n ) {}\n\n /**\n * Throws when `doc` cannot be drawn: diagram-js keeps one element per id in a plain object, so a\n * duplicate, an id of its own roots or the name of a built-in object property would throw halfway\n * through the import, after the previous document was cleared. Checked before anything is\n * removed, so a rejected import leaves no trace.\n */\n assertImportable(doc: CmDocument): void {\n const seen = new Set<string>();\n for (const { id } of [...doc.contexts, ...doc.relationships]) {\n const reserved = reservedIdProblem(id);\n if (reserved) throw new Error(`Cannot draw the map: ${reserved}.`);\n if (seen.has(id)) throw new Error(`The id \"${id}\" is used more than once.`);\n seen.add(id);\n }\n }\n\n import(doc: CmDocument): ImportWarning[] {\n const warnings: ImportWarning[] = [];\n this.eventBus.fire(\"import.render.start\", { document: doc });\n\n const root = this.documentRoot();\n const foreign = foreignFields(doc, DOCUMENT_KEYS);\n const unplacedRelationships: Relationship[] = [];\n root.businessObject = {\n title: doc.title,\n ...(Object.keys(foreign).length > 0 ? { foreign } : {}),\n };\n\n const byId = new Map<string, CmContext>();\n for (const ctx of doc.contexts) {\n const shape = this.factory.createContext(ctx);\n byId.set(ctx.id, shape);\n }\n\n // Connections first (back), then contexts (front).\n for (const rel of doc.relationships) {\n const source = byId.get(rel.from);\n const target = byId.get(rel.to);\n if (!source || !target) {\n unplacedRelationships.push(rel);\n warnings.push({\n message: `Relationship \"${rel.id}\" references a missing context; it stays in the file but is not drawn.`,\n elementId: rel.id,\n });\n continue;\n }\n const waypoints: Point[] = [\n borderPoint(source as unknown as Rect, centre(target as unknown as Rect)),\n borderPoint(target as unknown as Rect, centre(source as unknown as Rect)),\n ];\n const connection = this.factory.createRelationship(rel, source, target, waypoints);\n this.canvas.addConnection(connection, root);\n }\n for (const shape of byId.values()) {\n this.canvas.addShape(shape, root);\n }\n if (unplacedRelationships.length > 0)\n root.businessObject.unplacedRelationships = unplacedRelationships;\n\n this.eventBus.fire(\"import.render.done\", { warnings });\n return warnings;\n }\n\n /**\n * The document root, created on the first import. Any other root goes: diagram-js creates an\n * implicit one whenever something asks for the root before the first import (an export, a\n * palette create), and it would stay in the registry next to the document's root.\n */\n private documentRoot(): RootWithMeta {\n let root = this.elementRegistry.get(ROOT_ID) as RootWithMeta | undefined;\n if (!root) {\n root = this.elementFactory.createRoot({ id: ROOT_ID }) as RootWithMeta;\n this.canvas.setRootElement(root);\n }\n for (const other of this.canvas.getRootElements()) {\n if (other !== root) this.canvas.removeRootElement(other);\n }\n return root;\n }\n\n /** Removes every element but the roots (removing a root as a shape corrupts the canvas). */\n clear(): void {\n const roots = new Set<unknown>(this.canvas.getRootElements());\n for (const el of [...this.elementRegistry.getAll()]) {\n if (roots.has(el)) continue;\n try {\n if (\"waypoints\" in el) this.canvas.removeConnection(el.id);\n else this.canvas.removeShape(el.id);\n } catch {\n // already removed — ignore\n }\n }\n }\n}\n","/**\n * Rebuilds a canonical `CmDocument` from the diagram-js runtime model. Position\n * and size truth are the live `x/y/width/height`; editable fields (label,\n * subdomain, team, pattern, roles, colours) are read from runtime properties.\n */\n\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type { Root } from \"diagram-js/lib/model/Types\";\nimport { DOCUMENT_VERSION } from \"@miragon/context-maps-schema-model\";\nimport type { BoundedContext, Relationship, CmDocument } from \"@miragon/context-maps-schema-model\";\nimport { isCmContext, isCmRelationship } from \"../model/di-types.js\";\nimport { ROOT_ID, type RootBusinessObject } from \"./types.js\";\n\nexport default class CmExporter {\n static $inject = [\"elementRegistry\"];\n\n constructor(private readonly elementRegistry: ElementRegistry) {}\n\n export(): CmDocument {\n // Through the registry: asking the canvas would create an implicit root before the first import.\n const root = this.elementRegistry.get(ROOT_ID) as\n (Root & { businessObject?: RootBusinessObject }) | undefined;\n const meta = root?.businessObject;\n\n const contexts: BoundedContext[] = [];\n const relationships: Relationship[] = [];\n\n for (const el of this.elementRegistry.getAll()) {\n if (el.id === ROOT_ID) continue;\n\n if (isCmContext(el)) {\n const geom = el as unknown as { x: number; y: number; width: number; height: number };\n contexts.push({\n id: el.id,\n label: el.cmLabel ?? \"\",\n position: { x: geom.x, y: geom.y },\n size: { width: geom.width, height: geom.height },\n ...(el.subdomainType ? { subdomainType: el.subdomainType } : {}),\n ...(el.team ? { team: el.team } : {}),\n ...(el.description ? { description: el.description } : {}),\n ...(el.fill ? { fill: el.fill } : {}),\n ...(el.stroke ? { stroke: el.stroke } : {}),\n ...el.cmForeign,\n });\n } else if (isCmRelationship(el)) {\n const source = el.source as { id?: string } | undefined;\n const target = el.target as { id?: string } | undefined;\n if (!source?.id || !target?.id) continue;\n relationships.push({\n id: el.id,\n from: source.id,\n to: target.id,\n pattern: el.pattern,\n ...(el.upstreamRoles?.length ? { upstreamRoles: [...el.upstreamRoles] } : {}),\n ...(el.downstreamRoles?.length ? { downstreamRoles: [...el.downstreamRoles] } : {}),\n ...(el.cmLabel ? { label: el.cmLabel } : {}),\n ...(el.description ? { description: el.description } : {}),\n ...(el.implementationTechnology\n ? { implementationTechnology: el.implementationTechnology }\n : {}),\n ...el.cmForeign,\n });\n }\n }\n relationships.push(...(meta?.unplacedRelationships ?? []));\n\n return {\n version: DOCUMENT_VERSION,\n title: meta?.title ?? \"Untitled context map\",\n contexts,\n relationships,\n ...meta?.foreign,\n };\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmImporter from \"./CmImporter.js\";\nimport CmExporter from \"./CmExporter.js\";\n\n/** Document <-> diagram-js bridge (import / export). */\nexport const ioModule: ModuleDeclaration = {\n cmImporter: [\"type\", CmImporter],\n cmExporter: [\"type\", CmExporter],\n};\n\nexport { default as CmImporter } from \"./CmImporter.js\";\nexport { default as CmExporter } from \"./CmExporter.js\";\nexport { saveSVG } from \"./saveSvg.js\";\nexport { ROOT_ID } from \"./types.js\";\nexport type { ImportWarning, RootBusinessObject } from \"./types.js\";\n","import type { ModuleDeclaration } from \"didi\";\nimport { CmBaseViewer } from \"./CmBaseViewer.js\";\nimport { cmModelModule } from \"./model/index.js\";\nimport { cmDrawModule } from \"./draw/index.js\";\nimport { ioModule } from \"./io/index.js\";\n\n/** Read-only renderer: draws a Context Maps diagram with no interaction. */\nexport class Viewer extends CmBaseViewer {\n protected _getModules(): ModuleDeclaration[] {\n return [cmModelModule, cmDrawModule, ioModule];\n }\n}\n","/**\n * A fast hover tooltip for the map's own data (the native SVG <title> waits about 1.5s): a\n * context's description and team, a relationship's pattern, label, description and technology.\n * What the notation itself means lives in the legend. One element inside the canvas container, so\n * it never covers the chrome around the canvas, and it follows the pointer while it rests on an\n * element.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { RELATIONSHIP_PATTERN_SPECS } from \"@miragon/context-maps-schema-model\";\nimport type { RelationshipPatternSpec } from \"@miragon/context-maps-schema-model\";\nimport { isCmContext, isCmRelationship } from \"../model/di-types.js\";\n\ninterface HoverTip {\n title: string;\n body: string;\n}\n\n/** Gap between the pointer and the tooltip, in px. */\nconst POINTER_OFFSET = { x: 14, y: 18 };\n/** Distance the tooltip keeps from the container's right edge, in px. */\nconst EDGE_MARGIN = 12;\n\nexport function hoverTipFor(element: unknown): HoverTip | null {\n if (isCmContext(element)) {\n const parts: string[] = [];\n if (element.description) parts.push(element.description);\n if (element.team) parts.push(`Team: ${element.team}`);\n if (parts.length === 0) return null;\n return { title: element.cmLabel ?? \"Bounded context\", body: parts.join(\" · \") };\n }\n if (isCmRelationship(element)) {\n const spec = RELATIONSHIP_PATTERN_SPECS[element.pattern] as RelationshipPatternSpec | undefined;\n const pattern = spec?.label ?? element.pattern;\n const parts: string[] = [];\n if (element.description) parts.push(element.description);\n if (element.implementationTechnology) parts.push(element.implementationTechnology);\n const title = element.cmLabel ? `${pattern} · ${element.cmLabel}` : pattern;\n return { title, body: parts.join(\" · \") };\n }\n return null;\n}\n\nexport default class CmHoverTooltip {\n static $inject = [\"eventBus\", \"canvas\"];\n\n private readonly tooltip: HTMLElement;\n private readonly title: HTMLElement;\n private readonly body: HTMLElement;\n\n constructor(eventBus: EventBus, canvas: Canvas) {\n const container = canvas.getContainer();\n this.tooltip = document.createElement(\"div\");\n this.tooltip.className = \"cm-hover-tooltip\";\n this.tooltip.setAttribute(\"role\", \"tooltip\");\n this.tooltip.hidden = true;\n this.title = document.createElement(\"strong\");\n this.body = document.createElement(\"span\");\n this.tooltip.append(this.title, this.body);\n container.append(this.tooltip);\n\n const place = (event: MouseEvent): void => {\n const bounds = container.getBoundingClientRect();\n const width = this.tooltip.offsetWidth;\n const left = Math.min(\n event.clientX - bounds.left + POINTER_OFFSET.x,\n bounds.width - width - EDGE_MARGIN,\n );\n this.tooltip.style.left = `${Math.max(EDGE_MARGIN, left)}px`;\n this.tooltip.style.top = `${event.clientY - bounds.top + POINTER_OFFSET.y}px`;\n };\n const hide = (): void => {\n this.tooltip.hidden = true;\n container.removeEventListener(\"mousemove\", place);\n };\n\n eventBus.on(\"element.hover\", (event: { element?: unknown; originalEvent?: MouseEvent }) => {\n const tip = hoverTipFor(event.element);\n if (!tip) {\n hide();\n return;\n }\n this.title.textContent = tip.title;\n this.body.textContent = tip.body;\n this.body.hidden = tip.body === \"\";\n this.tooltip.hidden = false;\n if (event.originalEvent) place(event.originalEvent);\n container.addEventListener(\"mousemove\", place);\n });\n eventBus.on([\"element.out\", \"drag.init\", \"canvas.viewbox.changing\", \"diagram.clear\"], hide);\n eventBus.on(\"diagram.destroy\", () => {\n hide();\n this.tooltip.remove();\n });\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmHoverTooltip from \"./CmHoverTooltip.js\";\n\n/** A fast tooltip with an element's own data (description, team, technology) on hover. */\nexport const cmHoverTooltipModule: ModuleDeclaration = {\n __init__: [\"cmHoverTooltip\"],\n cmHoverTooltip: [\"type\", CmHoverTooltip],\n};\n\nexport { default as CmHoverTooltip, hoverTipFor } from \"./CmHoverTooltip.js\";\n","import type { ModuleDeclaration } from \"didi\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport ZoomScrollModule from \"diagram-js/lib/navigation/zoomscroll\";\nimport MoveCanvasModule from \"diagram-js/lib/navigation/movecanvas\";\nimport { Viewer } from \"./Viewer.js\";\nimport { cmHoverTooltipModule } from \"./hover-tooltip/index.js\";\n\n/** Read-only + navigation: zoom (scroll), pan (drag), selection, the elements' own data on hover. */\nexport class NavigatedViewer extends Viewer {\n protected override _getModules(): ModuleDeclaration[] {\n return [\n ...super._getModules(),\n SelectionModule,\n ZoomScrollModule,\n MoveCanvasModule,\n cmHoverTooltipModule,\n ];\n }\n}\n","/**\n * Generic, undo-able command that sets arbitrary Context Maps properties\n * (cmLabel, teamType, mode, fill, stroke, description). Returns the changed\n * element so the CommandStack fires `elements.changed` → re-render.\n */\n\nimport type { ElementLike } from \"diagram-js/lib/core/Types\";\nimport type CommandHandler from \"diagram-js/lib/command/CommandHandler\";\n\nexport interface UpdatePropertiesContext {\n element: ElementLike & Record<string, unknown>;\n properties: Record<string, unknown>;\n /** set internally by the handler (for revert). */\n oldProperties?: Record<string, unknown>;\n}\n\nfunction setOrDelete(obj: Record<string, unknown>, key: string, value: unknown): void {\n if (value === undefined) delete obj[key];\n else obj[key] = value;\n}\n\nexport default class UpdatePropertiesHandler implements CommandHandler {\n execute(context: UpdatePropertiesContext): ElementLike[] {\n const { element, properties } = context;\n const target = element as unknown as Record<string, unknown>;\n const old: Record<string, unknown> = {};\n for (const key of Object.keys(properties)) {\n old[key] = target[key];\n setOrDelete(target, key, properties[key]);\n }\n context.oldProperties = old;\n return [element];\n }\n\n revert(context: UpdatePropertiesContext): ElementLike[] {\n const { element, oldProperties } = context;\n const target = element as unknown as Record<string, unknown>;\n if (oldProperties) {\n for (const key of Object.keys(oldProperties)) setOrDelete(target, key, oldProperties[key]);\n }\n return [element];\n }\n}\n","/**\n * Swaps a relationship's two ends: source ⇄ target (and reverses the waypoints).\n * This flips the direction — what was upstream/supplier becomes downstream/\n * customer and vice versa. The integration roles stay bound to their SIDE, not\n * to a context: upstreamRoles (OHS/PL) always describe whichever context is\n * upstream after the swap, downstreamRoles (ACL/CF) the downstream one — the\n * role types are side-specific, so they cannot travel with a context.\n * Undoable (revert simply swaps back).\n */\n\nimport type CommandHandler from \"diagram-js/lib/command/CommandHandler\";\nimport type { Connection, Element } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\n\nexport interface SwapEndsContext {\n connection: Connection & { source: Element; target: Element; waypoints: Point[] };\n}\n\nfunction swap(connection: SwapEndsContext[\"connection\"]): Element[] {\n const oldSource = connection.source;\n connection.source = connection.target;\n connection.target = oldSource;\n if (Array.isArray(connection.waypoints)) {\n connection.waypoints = [...connection.waypoints].reverse();\n }\n return [connection];\n}\n\nexport default class SwapEndsHandler implements CommandHandler {\n execute(context: SwapEndsContext): Element[] {\n return swap(context.connection);\n }\n\n revert(context: SwapEndsContext): Element[] {\n return swap(context.connection);\n }\n}\n","/**\n * Renames the diagram: the title lives on the root's business object, not on an element, so it\n * gets a command of its own. Through the command stack the rename is undoable and reaches every\n * `commandStack.changed` listener (a host that saves on it, the collaborative-modeler contract's\n * content events) like any element edit.\n */\n\nimport type CommandHandler from \"diagram-js/lib/command/CommandHandler\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type { Element, Root } from \"diagram-js/lib/model/Types\";\nimport { ROOT_ID, type RootBusinessObject } from \"../../io/types.js\";\n\nexport interface UpdateTitleContext {\n title: string;\n /** set by the handler (for revert). */\n oldTitle?: string;\n}\n\ntype DocumentRoot = Root & { businessObject?: RootBusinessObject };\n\nexport default class UpdateTitleHandler implements CommandHandler {\n static $inject = [\"elementRegistry\"];\n\n constructor(private readonly elementRegistry: ElementRegistry) {}\n\n private root(): DocumentRoot {\n const root = this.elementRegistry.get(ROOT_ID) as DocumentRoot | undefined;\n if (!root?.businessObject) throw new Error(\"No context map is loaded to rename.\");\n return root;\n }\n\n execute(context: UpdateTitleContext): Element[] {\n const root = this.root();\n const current = root.businessObject!;\n context.oldTitle = current.title;\n root.businessObject = { ...current, title: context.title };\n return [];\n }\n\n revert(context: UpdateTitleContext): Element[] {\n const root = this.root();\n root.businessObject = { ...root.businessObject!, title: context.oldTitle ?? \"\" };\n return [];\n }\n}\n","/**\n * High-level Context Maps mutations that go through the command stack\n * (undo/redo). Registers the generic property command handler.\n */\n\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type GraphicsFactory from \"diagram-js/lib/core/GraphicsFactory\";\nimport {\n isSymmetricPattern,\n type DownstreamRole,\n type RelationshipPattern,\n type SubdomainType,\n type UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\nimport type { CmContext, CmElement, CmRelationship } from \"../model/di-types.js\";\nimport { isCmRelationship } from \"../model/di-types.js\";\nimport UpdatePropertiesHandler from \"./cmd/UpdatePropertiesHandler.js\";\nimport SwapEndsHandler, { type SwapEndsContext } from \"./cmd/SwapEndsHandler.js\";\nimport UpdateTitleHandler, { type UpdateTitleContext } from \"./cmd/UpdateTitleHandler.js\";\n\nconst UPDATE_PROPERTIES = \"element.updateProperties\";\nconst SWAP_ENDS = \"relationship.swapEnds\";\nconst UPDATE_TITLE = \"map.updateTitle\";\n\nexport default class CmModeling {\n static $inject = [\"commandStack\", \"elementRegistry\", \"graphicsFactory\"];\n\n constructor(\n private readonly commandStack: CommandStack,\n private readonly elementRegistry: ElementRegistry,\n private readonly graphicsFactory: GraphicsFactory,\n ) {\n commandStack.registerHandler(UPDATE_PROPERTIES, UpdatePropertiesHandler);\n commandStack.registerHandler(SWAP_ENDS, SwapEndsHandler);\n commandStack.registerHandler(UPDATE_TITLE, UpdateTitleHandler);\n }\n\n /** Rename the diagram (undoable). Throws while no document is loaded. */\n setTitle(title: string): void {\n this.commandStack.execute(UPDATE_TITLE, { title } as UpdateTitleContext);\n }\n\n /**\n * Force an immediate re-render of an element's graphics. diagram-js'\n * ChangeSupport only redraws on `elements.changed` when `element.parent` is\n * set; this guarantees the visual reflects a property/swap change regardless\n * (a redundant redraw is harmless — the visual layer is cleared first).\n */\n private redraw(element: CmElement): void {\n const gfx = this.elementRegistry.getGraphics(element);\n if (!gfx) return;\n this.graphicsFactory.update(isCmRelationship(element) ? \"connection\" : \"shape\", element, gfx);\n }\n\n /** Swap the two ends of a relationship (reverse upstream/downstream). */\n swapEnds(relationship: CmRelationship): void {\n this.commandStack.execute(SWAP_ENDS, {\n connection: relationship,\n } as unknown as SwapEndsContext);\n this.redraw(relationship);\n }\n\n updateProperties(element: CmElement, properties: Record<string, unknown>): void {\n this.commandStack.execute(UPDATE_PROPERTIES, { element, properties });\n this.redraw(element);\n }\n\n /** Rename / relabel any element. */\n updateLabel(element: CmElement, label: string): void {\n this.updateProperties(element, { cmLabel: label || undefined });\n }\n\n // --- context ------------------------------------------------------------\n\n setSubdomainType(context: CmContext, subdomainType: SubdomainType | undefined): void {\n this.updateProperties(context, { subdomainType });\n }\n\n setTeam(context: CmContext, team: string | undefined): void {\n this.updateProperties(context, { team: team || undefined });\n }\n\n setDescription(element: CmElement, description: string | undefined): void {\n this.updateProperties(element, { description: description || undefined });\n }\n\n /** Set or clear per-element colour overrides (`undefined` reverts to default). */\n setColors(context: CmContext, fill: string | undefined, stroke: string | undefined): void {\n this.updateProperties(context, { fill, stroke });\n }\n\n // --- relationship -------------------------------------------------------\n\n /**\n * Switch the pattern and sanitise the roles so the result is always valid:\n * symmetric patterns carry no roles; customer-supplier drops the inapplicable\n * OHS (upstream) and CF (downstream).\n */\n setPattern(relationship: CmRelationship, pattern: RelationshipPattern): void {\n const props: Record<string, unknown> = { pattern };\n if (isSymmetricPattern(pattern)) {\n props.upstreamRoles = undefined;\n props.downstreamRoles = undefined;\n } else if (pattern === \"customer-supplier\") {\n const up = (relationship.upstreamRoles ?? []).filter((r) => r !== \"OHS\");\n const down = (relationship.downstreamRoles ?? []).filter((r) => r !== \"CF\");\n props.upstreamRoles = up.length ? up : undefined;\n props.downstreamRoles = down.length ? down : undefined;\n }\n this.updateProperties(relationship, props);\n }\n\n setUpstreamRoles(relationship: CmRelationship, roles: UpstreamRole[]): void {\n this.updateProperties(relationship, { upstreamRoles: roles.length ? roles : undefined });\n }\n\n setDownstreamRoles(relationship: CmRelationship, roles: DownstreamRole[]): void {\n this.updateProperties(relationship, { downstreamRoles: roles.length ? roles : undefined });\n }\n\n setImplementationTechnology(relationship: CmRelationship, tech: string | undefined): void {\n this.updateProperties(relationship, { implementationTechnology: tech || undefined });\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmModeling from \"./CmModeling.js\";\nimport CmLayouter from \"../model/CmLayouter.js\";\n\n/**\n * High-level Context Maps mutations + command handlers. Also (re)binds the\n * cropping `layouter`: diagram-js' ModelingModule binds a default BaseLayouter,\n * and this module loads after it, so binding here wins and relationship lines\n * dock to the context box borders.\n */\nexport const cmModelingModule: ModuleDeclaration = {\n __init__: [\"cmModeling\"],\n cmModeling: [\"type\", CmModeling],\n layouter: [\"type\", CmLayouter],\n};\n\nexport { default as CmModeling } from \"./CmModeling.js\";\n","/**\n * Allowed editing operations.\n *\n * - Contexts are free, placed, fixed-size shapes that overlap but never nest.\n * - Relationships are connections between two distinct contexts (no\n * self-loops), at most ONE per pair of contexts — a second, overlapping\n * line between the same two contexts is impossible to tell apart visually.\n */\n\nimport RuleProvider from \"diagram-js/lib/features/rules/RuleProvider\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { isCmContext } from \"../model/di-types.js\";\n\ninterface MoveContext {\n target?: { parent?: unknown } | null;\n}\n\ninterface ConnectContext {\n source?: unknown;\n target?: unknown;\n}\n\ninterface ReconnectContext {\n source?: unknown;\n target?: unknown;\n connection?: unknown;\n}\n\nexport default class CmRules extends RuleProvider {\n static override $inject = [\"eventBus\"];\n\n constructor(eventBus: EventBus) {\n super(eventBus);\n }\n\n override init(): void {\n // Don't re-parent a dragged shape into whatever it is dropped on: contexts\n // are independent and only overlap. Dropping on the root (no parent) is fine.\n this.addRule([\"shape.move\", \"elements.move\"], (context: MoveContext) =>\n context.target && context.target.parent ? null : true,\n );\n this.addRule(\"shape.create\", () => true);\n // Boxes have a fixed size — the uniform card look is part of the notation.\n this.addRule(\"shape.resize\", () => false);\n\n // A relationship connects two distinct contexts. Returning an attributes\n // object (not just `true`) makes diagram-js stamp the new connection as a\n // relationship with a default pattern, so it renders correctly.\n this.addRule(\"connection.create\", (context: ConnectContext) =>\n canConnect(context.source, context.target),\n );\n this.addRule(\"connection.reconnect\", (context: ReconnectContext) =>\n canConnect(context.source, context.target, context.connection) ? true : false,\n );\n this.addRule(\"connection.updateWaypoints\", () => true);\n }\n}\n\ninterface ConnectedElement {\n incoming?: Array<{ source?: unknown; target?: unknown }>;\n outgoing?: Array<{ source?: unknown; target?: unknown }>;\n}\n\n/** True if any relationship (other than `ignore`) already links the two contexts, either way. */\nfunction alreadyConnected(source: unknown, target: unknown, ignore?: unknown): boolean {\n const { incoming = [], outgoing = [] } = source as ConnectedElement;\n return [...incoming, ...outgoing].some(\n (connection) =>\n connection !== ignore &&\n ((connection.source === source && connection.target === target) ||\n (connection.source === target && connection.target === source)),\n );\n}\n\n/** Returns default relationship attributes if the connection is allowed, else false. */\nfunction canConnect(\n source: unknown,\n target: unknown,\n ignore?: unknown,\n): false | { cmKind: \"relationship\"; pattern: \"upstream-downstream\" } {\n if (!isCmContext(source) || !isCmContext(target)) return false;\n if (source === target) return false;\n if (alreadyConnected(source, target, ignore)) return false;\n return { cmKind: \"relationship\", pattern: \"upstream-downstream\" };\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport RulesModule from \"diagram-js/lib/features/rules\";\nimport CmRules from \"./CmRules.js\";\n\n/** Context Maps editing rules (connect, move, create — no resize). */\nexport const cmRulesModule: ModuleDeclaration = {\n __depends__: [RulesModule],\n __init__: [\"cmRules\"],\n cmRules: [\"type\", CmRules],\n};\n\nexport { default as CmRules } from \"./CmRules.js\";\n","/**\n * Two model-keeping behaviours:\n *\n * 1. Flat model — diagram-js parents a newly created shape to whatever element\n * it is dropped on, which would nest overlapping contexts and glue them\n * together. Force every created shape onto the diagram root instead.\n * (Re-parenting on *move* is prevented separately in CmRules.)\n *\n * 2. Connection relayout — when a context moves or resizes, re-crop the\n * waypoints of its attached relationships to the new box borders, so lines\n * stay docked to the edges.\n */\n\nimport CommandInterceptor from \"diagram-js/lib/command/CommandInterceptor\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type { Connection, Shape } from \"diagram-js/lib/model/Types\";\n\ninterface MovedContext {\n shape?: Shape;\n shapes?: Shape[];\n}\n\nexport default class CmFlatModelBehavior extends CommandInterceptor {\n static override $inject = [\"eventBus\", \"canvas\", \"modeling\"];\n\n constructor(eventBus: EventBus, canvas: Canvas, modeling: Modeling) {\n super(eventBus);\n\n this.preExecute(\n [\"shape.create\", \"elements.create\"],\n (context: { parent?: unknown }) => {\n context.parent = canvas.getRootElement();\n },\n true,\n );\n\n // During a multi-element move, diagram-js' MoveHelper translates every\n // fully-enclosed connection (both ends moved) by the drag delta AFTER the\n // per-shape child commands ran. Re-cropping those connections here as well\n // would apply the delta twice — and a straight line whose two ends move by\n // the same delta is already correct after the plain translation. Track the\n // moved set so relayout only touches half-attached connections.\n let multiMove: Set<string> | null = null;\n this.preExecute(\n \"elements.move\",\n (context: MovedContext) => {\n multiMove = new Set((context.shapes ?? []).map((shape) => shape.id));\n },\n true,\n );\n this.postExecuted(\n \"elements.move\",\n () => {\n multiMove = null;\n },\n true,\n );\n\n const relayout = (context: MovedContext): void => {\n const shapes = context.shapes ?? (context.shape ? [context.shape] : []);\n const seen = new Set<string>();\n for (const shape of shapes) {\n const attached: Connection[] = [\n ...((shape.incoming as Connection[]) ?? []),\n ...((shape.outgoing as Connection[]) ?? []),\n ];\n for (const connection of attached) {\n if (seen.has(connection.id)) continue;\n seen.add(connection.id);\n const sourceId = connection.source?.id;\n const targetId = connection.target?.id;\n if (sourceId && targetId && multiMove?.has(sourceId) && multiMove.has(targetId)) {\n continue;\n }\n modeling.layoutConnection(connection);\n }\n }\n };\n\n this.postExecute([\"shape.move\", \"shape.resize\"], relayout, true);\n }\n}\n","/**\n * Marks the canvas container with `cm-dragging` while any drag operation\n * (connect, move, create) is in flight. The CSS keyed on it makes the HTML\n * overlays (connect handles, validation markers, tooltips) click-transparent,\n * so releasing a drag on top of one still reaches the element underneath —\n * otherwise a connect drag dropped on a warning triangle would silently die.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\n\nconst DRAGGING_CLS = \"cm-dragging\";\n\nexport default class CmDragBehavior {\n static $inject = [\"eventBus\", \"canvas\"];\n\n constructor(eventBus: EventBus, canvas: Canvas) {\n eventBus.on(\"drag.init\", () => {\n canvas.getContainer().classList.add(DRAGGING_CLS);\n });\n eventBus.on(\"drag.cleanup\", () => {\n canvas.getContainer().classList.remove(DRAGGING_CLS);\n });\n }\n}\n","/**\n * Clicking an already-selected element KEEPS it selected. diagram-js' stock\n * SelectionBehavior toggles instead (click on selected = deselect), which\n * reads as \"the editor lost my selection\" — especially since the connect\n * handles and the inspector vanish with it. Deselecting is done by clicking\n * the empty canvas. Ctrl/Cmd-click still toggles for multi-select workflows.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport { hasPrimaryModifier } from \"diagram-js/lib/util/Mouse\";\nimport { isCmElement } from \"../model/di-types.js\";\n\n/** Above SelectionBehavior's element.click listener (default priority 500). */\nconst BEFORE_SELECTION_BEHAVIOR = 2000;\n\nexport default class CmClickSelectionBehavior {\n static $inject = [\"eventBus\", \"selection\"];\n\n constructor(eventBus: EventBus, selection: Selection) {\n eventBus.on(\n \"element.click\",\n BEFORE_SELECTION_BEHAVIOR,\n (event: { element?: unknown } & Parameters<typeof hasPrimaryModifier>[0]) => {\n const element = event.element;\n if (!isCmElement(element)) return;\n if (hasPrimaryModifier(event)) return;\n if (selection.isSelected(element)) return false;\n },\n );\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmFlatModelBehavior from \"./CmFlatModelBehavior.js\";\nimport CmDragBehavior from \"./CmDragBehavior.js\";\nimport CmClickSelectionBehavior from \"./CmClickSelectionBehavior.js\";\n\n/** Editing behaviors: keep the model flat (no nesting), drag-state CSS marker. */\nexport const cmBehaviorsModule: ModuleDeclaration = {\n __init__: [\"cmFlatModelBehavior\", \"cmDragBehavior\", \"cmClickSelectionBehavior\"],\n cmFlatModelBehavior: [\"type\", CmFlatModelBehavior],\n cmDragBehavior: [\"type\", CmDragBehavior],\n cmClickSelectionBehavior: [\"type\", CmClickSelectionBehavior],\n};\n\nexport { default as CmFlatModelBehavior } from \"./CmFlatModelBehavior.js\";\nexport { default as CmDragBehavior } from \"./CmDragBehavior.js\";\nexport { default as CmClickSelectionBehavior } from \"./CmClickSelectionBehavior.js\";\n","import RuleProvider from \"diagram-js/lib/features/rules/RuleProvider\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\n\n/** Fired with `{ readOnly }` whenever the lock changes. */\nexport const READ_ONLY_CHANGED_EVENT = \"cm.readOnly.changed\";\n\n/** Above every edit rule of the renderer and diagram-js, so the lock wins. */\nconst LOCK_PRIORITY = 5000;\n\nconst EDIT_RULES = [\n \"elements.move\",\n \"shape.move\",\n \"shape.resize\",\n \"shape.create\",\n \"elements.create\",\n \"shape.append\",\n \"connection.start\",\n \"connection.create\",\n \"connection.reconnect\",\n \"connection.updateWaypoints\",\n \"elements.delete\",\n];\n\n/**\n * Locks every edit on the canvas while the document behind it cannot be saved from the canvas\n * (an invalid file in an IDE host, guide §13.5): no move, create, connect or delete through the\n * rules, and the keyboard, context pad, connect handles and label editor consult `isReadOnly()`.\n * Selection, zoom, pan and export stay.\n */\nexport default class CmReadOnly extends RuleProvider {\n static override $inject = [\"eventBus\"];\n\n private readOnly = false;\n\n constructor(private readonly bus: EventBus) {\n super(bus);\n }\n\n override init(): void {\n this.addRule(EDIT_RULES, LOCK_PRIORITY, () => (this.readOnly ? false : undefined));\n }\n\n isReadOnly(): boolean {\n return this.readOnly;\n }\n\n setReadOnly(readOnly: boolean): void {\n if (this.readOnly === readOnly) return;\n this.readOnly = readOnly;\n this.bus.fire(READ_ONLY_CHANGED_EVENT, { readOnly });\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport RulesModule from \"diagram-js/lib/features/rules\";\nimport CmReadOnly from \"./CmReadOnly.js\";\n\n/** The canvas edit lock (an invalid file in an IDE host). */\nexport const cmReadOnlyModule: ModuleDeclaration = {\n __depends__: [RulesModule],\n __init__: [\"cmReadOnly\"],\n cmReadOnly: [\"type\", CmReadOnly],\n};\n\nexport { default as CmReadOnly, READ_ONLY_CHANGED_EVENT } from \"./CmReadOnly.js\";\n","/**\n * In-place editing via diagram-js-direct-editing (the bpmn.io mechanism):\n * double-click a context or relationship — or use the context pad's rename\n * action — and the name becomes editable directly inside the element, at the\n * spot and size it is rendered (Shift+Enter inserts a line break the renderer\n * preserves). The owning-team caption edits the same way: the pad's team\n * action (or a double-click on the caption) opens the box right over it.\n * Enter/blur commits through `cmModeling` (undoable), Escape cancels, and\n * starting a drag completes the edit. A pan or zoom keeps the box open and\n * moves it with its element. The edited text is hidden behind an element\n * marker while the box is open so nothing doubles up. Neither an import nor\n * a view change commits an open edit: an import takes it down before and\n * reopens it on the element with the same id afterwards, with the text typed\n * so far.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { Element, ShapeLike } from \"diagram-js/lib/model/Types\";\nimport { CONTEXT_NAME_TOP, CONTEXT_TEAM_RESERVE, FONT } from \"../draw/styles.js\";\nimport { isCmContext, isCmElement, type CmContext, type CmElement } from \"../model/di-types.js\";\nimport type CmModeling from \"../modeling/CmModeling.js\";\nimport { READ_ONLY_CHANGED_EVENT, type CmReadOnly } from \"../read-only/index.js\";\n\ntype EditMode = \"name\" | \"team\";\n\n/** Hide the rendered text being edited: `.cm-name` resp. `.cm-team` (CSS). */\nconst MARKERS: Record<EditMode, string> = {\n name: \"cm-direct-editing\",\n team: \"cm-direct-editing-team\",\n};\n\n/** Mirrors the renderer: label wrap inset (10px each side). */\nconst LABEL_INSET_X = 10;\n/** The team caption band at the bottom of the box (renderer: centre at h-12). */\nconst TEAM_BAND_HEIGHT = 20;\nconst TEAM_BAND_BOTTOM_GAP = 2;\n\n// The service surface of the (untyped, plain-JS) diagram-js-direct-editing\n// package — typed locally so nothing untyped leaks into the published d.ts.\ninterface DirectEditingContext {\n bounds: { x: number; y: number; width: number; height: number };\n text: string;\n style?: Record<string, string | number>;\n options?: { centerVertically?: boolean; autoResize?: boolean; resizable?: boolean };\n}\n\ninterface DirectEditingService {\n registerProvider(provider: {\n activate(element: Element): DirectEditingContext | undefined;\n update(element: Element, newText: string): void;\n }): void;\n activate(element: Element): boolean;\n isActive(element?: Element): boolean;\n cancel(): void;\n complete(): void;\n getValue(): string;\n /** The text box's parent element of the edit open right now. */\n $textbox?: HTMLElement;\n}\n\n/** An open edit taken down for an import: its element, what it edits, the text typed so far. */\ninterface SuspendedEdit {\n elementId: string;\n mode: EditMode;\n text: string;\n}\n\nexport default class CmLabelEditing {\n static $inject = [\n \"eventBus\",\n \"canvas\",\n \"directEditing\",\n \"cmModeling\",\n \"elementRegistry\",\n \"cmReadOnly\",\n ];\n\n /** Which property the CURRENT activation edits (set right before activate). */\n private mode: EditMode = \"name\";\n private activeMarker?: { element: Element; marker: string };\n private suspended?: SuspendedEdit;\n private resumeTimer?: ReturnType<typeof setTimeout>;\n\n constructor(\n eventBus: EventBus,\n private readonly canvas: Canvas,\n private readonly directEditing: DirectEditingService,\n private readonly modeling: CmModeling,\n private readonly elementRegistry: ElementRegistry,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n // Registered as a plain object: the provider contract claims the method\n // name `activate` for context creation, while this service keeps\n // `activate(element)` as the public \"start editing\" API.\n directEditing.registerProvider({\n activate: (element) => this.activationContext(element),\n update: (element, newText) => this.commit(element, newText),\n });\n\n eventBus.on(\n \"element.dblclick\",\n (event: { element?: unknown; originalEvent?: { clientY?: number } }) => {\n const element = event.element;\n if (!isCmElement(element)) return;\n // A double-click on the team caption band edits the team, not the name.\n this.mode =\n isCmContext(element) && element.team && this.isInTeamBand(element, event.originalEvent)\n ? \"team\"\n : \"name\";\n directEditing.activate(element as Element);\n },\n );\n\n // Only the user's own gestures commit (Enter, blur, a drag): diagram-js cannot tell a wheel\n // zoom from a host's setViewState or fit, and a commit there would write half-typed text into\n // the document every peer shares.\n eventBus.on(\"drag.init\", () => directEditing.complete());\n eventBus.on(\"canvas.viewbox.changed\", () => this.placeOpenEdit());\n\n eventBus.on(\"directEditing.activate\", (event: { active?: { element?: Element } }) => {\n const element = event.active?.element;\n if (!element) return;\n const marker = MARKERS[this.mode];\n canvas.addMarker(element as unknown as ShapeLike, marker);\n this.activeMarker = { element, marker };\n });\n eventBus.on([\"directEditing.complete\", \"directEditing.cancel\"], () => {\n const active = this.activeMarker;\n if (active) canvas.removeMarker(active.element as unknown as ShapeLike, active.marker);\n this.activeMarker = undefined;\n });\n eventBus.on(\"diagram.destroy\", () => {\n clearTimeout(this.resumeTimer);\n this.suspended = undefined;\n });\n // A read-only canvas has no label editor (guide §13.5), also not on a double-click.\n eventBus.on(\"directEditing.activate.allowed\", 2000, () =>\n this.readOnly.isReadOnly() ? false : undefined,\n );\n eventBus.on(READ_ONLY_CHANGED_EVENT, (event: { readOnly?: boolean }) => {\n if (event.readOnly) directEditing.cancel();\n });\n }\n\n /**\n * Takes an open edit down WITHOUT committing it, for an import that replaces the elements: a\n * later commit (Enter, blur) would land on a removed shape and be wiped with the history.\n * `resumeAfterImport` brings the editor back with the typed text.\n */\n suspend(): void {\n clearTimeout(this.resumeTimer);\n const element = this.activeMarker?.element;\n if (!this.directEditing.isActive() || !element) return;\n this.suspended = {\n elementId: element.id,\n mode: this.mode,\n text: this.directEditing.getValue(),\n };\n this.directEditing.cancel();\n }\n\n /**\n * Reopens a suspended edit on the element with the same id, if the imported document still has\n * it. Deferred to the next task, after the host has restored its viewbox and selection around the\n * import, so the editor opens where the element ends up.\n */\n resumeAfterImport(): void {\n clearTimeout(this.resumeTimer);\n if (!this.suspended) return;\n this.resumeTimer = setTimeout(() => {\n const edit = this.suspended;\n this.suspended = undefined;\n if (edit && !this.directEditing.isActive()) this.resume(edit);\n }, 0);\n }\n\n /** The edit open right now (its element and the uncommitted text), for hosts and tests. */\n openEdit(): { elementId: string; text: string } | undefined {\n const element = this.activeMarker?.element;\n if (!this.directEditing.isActive() || !element) return undefined;\n return { elementId: element.id, text: this.directEditing.getValue() };\n }\n\n /** The open box follows its element through a pan or zoom: same text, caret and focus. */\n private placeOpenEdit(): void {\n const element = this.activeMarker?.element;\n const textbox = this.directEditing.$textbox;\n if (!this.directEditing.isActive() || !element || !textbox) return;\n const context = this.activationContext(element);\n if (!context) return;\n const { x, y, width, height } = context.bounds;\n Object.assign(textbox.style, {\n left: `${x}px`,\n top: `${y}px`,\n width: `${width}px`,\n height: `${height}px`,\n });\n const content = textbox.querySelector<HTMLElement>(\"[contenteditable]\");\n const fontSize = context.style?.fontSize;\n if (content && fontSize !== undefined) content.style.fontSize = String(fontSize);\n }\n\n private resume(edit: SuspendedEdit): void {\n const element = this.elementRegistry.get(edit.elementId);\n if (!isCmElement(element)) return;\n if (edit.mode === \"team\" && !isCmContext(element)) return;\n this.mode = edit.mode;\n if (!this.directEditing.activate(element as Element)) return;\n const content = this.directEditing.$textbox?.querySelector<HTMLElement>(\"[contenteditable]\");\n if (!content) return;\n content.innerText = edit.text;\n placeCaretAtEnd(content);\n }\n\n /** Start in-place editing of the element's name (context pad, hosts). */\n activate(element: CmElement): void {\n this.mode = \"name\";\n this.directEditing.activate(element as Element);\n }\n\n /** Start in-place editing of the owning-team caption at the box bottom. */\n activateTeam(context: CmContext): void {\n this.mode = \"team\";\n this.directEditing.activate(context as unknown as Element);\n }\n\n cancel(): void {\n this.directEditing.cancel();\n }\n\n private isInTeamBand(context: CmContext, originalEvent?: { clientY?: number }): boolean {\n if (typeof originalEvent?.clientY !== \"number\") return false;\n const zoom = this.canvas.zoom();\n const bbox = this.canvas.getAbsoluteBBox(context as unknown as ShapeLike);\n const containerTop = this.canvas.getContainer().getBoundingClientRect().top;\n const y = originalEvent.clientY - containerTop;\n return y >= bbox.y + bbox.height - (TEAM_BAND_HEIGHT + TEAM_BAND_BOTTOM_GAP) * zoom;\n }\n\n private activationContext(element: Element): DirectEditingContext | undefined {\n if (!isCmElement(element)) return undefined;\n if (this.mode === \"team\" && !isCmContext(element)) this.mode = \"name\";\n const zoom = this.canvas.zoom();\n const bbox = this.canvas.getAbsoluteBBox(element as unknown as ShapeLike);\n\n if (this.mode === \"team\") {\n const context = element as CmContext;\n // Right over the caption at the box bottom, in the caption's type size.\n return {\n bounds: {\n x: bbox.x + LABEL_INSET_X * zoom,\n y: bbox.y + bbox.height - (TEAM_BAND_HEIGHT + TEAM_BAND_BOTTOM_GAP) * zoom,\n width: bbox.width - 2 * LABEL_INSET_X * zoom,\n height: TEAM_BAND_HEIGHT * zoom,\n },\n text: context.team ?? \"\",\n style: {\n fontFamily: FONT.family,\n fontSize: `${FONT.small * zoom}px`,\n fontWeight: 400,\n lineHeight: 1.2,\n backgroundColor: \"transparent\",\n border: \"1px dashed var(--cd-ui-interaktion)\",\n textAlign: \"center\",\n },\n options: { centerVertically: true },\n };\n }\n\n const style: Record<string, string | number> = {\n fontFamily: FONT.family,\n fontSize: `${FONT.label * zoom}px`,\n fontWeight: 650,\n lineHeight: 1.2,\n // In-place illusion: the element's own fill stays visible, a dashed\n // accent frame signals the edit state (the rendered name is hidden).\n backgroundColor: \"transparent\",\n border: \"1px dashed var(--cd-ui-interaktion)\",\n textAlign: \"center\",\n };\n\n if (isCmContext(element)) {\n // The renderer anchors the name at the fixed top offset below the type\n // header — mirror that band exactly so the text does not jump. The 1px\n // dashed border (box-sizing: border-box) pushes the text down — offset\n // the box up by it.\n const reserve = element.team ? CONTEXT_TEAM_RESERVE * zoom : 0;\n return {\n bounds: {\n x: bbox.x + LABEL_INSET_X * zoom,\n y: bbox.y + CONTEXT_NAME_TOP * zoom - 1,\n width: bbox.width - 2 * LABEL_INSET_X * zoom,\n height: bbox.height - CONTEXT_NAME_TOP * zoom - reserve,\n },\n text: element.cmLabel ?? \"\",\n style,\n };\n }\n\n // Relationship: a compact box centred on the line (the canvas shows the\n // label only in the hover tooltip, so the box needs its own paper).\n const width = 160 * zoom;\n const height = 44 * zoom;\n return {\n bounds: {\n x: bbox.x + bbox.width / 2 - width / 2,\n y: bbox.y + bbox.height / 2 - height / 2,\n width,\n height,\n },\n text: (element as CmElement).cmLabel ?? \"\",\n style: { ...style, backgroundColor: \"var(--cd-ui-flaeche-hoch)\" },\n options: { centerVertically: true },\n };\n }\n\n private commit(element: Element, newText: string): void {\n const value = newText.trim();\n // DirectEditing also calls update() on pure bounds jitter — don't push a\n // no-op command (an empty undo step) when nothing changed.\n if (this.mode === \"team\") {\n const context = element as unknown as CmContext;\n if (value === (context.team ?? \"\")) return;\n this.modeling.setTeam(context, value || undefined);\n return;\n }\n if (value === ((element as CmElement).cmLabel ?? \"\")) return;\n this.modeling.updateLabel(element as CmElement, value);\n }\n}\n\nfunction placeCaretAtEnd(field: HTMLElement): void {\n const range = document.createRange();\n range.selectNodeContents(field);\n range.collapse(false);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport DirectEditingModule from \"diagram-js-direct-editing\";\nimport { cmModelingModule } from \"../modeling/index.js\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmLabelEditing from \"./CmLabelEditing.js\";\n\n/** In-place name editing (double-click / context pad), bpmn.io style. */\nexport const cmLabelEditingModule: ModuleDeclaration = {\n __depends__: [DirectEditingModule, cmModelingModule, cmReadOnlyModule],\n __init__: [\"cmLabelEditing\"],\n cmLabelEditing: [\"type\", CmLabelEditing],\n};\n\nexport { default as CmLabelEditing } from \"./CmLabelEditing.js\";\n","/**\n * Tiny inline-SVG glyphs for the palette / legend — the same shapes the canvas\n * draws (contexts coloured by subdomain, plus a relationship line). Returned as\n * HTML strings for diagram-js palette `html`.\n */\n\nimport {\n MARK_COLORS,\n MARK_TEXT_COLOR,\n RELATIONSHIP_PATTERN_SPECS,\n SUBDOMAIN_TYPE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type {\n DownstreamRole,\n RelationshipPattern,\n SubdomainType,\n SubdomainTypeSpec,\n UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\nimport { FONT, NEUTRAL_FILL, NEUTRAL_STROKE } from \"./styles.js\";\n\nfunction svg(inner: string, size = 24): string {\n return `<svg class=\"cm-palette-svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 26 26\" aria-hidden=\"true\">${inner}</svg>`;\n}\n\n// Kaiser subdomain glyphs (Material star / pan_tool), 24×24 viewBox.\nconst STAR = \"M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14l-5-4.87 7.1-1.01z\";\nconst HAND =\n \"M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z\";\n\n/** The subdomain glyph centred at (cx, cy) at `size` px: star / hand / dotted circle. */\nfunction subdomainGlyph(\n type: SubdomainType,\n cx: number,\n cy: number,\n size: number,\n color: string,\n): string {\n if (type === \"generic\") {\n return `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${size / 2 - 0.5}\" fill=\"none\" stroke=\"${color}\" stroke-width=\"1.4\" stroke-dasharray=\"1.8 1.8\"/>`;\n }\n const scale = size / 24;\n const rot = type === \"supporting\" ? ` rotate(90 12 12)` : \"\";\n const t = `translate(${cx - 12 * scale} ${cy - 12 * scale}) scale(${scale})${rot}`;\n return `<path d=\"${type === \"core\" ? STAR : HAND}\" fill=\"${color}\" transform=\"${t}\"/>`;\n}\n\n/** No (or unknown) type → the neutral box an unclassified context gets on the canvas. */\nexport function contextIconSvg(type?: SubdomainType): string {\n const s = type ? SUBDOMAIN_TYPE_SPECS[type] : undefined;\n if (!type || !s) {\n return svg(\n `<rect x=\"2\" y=\"4\" width=\"22\" height=\"18\" rx=\"3.5\" fill=\"${NEUTRAL_FILL}\" stroke=\"${NEUTRAL_STROKE}\" stroke-width=\"1.5\"/>`,\n );\n }\n return svg(\n `<rect x=\"2\" y=\"4\" width=\"22\" height=\"18\" rx=\"3.5\" fill=\"${s.fill}\" stroke=\"${s.stroke}\" stroke-width=\"1.5\"/>` +\n subdomainGlyph(type, 13, 13, 12, s.stroke),\n );\n}\n\n/** The bare subdomain glyph (star / hand / dotted circle) without the box — legend rows. */\nexport function subdomainIconSvg(type: SubdomainType, size = 18): string {\n const s = SUBDOMAIN_TYPE_SPECS[type] as SubdomainTypeSpec | undefined;\n const color = s?.stroke ?? NEUTRAL_STROKE;\n const inner =\n !s || type === \"generic\"\n ? `<circle cx=\"12\" cy=\"12\" r=\"9\" fill=\"none\" stroke=\"${color}\" stroke-width=\"1.8\" stroke-dasharray=\"2.4 2.4\"/>`\n : `<path d=\"${type === \"core\" ? STAR : HAND}\" fill=\"${color}\"/>`;\n return `<svg class=\"cm-palette-svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">${inner}</svg>`;\n}\n\n/** The same coloured role chip (OHS/PL/ACL/CF) the canvas draws at relationship ends. */\nexport function roleChipSvg(role: UpstreamRole | DownstreamRole): string {\n return svg(\n `<rect x=\"1\" y=\"6.5\" width=\"24\" height=\"13\" rx=\"3\" fill=\"${MARK_COLORS[role] ?? NEUTRAL_STROKE}\"/>` +\n `<text x=\"13\" y=\"16.4\" text-anchor=\"middle\" font-size=\"9.5\" font-weight=\"700\" fill=\"${MARK_TEXT_COLOR}\" font-family=\"${FONT.family}\">${role}</text>`,\n );\n}\n\nexport function relationshipIconSvg(\n pattern: RelationshipPattern = \"upstream-downstream\",\n size = 24,\n): string {\n const s =\n RELATIONSHIP_PATTERN_SPECS[pattern] ?? RELATIONSHIP_PATTERN_SPECS[\"upstream-downstream\"];\n const dash = s.dash ? ` stroke-dasharray=\"${s.dash}\"` : \"\";\n const w = Math.min(s.strokeWidth, 2.6);\n return svg(\n `<g stroke=\"${s.stroke}\" stroke-width=\"${w}\" stroke-linecap=\"round\">` +\n `<circle cx=\"5\" cy=\"13\" r=\"2.5\" fill=\"${s.stroke}\" stroke=\"none\"/>` +\n `<line x1=\"7\" y1=\"13\" x2=\"19\" y2=\"13\"${dash}/>` +\n `<circle cx=\"21\" cy=\"13\" r=\"2.5\" fill=\"${s.stroke}\" stroke=\"none\"/></g>`,\n size,\n );\n}\n","/**\n * The Lucide icons of the in-canvas chrome (context pad, connect handles, the lasso tool, the\n * shortcuts dialog), inlined so the renderer has no icon runtime dependency. Copied unchanged from\n * lucide-static 1.59.0 (`icon-nodes.json`; ISC, © Lucide Icons and Contributors; `arrow-right`,\n * `circle-x`, `trash`, `triangle-alert` and `x` derive from Feather, MIT, © Cole Bemis).\n */\nexport const LUCIDE = {\n \"arrow-left-right\":\n '<path d=\"M8 3 4 7l4 4\"/><path d=\"M4 7h16\"/><path d=\"m16 21 4-4-4-4\"/><path d=\"M20 17H4\"/>',\n \"arrow-right\": '<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>',\n \"circle-x\": '<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"m15 9-6 6\"/><path d=\"m9 9 6 6\"/>',\n pencil:\n '<path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\"/><path d=\"m15 5 4 4\"/>',\n \"sliders-horizontal\":\n '<path d=\"M10 5H3\"/><path d=\"M12 19H3\"/><path d=\"M14 3v4\"/><path d=\"M16 17v4\"/><path d=\"M21 12h-9\"/><path d=\"M21 19h-5\"/><path d=\"M21 5h-7\"/><path d=\"M8 10v4\"/><path d=\"M8 12H3\"/>',\n \"square-dashed-mouse-pointer\":\n '<path d=\"M12.034 12.681a.498.498 0 0 1 .647-.647l9 3.5a.5.5 0 0 1-.033.943l-3.444 1.068a1 1 0 0 0-.66.66l-1.067 3.443a.5.5 0 0 1-.943.033z\"/><path d=\"M5 3a2 2 0 0 0-2 2\"/><path d=\"M19 3a2 2 0 0 1 2 2\"/><path d=\"M5 21a2 2 0 0 1-2-2\"/><path d=\"M9 3h1\"/><path d=\"M9 21h2\"/><path d=\"M14 3h1\"/><path d=\"M3 9v1\"/><path d=\"M21 9v2\"/><path d=\"M3 14v1\"/>',\n \"square-plus\":\n '<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/><path d=\"M8 12h8\"/><path d=\"M12 8v8\"/>',\n \"text-align-start\": '<path d=\"M21 5H3\"/><path d=\"M15 12H3\"/><path d=\"M17 19H3\"/>',\n \"triangle-alert\":\n '<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>',\n trash:\n '<path d=\"M10 11v6\"/><path d=\"M14 11v6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\"/><path d=\"M3 6h18\"/><path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/>',\n users:\n '<path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\"/><path d=\"M16 3.128a4 4 0 0 1 0 7.744\"/><path d=\"M22 21v-2a4 4 0 0 0-3-3.87\"/><circle cx=\"9\" cy=\"7\" r=\"4\"/>',\n x: '<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>',\n} as const;\n\nexport type LucideIconName = keyof typeof LUCIDE;\n\nfunction lucideSvg(name: LucideIconName, size: number, strokeWidth: number): string {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"${strokeWidth}\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">${LUCIDE[name]}</svg>`;\n}\n\n/**\n * A chrome icon (guide §5.14, §11): 16px with stroke 2.5 on the 24 grid, so the stroke matches the\n * shell's chrome icons; `currentColor`, so the surrounding role decides the colour.\n */\nexport function chromeIcon(name: LucideIconName): string {\n return lucideSvg(name, 16, 2.5);\n}\n\n/** A palette tool icon (guide §5.5): 20px with stroke 2, the same 1.67px line as the chrome. */\nexport function toolIcon(name: LucideIconName): string {\n return lucideSvg(name, 20, 2);\n}\n","/**\n * The tool palette: the lasso tool first, then the three subdomain types of bounded context.\n * Relationships are drawn via the context pad's connect arrow, not from the palette. A pointer\n * drags or clicks a context onto the canvas; Enter or Space on an entry (a click without a\n * pointer, `detail === 0`, as the Miragon modeler shell sends it) places it in the centre of the\n * free rectangle instead, selected and with its name editor open (guide §5.5).\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type Create from \"diagram-js/lib/features/create/Create\";\nimport type LassoTool from \"diagram-js/lib/features/lasso-tool/LassoTool\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type Palette from \"diagram-js/lib/features/palette/Palette\";\nimport type {\n PaletteEntries,\n default as PaletteProvider,\n} from \"diagram-js/lib/features/palette/PaletteProvider\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type { Element, Shape } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { ALL_SUBDOMAIN_SPECS } from \"@miragon/context-maps-schema-model\";\nimport type { FreeRectInsets } from \"../CmBaseViewer.js\";\nimport { contextIconSvg } from \"../draw/palette-icons.js\";\nimport { toolIcon } from \"../draw/lucide.js\";\nimport type CmLabelEditing from \"../label-editing/CmLabelEditing.js\";\nimport type CmElementFactory from \"../model/CmElementFactory.js\";\nimport { isCmContext, type CmContext } from \"../model/di-types.js\";\nimport type { CmReadOnly } from \"../read-only/index.js\";\n\n/** diagram-js highlights tools only inside the group named exactly `tools`. */\nconst GROUP_TOOLS = \"tools\";\nconst GROUP_CONTEXTS = \"cm-1-contexts\";\n\n/** Guide §5.5: a keyboard-created element lands this far down-right of one already centred there. */\nconst KEYBOARD_CREATE_OFFSET = 24;\n\nexport interface CmPaletteConfig {\n freeRectInsets?: (() => FreeRectInsets) | undefined;\n /** The free rectangle's centre in diagram coordinates, when the host knows it better. */\n freeRectCenter?: (() => Point | undefined) | undefined;\n}\n\nfunction entryHtml(icon: string, draggable: boolean): string {\n const drag = draggable ? ` draggable=\"true\"` : \"\";\n return `<div class=\"entry cm-palette-entry\"${drag}>${icon}</div>`;\n}\n\n/** \"Supporting Subdomain\" → \"Supporting subdomain\": tooltips are in sentence case (guide §5.6). */\nfunction sentenceCase(label: string): string {\n return label.charAt(0) + label.slice(1).toLowerCase();\n}\n\n/** A click the shell synthesises for Enter or Space on a palette entry (no pointer, detail 0). */\nfunction isKeyboardClick(event: Event): boolean {\n return event.type === \"click\" && (event as MouseEvent).detail === 0;\n}\n\nexport default class CmPaletteProvider implements PaletteProvider {\n static $inject = [\n \"palette\",\n \"create\",\n \"lassoTool\",\n \"cmElementFactory\",\n \"canvas\",\n \"modeling\",\n \"selection\",\n \"elementRegistry\",\n \"cmLabelEditing\",\n \"cmReadOnly\",\n \"config.cmPalette\",\n ];\n\n constructor(\n palette: Palette,\n private readonly create: Create,\n private readonly lassoTool: LassoTool,\n private readonly factory: CmElementFactory,\n private readonly canvas: Canvas,\n private readonly modeling: Modeling,\n private readonly selection: Selection,\n private readonly elementRegistry: ElementRegistry,\n private readonly labelEditing: CmLabelEditing,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n private readonly config: CmPaletteConfig | undefined,\n ) {\n palette.registerProvider(this);\n }\n\n getPaletteEntries(): PaletteEntries {\n const entries: PaletteEntries = {};\n\n // Entry keys must end in `-tool` (\"lasso-tool\" ↔ tool \"lasso\") for diagram-js'\n // tool-manager highlight to find them; Esc cancels any tool.\n entries[\"lasso-tool\"] = {\n group: GROUP_TOOLS,\n title: \"Lasso\",\n html: entryHtml(toolIcon(\"square-dashed-mouse-pointer\"), false),\n action: {\n click: (event: Event) => this.lassoTool.activateSelection(event as MouseEvent),\n },\n };\n\n for (const spec of ALL_SUBDOMAIN_SPECS) {\n const start = (event: Event) => {\n const shape = this.factory.createNewContext(spec.type, spec.label);\n if (isKeyboardClick(event)) this.placeInFreeRect(shape);\n else this.create.start(event as MouseEvent, shape as unknown as Element);\n };\n entries[`context.${spec.type}`] = {\n group: GROUP_CONTEXTS,\n title: sentenceCase(spec.label),\n html: entryHtml(contextIconSvg(spec.type), true),\n action: { dragstart: start, click: start },\n };\n }\n\n return entries;\n }\n\n /**\n * Enter or Space on a creating entry (guide §5.5): a create that follows the pointer never ends\n * without one, so the context goes straight to the centre of the free rectangle (24px down-right\n * while that spot is taken), selected, with the canvas focused and its name editor open.\n */\n private placeInFreeRect(shape: CmContext): void {\n if (this.readOnly.isReadOnly()) return;\n const named = this.config?.freeRectCenter?.();\n const centre = named ? { x: named.x, y: named.y } : this.freeRectCentre();\n const taken = (point: Point): boolean =>\n this.elementRegistry\n .filter((element) => isCmContext(element))\n .some((element) => {\n const box = element as unknown as { x: number; y: number; width: number; height: number };\n return (\n Math.abs(box.x + box.width / 2 - point.x) < 1 &&\n Math.abs(box.y + box.height / 2 - point.y) < 1\n );\n });\n while (taken(centre)) {\n centre.x += KEYBOARD_CREATE_OFFSET;\n centre.y += KEYBOARD_CREATE_OFFSET;\n }\n const created = this.modeling.createShape(\n shape as unknown as Shape,\n centre,\n this.canvas.getRootElement() as Shape,\n );\n this.selection.select(created);\n this.canvas.focus();\n this.labelEditing.activate(created as unknown as CmContext);\n }\n\n /** The centre of the container minus the host's chrome, in diagram coordinates. */\n private freeRectCentre(): Point {\n const viewbox = this.canvas.viewbox();\n const insets = this.config?.freeRectInsets?.() ?? { top: 0, right: 0, bottom: 0, left: 0 };\n const freeWidth = Math.max(0, viewbox.outer.width - insets.left - insets.right);\n const freeHeight = Math.max(0, viewbox.outer.height - insets.top - insets.bottom);\n return {\n x: viewbox.x + (insets.left + freeWidth / 2) / viewbox.scale,\n y: viewbox.y + (insets.top + freeHeight / 2) / viewbox.scale,\n };\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport PaletteModule from \"diagram-js/lib/features/palette\";\nimport CreateModule from \"diagram-js/lib/features/create\";\nimport ConnectModule from \"diagram-js/lib/features/connect\";\nimport LassoToolModule from \"diagram-js/lib/features/lasso-tool\";\nimport ModelingModule from \"diagram-js/lib/features/modeling\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport { cmLabelEditingModule } from \"../label-editing/index.js\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmPaletteProvider from \"./CmPaletteProvider.js\";\n\n/** Tool palette: lasso tool + create contexts (drag, click or Enter/Space). */\nexport const cmPaletteModule: ModuleDeclaration = {\n __depends__: [\n PaletteModule,\n CreateModule,\n ConnectModule,\n LassoToolModule,\n ModelingModule,\n SelectionModule,\n cmLabelEditingModule,\n cmReadOnlyModule,\n ],\n __init__: [\"cmPaletteProvider\"],\n cmPaletteProvider: [\"type\", CmPaletteProvider],\n};\n\nexport { default as CmPaletteProvider } from \"./CmPaletteProvider.js\";\nexport type { CmPaletteConfig } from \"./CmPaletteProvider.js\";\n","/**\n * Per-element quick actions (diagram-js context pad + popup menus), so every\n * embedder of the Modeler gets element-level editing out of the box — not just\n * hosts that build their own inspector.\n *\n * - Bounded context: append a connected context, connect, subdomain type\n * (menu), owning team (in-place over its caption), rename (in-place direct\n * editing), description (anchored prompt), delete.\n * - Relationship: pattern (menu); integration roles (menu) and swap ends\n * while the pattern is asymmetric; rename, description, delete.\n * - Multi-selection: delete.\n *\n * Every mutation goes through `cmModeling`/`modeling`, so it is undoable and\n * lands in `exportDocument()`. Role/pattern constraints mirror the reference\n * inspector: upstream roles combine, downstream roles exclude each other, and\n * customer-supplier blocks OHS (upstream) and CF (downstream).\n */\n\nimport type ContextPad from \"diagram-js/lib/features/context-pad/ContextPad\";\nimport type {\n ContextPadEntries,\n ContextPadEntry,\n default as ContextPadProvider,\n} from \"diagram-js/lib/features/context-pad/ContextPadProvider\";\nimport type PopupMenu from \"diagram-js/lib/features/popup-menu/PopupMenu\";\nimport type { PopupMenuTarget } from \"diagram-js/lib/features/popup-menu/PopupMenu\";\nimport type { PopupMenuEntries } from \"diagram-js/lib/features/popup-menu/PopupMenuProvider\";\nimport type Connect from \"diagram-js/lib/features/connect/Connect\";\nimport type Create from \"diagram-js/lib/features/create/Create\";\nimport type AutoPlace from \"diagram-js/lib/features/auto-place/AutoPlace\";\nimport type Dragging from \"diagram-js/lib/features/dragging/Dragging\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type Rules from \"diagram-js/lib/features/rules/Rules\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type Scheduler from \"diagram-js/lib/features/scheduler/Scheduler\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type { Element, Shape } from \"diagram-js/lib/model/Types\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { asTRBL, getMid } from \"diagram-js/lib/layout/LayoutUtil\";\nimport {\n DEFAULT_DISTANCE,\n findFreePosition,\n generateGetNextPosition,\n} from \"diagram-js/lib/features/auto-place/AutoPlaceUtil\";\nimport {\n ALL_PATTERN_SPECS,\n ALL_SUBDOMAIN_SPECS,\n DOWNSTREAM_ROLES,\n DOWNSTREAM_ROLE_SPECS,\n RELATIONSHIP_PATTERN_SPECS,\n SUBDOMAIN_TYPE_SPECS,\n UPSTREAM_ROLES,\n UPSTREAM_ROLE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type {\n DownstreamRole,\n RelationshipPatternSpec,\n UpstreamRole,\n} from \"@miragon/context-maps-schema-model\";\nimport {\n isCmContext,\n isCmElement,\n isCmRelationship,\n type CmContext,\n type CmElement,\n type CmRelationship,\n} from \"../model/di-types.js\";\nimport type CmModeling from \"../modeling/CmModeling.js\";\nimport type CmLabelEditing from \"../label-editing/CmLabelEditing.js\";\nimport type CmElementFactory from \"../model/CmElementFactory.js\";\nimport { READ_ONLY_CHANGED_EVENT, type CmReadOnly } from \"../read-only/index.js\";\nimport { contextIconSvg, relationshipIconSvg, roleChipSvg } from \"../draw/palette-icons.js\";\nimport { chromeIcon } from \"../draw/lucide.js\";\n\nconst SUBDOMAIN_MENU = \"cm-subdomain-menu\";\nconst PATTERN_MENU = \"cm-pattern-menu\";\nconst ROLES_MENU = \"cm-roles-menu\";\n\n/** Marks the entry matching the element's current state (check + accent, CSS). */\nconst ACTIVE_CLASS = \"cm-popup-active\";\nconst MENU_GAP = 8;\n\n/** Why OHS / CF are unavailable while the pattern is customer-supplier. */\nconst CUSTOMER_SUPPLIER_BLOCKERS: Partial<Record<UpstreamRole | DownstreamRole, string>> = {\n OHS: \"Open Host Service is one-size-fits-all and not applicable in a customer-supplier relationship.\",\n CF: \"Conformist is not applicable in a customer-supplier relationship — a customer can negotiate.\",\n};\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction padEntryHtml(\n icon: string,\n title: string,\n options: { draggable?: boolean; danger?: boolean } = {},\n): string {\n const draggable = options.draggable ? ` draggable=\"true\"` : \"\";\n const danger = options.danger ? \" cm-pad-entry--danger\" : \"\";\n const label = escapeAttribute(title);\n return `<div class=\"entry cm-pad-entry${danger}\"${draggable} title=\"${label}\" aria-label=\"${label}\">${icon}</div>`;\n}\n\n/**\n * Beside the pad entry that opened the card, kept on screen when the entry sits at a viewport\n * edge: no room on the right → flip to the entry's left, bottom → shift up.\n */\nfunction placePromptBeside(card: HTMLElement, anchor: HTMLElement): void {\n const bounds = anchor.getBoundingClientRect();\n card.style.left = `${bounds.right + MENU_GAP}px`;\n card.style.top = `${bounds.top}px`;\n const cardBounds = card.getBoundingClientRect();\n const margin = 8;\n if (cardBounds.right > window.innerWidth - margin) {\n card.style.left = `${Math.max(margin, bounds.left - cardBounds.width - MENU_GAP)}px`;\n }\n if (cardBounds.bottom > window.innerHeight - margin) {\n card.style.top = `${Math.max(margin, window.innerHeight - margin - cardBounds.height)}px`;\n }\n}\n\nexport default class CmContextPadProvider implements ContextPadProvider {\n static $inject = [\n \"contextPad\",\n \"popupMenu\",\n \"eventBus\",\n \"connect\",\n \"create\",\n \"autoPlace\",\n \"rules\",\n \"dragging\",\n \"modeling\",\n \"cmModeling\",\n \"cmLabelEditing\",\n \"cmElementFactory\",\n \"selection\",\n \"canvas\",\n \"scheduler\",\n \"cmReadOnly\",\n ];\n\n /** The last pad-opened menu, so a roles toggle can re-open it in place. */\n private currentMenu?: { element: CmElement; menuId: string; title: string; position: Point };\n\n constructor(\n private readonly contextPad: ContextPad,\n private readonly popupMenu: PopupMenu,\n private readonly eventBus: EventBus,\n connect: Connect,\n private readonly create: Create,\n private readonly autoPlace: AutoPlace,\n private readonly rules: Rules,\n private readonly dragging: Dragging,\n private readonly modeling: Modeling,\n private readonly cmModeling: CmModeling,\n private readonly labelEditing: CmLabelEditing,\n private readonly elementFactory: CmElementFactory,\n private readonly selection: Selection,\n private readonly canvas: Canvas,\n private readonly scheduler: Scheduler,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n // Injecting Connect instantiates it so its connect.* drag handlers exist\n // (same reason as CmConnectHandles — the module does not eagerly init it).\n void connect;\n contextPad.registerProvider(this);\n // A read-only canvas has no context pad (guide §13.5): nothing it offers may change the map.\n eventBus.on(\"contextPad.open.allowed\", 2000, () =>\n this.readOnly.isReadOnly() ? false : undefined,\n );\n eventBus.on(READ_ONLY_CHANGED_EVENT, (event: { readOnly?: boolean }) => {\n if (event.readOnly) {\n this.cancelPrompt();\n popupMenu.close();\n contextPad.close();\n return;\n }\n // Unlocked with an element still selected: its pad comes back, as a fresh selection would.\n const selected = selection.get() as Element[];\n if (selected.length === 1) contextPad.open(selected[0]!, true);\n else if (selected.length > 1) contextPad.open(selected, true);\n });\n popupMenu.registerProvider(SUBDOMAIN_MENU, {\n getPopupMenuEntries: (target: PopupMenuTarget) => this.subdomainMenuEntries(target),\n });\n popupMenu.registerProvider(PATTERN_MENU, {\n getPopupMenuEntries: (target: PopupMenuTarget) => this.patternMenuEntries(target),\n });\n popupMenu.registerProvider(ROLES_MENU, {\n getPopupMenuEntries: (target: PopupMenuTarget) => this.rolesMenuEntries(target),\n });\n // Deconflict auto-placed appends: diagram-js' stock position (right of the\n // source) ignores occupied slots — step downwards until the slot is free.\n // Registered at default priority, beating the stock low-priority listener.\n eventBus.on(\"autoPlace\", (event: { source: Shape; shape: Shape }) => {\n const { source, shape } = event;\n const position = {\n x: asTRBL(source).right + DEFAULT_DISTANCE + shape.width / 2,\n y: getMid(source).y,\n };\n return findFreePosition(\n source,\n shape,\n position,\n generateGetNextPosition({ y: { margin: 30, minDistance: 30 } }),\n );\n });\n // The pad's placement is corrected purely via CSS classes: connections\n // flip it away from the target context their last segment points into.\n eventBus.on(\"contextPad.create\", (event: { target?: unknown; pad?: HTMLElement }) => {\n const { pad, target } = event;\n if (!pad) return;\n let flipX = false;\n let flipY = false;\n if (isCmRelationship(target)) {\n const waypoints = (target.waypoints ?? []) as Point[];\n const last = waypoints[waypoints.length - 1];\n const previous = waypoints[waypoints.length - 2];\n if (last && previous) {\n const dx = last.x - previous.x;\n const dy = last.y - previous.y;\n flipX = Math.abs(dx) >= Math.abs(dy) && dx > 0;\n flipY = Math.abs(dy) > Math.abs(dx) && dy > 0;\n }\n }\n pad.classList.toggle(\"cm-pad-flip-x\", flipX);\n pad.classList.toggle(\"cm-pad-flip-y\", flipY);\n });\n // diagram-js positions the pad without any viewport clamping, and the\n // canvas container clips (overflow: hidden) — pull an overflowing pad back\n // in so its actions stay reachable for shapes at the canvas edge. Runs\n // after diagram-js' own scheduled position update (lower listener priority\n // → later schedule() call → later task).\n eventBus.on([\"contextPad.open\", \"contextPad.show\", \"canvas.viewbox.changed\"], 250, () =>\n this.clampPadIntoView(),\n );\n }\n\n private clampPadIntoView(): void {\n void this.scheduler.schedule(() => {\n const container = this.canvas.getContainer();\n const pad = container.querySelector<HTMLElement>(\".djs-context-pad.open\");\n if (!pad) return;\n const containerBounds = container.getBoundingClientRect();\n const padBounds = pad.getBoundingClientRect();\n const margin = 4;\n const overflowRight = padBounds.right - (containerBounds.right - margin);\n if (overflowRight > 0) {\n pad.style.left = `${parseFloat(pad.style.left || \"0\") - overflowRight}px`;\n }\n // The cm-pad-flip-x transform can carry a connection's pad past the\n // LEFT border (its anchor is the unclamped last waypoint).\n const overflowLeft = containerBounds.left + margin - padBounds.left;\n if (overflowLeft > 0) {\n pad.style.left = `${parseFloat(pad.style.left || \"0\") + overflowLeft}px`;\n }\n // Vertically pull an overflowing pad up — but never past the top\n // border: when the stack is taller than the canvas, the top actions\n // stay reachable rather than none of them.\n let shiftY = 0;\n const overflowBottom = padBounds.bottom - (containerBounds.bottom - margin);\n if (overflowBottom > 0) shiftY = -overflowBottom;\n const overflowTop = containerBounds.top + margin - (padBounds.top + shiftY);\n if (overflowTop > 0) shiftY += overflowTop;\n if (shiftY !== 0) {\n pad.style.top = `${parseFloat(pad.style.top || \"0\") + shiftY}px`;\n }\n }, \"cmContextPad#clampIntoView\");\n }\n\n getContextPadEntries(element: Element): ContextPadEntries {\n if (this.readOnly.isReadOnly()) return {};\n if (isCmContext(element)) return this.contextEntries(element);\n if (isCmRelationship(element)) return this.relationshipEntries(element);\n return {};\n }\n\n getMultiElementContextPadEntries(elements: Element[]): ContextPadEntries {\n if (this.readOnly.isReadOnly()) return {};\n const cmElements = elements.filter(isCmElement);\n if (cmElements.length !== elements.length) return {};\n return { delete: this.deleteEntry(cmElements, \"Delete selection\") };\n }\n\n // --- bounded context ------------------------------------------------------\n\n private contextEntries(context: CmContext): ContextPadEntries {\n const spec = context.subdomainType ? SUBDOMAIN_TYPE_SPECS[context.subdomainType] : undefined;\n return {\n \"append-context\": {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"square-plus\"),\n \"Append a connected context — click to place automatically, drag to position\",\n { draggable: true },\n ),\n action: {\n click: () => this.appendContext(context),\n dragstart: (event: Event) => this.startAppend(event, context),\n },\n },\n connect: {\n group: \"edit\",\n html: padEntryHtml(chromeIcon(\"arrow-right\"), \"Connect to another context\", {\n draggable: true,\n }),\n action: {\n click: (event: Event) => this.startConnect(event, context, true),\n dragstart: (event: Event) => this.startConnect(event, context, false),\n },\n },\n \"subdomain-type\": {\n group: \"edit\",\n html: padEntryHtml(\n contextIconSvg(context.subdomainType),\n `Change subdomain type — currently ${spec?.label ?? \"unclassified\"}`,\n ),\n action: {\n click: (event: Event) => this.openMenu(event, context, SUBDOMAIN_MENU, \"Subdomain type\"),\n },\n },\n team: {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"users\"),\n `Set owning team — currently ${context.team ?? \"none\"}`,\n ),\n action: { click: () => this.labelEditing.activateTeam(context) },\n },\n \"edit-label\": this.editLabelEntry(context, \"Rename context\"),\n description: this.descriptionEntry(context, \"Purpose, ubiquitous language, notes…\"),\n delete: this.deleteEntry([context], \"Delete context\"),\n };\n }\n\n /**\n * Same payload as Connect#start, mirroring CmConnectHandles, but with\n * diagram-js' ghost-click trap OFF for both variants: the trap relies on the\n * gesture-ending canvas click, which Chromium suppresses whenever the\n * mousedown target was re-rendered by the connect command — the unconsumed\n * trap would then swallow the user's NEXT click. The click variant instead\n * blocks exactly one immediately-following element.click itself (when it\n * does fire, it must not re-select the target over the fresh relationship).\n */\n private startConnect(event: Event, source: CmContext, viaClick: boolean): void {\n this.dragging.init(event as MouseEvent, \"connect\", {\n autoActivate: viaClick,\n trapClick: false,\n data: {\n shape: source,\n context: { start: source, connectionStart: getMid(source) },\n },\n });\n if (viaClick) {\n const swallowGestureClick = () => false;\n this.eventBus.once(\"connect.cleanup\", 250, () => {\n this.eventBus.once(\"element.click\", 10000, swallowGestureClick);\n const disarm = (): void => this.eventBus.off(\"element.click\", swallowGestureClick);\n // Dragging binds endDrag to mousedown AND mouseup — the gesture already\n // ends in the *mousedown* of the finishing click, whose click event is\n // only delivered after the following mouseup. Hold the blocker until\n // then: the capture-mouseup runs before the click, the 0ms task after.\n document.addEventListener(\"mouseup\", () => setTimeout(disarm, 0), {\n capture: true,\n once: true,\n });\n // Safety net (same window as diagram-js' ClickTrap): if the click never\n // arrives, the blocker must not eat a later real one.\n setTimeout(disarm, 400);\n });\n }\n // The drag lifecycle clears the selection; the user is still \"at\" the source.\n this.eventBus.once(\"connect.cleanup\", 250, () => {\n if (this.selection.get().length === 0) this.selection.select(source);\n });\n }\n\n /**\n * Append a fresh, unclassified context connected to the source. The click\n * variant auto-places it (diagram-js auto-place, which also selects it), the\n * drag variant hands placement to the create tool with a `source` hint —\n * both stamp the connection through the `connection.create` rule. After\n * placement the subdomain-type menu opens so classifying is one click away.\n */\n private appendContext(source: CmContext): void {\n const shape = this.elementFactory.createNewContext();\n // CmRules returns the relationship attrs (cmKind + default pattern), not\n // just a boolean — pass them on so the connection is stamped correctly.\n const connection = this.rules.allowed(\"connection.create\", {\n source,\n target: shape,\n }) as unknown as false | null | Record<string, unknown>;\n const appended = this.autoPlace.append(\n source,\n shape,\n connection && typeof connection === \"object\" ? { connection } : {},\n ) as unknown as CmContext;\n this.openTypeMenu(appended);\n }\n\n private startAppend(event: Event, source: CmContext): void {\n const shape = this.elementFactory.createNewContext();\n const onCreated = () => this.openTypeMenu(shape);\n this.eventBus.once(\"create.end\", 250, onCreated);\n // A cancelled create must not leave the armed listener behind — it would\n // fire on the next palette create otherwise.\n this.eventBus.once(\"create.cleanup\", () => this.eventBus.off(\"create.end\", onCreated));\n this.create.start(event as MouseEvent, shape, { source });\n }\n\n /** Open the subdomain-type menu for a freshly appended context, anchored to\n * its pad entry — deferred one task so the pad has been positioned first. */\n private openTypeMenu(context: CmContext): void {\n void this.scheduler.schedule(() => {\n if (!this.contextPad.isOpen(context)) return;\n const entry = this.canvas\n .getContainer()\n .querySelector<HTMLElement>('.djs-context-pad.open [data-action=\"subdomain-type\"]');\n if (!entry) return;\n this.openMenuBeside(entry.getBoundingClientRect(), context, SUBDOMAIN_MENU, \"Subdomain type\");\n }, \"cmContextPad#openTypeMenu\");\n }\n\n // --- relationship ---------------------------------------------------------\n\n private relationshipEntries(relationship: CmRelationship): ContextPadEntries {\n // Tolerate unknown patterns (unvalidated imports), like the renderer does:\n // the pad must still open so the pattern menu can repair the element.\n const spec = RELATIONSHIP_PATTERN_SPECS[relationship.pattern] as\n RelationshipPatternSpec | undefined;\n const entries: ContextPadEntries = {\n pattern: {\n group: \"edit\",\n html: padEntryHtml(\n relationshipIconSvg(spec?.pattern),\n `Change pattern — currently ${spec?.label ?? relationship.pattern}`,\n ),\n action: {\n click: (event: Event) =>\n this.openMenu(event, relationship, PATTERN_MENU, \"Relationship pattern\"),\n },\n },\n };\n if (spec && !spec.symmetric) {\n entries.roles = {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"sliders-horizontal\"),\n \"Edit integration roles — OHS/PL upstream, ACL/CF downstream\",\n ),\n action: {\n click: (event: Event) =>\n this.openMenu(event, relationship, ROLES_MENU, \"Integration roles\"),\n },\n };\n entries[\"swap-ends\"] = {\n group: \"edit\",\n html: padEntryHtml(\n chromeIcon(\"arrow-left-right\"),\n \"Swap ends — reverse upstream/downstream\",\n ),\n action: { click: () => this.cmModeling.swapEnds(relationship) },\n };\n }\n entries[\"edit-label\"] = this.editLabelEntry(relationship, \"Edit label\");\n entries.description = this.descriptionEntry(relationship, \"What flows here, contracts, notes…\");\n entries.delete = this.deleteEntry([relationship], \"Delete relationship\");\n return entries;\n }\n\n // --- shared entries -------------------------------------------------------\n\n private editLabelEntry(element: CmElement, title: string): ContextPadEntry {\n return {\n group: \"edit\",\n html: padEntryHtml(chromeIcon(\"pencil\"), `${title} — edit the name in place`),\n action: { click: () => this.labelEditing.activate(element) },\n };\n }\n\n private descriptionEntry(element: CmElement, placeholder: string): ContextPadEntry {\n return {\n group: \"edit\",\n html: padEntryHtml(chromeIcon(\"text-align-start\"), \"Edit description\"),\n action: {\n click: (event: Event) =>\n this.openPrompt(event, {\n value: element.description ?? \"\",\n placeholder,\n label: \"Description\",\n multiline: true,\n onCommit: (value) => this.cmModeling.setDescription(element, value || undefined),\n }),\n },\n };\n }\n\n /**\n * A small input card anchored beside the clicked pad entry (like the popup\n * menus — below would cover the rest of the vertical stack) — for the\n * free-text properties, which should not open centred over the element.\n * Enter (Ctrl/Cmd+Enter in the multiline variant) and blur commit, Escape\n * cancels.\n */\n private activePrompt?: { cancel(): void };\n\n /** Closes an open description prompt without saving it (an import replaces its element). */\n cancelPrompt(): void {\n this.activePrompt?.cancel();\n }\n\n private openPrompt(\n event: Event,\n config: {\n value: string;\n placeholder: string;\n label: string;\n multiline?: boolean;\n onCommit(value: string): void;\n },\n ): void {\n this.activePrompt?.cancel();\n const anchor = ((event as { delegateTarget?: EventTarget }).delegateTarget ??\n event.target) as HTMLElement;\n\n const card = document.createElement(\"div\");\n card.className = \"cm-pad-prompt\";\n\n const field = document.createElement(config.multiline ? \"textarea\" : \"input\") as\n HTMLInputElement | HTMLTextAreaElement;\n field.className = \"cm-pad-prompt__field\";\n field.value = config.value;\n field.placeholder = config.placeholder;\n field.setAttribute(\"aria-label\", config.label);\n if (field instanceof HTMLTextAreaElement) field.rows = 4;\n card.appendChild(field);\n\n if (config.multiline) {\n const hint = document.createElement(\"div\");\n hint.className = \"cm-pad-prompt__hint\";\n hint.textContent = \"Esc to cancel · ⌘/Ctrl+Enter to save\";\n card.appendChild(hint);\n }\n\n this.canvas.getContainer().appendChild(card);\n placePromptBeside(card, anchor);\n field.focus();\n if (field instanceof HTMLTextAreaElement) {\n // Select-all in a filled textarea makes the first keystroke wipe the\n // text — park the caret at the end instead.\n field.setSelectionRange(field.value.length, field.value.length);\n } else {\n field.select();\n }\n\n // A pan or zoom moves the pad, also one the host makes (setViewState, a fit): the card follows\n // its entry and keeps the typed text instead of committing it (mirrors the label editor).\n // After the pad's own position update and clamp, which are scheduled at a higher priority.\n const followPad = (): void => {\n void this.scheduler.schedule(() => {\n if (anchor.isConnected) placePromptBeside(card, anchor);\n }, \"cmContextPad#placePrompt\");\n };\n this.eventBus.on(\"canvas.viewbox.changed\", 200, followPad);\n\n let done = false;\n const cleanup = (): void => {\n if (done) return;\n done = true;\n this.eventBus.off(\"canvas.viewbox.changed\", followPad);\n this.scheduler.cancel(\"cmContextPad#placePrompt\");\n card.remove();\n this.activePrompt = undefined;\n (this.canvas as { restoreFocus?: () => void }).restoreFocus?.();\n };\n const commit = (): void => {\n if (done) return;\n const value = field.value.trim();\n const changed = value !== config.value.trim();\n cleanup();\n if (changed) config.onCommit(value);\n };\n field.addEventListener(\"keydown\", (event: Event) => {\n const keyEvent = event as KeyboardEvent;\n if (keyEvent.key === \"Escape\") {\n keyEvent.preventDefault();\n keyEvent.stopPropagation();\n cleanup();\n } else if (\n keyEvent.key === \"Enter\" &&\n (!config.multiline || keyEvent.ctrlKey || keyEvent.metaKey)\n ) {\n keyEvent.preventDefault();\n commit();\n }\n });\n field.addEventListener(\"blur\", commit);\n this.activePrompt = { cancel: cleanup };\n }\n\n private deleteEntry(elements: CmElement[], title: string): ContextPadEntry {\n return {\n group: \"delete\",\n html: padEntryHtml(chromeIcon(\"trash\"), title, { danger: true }),\n action: { click: () => this.modeling.removeElements(elements as Element[]) },\n };\n }\n\n private openMenu(event: Event, element: CmElement, menuId: string, title: string): void {\n const anchor = ((event as { delegateTarget?: EventTarget }).delegateTarget ??\n event.target) as HTMLElement;\n this.openMenuBeside(anchor.getBoundingClientRect(), element, menuId, title);\n }\n\n /**\n * Menus open beside the clicked entry — beneath it they would cover the\n * rest of the vertical stack. At the viewport's right edge PopupMenu flips\n * an overflowing menu back across its anchor (and the whole pad column), so\n * a flipped menu is pushed fully left of the pad instead; the popup applies\n * its initial position only once, so the correction sticks (and is saved\n * for `reopenMenu`).\n */\n private openMenuBeside(\n entryBounds: DOMRect,\n element: CmElement,\n menuId: string,\n title: string,\n ): void {\n const position = { x: entryBounds.right + MENU_GAP, y: entryBounds.top };\n this.popupMenu.open(element, menuId, position, { title });\n const popup = document.querySelector<HTMLElement>(\".djs-popup\");\n const popupBounds = popup?.getBoundingClientRect();\n if (popup && popupBounds && popupBounds.left < entryBounds.right) {\n position.x = Math.max(MENU_GAP, entryBounds.left - MENU_GAP - popupBounds.width);\n popup.style.left = `${position.x}px`;\n }\n this.currentMenu = { element, menuId, title, position };\n }\n\n /**\n * Re-open a menu after a command: the command stack's `commandStack.changed`\n * auto-closes any popup, but a multi-select menu (integration roles) should\n * survive a toggle so combinations don't require re-opening the pad entry.\n */\n private reopenMenu(element: CmElement, menuId: string): void {\n const menu = this.currentMenu;\n if (!menu || menu.menuId !== menuId || menu.element !== element) return;\n this.popupMenu.open(element, menuId, menu.position, { title: menu.title });\n }\n\n // --- popup menus ----------------------------------------------------------\n\n private subdomainMenuEntries(target: PopupMenuTarget): PopupMenuEntries {\n if (!isCmContext(target)) return {};\n const current = target.subdomainType;\n const entries: PopupMenuEntries = {};\n for (const spec of ALL_SUBDOMAIN_SPECS) {\n entries[`type-${spec.type}`] = {\n label: spec.label,\n description: spec.description,\n imageHtml: contextIconSvg(spec.type),\n ...(spec.type === current ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (spec.type !== current) this.cmModeling.setSubdomainType(target, spec.type);\n },\n };\n }\n entries[\"type-none\"] = {\n label: \"Unclassified\",\n description: \"No subdomain classification.\",\n imageHtml: contextIconSvg(),\n ...(current === undefined ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (current !== undefined) this.cmModeling.setSubdomainType(target, undefined);\n },\n };\n return entries;\n }\n\n private patternMenuEntries(target: PopupMenuTarget): PopupMenuEntries {\n if (!isCmRelationship(target)) return {};\n const current = target.pattern;\n const entries: PopupMenuEntries = {};\n for (const spec of ALL_PATTERN_SPECS) {\n entries[`pattern-${spec.pattern}`] = {\n label: spec.label,\n description: spec.description,\n imageHtml: relationshipIconSvg(spec.pattern),\n ...(spec.pattern === current ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (spec.pattern !== current) this.cmModeling.setPattern(target, spec.pattern);\n },\n };\n }\n return entries;\n }\n\n private rolesMenuEntries(target: PopupMenuTarget): PopupMenuEntries {\n if (!isCmRelationship(target)) return {};\n const spec = RELATIONSHIP_PATTERN_SPECS[target.pattern] as RelationshipPatternSpec | undefined;\n if (!spec || spec.symmetric) return {};\n const customerSupplier = target.pattern === \"customer-supplier\";\n const upstream = target.upstreamRoles ?? [];\n const downstream = target.downstreamRoles ?? [];\n const entries: PopupMenuEntries = {};\n\n for (const role of UPSTREAM_ROLES) {\n const active = upstream.includes(role);\n const blocker = customerSupplier ? CUSTOMER_SUPPLIER_BLOCKERS[role] : undefined;\n // A blocked role that is already set (unvalidated import, CML) stays\n // clickable — deselecting it is the repair, not the violation.\n const blocked = blocker !== undefined && !active;\n entries[`upstream-${role}`] = {\n label: UPSTREAM_ROLE_SPECS[role].label,\n description: blocker\n ? active\n ? `${blocker} Click to remove it.`\n : blocker\n : UPSTREAM_ROLE_SPECS[role].description,\n imageHtml: roleChipSvg(role),\n group: { id: \"upstream\", name: \"Upstream (from) — OHS and/or PL\" },\n ...(blocked ? { disabled: true } : {}),\n ...(active ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (blocked) return;\n this.cmModeling.setUpstreamRoles(\n target,\n active ? upstream.filter((existing) => existing !== role) : [...upstream, role],\n );\n this.reopenMenu(target, ROLES_MENU);\n },\n };\n }\n for (const role of DOWNSTREAM_ROLES) {\n const active = downstream.includes(role);\n const blocker = customerSupplier ? CUSTOMER_SUPPLIER_BLOCKERS[role] : undefined;\n const blocked = blocker !== undefined && !active;\n entries[`downstream-${role}`] = {\n label: DOWNSTREAM_ROLE_SPECS[role].label,\n description: blocker\n ? active\n ? `${blocker} Click to remove it.`\n : blocker\n : DOWNSTREAM_ROLE_SPECS[role].description,\n imageHtml: roleChipSvg(role),\n group: { id: \"downstream\", name: \"Downstream (to) — ACL or CF, not both\" },\n ...(blocked ? { disabled: true } : {}),\n ...(active ? { className: ACTIVE_CLASS } : {}),\n action: () => {\n if (blocked) return;\n this.cmModeling.setDownstreamRoles(target, active ? [] : [role]);\n this.reopenMenu(target, ROLES_MENU);\n },\n };\n }\n return entries;\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport ContextPadModule from \"diagram-js/lib/features/context-pad\";\nimport PopupMenuModule from \"diagram-js/lib/features/popup-menu\";\nimport ConnectModule from \"diagram-js/lib/features/connect\";\nimport CreateModule from \"diagram-js/lib/features/create\";\nimport AutoPlaceModule from \"diagram-js/lib/features/auto-place\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport ModelingModule from \"diagram-js/lib/features/modeling\";\nimport { cmModelingModule } from \"../modeling/index.js\";\nimport { cmRulesModule } from \"../rules/index.js\";\nimport { cmLabelEditingModule } from \"../label-editing/index.js\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmContextPadProvider from \"./CmContextPadProvider.js\";\n\nexport const cmContextPadModule: ModuleDeclaration = {\n __depends__: [\n ContextPadModule,\n PopupMenuModule,\n ConnectModule,\n CreateModule,\n AutoPlaceModule,\n SelectionModule,\n ModelingModule,\n cmModelingModule,\n // The connect action needs CmRules: only its connection.create rule stamps\n // the new connection as a relationship (cmKind + default pattern).\n cmRulesModule,\n cmLabelEditingModule,\n cmReadOnlyModule,\n ],\n __init__: [\"cmContextPadProvider\"],\n cmContextPadProvider: [\"type\", CmContextPadProvider],\n};\n\nexport { default as CmContextPadProvider } from \"./CmContextPadProvider.js\";\n","/**\n * Keyboard shortcuts: select all, undo / redo, delete-selection. Bound to the document so they\n * work without first clicking (focusing) the canvas, but only for keys aimed at the canvas: keys\n * from outside its container (a host's chrome) and keys someone closer to the target already\n * handled (`defaultPrevented`) are left alone, and typing inside form fields is never\n * intercepted. No container `tabindex`, so the canvas adds no tab stop of its own.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type Modeling from \"diagram-js/lib/features/modeling/Modeling\";\nimport type { Element } from \"diagram-js/lib/model/Types\";\nimport { isCmElement } from \"../model/di-types.js\";\nimport type CmReadOnly from \"../read-only/CmReadOnly.js\";\n\nexport interface CmKeyboardConfig {\n /**\n * Bind Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z and Cmd/Ctrl+Y to the canvas command stack (default true).\n * A host that owns the history (the VS Code document) passes false, so the keys reach it.\n */\n undoRedoKeys?: boolean | undefined;\n}\n\nfunction isTypingTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null;\n if (!el) return false;\n return (\n el.tagName === \"INPUT\" ||\n el.tagName === \"TEXTAREA\" ||\n el.tagName === \"SELECT\" ||\n el.isContentEditable\n );\n}\n\n/**\n * A key aimed at the canvas: from inside its container, or with nothing focused at all. The\n * palette lives in the container too, but a key on a focused palette entry is the palette's: Delete\n * there must not remove the selected elements.\n */\nfunction isCanvasTarget(target: EventTarget | null, container: HTMLElement): boolean {\n if (!(target instanceof Node)) return false;\n if (target instanceof Element && target.closest(\".djs-palette\")) return false;\n const ownerDocument = container.ownerDocument;\n return (\n container.contains(target) ||\n target === ownerDocument.body ||\n target === ownerDocument.documentElement\n );\n}\n\nexport default class CmKeyboard {\n static $inject = [\n \"config.cmKeyboard\",\n \"canvas\",\n \"commandStack\",\n \"selection\",\n \"modeling\",\n \"elementRegistry\",\n \"eventBus\",\n \"cmReadOnly\",\n ];\n\n constructor(\n config: CmKeyboardConfig | undefined,\n canvas: Canvas,\n commandStack: CommandStack,\n selection: Selection,\n modeling: Modeling,\n elementRegistry: ElementRegistry,\n eventBus: EventBus,\n readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n const container = canvas.getContainer();\n const doc = container.ownerDocument ?? document;\n const undoRedoKeys = config?.undoRedoKeys ?? true;\n\n const onKeydown = (e: KeyboardEvent): void => {\n if (e.defaultPrevented) return;\n if (!isCanvasTarget(e.target, container)) return;\n if (isTypingTarget(e.target)) return;\n const cmd = e.ctrlKey || e.metaKey;\n const key = e.key.toLowerCase();\n\n // Select all reads the map, so it stays under the read-only lock; without it the host\n // (VS Code) would run its own Select All over the chrome's text.\n if (cmd && key === \"a\" && !e.shiftKey && !e.altKey) {\n e.preventDefault();\n selection.select(elementRegistry.filter((element) => isCmElement(element)) as Element[]);\n return;\n }\n if (readOnly.isReadOnly()) return;\n\n const isUndo = cmd && key === \"z\" && !e.shiftKey;\n const isRedo = (cmd && key === \"z\" && e.shiftKey) || (cmd && key === \"y\" && !e.shiftKey);\n if (isUndo || isRedo) {\n if (!undoRedoKeys) return;\n e.preventDefault();\n if (isUndo && commandStack.canUndo()) commandStack.undo();\n if (isRedo && commandStack.canRedo()) commandStack.redo();\n } else if (key === \"delete\" || key === \"backspace\") {\n const sel = selection.get() as Element[];\n if (sel.length) {\n e.preventDefault();\n modeling.removeElements([...sel]);\n }\n }\n };\n\n doc.addEventListener(\"keydown\", onKeydown);\n eventBus.on(\"diagram.destroy\", () => doc.removeEventListener(\"keydown\", onKeydown));\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmKeyboard from \"./CmKeyboard.js\";\n\n/** Select all, undo/redo and delete-selection for keys aimed at the canvas. */\nexport const cmKeyboardModule: ModuleDeclaration = {\n __depends__: [cmReadOnlyModule],\n __init__: [\"cmKeyboard\"],\n cmKeyboard: [\"type\", CmKeyboard],\n};\n\nexport { default as CmKeyboard } from \"./CmKeyboard.js\";\nexport type { CmKeyboardConfig } from \"./CmKeyboard.js\";\n","/**\n * Live semantic-rule markers on the canvas: a relationship with validation\n * findings gets a small marker next to the issue — the problem pill's icons in\n * the status roles: `triangle-alert` for warnings, `circle-x` if any finding is\n * an error. Sided findings (e.g. an ACL issue\n * is a downstream concern) anchor at the BOTTOM-RIGHT corner of that end's\n * role-chip box (geometry shared with the renderer via endRoleChipLayout);\n * findings about the relationship as a whole sit at the middle of the line.\n * Hovering shows the message(s) instantly via a CSS tooltip (a native `title`\n * would only appear after the OS hover delay). Implemented as diagram-js\n * overlays (HTML above the SVG), so hover is not swallowed by the connection\n * hit layer and the marker follows its element. Recomputed on every change.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type Overlays from \"diagram-js/lib/features/overlays/Overlays\";\nimport type { Point } from \"diagram-js/lib/util/Types\";\nimport { validateDocument, type SemanticFinding } from \"@miragon/context-maps-schema-model\";\nimport type CmExporter from \"../io/CmExporter.js\";\nimport { isCmRelationship, type CmRelationship } from \"../model/di-types.js\";\nimport { endRoleChipLayout } from \"../draw/endRoleChips.js\";\nimport { chromeIcon } from \"../draw/lucide.js\";\n\nconst OVERLAY_TYPE = \"cm-validation\";\nconst MARKER_SIZE = 22;\nconst LINE_OFFSET = 16;\n/** Fallback distance from the endpoint when the end has no role chips. */\nconst END_DISTANCE = 44;\n\ntype MarkerSide = \"upstream\" | \"downstream\" | \"middle\";\n\ninterface RankedFinding extends SemanticFinding {\n kind: \"error\" | \"warning\";\n}\n\nfunction markerHtml(findings: RankedFinding[]): HTMLElement {\n const hasError = findings.some((finding) => finding.kind === \"error\");\n const marker = document.createElement(\"div\");\n marker.className = \"cm-validation-marker\";\n marker.dataset.severity = hasError ? \"error\" : \"warning\";\n marker.innerHTML = chromeIcon(hasError ? \"circle-x\" : \"triangle-alert\");\n\n const tooltip = document.createElement(\"div\");\n tooltip.className = \"cm-validation-tooltip\";\n for (const finding of findings) {\n const message = document.createElement(\"div\");\n message.className = \"cm-validation-tooltip__message\";\n message.textContent = finding.message;\n tooltip.appendChild(message);\n }\n marker.appendChild(tooltip);\n return marker;\n}\n\n/**\n * Where the marker sits. Sided findings anchor at the bottom-right corner of\n * the role-chip box of that end (that is where the offending OHS/PL/ACL/CF\n * badge is drawn); without chips they fall back to a point near the endpoint.\n * Whole-relationship findings sit at the middle of the line, nudged off it.\n */\nfunction anchorPoint(relationship: CmRelationship, waypoints: Point[], side: MarkerSide): Point {\n const start = waypoints[0];\n const end = waypoints[waypoints.length - 1];\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n const length = Math.hypot(dx, dy) || 1;\n const ux = dx / length;\n const uy = dy / length;\n\n if (side === \"middle\") {\n return {\n x: (start.x + end.x) / 2 + -uy * LINE_OFFSET,\n y: (start.y + end.y) / 2 + ux * LINE_OFFSET,\n };\n }\n\n const customerSupplier = relationship.pattern === \"customer-supplier\";\n const layout =\n side === \"upstream\"\n ? endRoleChipLayout(\n start,\n end,\n customerSupplier ? \"S\" : \"U\",\n relationship.upstreamRoles ?? [],\n )\n : endRoleChipLayout(\n end,\n start,\n customerSupplier ? \"C\" : \"D\",\n relationship.downstreamRoles ?? [],\n );\n if (layout) {\n // Centred (almost) on the chip box corner: the triangle's visible body is\n // bottom-heavy, so half the marker overlapping the corner reads as sitting\n // right AT the corner instead of floating next to it.\n const corner = { x: layout.box.x + layout.box.width, y: layout.box.y + layout.box.height };\n return { x: corner.x + 1, y: corner.y + 1 };\n }\n\n const along = Math.min(END_DISTANCE, length * 0.35);\n const baseX = side === \"upstream\" ? start.x + ux * along : end.x - ux * along;\n const baseY = side === \"upstream\" ? start.y + uy * along : end.y - uy * along;\n return { x: baseX + -uy * LINE_OFFSET, y: baseY + ux * LINE_OFFSET };\n}\n\nexport default class CmValidationMarkers {\n static $inject = [\"eventBus\", \"elementRegistry\", \"overlays\", \"cmExporter\"];\n\n constructor(\n eventBus: EventBus,\n private readonly elementRegistry: ElementRegistry,\n private readonly overlays: Overlays,\n private readonly exporter: CmExporter,\n ) {\n const refresh = (): void => this.refresh();\n eventBus.on(\"import.render.done\", refresh);\n eventBus.on(\"commandStack.changed\", refresh);\n }\n\n private refresh(): void {\n this.overlays.remove({ type: OVERLAY_TYPE });\n\n const report = validateDocument(this.exporter.export());\n // One marker per relationship END the findings point at (or the middle for\n // whole-relationship findings), so the triangle sits next to the issue.\n const byAnchor = new Map<string, { relationshipId: string; findings: RankedFinding[] }>();\n const collect = (findings: SemanticFinding[], kind: RankedFinding[\"kind\"]): void => {\n for (const finding of findings) {\n if (!finding.relationshipId) continue;\n const key = `${finding.relationshipId} ${finding.side ?? \"middle\"}`;\n const group = byAnchor.get(key) ?? { relationshipId: finding.relationshipId, findings: [] };\n group.findings.push({ ...finding, kind });\n byAnchor.set(key, group);\n }\n };\n collect(report.errors, \"error\");\n collect(report.warnings, \"warning\");\n\n for (const [key, group] of byAnchor) {\n const element = this.elementRegistry.get(group.relationshipId);\n if (!isCmRelationship(element)) continue;\n const waypoints = (element.waypoints ?? []) as Point[];\n if (waypoints.length < 2) continue;\n const side = key.split(\" \")[1] as MarkerSide;\n const { x: markerX, y: markerY } = anchorPoint(element, waypoints, side);\n\n // Overlay positions on a connection are relative to its waypoint bbox.\n const bboxX = Math.min(...waypoints.map((p) => p.x));\n const bboxY = Math.min(...waypoints.map((p) => p.y));\n this.overlays.add(element, OVERLAY_TYPE, {\n position: {\n left: markerX - bboxX - MARKER_SIZE / 2,\n top: markerY - bboxY - MARKER_SIZE / 2,\n },\n html: markerHtml(group.findings),\n });\n }\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport OverlaysModule from \"diagram-js/lib/features/overlays\";\nimport CmValidationMarkers from \"./CmValidationMarkers.js\";\n\n/** Live semantic-rule markers (warning triangles with tooltips) on the canvas. */\nexport const cmValidationModule: ModuleDeclaration = {\n __depends__: [OverlaysModule],\n __init__: [\"cmValidationMarkers\"],\n cmValidationMarkers: [\"type\", CmValidationMarkers],\n};\n\nexport { default as CmValidationMarkers } from \"./CmValidationMarkers.js\";\n","/**\n * Enforces a fixed stacking order regardless of creation order, by reordering\n * the element graphics within the canvas layer. Back → front:\n *\n * relationships < contexts\n *\n * So the relationship lines always read behind the context boxes and appear to\n * dock to the box borders (the segment inside a box is covered by the box).\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { isCmElement, isCmRelationship, type CmElement } from \"../model/di-types.js\";\n\n/** Lower = further back. */\nfunction tier(el: CmElement): number {\n return isCmRelationship(el) ? 0 : 1;\n}\n\nexport default class CmZOrder {\n static $inject = [\"eventBus\", \"canvas\", \"elementRegistry\"];\n\n private importing = false;\n\n constructor(\n eventBus: EventBus,\n private readonly canvas: Canvas,\n private readonly elementRegistry: ElementRegistry,\n ) {\n eventBus.on(\"import.render.start\", () => {\n this.importing = true;\n });\n eventBus.on(\"import.render.done\", () => {\n this.importing = false;\n this.reorder();\n });\n eventBus.on(\"commandStack.changed\", () => {\n if (!this.importing) this.reorder();\n });\n }\n\n /** Re-append each element's graphics group in ascending tier order (back → front). */\n reorder(): void {\n const ordered = (this.elementRegistry.getAll().filter(isCmElement) as CmElement[]).sort(\n (a, b) => tier(a) - tier(b),\n );\n for (const el of ordered) {\n const gfx = this.canvas.getGraphics(el) as SVGElement | undefined;\n const wrapper = gfx?.parentNode as (Node & ChildNode) | null;\n const layer = wrapper?.parentNode as (Node & { appendChild(n: Node): Node }) | null;\n if (wrapper && layer) layer.appendChild(wrapper);\n }\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmZOrder from \"./CmZOrder.js\";\n\n/** Keeps the fixed stacking order (interactions on top, base teams at the back). */\nexport const cmZOrderModule: ModuleDeclaration = {\n __init__: [\"cmZOrder\"],\n cmZOrder: [\"type\", CmZOrder],\n};\n\nexport { default as CmZOrder } from \"./CmZOrder.js\";\n","import type { ModuleDeclaration } from \"didi\";\nimport type CommandStack from \"diagram-js/lib/command/CommandStack\";\n\nimport ConnectionPreviewModule from \"diagram-js/lib/features/connection-preview\";\nimport ModelingModule from \"diagram-js/lib/features/modeling\";\nimport MoveModule from \"diagram-js/lib/features/move\";\nimport OutlineModule from \"diagram-js/lib/features/outline\";\n\nimport { NavigatedViewer } from \"./NavigatedViewer.js\";\nimport { cmModelingModule } from \"./modeling/index.js\";\nimport { cmRulesModule } from \"./rules/index.js\";\nimport { cmBehaviorsModule } from \"./behaviors/index.js\";\nimport { cmPaletteModule } from \"./palette/index.js\";\nimport { cmContextPadModule } from \"./context-pad/index.js\";\nimport { cmLabelEditingModule } from \"./label-editing/index.js\";\nimport { cmKeyboardModule } from \"./keyboard/index.js\";\nimport { cmValidationModule } from \"./validation/index.js\";\nimport { cmZOrderModule } from \"./zorder/index.js\";\nimport { cmReadOnlyModule } from \"./read-only/index.js\";\n\n/**\n * Full Context Maps editor: palette/create, move, connect with rules,\n * context pad, inline label editing, undo/redo, and the edit lock for a\n * document the host cannot take edits for (`cmReadOnly`). Boxes are\n * fixed-size — no resize feature.\n */\nexport class Modeler extends NavigatedViewer {\n protected override _getModules(): ModuleDeclaration[] {\n return [\n ...super._getModules(),\n // diagram-js stock\n ConnectionPreviewModule,\n ModelingModule,\n MoveModule,\n OutlineModule,\n // Context Maps editor\n cmReadOnlyModule,\n cmModelingModule,\n cmRulesModule,\n cmBehaviorsModule,\n cmPaletteModule,\n cmContextPadModule,\n cmLabelEditingModule,\n cmKeyboardModule,\n cmValidationModule,\n cmZOrderModule,\n ];\n }\n\n undo(): void {\n this.get<CommandStack>(\"commandStack\").undo();\n }\n\n redo(): void {\n this.get<CommandStack>(\"commandStack\").redo();\n }\n\n canUndo(): boolean {\n return this.get<CommandStack>(\"commandStack\").canUndo();\n }\n\n canRedo(): boolean {\n return this.get<CommandStack>(\"commandStack\").canRedo();\n }\n}\n","import {\n MODELER_API_VERSION,\n type CollaborativeModeler,\n type CollaborativeModelerOptions,\n type ElementBounds,\n type ElementInfo,\n type ElementsSurface,\n type ImportResult,\n type ModelerMeta,\n} from \"@miragon/modeler-api\";\nimport type { ModuleDeclaration } from \"didi\";\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type ElementRegistry from \"diagram-js/lib/core/ElementRegistry\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type { Element } from \"diagram-js/lib/model/Types\";\nimport { getBBox } from \"diagram-js/lib/util/Elements\";\nimport type { CmViewerOptions, FreeRectInsets } from \"../CmBaseViewer.js\";\nimport { Modeler } from \"../Modeler.js\";\nimport { NavigatedViewer } from \"../NavigatedViewer.js\";\nimport { isCmElement, type CmElement } from \"../model/di-types.js\";\n\n/** Stable notation id in `meta.notation` of the collaborative-modeler contract. */\nexport const CONTEXT_MAPS_NOTATION = \"context-maps\";\n\n/**\n * The contract's factory options (`freeArea`, `fitOnImport`, `undoRedoKeys`, see\n * `CmViewerOptions`) and the renderer's own. The viewer ignores `undoRedoKeys`.\n */\nexport interface CollaborativeContextMapsOptions extends CollaborativeModelerOptions {\n /** Appended to the renderer's own modules (e.g. a host's chrome module). */\n additionalModules?: ModuleDeclaration[] | undefined;\n /** @deprecated Use `freeArea: { insets }`; accepted through the 0.5 releases, ignored next to it. */\n freeRectInsets?: (() => FreeRectInsets) | undefined;\n}\n\n/** The contract surface plus the wrapped diagram for host-specific wiring. */\nexport interface CollaborativeContextMapsModeler extends CollaborativeModeler {\n readonly elements: ElementsSurface & { bounds(id: string): ElementBounds | undefined };\n contentBounds(): ElementBounds | undefined;\n readonly diagram: Modeler | NavigatedViewer;\n}\n\ninterface ViewState {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * The editing mount (`meta.editable: true`) of the collaborative-modeler contract: the text lane\n * is the canonical JSON of a `.cm`/`.cm.json` file (`serializeDocumentText`).\n */\nexport function createCollaborativeModeler(\n options: CollaborativeContextMapsOptions = {},\n): CollaborativeContextMapsModeler {\n return collaborative(\n new Modeler({ ...diagramOptions(options), undoRedoKeys: options.undoRedoKeys ?? true }),\n true,\n );\n}\n\n/** The read-only mount (`meta.editable: false`): imports, exports and reveals, never edits. */\nexport function createCollaborativeViewer(\n options: CollaborativeContextMapsOptions = {},\n): CollaborativeContextMapsModeler {\n return collaborative(new NavigatedViewer(diagramOptions(options)), false);\n}\n\nfunction diagramOptions(options: CollaborativeContextMapsOptions): CmViewerOptions {\n return {\n width: \"100%\",\n height: \"100%\",\n additionalModules: options.additionalModules ?? [],\n freeArea: options.freeArea,\n freeRectInsets: options.freeRectInsets,\n fitOnImport: options.fitOnImport,\n };\n}\n\nfunction collaborative(\n diagram: Modeler | NavigatedViewer,\n editable: boolean,\n): CollaborativeContextMapsModeler {\n const eventBus = diagram.get<EventBus>(\"eventBus\");\n const canvas = diagram.get<Canvas>(\"canvas\");\n const elementRegistry = diagram.get<ElementRegistry>(\"elementRegistry\");\n const selection = diagram.get<Selection>(\"selection\");\n const contentListeners = new Set<() => void>();\n let destroyed = false;\n let lastExport = \"\";\n\n const meta: ModelerMeta = {\n notation: CONTEXT_MAPS_NOTATION,\n apiVersion: MODELER_API_VERSION,\n editable,\n };\n\n // An import never touches the command stack (it erases the history without an event), so every\n // `commandStack.changed` is a user-visible change: element commands, the title, undo and redo.\n if (editable) {\n eventBus.on(\"commandStack.changed\", () => {\n for (const listener of [...contentListeners]) listener();\n });\n }\n\n const elements: CollaborativeContextMapsModeler[\"elements\"] = {\n list: () =>\n destroyed ? [] : (elementRegistry.getAll() as unknown[]).filter(isCmElement).map(elementInfo),\n bounds(id) {\n if (destroyed) return undefined;\n const element = elementRegistry.get(id);\n return isCmElement(element) ? boundsOf(element) : undefined;\n },\n reveal(id) {\n if (destroyed) return false;\n const element = elementRegistry.get(id);\n if (!isCmElement(element)) return false;\n selection.select(element as Element);\n canvas.scrollToElement(element as Element);\n return true;\n },\n selection: () => (destroyed ? [] : elementIds(selection.get())),\n onSelection(callback) {\n const listener = (event: unknown) =>\n callback(elementIds((event as { newSelection?: unknown[] }).newSelection ?? []));\n eventBus.on(\"selection.changed\", listener);\n return () => eventBus.off(\"selection.changed\", listener);\n },\n };\n\n return {\n meta,\n elements,\n diagram,\n attachTo(host) {\n diagram.attachTo(host as HTMLElement);\n },\n async importText(text): Promise<ImportResult> {\n if (destroyed) throw new Error(\"The modeler was destroyed.\");\n const { warnings } = diagram.importText(text);\n return { warnings: warnings.map((warning) => warning.message) };\n },\n exportText() {\n // Asking a destroyed diagram would build a new one on the detached container.\n if (destroyed) return lastExport;\n return diagram.exportText();\n },\n onContentChanged(callback) {\n if (!editable) return () => undefined;\n contentListeners.add(callback);\n return () => contentListeners.delete(callback);\n },\n getViewState(): ViewState | undefined {\n if (destroyed) return undefined;\n try {\n const { x, y, width, height } = canvas.viewbox();\n const state = { x, y, width, height };\n return isViewState(state) ? state : undefined;\n } catch {\n return undefined;\n }\n },\n setViewState(state) {\n if (destroyed || !isViewState(state)) return;\n canvas.viewbox({ x: state.x, y: state.y, width: state.width, height: state.height });\n },\n contentBounds: () => (destroyed ? undefined : diagram.contentBounds()),\n destroy() {\n if (destroyed) return;\n try {\n lastExport = diagram.exportText();\n } catch {\n lastExport = \"\";\n }\n destroyed = true;\n contentListeners.clear();\n diagram.destroy();\n },\n };\n}\n\nfunction elementIds(elements: readonly unknown[]): string[] {\n return elements.filter(isCmElement).map((element) => element.id);\n}\n\n/** The shape's box, or the box around a relationship's waypoints, in diagram coordinates. */\nfunction boundsOf(element: CmElement): ElementBounds {\n const { x, y, width, height } = getBBox(element as unknown as Element);\n return { x, y, width, height };\n}\n\nfunction elementInfo(element: CmElement): ElementInfo {\n return element.cmLabel ? { id: element.id, name: element.cmLabel } : { id: element.id };\n}\n\nfunction isViewState(state: unknown): state is ViewState {\n if (typeof state !== \"object\" || state === null) return false;\n const { x, y, width, height } = state as Record<string, unknown>;\n return (\n isFiniteNumber(x) &&\n isFiniteNumber(y) &&\n isFiniteNumber(width) &&\n isFiniteNumber(height) &&\n width > 0 &&\n height > 0\n );\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n","/**\n * Four connect handles around a selected bounded context — one arrow at the\n * middle of each side (top, right, bottom, left), each pointing outward.\n * Press a handle, drag, release over another context to draw the relationship\n * (press-drag-release ONLY: a click listener would restart the tool after the\n * mouseup and leave the preview line chasing the cursor). Implemented as\n * diagram-js overlays so the handles float outside the shape, follow it, and\n * never collide with the resize handles on the selection outline.\n */\n\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport type Overlays from \"diagram-js/lib/features/overlays/Overlays\";\nimport type Selection from \"diagram-js/lib/features/selection/Selection\";\nimport type Connect from \"diagram-js/lib/features/connect/Connect\";\nimport type Dragging from \"diagram-js/lib/features/dragging/Dragging\";\nimport type { Element } from \"diagram-js/lib/model/Types\";\nimport { getMid } from \"diagram-js/lib/layout/LayoutUtil\";\nimport { isCmContext } from \"../model/di-types.js\";\nimport { chromeIcon } from \"../draw/lucide.js\";\nimport { READ_ONLY_CHANGED_EVENT, type CmReadOnly } from \"../read-only/index.js\";\n\nconst OVERLAY_TYPE = \"cm-connect-handle\";\nconst HANDLE_SIZE = 28;\n/** Clear of the selection outline and its mid-side resize handles. */\nconst HANDLE_GAP = 12;\n\nconst SIDES = [\n { side: \"top\", rotationDeg: -90 },\n { side: \"right\", rotationDeg: 0 },\n { side: \"bottom\", rotationDeg: 90 },\n { side: \"left\", rotationDeg: 180 },\n] as const;\n\ntype Side = (typeof SIDES)[number][\"side\"];\n\nfunction handlePosition(\n side: Side,\n shape: { width: number; height: number },\n): { top: number; left: number } {\n const centeredLeft = shape.width / 2 - HANDLE_SIZE / 2;\n const centeredTop = shape.height / 2 - HANDLE_SIZE / 2;\n const outside = HANDLE_SIZE + HANDLE_GAP;\n switch (side) {\n case \"top\":\n return { top: -outside, left: centeredLeft };\n case \"bottom\":\n return { top: shape.height + HANDLE_GAP, left: centeredLeft };\n case \"left\":\n return { top: centeredTop, left: -outside };\n case \"right\":\n return { top: centeredTop, left: shape.width + HANDLE_GAP };\n }\n}\n\nexport default class CmConnectHandles {\n static $inject = [\"eventBus\", \"selection\", \"overlays\", \"connect\", \"dragging\", \"cmReadOnly\"];\n\n constructor(\n private readonly eventBus: EventBus,\n private readonly selection: Selection,\n private readonly overlays: Overlays,\n connect: Connect,\n private readonly dragging: Dragging,\n private readonly readOnly: Pick<CmReadOnly, \"isReadOnly\">,\n ) {\n // Not used to start the drag, but injecting Connect instantiates it so its\n // connect.* event handlers (hover/end → modeling.connect) are registered —\n // the connect module does not eagerly initialize it.\n void connect;\n const refresh = (): void => this.refresh();\n eventBus.on(\"selection.changed\", refresh);\n // Re-anchor after resize/undo/redo (handle offsets depend on width/height).\n eventBus.on(\"commandStack.changed\", refresh);\n eventBus.on(READ_ONLY_CHANGED_EVENT, refresh);\n }\n\n private refresh(): void {\n this.overlays.remove({ type: OVERLAY_TYPE });\n\n if (this.readOnly.isReadOnly()) return;\n const selected = this.selection.get() as Element[];\n if (selected.length !== 1) return;\n const element = selected[0];\n if (!isCmContext(element)) return;\n const shape = element as unknown as { width: number; height: number };\n\n for (const { side, rotationDeg } of SIDES) {\n const handle = document.createElement(\"div\");\n handle.className = \"cm-connect-handle\";\n handle.dataset.side = side;\n handle.title = \"Connect to another context\";\n handle.setAttribute(\"aria-label\", \"Connect to another context\");\n const arrow = document.createElement(\"span\");\n arrow.className = \"cm-connect-handle__arrow\";\n arrow.style.transform = `rotate(${rotationDeg}deg)`;\n arrow.innerHTML = chromeIcon(\"arrow-right\");\n handle.append(arrow);\n handle.addEventListener(\"mousedown\", (event: MouseEvent) => {\n if (event.button !== 0) return;\n event.preventDefault();\n event.stopPropagation();\n // Same payload as Connect#start, but with trapClick OFF: the ghost-\n // click trap Dragging arms after a drag is only consumed by a click\n // that reaches the canvas — a drag started on this HTML handle never\n // produces one, so the trap would instead swallow the user's NEXT\n // click on a context (no selection, seemingly broken editor).\n this.dragging.init(event, \"connect\", {\n autoActivate: false,\n trapClick: false,\n data: {\n shape: element,\n context: { start: element, connectionStart: getMid(element) },\n },\n });\n // Keep the source context marked after the drag: the drag lifecycle\n // clears the selection, but the user is still \"at\" this context. Low\n // priority so this runs after the stock cleanup listeners.\n this.eventBus.once(\"connect.cleanup\", 250, () => {\n if (this.selection.get().length === 0) this.selection.select(element);\n });\n });\n\n this.overlays.add(element, OVERLAY_TYPE, {\n position: handlePosition(side, shape),\n html: handle,\n });\n }\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport ConnectModule from \"diagram-js/lib/features/connect\";\nimport OverlaysModule from \"diagram-js/lib/features/overlays\";\nimport SelectionModule from \"diagram-js/lib/features/selection\";\nimport { cmReadOnlyModule } from \"../read-only/index.js\";\nimport CmConnectHandles from \"./CmConnectHandles.js\";\n\n/** Four outward connect arrows around a selected context (top/right/bottom/left). */\nexport const cmConnectHandlesModule: ModuleDeclaration = {\n __depends__: [ConnectModule, OverlaysModule, SelectionModule, cmReadOnlyModule],\n __init__: [\"cmConnectHandles\"],\n cmConnectHandles: [\"type\", CmConnectHandles],\n};\n\nexport { default as CmConnectHandles } from \"./CmConnectHandles.js\";\n","/**\n * The notation legend's content — subdomain types, integration roles and relationship patterns —\n * driven entirely by the notation spec, so it can never drift from what the canvas draws. The\n * Miragon modeler shell renders it into its legend card (`legend.render`); the rows use the\n * shell's row classes, so they look like every other modeler's legend.\n */\n\nimport {\n ALL_PATTERN_SPECS,\n ALL_SUBDOMAIN_SPECS,\n DOWNSTREAM_ROLE_SPECS,\n UPSTREAM_ROLE_SPECS,\n} from \"@miragon/context-maps-schema-model\";\nimport type { DownstreamRole, UpstreamRole } from \"@miragon/context-maps-schema-model\";\nimport { contextIconSvg, relationshipIconSvg, roleChipSvg } from \"../draw/palette-icons.js\";\n\nexport interface LegendRow {\n /** The 24px notation preview, as SVG markup (the palette's and the context pad's). */\n readonly preview: string;\n readonly label: string;\n /** What the notation means, for the row's tooltip. */\n readonly explanation: string;\n}\n\nexport interface LegendGroup {\n readonly label: string;\n readonly rows: readonly LegendRow[];\n}\n\nconst ROLES: ReadonlyArray<{\n token: UpstreamRole | DownstreamRole;\n label: string;\n description: string;\n}> = [\n { token: \"OHS\", ...UPSTREAM_ROLE_SPECS.OHS },\n { token: \"PL\", ...UPSTREAM_ROLE_SPECS.PL },\n { token: \"ACL\", ...DOWNSTREAM_ROLE_SPECS.ACL },\n { token: \"CF\", ...DOWNSTREAM_ROLE_SPECS.CF },\n];\n\n/** The legend's groups and rows, in reading order. */\nexport function legendGroups(): LegendGroup[] {\n return [\n {\n label: \"Subdomain types\",\n rows: ALL_SUBDOMAIN_SPECS.map((spec) => ({\n preview: contextIconSvg(spec.type),\n label: spec.label,\n explanation: spec.description,\n })),\n },\n {\n label: \"Integration roles\",\n rows: ROLES.map((role) => ({\n preview: roleChipSvg(role.token),\n label: `${role.token} · ${role.label}`,\n explanation: role.description,\n })),\n },\n {\n label: \"Relationship patterns\",\n rows: ALL_PATTERN_SPECS.map((spec) => ({\n preview: relationshipIconSvg(spec.pattern),\n label: `${spec.abbreviation} · ${spec.label}`,\n explanation: spec.description,\n })),\n },\n ];\n}\n\n/**\n * The chrome tooltip of the host (the shell's `shell.tooltip`): shown after the hover delay, on\n * the chrome's tooltip layer above the legend, so a glass card's backdrop filter cannot clip it.\n */\nexport interface LegendTooltip {\n attach(control: HTMLElement, content: { label: string }): () => void;\n}\n\nexport interface LegendRenderOptions {\n /** Explains each row on hover; without it the explanation is the row's hidden description. */\n readonly tooltip?: LegendTooltip | undefined;\n}\n\n/**\n * Renders the legend's rows into `body` (the shell's `legend.render`) and returns the function\n * that detaches their tooltips again.\n */\nexport function renderLegend(body: HTMLElement, options: LegendRenderOptions = {}): () => void {\n const detachers: Array<() => void> = [];\n legendGroups().forEach((group, index) => {\n if (index > 0) {\n const separator = document.createElement(\"div\");\n separator.className = \"cd-shell-legend-separator\";\n separator.setAttribute(\"role\", \"separator\");\n body.append(separator);\n }\n const groupElement = document.createElement(\"div\");\n groupElement.className = \"cm-legend-group\";\n groupElement.setAttribute(\"role\", \"group\");\n groupElement.setAttribute(\"aria-label\", group.label);\n for (const row of group.rows) {\n const rowElement = document.createElement(\"div\");\n rowElement.className = \"cd-shell-legend-row cm-legend-row\";\n const preview = document.createElement(\"span\");\n preview.className = \"cd-shell-legend-preview\";\n preview.innerHTML = row.preview;\n const label = document.createElement(\"span\");\n label.textContent = row.label;\n rowElement.append(preview, label);\n if (options.tooltip) {\n detachers.push(options.tooltip.attach(rowElement, { label: row.explanation }));\n } else {\n const explanation = document.createElement(\"span\");\n explanation.className = \"cm-visually-hidden\";\n explanation.textContent = `: ${row.explanation}`;\n rowElement.append(explanation);\n }\n groupElement.append(rowElement);\n }\n body.append(groupElement);\n });\n return () => {\n for (const detach of detachers.splice(0)) detach();\n };\n}\n","/**\n * The notation legend as a card of its own, for hosts without the Miragon\n * modeler shell (opt-in: `additionalModules: [cmLegendModule]`; the shell\n * renders `renderLegend` into its own legend instead). A collapsible card\n * (bottom-left of the canvas): subdomain types, integration roles (OHS/PL/ACL/CF) and the\n * relationship patterns — driven entirely by the notation spec, so it can\n * never drift from what the canvas draws. Shipped by the renderer so every\n * embedder gets it, replacing the per-host copies the reference apps carried.\n * Hovering a row shows the spelled-out explanation instantly (custom CSS\n * tooltip — a native `title` only appears after the OS hover delay).\n * Collapsed it shrinks to a button in the same corner, never disappearing. It starts closed on\n * every canvas, so the card never covers the diagram unasked: the user opens it with its button,\n * and a host restores a state it stored with `setOpen()`.\n */\n\nimport type Canvas from \"diagram-js/lib/core/Canvas\";\nimport type EventBus from \"diagram-js/lib/core/EventBus\";\nimport { chromeIcon } from \"../draw/lucide.js\";\nimport { legendGroups, type LegendRow } from \"./legendContent.js\";\n\nfunction legendRow(row: LegendRow): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"cm-legend__row cm-legend-item\";\n const icon = document.createElement(\"span\");\n icon.className = \"cm-legend__icon\";\n icon.innerHTML = row.preview;\n const text = document.createElement(\"span\");\n text.textContent = row.label;\n const tip = document.createElement(\"span\");\n tip.className = \"cm-legend-tip\";\n tip.textContent = row.explanation;\n // The tip is position: fixed (anchored here) so it escapes the card's\n // scroll clipping when a small canvas forces the legend body to scroll.\n element.addEventListener(\"mouseenter\", () => {\n const bounds = element.getBoundingClientRect();\n tip.style.left = `${bounds.right + 10}px`;\n tip.style.top = `${bounds.top + bounds.height / 2}px`;\n });\n element.append(icon, text, tip);\n return element;\n}\n\nfunction group(label: string, rows: HTMLElement[]): HTMLElement {\n const el = document.createElement(\"div\");\n el.className = \"cm-legend__group\";\n el.setAttribute(\"role\", \"group\");\n el.setAttribute(\"aria-label\", label);\n el.append(...rows);\n return el;\n}\n\nfunction divider(): HTMLElement {\n const el = document.createElement(\"div\");\n el.className = \"cm-legend__divider\";\n return el;\n}\n\nexport default class CmLegend {\n static $inject = [\"canvas\", \"eventBus\"];\n\n private openState = false;\n private readonly host: HTMLElement;\n\n constructor(canvas: Canvas, eventBus: EventBus) {\n this.host = document.createElement(\"div\");\n canvas.getContainer().appendChild(this.host);\n this.render();\n eventBus.on(\"diagram.destroy\", () => this.host.remove());\n }\n\n isOpen(): boolean {\n return this.openState;\n }\n\n setOpen(open: boolean): void {\n if (this.openState === open) return;\n this.openState = open;\n this.render();\n }\n\n toggle(): void {\n this.setOpen(!this.openState);\n }\n\n private render(): void {\n // The activated toggle removes itself with the re-render — hand the focus\n // to its counterpart so the keyboard path survives, but only when the\n // focus actually was inside (the initial render must not steal it).\n const hadFocus = this.host.contains(this.host.ownerDocument.activeElement);\n this.host.replaceChildren(this.openState ? this.panel() : this.collapsedButton());\n if (hadFocus) {\n this.host.querySelector<HTMLButtonElement>(\".cm-legend__close, .cm-legend-toggle\")?.focus();\n }\n }\n\n private panel(): HTMLElement {\n const box = document.createElement(\"div\");\n box.className = \"cm-legend\";\n box.setAttribute(\"aria-label\", \"Legend\");\n\n const head = document.createElement(\"div\");\n head.className = \"cm-legend__head\";\n const title = document.createElement(\"strong\");\n title.textContent = \"Legend\";\n const close = document.createElement(\"button\");\n close.type = \"button\";\n close.className = \"cm-legend__close\";\n close.setAttribute(\"aria-expanded\", \"true\");\n close.setAttribute(\"aria-label\", \"Close legend\");\n close.innerHTML = chromeIcon(\"x\");\n close.addEventListener(\"click\", () => this.toggle());\n head.append(title, close);\n\n const groups = legendGroups().map((entry) => group(entry.label, entry.rows.map(legendRow)));\n // Groups live in a scrollable body so a small canvas never clips the head\n // (and with it the collapse button) away.\n const body = document.createElement(\"div\");\n body.className = \"cm-legend__body\";\n groups.forEach((element, index) => body.append(...(index > 0 ? [divider()] : []), element));\n box.append(head, body);\n return box;\n }\n\n private collapsedButton(): HTMLElement {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = \"cm-legend-toggle\";\n button.setAttribute(\"aria-expanded\", \"false\");\n button.setAttribute(\"aria-label\", \"Show legend\");\n button.textContent = \"Legend\";\n button.addEventListener(\"click\", () => this.toggle());\n return button;\n }\n}\n","import type { ModuleDeclaration } from \"didi\";\nimport CmLegend from \"./CmLegend.js\";\n\n/**\n * The legend as a card on the canvas, for hosts without the Miragon modeler shell; with the shell,\n * render `renderLegend` into its legend instead.\n */\nexport const cmLegendModule: ModuleDeclaration = {\n __init__: [\"cmLegend\"],\n cmLegend: [\"type\", CmLegend],\n};\n\nexport { default as CmLegend } from \"./CmLegend.js\";\nexport { legendGroups, renderLegend } from \"./legendContent.js\";\nexport type {\n LegendGroup,\n LegendRenderOptions,\n LegendRow,\n LegendTooltip,\n} from \"./legendContent.js\";\n","/*\n * The context map's entries of the chrome menu (guide §5.4), the same in every host. The types\n * mirror the menu groups of `@miragon/modeler-shell` structurally, so an app hands the result to\n * the shell as it is while the renderer never imports the shell. The Model group's \"Legend\"\n * checkbox is the shell's own, added with its legend.\n */\n\n/** The icons the guide gives these entries (guide §5.14, the shell's common set). */\nexport type MapMenuIcon = \"file-image\" | \"file-code-corner\" | \"keyboard\";\n\ninterface MapMenuItem {\n readonly id: string;\n readonly label: string;\n readonly icon?: MapMenuIcon;\n readonly keepEnabledWhenReadOnly?: boolean;\n}\n\nexport interface MapMenuAction extends MapMenuItem {\n readonly kind: \"action\";\n readonly shortcut?: string;\n onSelect(): void;\n}\n\nexport interface MapMenuDialog extends MapMenuItem {\n readonly kind: \"dialog\";\n onSelect(): void;\n}\n\nexport type MapMenuEntry = MapMenuAction | MapMenuDialog;\n\nexport interface MapMenu {\n readonly model: readonly MapMenuEntry[];\n readonly export: readonly MapMenuEntry[];\n readonly help: readonly MapMenuEntry[];\n}\n\nexport interface MapExport {\n onSelect(): void;\n /** The chip of an app key that runs the same export, e.g. \"⌘S\". */\n readonly shortcut?: string | undefined;\n}\n\n/**\n * The exports a host offers, in the guide's order: PNG first (the more frequent target), then\n * SVG, then the map's own JSON and Context Mapper's CML.\n */\nexport interface MapExports {\n readonly png: MapExport;\n readonly svg: MapExport;\n readonly json: MapExport;\n readonly cml: MapExport;\n}\n\nexport interface MapMenuActions {\n readonly exports: MapExports;\n showKeyboardShortcuts(): void;\n /** Opens the dialog that renames the map; without it the Model group has no title entry. */\n editTitle?: (() => void) | undefined;\n}\n\n/** The map's native file in the Export group and in the shortcuts dialog. */\nexport const JSON_EXPORT_LABEL = \"Export as JSON\";\n\nfunction exportEntry(\n id: string,\n label: string,\n action: MapExport,\n icon?: MapMenuIcon,\n): MapMenuAction {\n return {\n kind: \"action\",\n id,\n label,\n ...(icon ? { icon } : {}),\n ...(action.shortcut ? { shortcut: action.shortcut } : {}),\n onSelect: () => action.onSelect(),\n };\n}\n\n/** The menu groups of the context map (guide §5.4): Model, Export with PNG first, Help. */\nexport function contextMapMenu(actions: MapMenuActions): MapMenu {\n const { editTitle } = actions;\n return {\n model: editTitle\n ? [{ kind: \"dialog\", id: \"map-title\", label: \"Map title…\", onSelect: () => editTitle() }]\n : [],\n export: [\n exportEntry(\"export-png\", \"Export as PNG\", actions.exports.png, \"file-image\"),\n exportEntry(\"export-svg\", \"Export as SVG\", actions.exports.svg, \"file-code-corner\"),\n exportEntry(\"export-json\", JSON_EXPORT_LABEL, actions.exports.json),\n exportEntry(\"export-cml\", \"Export as CML\", actions.exports.cml),\n ],\n help: [\n {\n kind: \"dialog\",\n id: \"keyboard-shortcuts\",\n label: \"Keyboard shortcuts…\",\n icon: \"keyboard\",\n onSelect: () => actions.showKeyboardShortcuts(),\n },\n ],\n };\n}\n","import { JSON_EXPORT_LABEL } from \"./menu.js\";\n\n/*\n * Every shortcut of the context map for the \"Keyboard shortcuts…\" dialog (guide §5.4): one table\n * per group, the keys as chips like the chrome tooltip's (guide §5.6). The chrome's texts and key\n * names come in structurally (a `@miragon/modeler-shell` handle fits), so the View rows say what\n * the zoom panel's tooltips say.\n */\n\nexport type ShortcutPlatform = \"mac\" | \"other\";\n\nexport interface ShortcutKeyNames {\n readonly ctrl: string;\n readonly shift: string;\n readonly plus: string;\n readonly minus: string;\n}\n\n/** What the shortcuts need of the chrome around the map. */\nexport interface ShortcutsChrome {\n readonly platform: ShortcutPlatform;\n /** The tool's UI language, for the percentage in \"Zoom to 100%\". */\n readonly lang: string;\n readonly messages: {\n readonly zoomIn: string;\n readonly zoomOut: string;\n zoomToActual(percent: string): string;\n readonly fit: string;\n /** The File group's \"Open…\" (the shell's `messages.openFile`); default \"Open…\". */\n readonly openFile?: string | undefined;\n readonly keyNames: ShortcutKeyNames;\n };\n}\n\nexport interface ShortcutRow {\n readonly action: string;\n /** Alternative key combinations, each shown as its own chip. */\n readonly keys: readonly string[];\n}\n\nexport interface ShortcutGroup {\n readonly title: string;\n readonly rows: readonly ShortcutRow[];\n}\n\nexport interface ContextMapShortcutOptions {\n /** The web app's file keys: Cmd/Ctrl+O opens a file, Cmd/Ctrl+S exports the map as JSON. */\n readonly fileKeys?: boolean | undefined;\n}\n\n/** \"⌘O\" on macOS, \"Ctrl+O\" elsewhere: the chip of a Cmd/Ctrl key the app binds itself. */\nfunction commandKeyLabel(\n key: string,\n platform: ShortcutPlatform,\n keyNames: Pick<ShortcutKeyNames, \"ctrl\">,\n): string {\n return platform === \"mac\" ? `⌘${key}` : `${keyNames.ctrl}+${key}`;\n}\n\nfunction percentOfActualSize(lang: string): string {\n try {\n return new Intl.NumberFormat(lang, { style: \"percent\" }).format(1);\n } catch {\n return new Intl.NumberFormat(\"en\", { style: \"percent\" }).format(1);\n }\n}\n\n/** The chrome's zoom and fit keys as its tooltips name them (guide §5.8). */\nfunction viewKeys(platform: ShortcutPlatform, keyNames: ShortcutKeyNames) {\n if (platform === \"mac\") {\n return { zoomIn: \"⌘+\", zoomOut: \"⌘−\", zoomToActual: \"⌘0\", fit: \"⇧1\" };\n }\n const { ctrl, shift, plus, minus } = keyNames;\n return {\n zoomIn: `${ctrl}+${plus}`,\n zoomOut: `${ctrl}+${minus}`,\n zoomToActual: `${ctrl}+0`,\n fit: `${shift}+1`,\n };\n}\n\nfunction editKeys(platform: ShortcutPlatform, keyNames: ShortcutKeyNames) {\n if (platform === \"mac\") {\n return {\n undo: [\"⌘Z\"],\n redo: [\"⌘⇧Z\"],\n selectAll: [\"⌘A\"],\n remove: [\"⌫\"],\n lineBreak: [\"⇧Enter\"],\n lassoDrag: [\"⇧ Drag\"],\n };\n }\n const { ctrl, shift } = keyNames;\n return {\n undo: [`${ctrl}+Z`],\n redo: [`${ctrl}+${shift}+Z`, `${ctrl}+Y`],\n selectAll: [`${ctrl}+A`],\n remove: [\"Del\", \"Backspace\"],\n lineBreak: [`${shift}+Enter`],\n lassoDrag: [`${shift}+Drag`],\n };\n}\n\nfunction fileGroup(chrome: ShortcutsChrome): ShortcutGroup {\n const { platform, messages } = chrome;\n return {\n title: \"File\",\n rows: [\n {\n action: messages.openFile ?? \"Open…\",\n keys: [commandKeyLabel(\"O\", platform, messages.keyNames)],\n },\n { action: JSON_EXPORT_LABEL, keys: [commandKeyLabel(\"S\", platform, messages.keyNames)] },\n ],\n };\n}\n\n/**\n * Every shortcut of the map, grouped as guide §5.4 asks (View, Edit, Tools), after the web app's\n * File keys where it binds them.\n */\nexport function contextMapShortcuts(\n chrome: ShortcutsChrome,\n options: ContextMapShortcutOptions = {},\n): ShortcutGroup[] {\n const { platform, messages } = chrome;\n const view = viewKeys(platform, messages.keyNames);\n const edit = editKeys(platform, messages.keyNames);\n return [\n ...(options.fileKeys ? [fileGroup(chrome)] : []),\n {\n title: \"View\",\n rows: [\n { action: messages.zoomIn, keys: [view.zoomIn] },\n { action: messages.zoomOut, keys: [view.zoomOut] },\n {\n action: messages.zoomToActual(percentOfActualSize(chrome.lang)),\n keys: [view.zoomToActual],\n },\n { action: messages.fit, keys: [view.fit] },\n ],\n },\n {\n title: \"Edit\",\n rows: [\n { action: \"Undo\", keys: edit.undo },\n { action: \"Redo\", keys: edit.redo },\n { action: \"Select all\", keys: edit.selectAll },\n { action: \"Delete\", keys: edit.remove },\n { action: \"Rename\", keys: [\"Double-click\"] },\n { action: \"Save a name\", keys: [\"Enter\"] },\n { action: \"Line break in a name\", keys: edit.lineBreak },\n { action: \"Discard a name\", keys: [\"Esc\"] },\n ],\n },\n {\n title: \"Tools\",\n rows: [\n { action: \"Create a context from the palette\", keys: [\"Enter\", \"Space\"] },\n { action: \"Lasso by dragging\", keys: edit.lassoDrag },\n ],\n },\n ];\n}\n","import { chromeIcon } from \"../draw/lucide.js\";\n\n/** What a dialog needs of the chrome around the map; a `@miragon/modeler-shell` handle fits. */\nexport interface DialogChrome {\n /** Where the dialog lives (the shell root), so it shares the chrome's mode and fonts. */\n readonly root: HTMLElement;\n readonly messages: { readonly close: string };\n /** The control the focus returns to once the dialog closes. */\n readonly menu: { readonly trigger: HTMLElement };\n}\n\nexport interface ChromeDialog {\n open(): void;\n isOpen(): boolean;\n close(): void;\n destroy(): void;\n}\n\nexport interface ChromeDialogSpec {\n /** Class of the `<dialog>` next to `cm-dialog`, for the dialog's own rules. */\n readonly className: string;\n readonly titleId: string;\n readonly title: string;\n /** The parts below the header, built once on the first open. */\n content(close: () => void): Node[];\n /** Runs before every open, while the dialog is still closed. */\n beforeOpen?(): void;\n /** Runs after every open, once the dialog shows and holds the focus. */\n afterOpen?(): void;\n}\n\nexport function element<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n className: string,\n text?: string,\n): HTMLElementTagNameMap[K] {\n const created = document.createElement(tag);\n created.className = className;\n if (text !== undefined) created.textContent = text;\n return created;\n}\n\nfunction header(chrome: DialogChrome, spec: ChromeDialogSpec, onClose: () => void): HTMLElement {\n const head = element(\"header\", \"cm-dialog-header\");\n const title = element(\"h3\", \"cm-dialog-title\", spec.title);\n title.id = spec.titleId;\n const close = element(\"button\", \"cm-dialog-close\");\n close.type = \"button\";\n close.setAttribute(\"aria-label\", chrome.messages.close);\n close.innerHTML = chromeIcon(\"x\");\n close.addEventListener(\"click\", onClose);\n head.append(title, close);\n return head;\n}\n\n/**\n * A dialog of the map's chrome (guide §8, \"Modeler dialogs\" of the shell's API): a native modal\n * <dialog> inside the chrome's root, so the browser keeps the focus inside it and closes it on\n * Escape. Built on the first open and kept (closed) afterwards; `destroy()` removes it. The host\n * calls it with the diagram's teardown, since the chrome removes only what it added itself.\n */\nexport function createChromeDialog(chrome: DialogChrome, spec: ChromeDialogSpec): ChromeDialog {\n let dialog: HTMLDialogElement | undefined;\n\n function build(): HTMLDialogElement {\n const created = element(\"dialog\", `cm-dialog ${spec.className}`);\n created.setAttribute(\"aria-labelledby\", spec.titleId);\n const close = (): void => created.close();\n const panel = element(\"div\", \"cm-dialog-panel\");\n panel.append(header(chrome, spec, close), ...spec.content(close));\n created.append(panel);\n // A click on the backdrop targets the <dialog> itself; the panel covers all of its own box.\n created.addEventListener(\"click\", (event) => {\n if (event.target === created) created.close();\n });\n created.addEventListener(\"close\", () => {\n if (!chrome.menu.trigger.hidden) chrome.menu.trigger.focus({ preventScroll: true });\n });\n chrome.root.append(created);\n return created;\n }\n\n return {\n open() {\n dialog ??= build();\n if (dialog.open) return;\n spec.beforeOpen?.();\n dialog.showModal();\n spec.afterOpen?.();\n },\n close() {\n dialog?.close();\n },\n isOpen: () => dialog?.open === true,\n destroy() {\n dialog?.remove();\n dialog = undefined;\n },\n };\n}\n","import { createChromeDialog, element, type ChromeDialog, type DialogChrome } from \"./dialog.js\";\nimport {\n contextMapShortcuts,\n type ContextMapShortcutOptions,\n type ShortcutGroup,\n type ShortcutsChrome,\n} from \"./shortcuts.js\";\n\nconst DIALOG_CLASS = \"cm-shortcuts\";\nconst TITLE_ID = \"cm-shortcuts-title\";\n\n/** What the dialog needs of the chrome around the map; a `@miragon/modeler-shell` handle fits. */\nexport interface ShortcutsDialogChrome extends ShortcutsChrome, DialogChrome {\n readonly messages: ShortcutsChrome[\"messages\"] & DialogChrome[\"messages\"];\n}\n\nexport type ShortcutsDialog = ChromeDialog;\n\nfunction shortcutTable(group: ShortcutGroup, index: number): HTMLElement {\n const section = element(\"section\", `${DIALOG_CLASS}-group`);\n const headingId = `${TITLE_ID}-group-${index}`;\n const heading = element(\"h4\", `${DIALOG_CLASS}-group-title`, group.title);\n heading.id = headingId;\n const table = element(\"table\", `${DIALOG_CLASS}-table`);\n table.setAttribute(\"aria-labelledby\", headingId);\n const body = table.createTBody();\n for (const row of group.rows) {\n const line = body.insertRow();\n const action = element(\"th\", `${DIALOG_CLASS}-action`, row.action);\n action.scope = \"row\";\n const keys = element(\"td\", `${DIALOG_CLASS}-keys`);\n for (const key of row.keys) keys.append(element(\"kbd\", `${DIALOG_CLASS}-key`, key));\n line.append(action, keys);\n }\n section.append(heading, table);\n return section;\n}\n\n/**\n * The \"Keyboard shortcuts…\" dialog of the Help group (guide §5.4, §8): one table per group, the\n * keys as chips like the chrome tooltip's.\n */\nexport function createShortcutsDialog(\n chrome: ShortcutsDialogChrome,\n options: ContextMapShortcutOptions = {},\n): ShortcutsDialog {\n return createChromeDialog(chrome, {\n className: DIALOG_CLASS,\n titleId: TITLE_ID,\n title: \"Keyboard shortcuts\",\n content() {\n const body = element(\"div\", \"cm-dialog-body cm-shortcuts-body\");\n body.append(...contextMapShortcuts(chrome, options).map(shortcutTable));\n return [body];\n },\n });\n}\n","import { createChromeDialog, element, type ChromeDialog, type DialogChrome } from \"./dialog.js\";\n\nconst DIALOG_CLASS = \"cm-title-dialog\";\nconst TITLE_ID = \"cm-title-dialog-title\";\nconst FIELD_ID = \"cm-title-dialog-field\";\n\n/** The map's title, read when the dialog opens and written when it applies. */\nexport interface MapTitle {\n title(): string;\n setTitle(title: string): void;\n}\n\nexport type TitleDialogChrome = DialogChrome;\nexport type TitleDialog = ChromeDialog;\n\nfunction button(label: string, variant: \"primary\" | \"secondary\"): HTMLButtonElement {\n const created = element(\"button\", \"cm-dialog-button\", label);\n created.type = variant === \"primary\" ? \"submit\" : \"button\";\n created.dataset.variant = variant;\n return created;\n}\n\n/**\n * The \"Map title…\" dialog of the Model group: guide §5.4 keeps form fields out of the menu, so the\n * entry opens a dialog (§8) with the title field, Cancel and Apply. Enter applies, Escape cancels;\n * an unchanged title writes nothing, so the map's history gets no empty step.\n */\nexport function createTitleDialog(chrome: TitleDialogChrome, mapTitle: MapTitle): TitleDialog {\n const field = element(\"input\", \"cm-dialog-input\");\n field.id = FIELD_ID;\n field.type = \"text\";\n field.autocomplete = \"off\";\n field.spellcheck = false;\n // showModal() focuses the first focusable element, which would be the header's Close button.\n field.autofocus = true;\n\n return createChromeDialog(chrome, {\n className: DIALOG_CLASS,\n titleId: TITLE_ID,\n title: \"Map title\",\n beforeOpen() {\n field.value = mapTitle.title();\n },\n afterOpen() {\n field.select();\n },\n content(close) {\n const form = element(\"form\", \"cm-dialog-form\");\n form.noValidate = true;\n const body = element(\"div\", \"cm-dialog-body\");\n const label = element(\"label\", \"cm-dialog-label\", \"Title\");\n label.htmlFor = FIELD_ID;\n body.append(label, field);\n const footer = element(\"div\", \"cm-dialog-footer\");\n const cancel = button(\"Cancel\", \"secondary\");\n cancel.addEventListener(\"click\", close);\n footer.append(cancel, button(\"Apply\", \"primary\"));\n form.append(body, footer);\n form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n const title = field.value.trim();\n close();\n if (title !== mapTitle.title()) mapTitle.setTitle(title);\n });\n return [form];\n },\n });\n}\n"],"mappings":"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"}