@miragon/event-storming-renderer 0.1.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.
Files changed (125) hide show
  1. package/README.md +55 -0
  2. package/dist/EventStormingBaseViewer.d.ts +56 -0
  3. package/dist/EventStormingBaseViewer.d.ts.map +1 -0
  4. package/dist/Modeler.d.ts +15 -0
  5. package/dist/Modeler.d.ts.map +1 -0
  6. package/dist/NavigatedViewer.d.ts +10 -0
  7. package/dist/NavigatedViewer.d.ts.map +1 -0
  8. package/dist/Viewer.d.ts +6 -0
  9. package/dist/Viewer.d.ts.map +1 -0
  10. package/dist/append/EventStormingAppendBehavior.d.ts +17 -0
  11. package/dist/append/EventStormingAppendBehavior.d.ts.map +1 -0
  12. package/dist/append/index.d.ts +9 -0
  13. package/dist/append/index.d.ts.map +1 -0
  14. package/dist/attach/EventStormingAttachBehavior.d.ts +17 -0
  15. package/dist/attach/EventStormingAttachBehavior.d.ts.map +1 -0
  16. package/dist/attach/index.d.ts +9 -0
  17. package/dist/attach/index.d.ts.map +1 -0
  18. package/dist/board-bounds/BoardBounds.d.ts +23 -0
  19. package/dist/board-bounds/BoardBounds.d.ts.map +1 -0
  20. package/dist/board-bounds/index.d.ts +6 -0
  21. package/dist/board-bounds/index.d.ts.map +1 -0
  22. package/dist/color-picker/EventStormingColorPicker.d.ts +23 -0
  23. package/dist/color-picker/EventStormingColorPicker.d.ts.map +1 -0
  24. package/dist/color-picker/index.d.ts +5 -0
  25. package/dist/color-picker/index.d.ts.map +1 -0
  26. package/dist/context-pad/EventStormingContextPadProvider.d.ts +26 -0
  27. package/dist/context-pad/EventStormingContextPadProvider.d.ts.map +1 -0
  28. package/dist/context-pad/index.d.ts +5 -0
  29. package/dist/context-pad/index.d.ts.map +1 -0
  30. package/dist/draw/EventStormingRenderer.d.ts +27 -0
  31. package/dist/draw/EventStormingRenderer.d.ts.map +1 -0
  32. package/dist/draw/icons.d.ts +43 -0
  33. package/dist/draw/icons.d.ts.map +1 -0
  34. package/dist/draw/index.d.ts +6 -0
  35. package/dist/draw/index.d.ts.map +1 -0
  36. package/dist/draw/note-markdown.d.ts +26 -0
  37. package/dist/draw/note-markdown.d.ts.map +1 -0
  38. package/dist/draw/palette-icons.d.ts +4 -0
  39. package/dist/draw/palette-icons.d.ts.map +1 -0
  40. package/dist/draw/styles.d.ts +98 -0
  41. package/dist/draw/styles.d.ts.map +1 -0
  42. package/dist/draw-tool/EventStormingDrawTool.d.ts +48 -0
  43. package/dist/draw-tool/EventStormingDrawTool.d.ts.map +1 -0
  44. package/dist/draw-tool/EventStormingDrawingHandles.d.ts +29 -0
  45. package/dist/draw-tool/EventStormingDrawingHandles.d.ts.map +1 -0
  46. package/dist/draw-tool/EventStormingDrawingHitProvider.d.ts +13 -0
  47. package/dist/draw-tool/EventStormingDrawingHitProvider.d.ts.map +1 -0
  48. package/dist/draw-tool/index.d.ts +6 -0
  49. package/dist/draw-tool/index.d.ts.map +1 -0
  50. package/dist/event-storming.css +2 -0
  51. package/dist/index.d.ts +31 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +2484 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/io/EventStormingExporter.d.ts +18 -0
  56. package/dist/io/EventStormingExporter.d.ts.map +1 -0
  57. package/dist/io/EventStormingImporter.d.ts +26 -0
  58. package/dist/io/EventStormingImporter.d.ts.map +1 -0
  59. package/dist/io/index.d.ts +8 -0
  60. package/dist/io/index.d.ts.map +1 -0
  61. package/dist/io/saveSvg.d.ts +17 -0
  62. package/dist/io/saveSvg.d.ts.map +1 -0
  63. package/dist/io/types.d.ts +12 -0
  64. package/dist/io/types.d.ts.map +1 -0
  65. package/dist/keyboard/EventStormingKeyboard.d.ts +20 -0
  66. package/dist/keyboard/EventStormingKeyboard.d.ts.map +1 -0
  67. package/dist/keyboard/index.d.ts +5 -0
  68. package/dist/keyboard/index.d.ts.map +1 -0
  69. package/dist/label-editing/EventStormingLabelEditing.d.ts +43 -0
  70. package/dist/label-editing/EventStormingLabelEditing.d.ts.map +1 -0
  71. package/dist/label-editing/index.d.ts +7 -0
  72. package/dist/label-editing/index.d.ts.map +1 -0
  73. package/dist/label-editing/note-editor-dom.d.ts +57 -0
  74. package/dist/label-editing/note-editor-dom.d.ts.map +1 -0
  75. package/dist/lasso/EventStormingLassoBehavior.d.ts +12 -0
  76. package/dist/lasso/EventStormingLassoBehavior.d.ts.map +1 -0
  77. package/dist/lasso/index.d.ts +5 -0
  78. package/dist/lasso/index.d.ts.map +1 -0
  79. package/dist/model/EventStormingElementFactory.d.ts +51 -0
  80. package/dist/model/EventStormingElementFactory.d.ts.map +1 -0
  81. package/dist/model/di-types.d.ts +62 -0
  82. package/dist/model/di-types.d.ts.map +1 -0
  83. package/dist/model/index.d.ts +6 -0
  84. package/dist/model/index.d.ts.map +1 -0
  85. package/dist/modeling/EventStormingCopyPaste.d.ts +43 -0
  86. package/dist/modeling/EventStormingCopyPaste.d.ts.map +1 -0
  87. package/dist/modeling/EventStormingModeling.d.ts +44 -0
  88. package/dist/modeling/EventStormingModeling.d.ts.map +1 -0
  89. package/dist/modeling/cmd/UpdatePropertiesHandler.d.ts +18 -0
  90. package/dist/modeling/cmd/UpdatePropertiesHandler.d.ts.map +1 -0
  91. package/dist/modeling/index.d.ts +6 -0
  92. package/dist/modeling/index.d.ts.map +1 -0
  93. package/dist/ordering/EventStormingOrderingProvider.d.ts +17 -0
  94. package/dist/ordering/EventStormingOrderingProvider.d.ts.map +1 -0
  95. package/dist/ordering/index.d.ts +5 -0
  96. package/dist/ordering/index.d.ts.map +1 -0
  97. package/dist/palette/EventStormingPaletteProvider.d.ts +19 -0
  98. package/dist/palette/EventStormingPaletteProvider.d.ts.map +1 -0
  99. package/dist/palette/index.d.ts +5 -0
  100. package/dist/palette/index.d.ts.map +1 -0
  101. package/dist/popup/EventStormingElementSettingsProvider.d.ts +17 -0
  102. package/dist/popup/EventStormingElementSettingsProvider.d.ts.map +1 -0
  103. package/dist/popup/index.d.ts +5 -0
  104. package/dist/popup/index.d.ts.map +1 -0
  105. package/dist/resize/EventStormingResizeBehavior.d.ts +12 -0
  106. package/dist/resize/EventStormingResizeBehavior.d.ts.map +1 -0
  107. package/dist/resize/index.d.ts +9 -0
  108. package/dist/resize/index.d.ts.map +1 -0
  109. package/dist/rules/EventStormingRules.d.ts +13 -0
  110. package/dist/rules/EventStormingRules.d.ts.map +1 -0
  111. package/dist/rules/index.d.ts +5 -0
  112. package/dist/rules/index.d.ts.map +1 -0
  113. package/dist/snapping/ElementSnapping.d.ts +15 -0
  114. package/dist/snapping/ElementSnapping.d.ts.map +1 -0
  115. package/dist/snapping/index.d.ts +5 -0
  116. package/dist/snapping/index.d.ts.map +1 -0
  117. package/dist/theme/index.d.ts +2 -0
  118. package/dist/theme/index.d.ts.map +1 -0
  119. package/dist/theme/palette.d.ts +56 -0
  120. package/dist/theme/palette.d.ts.map +1 -0
  121. package/dist/view-options/EventStormingViewOptions.d.ts +20 -0
  122. package/dist/view-options/EventStormingViewOptions.d.ts.map +1 -0
  123. package/dist/view-options/index.d.ts +9 -0
  124. package/dist/view-options/index.d.ts.map +1 -0
  125. package/package.json +53 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/io/saveSvg.ts","../src/EventStormingBaseViewer.ts","../src/theme/palette.ts","../src/draw/note-markdown.ts","../src/draw/styles.ts","../src/model/di-types.ts","../src/model/EventStormingElementFactory.ts","../src/model/index.ts","../src/board-bounds/BoardBounds.ts","../src/board-bounds/index.ts","../src/view-options/EventStormingViewOptions.ts","../src/view-options/index.ts","../src/draw/EventStormingRenderer.ts","../src/draw/index.ts","../src/io/EventStormingImporter.ts","../src/io/EventStormingExporter.ts","../src/io/index.ts","../src/Viewer.ts","../src/NavigatedViewer.ts","../src/attach/EventStormingAttachBehavior.ts","../src/attach/index.ts","../src/modeling/cmd/UpdatePropertiesHandler.ts","../src/modeling/EventStormingModeling.ts","../src/modeling/EventStormingCopyPaste.ts","../src/modeling/index.ts","../src/lasso/EventStormingLassoBehavior.ts","../src/lasso/index.ts","../src/rules/EventStormingRules.ts","../src/rules/index.ts","../src/snapping/ElementSnapping.ts","../src/snapping/index.ts","../src/draw/palette-icons.ts","../src/palette/EventStormingPaletteProvider.ts","../src/palette/index.ts","../src/popup/EventStormingElementSettingsProvider.ts","../src/popup/index.ts","../src/draw/icons.ts","../src/context-pad/EventStormingContextPadProvider.ts","../src/context-pad/index.ts","../src/label-editing/note-editor-dom.ts","../src/label-editing/EventStormingLabelEditing.ts","../src/label-editing/index.ts","../src/keyboard/EventStormingKeyboard.ts","../src/keyboard/index.ts","../src/append/EventStormingAppendBehavior.ts","../src/append/index.ts","../src/color-picker/EventStormingColorPicker.ts","../src/color-picker/index.ts","../src/ordering/EventStormingOrderingProvider.ts","../src/ordering/index.ts","../src/draw-tool/EventStormingDrawTool.ts","../src/draw-tool/EventStormingDrawingHandles.ts","../src/draw-tool/EventStormingDrawingHitProvider.ts","../src/draw-tool/index.ts","../src/resize/EventStormingResizeBehavior.ts","../src/resize/index.ts","../src/Modeler.ts"],"sourcesContent":["import type Canvas from 'diagram-js/lib/core/Canvas';\nimport { DEFAULT_BOARD_SIZE } from '@miragon/event-storming-schema-model';\n\nexport interface SvgBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Serializes the current canvas into standalone SVG (snapshot/export).\n * `bounds` is the framing box (typically `BoardBounds.contentBounds()`), so the whole board is\n * exported wherever its stickies sit on the free canvas; if omitted, the empty-board default\n * framing is used. Independent of the current zoom/scroll.\n */\nexport function saveSVG(canvas: Canvas, bounds?: SvgBounds): { svg: string } {\n const container = canvas.getContainer();\n const source = container.querySelector('svg');\n if (!source) throw new Error('No SVG found in the canvas container.');\n\n const clone = source.cloneNode(true) as SVGSVGElement;\n\n const box = bounds ?? { x: 0, y: 0, ...DEFAULT_BOARD_SIZE };\n clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n clone.setAttribute('viewBox', `${box.x} ${box.y} ${box.width} ${box.height}`);\n clone.setAttribute('width', String(box.width));\n clone.setAttribute('height', String(box.height));\n\n // diagram-js sets a viewbox transform on the outermost layer; for the static export we\n // neutralize pan/zoom by letting the viewBox (above) determine 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","import 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 EventBus from 'diagram-js/lib/core/EventBus';\nimport type { EventStormingBoard } from '@miragon/event-storming-schema-model';\nimport { parseDSLWithDiagnostics, serializeDSL } from '@miragon/event-storming-dsl';\nimport { saveSVG } from './io/saveSvg.js';\nimport type EventStormingImporter from './io/EventStormingImporter.js';\nimport type EventStormingExporter from './io/EventStormingExporter.js';\nimport type BoardBounds from './board-bounds/BoardBounds.js';\nimport type { ImportWarning } from './io/types.js';\n\nexport interface EventStormingViewerOptions {\n /** Host element. If missing, a detached <div> is created (can be attached later via attachTo). */\n container?: HTMLElement;\n width?: number | string;\n height?: number | string;\n /** Concatenated to the end of the module list (extension point). */\n additionalModules?: ModuleDeclaration[];\n}\n\nexport type EventCallback<T = unknown> = (event: T) => void;\n\nfunction sizeToCss(value: number | string): string {\n return typeof value === 'number' ? `${value}px` : value;\n}\n\n/**\n * Shared lifecycle & DI bootstrap for all Event Storming viewers (analogous to bpmn-js\n * BaseViewer, but OUR OWN code — no bpmn-js as a dependency). Subclasses only override\n * `_getModules()` (a method rather than a field, to sidestep the constructor/field\n * initialization order). `attachTo`/`detach` are own implementations (not a diagram-js\n * primitive).\n */\nexport abstract class EventStormingBaseViewer {\n protected abstract _getModules(): ModuleDeclaration[];\n\n private _diagram: Diagram | undefined;\n private readonly _container: HTMLElement;\n private readonly _options: EventStormingViewerOptions;\n\n constructor(options: EventStormingViewerOptions = {}) {\n this._options = options;\n this._container = this._createContainer(options);\n }\n\n private _createContainer(options: EventStormingViewerOptions): HTMLElement {\n const container = options.container ?? document.createElement('div');\n container.classList.add('event-storming-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({ canvas: { container: this._container }, modules });\n }\n return this._diagram;\n }\n\n get<T>(name: string): T {\n return this._ensureDiagram().get<T>(name);\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 /** Load a board into the canvas (replaces existing content). */\n async importMap(board: EventStormingBoard): Promise<{ warnings: ImportWarning[] }> {\n const diagram = this._ensureDiagram();\n const eventBus = diagram.get<EventBus>('eventBus');\n const importer = diagram.get<EventStormingImporter>('eventStormingImporter');\n importer.clear();\n const warnings = importer.import(board);\n this._applyStyleClass(board.config.style);\n // Discard the PREVIOUS board's undo history: undo on orphaned elements would otherwise\n // crash or insert zombie elements into the new board.\n diagram.get<CommandStack>('commandStack').clear();\n eventBus.fire('import.done', { warnings });\n return { warnings };\n }\n\n /** DSL `style` directive as a CSS class on the container (`event-storming-dark` etc.). */\n private _applyStyleClass(style?: string): void {\n const cls = this._container.classList;\n for (const s of ['classic', 'dark']) cls.remove(`event-storming-${s}`);\n if (style && style !== 'classic') cls.add(`event-storming-${style}`);\n }\n\n /** Load `.storm` DSL text (internally parse -> importMap). Parser findings land in the warnings. */\n async importDSL(text: string): Promise<{ warnings: ImportWarning[] }> {\n const eventBus = this._ensureDiagram().get<EventBus>('eventBus');\n eventBus.fire('import.parse.start', { text });\n const { board, diagnostics } = parseDSLWithDiagnostics(text);\n eventBus.fire('import.parse.done', { board, diagnostics });\n const { warnings } = await this.importMap(board);\n return {\n warnings: [\n ...diagnostics.map((d) => ({ message: `Line ${d.line}: ${d.message} — \"${d.text}\"` })),\n ...warnings,\n ],\n };\n }\n\n /** Current state as the canonical model (from the DI properties). */\n exportMap(): EventStormingBoard {\n return this.get<EventStormingExporter>('eventStormingExporter').export();\n }\n\n exportDSL(): string {\n return serializeDSL(this.exportMap());\n }\n\n /** Static, standalone SVG — framed by the content bounds of the free canvas. */\n async saveSVG(): Promise<{ svg: string }> {\n return saveSVG(\n this.get<Canvas>('canvas'),\n this.get<BoardBounds>('boardBounds').contentBounds(),\n );\n }\n\n /** Own implementation (not a diagram-js primitive): attach the container to `target`. */\n attachTo(target: HTMLElement): void {\n target.appendChild(this._container);\n this.get<Canvas>('canvas').resized();\n }\n\n /** Own implementation: detach the container from the DOM, keeping 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 * Miragon design tokens — the single source of truth for every colour in the renderer's chrome.\n *\n * Values mirror the Miragon design system — the `miragon-brand:modeler-tool-design` skill in\n * `Miragon/corporate-identity` (its vendored `cd-tokens.generated.css` defines the `--cd-*`\n * variables, generated from `brand/tokens.json`). Re-copy from the skill to update; never fork the\n * hex values by hand. WHY this file exists: colours used to live in three hand-duplicated places\n * (the SVG `COLORS` object, the `--event-storming-*` CSS variables, and the webapp's own `:root`).\n * Here they are declared once. `draw/styles.ts` derives the public `COLORS`/`FONT`/… from\n * `MIRAGON`; `assets/event-storming.css` mirrors the `CHROME_VARS` / `DARK_BOARD_VARS` maps (a\n * unit test, `test/theme.sync.test.ts`, fails if the CSS drifts).\n *\n * Pure data — no DOM, no imports — so it stays inside the P1 DOM-free discipline.\n *\n * There is one theme (the CI defines no dark theme). Brand rule: blue leads (`blau` — surfaces,\n * buttons, links), green accents (`gruen` — key visual, highlights; never body text on white).\n */\n\n/** Raw Miragon brand ramp — exact `brand/tokens.json` values. */\nexport const MIRAGON = {\n /** Primary: surfaces, buttons, links, 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 links / accents on dark surfaces (the opt-in \"dark board\"). */\n blauHell: '#6B8AFF',\n /** Accent: key visual, highlights, one emphasised word. Bright — a fill, never text on white. */\n gruen: '#00E676',\n /** Calm neutral surface (warm off-white). */\n grau: '#F9F7F7',\n /** Text on light, monochrome logo. Not pure black. */\n schwarz: '#1D1D1D',\n weiss: '#FFFFFF',\n /** Functional / status layer (own layer beside the brand palette; AA as text on white). */\n success: '#0B7A55',\n warning: '#92610A',\n danger: '#C92A2A',\n info: '#2B50D4',\n /** Dark base — the CI hero / nav-glass colour (rgb 8,10,32). Used only by the opt-in \"dark board\". */\n navy: '#080A20',\n /** Signature brand gradient — hero, large surfaces, brand moments. Use verbatim. */\n gradientBrand: 'linear-gradient(120deg, #335DE5 30%, #00E676)',\n} as const;\n\n/**\n * Chrome CSS variables (`--event-storming-*`) authored in `assets/event-storming.css`. The drift\n * test keeps them in sync. WHY a separate map from `COLORS`: chrome needs surface/brand/danger/\n * shadow that the canvas does not, and only a subset of the canvas colours.\n */\nexport const CHROME_VARS: Record<string, string> = {\n '--event-storming-paper': MIRAGON.grau,\n '--event-storming-ink': MIRAGON.schwarz,\n '--event-storming-ink-soft': '#5B5B5B',\n '--event-storming-surface': MIRAGON.weiss,\n '--event-storming-border': '#E6E2E2',\n '--event-storming-accent': MIRAGON.blau,\n '--event-storming-accent-soft': 'rgba(51, 93, 229, 0.12)',\n '--event-storming-brand': MIRAGON.gruen,\n '--event-storming-danger': MIRAGON.danger,\n '--event-storming-shadow': 'rgba(29, 29, 29, 0.1)',\n '--event-storming-drawing-ink': MIRAGON.schwarz,\n};\n\n/**\n * The per-board `style dark` directive (`.event-storming-container.event-storming-dark`)\n * overrides only the surround plus the default drawing ink (near-black strokes would vanish on\n * navy). This is the ONLY dark surface — there is no app-level dark mode. The stickies keep\n * their SVG presentation colours, so exports stay stable.\n */\nexport const DARK_BOARD_VARS: Record<string, string> = {\n '--event-storming-paper': MIRAGON.navy,\n '--event-storming-drawing-ink': MIRAGON.grau,\n};\n","/**\n * The tiny Markdown subset stored inside note labels (notes only — stickies stay plain):\n * `**bold**`, `*italic*`, `***bold italic***` inline runs and `- ` bullet lines. The label\n * stays ONE string in the model/DSL — this module is the single translation point between\n * that string and styled runs (renderer + WYSIWYG editor). Unmatched markers are literal\n * text: parsing never throws and never eats characters. `serialize(parse(x))` is a fixed\n * point for canonical input; non-canonical input canonicalizes in one parse→serialize cycle\n * and is then stable.\n */\n\nexport interface NoteRun {\n readonly text: string;\n readonly bold: boolean;\n readonly italic: boolean;\n}\n\nexport interface NoteLine {\n /** Line started with the `- ` marker (stripped from the runs). */\n readonly bullet: boolean;\n readonly runs: NoteRun[];\n}\n\n// Longest marker first: `***` must win over `**`/`*` so the combined form parses as one run.\nconst MARKERS = [\n { marker: '***', bold: true, italic: true },\n { marker: '**', bold: true, italic: false },\n { marker: '*', bold: false, italic: true },\n] as const;\n\n/** One entry per '\\n' line; bullet lines have the `- ` marker stripped. */\nexport function parseNoteMarkdown(label: string): NoteLine[] {\n return label.split('\\n').map((raw) => {\n const bullet = raw.startsWith('- ');\n return { bullet, runs: parseInline(bullet ? raw.slice(2) : raw) };\n });\n}\n\n/** Exact inverse of `parseNoteMarkdown`: canonical markers, adjacent same-style runs merged. */\nexport function serializeNoteMarkdown(lines: NoteLine[]): string {\n return lines\n .map((line) => {\n const text = mergeRuns(line.runs)\n .map((run) => {\n const marker = run.bold && run.italic ? '***' : run.bold ? '**' : run.italic ? '*' : '';\n return marker + run.text + marker;\n })\n .join('');\n return (line.bullet ? '- ' : '') + text;\n })\n .join('\\n');\n}\n\n/** Markers stripped, bullets as '• ' prefix — the string the text measurement sees. */\nexport function plainNoteText(label: string): string {\n return parseNoteMarkdown(label)\n .map((line) => (line.bullet ? '• ' : '') + line.runs.map((run) => run.text).join(''))\n .join('\\n');\n}\n\nfunction parseInline(text: string): NoteRun[] {\n const runs: NoteRun[] = [];\n let literal = '';\n const flushLiteral = () => {\n if (literal) runs.push({ text: literal, bold: false, italic: false });\n literal = '';\n };\n let i = 0;\n while (i < text.length) {\n const span = text[i] === '*' ? matchSpan(text, i) : undefined;\n if (!span) {\n literal += text[i];\n i++;\n continue;\n }\n flushLiteral();\n runs.push({ text: span.content, bold: span.bold, italic: span.italic });\n i = span.end;\n }\n flushLiteral();\n return mergeRuns(runs);\n}\n\n/**\n * A styled span starting at `i`: the longest opening marker with a same-length closer and\n * non-empty content. Only the FIRST closer counts (no backtracking) — inner `*` characters\n * become literal content, which re-serializes to the same string (the one-cycle stability\n * guarantee above).\n */\nfunction matchSpan(\n text: string,\n i: number,\n): { content: string; bold: boolean; italic: boolean; end: number } | undefined {\n for (const { marker, bold, italic } of MARKERS) {\n if (!text.startsWith(marker, i)) continue;\n const close = text.indexOf(marker, i + marker.length);\n if (close <= i + marker.length) continue; // no closer (-1) or empty content\n return {\n content: text.slice(i + marker.length, close),\n bold,\n italic,\n end: close + marker.length,\n };\n }\n return undefined;\n}\n\n/** Drops empty runs and joins style-identical neighbors — the canonical run form. */\nfunction mergeRuns(runs: NoteRun[]): NoteRun[] {\n const merged: Array<{ text: string; bold: boolean; italic: boolean }> = [];\n for (const run of runs) {\n if (!run.text) continue;\n const last = merged[merged.length - 1];\n if (last && last.bold === run.bold && last.italic === run.italic) last.text += run.text;\n else merged.push({ text: run.text, bold: run.bold, italic: run.italic });\n }\n return merged;\n}\n","/** Central rendering constants (geometry, colors, typography) — Miragon corporate identity. */\n\nimport { MIRAGON } from '../theme/index.js';\nimport type { StickyKind } from '../model/di-types.js';\nimport { plainNoteText } from './note-markdown.js';\n\nexport interface StickyStyle {\n /** Default label for a freshly created sticky. */\n readonly label: string;\n readonly width: number;\n readonly height: number;\n readonly fill: string;\n readonly stroke: string;\n}\n\n/**\n * The canonical sticky-note look per kind (Brandolini's color grammar): default label, fixed\n * size and fill/border. Single source for the renderer, element factory, palette previews and\n * the color-picker swatches. Aggregate, policy and external system share the large block format —\n * they occupy the same slot in the grammar (receive commands / react to events); actors are the\n * small corner stickies.\n */\nexport const STICKY_STYLES: Record<StickyKind, StickyStyle> = {\n event: { label: 'Domain Event', width: 130, height: 90, fill: '#FFB84D', stroke: '#E89A2E' },\n command: { label: 'Command', width: 130, height: 90, fill: '#7EC8F0', stroke: '#4FA8D8' },\n actor: { label: 'Actor', width: 100, height: 65, fill: '#FFF9B1', stroke: '#E6DB7A' },\n aggregate: { label: 'Aggregate', width: 180, height: 110, fill: '#FFE066', stroke: '#E0BE3F' },\n policy: { label: 'Policy', width: 180, height: 110, fill: '#C9A0DC', stroke: '#A97CC4' },\n readmodel: { label: 'Read Model', width: 130, height: 90, fill: '#A8D08D', stroke: '#7FB35D' },\n external: {\n label: 'External System',\n width: 180,\n height: 110,\n fill: '#F4A6C0',\n stroke: '#DE7EA2',\n },\n hotspot: { label: 'Hotspot', width: 130, height: 90, fill: '#E85D75', stroke: '#C43B55' },\n} as const;\n\n/** Free-text note: grows with its text (see `noteMetrics`) unless resized by hand, neutral grey. */\nexport const NOTE_STYLE = { label: 'Note', fill: '#ECECEC', stroke: '#C4C4C4' } as const;\n\n/** Smallest hand-resized note box — keeps a shrunken note grabbable and its handles apart. */\nexport const NOTE_MIN_RESIZE = { width: 60, height: 40 } as const;\n\n/** Corner radius shared by all stickies (and the palette previews) — 0: paper has sharp corners. */\nexport const STICKY_RADIUS = 0;\n/** Inner text padding of a sticky (px, each side). */\nexport const STICKY_PADDING = 8;\n\nexport const STICKY_LINE_HEIGHT = 17;\n/** Estimated character width at the 13px label size — good enough for wrapping/box sizing. */\nexport const STICKY_CHAR_WIDTH = 7.5;\n/** Hanging indent (px) of note bullet lines — '•' rows and their wrapped continuations. */\nexport const NOTE_BULLET_INDENT = 12;\n/**\n * Default note box — the aggregate block format, so a fresh note reads as a full sticky instead of\n * a text-sized speck. Notes only grow beyond it; shrinking below it stays a hand resize\n * (`NOTE_MIN_RESIZE`).\n */\nconst NOTE_DEFAULT_SIZE = {\n width: STICKY_STYLES.aggregate.width,\n height: STICKY_STYLES.aggregate.height,\n} as const;\n\n/**\n * Box dimensions of a note from its (possibly multi-line) text. The note shape grows as large as\n * its text -> the move/click hitbox grows with it (never below `NOTE_DEFAULT_SIZE`). Vertical\n * padding matches the renderer's clip padding (`STICKY_PADDING`) — a smaller padding here would\n * make the renderer's maxLines clip drop the last text line. Measured on `plainNoteText`: the\n * markdown markers are invisible on canvas, so they must not widen the box (bullets count their\n * visible '• ' prefix).\n */\nexport function noteMetrics(label: string): { lines: string[]; width: number; height: number } {\n const plain = plainNoteText(label);\n const lines = (plain && plain.length ? plain : 'note').split('\\n');\n const maxLen = Math.max(1, ...lines.map((l) => l.length));\n return {\n lines,\n width: Math.max(\n NOTE_DEFAULT_SIZE.width,\n Math.round(maxLen * STICKY_CHAR_WIDTH) + STICKY_PADDING * 2,\n ),\n height: Math.max(\n NOTE_DEFAULT_SIZE.height,\n lines.length * STICKY_LINE_HEIGHT + STICKY_PADDING * 2,\n ),\n };\n}\n\n/**\n * The auto-vs-manual rule: a note box is MANUAL iff it differs from `noteMetrics(label)`.\n * Single comparison shared by the exporter (emit `size` only for manual boxes), relabel\n * (preserve manual boxes) and copy-paste (recompute only auto clones) — divergence between\n * these callers would make boards change on a plain reload.\n */\nexport function isManualNoteBox(label: string, box: { width: number; height: number }): boolean {\n const metrics = noteMetrics(label);\n return box.width !== metrics.width || box.height !== metrics.height;\n}\n\n/**\n * Canvas colours — Miragon palette. Keys are the public contract; brand values come from the\n * single source of truth in `theme/palette.ts` (`MIRAGON`). Referenced (not spread) so the\n * literal-string types survive into the published `.d.ts`. The sticky fills live in\n * `STICKY_STYLES` — this map only carries the non-sticky canvas colours.\n */\nexport const COLORS = {\n paper: MIRAGON.grau,\n ink: MIRAGON.schwarz,\n inkSoft: '#5B5B5B',\n surface: MIRAGON.weiss,\n stroke: MIRAGON.schwarz,\n /** The single connection style: gray arrowed line. */\n arrow: '#9E9E9E',\n accent: MIRAGON.blau,\n accentSoft: 'rgba(51,93,229,0.12)',\n /** Dark text inside every sticky. */\n stickyText: '#333333',\n} as const;\n\n/**\n * Default stroke for freeform drawings and the draw-tool preview: theme-aware via CSS variable\n * (dark boards flip it to a light ink — near-black on navy is invisible), with the light value as\n * literal fallback so exported SVGs opened standalone (no stylesheet) stay stable.\n */\nexport const DRAWING_INK = `var(--event-storming-drawing-ink, ${MIRAGON.schwarz})`;\n\nexport const FONT = {\n /**\n * Set as the `font-family` attribute DIRECTLY on all SVG text elements (canvas labels and\n * consequently the SVG export too) – not inherited from a CSS container. In EVERY context it\n * reaches for the self-hosted 'Geist' (Miragon corporate typeface) if the consumer provides it;\n * otherwise (e.g. an export SVG opened standalone) it falls back safely to a system sans. The\n * library does NOT ship the font – consumers must self-host Geist themselves\n * (e.g. via @fontsource-variable/geist), see README.\n */\n family: \"'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif\",\n label: 13,\n} as const;\n","import type { Shape, Connection } from 'diagram-js/lib/model/Types';\nimport {\n ATTACHABLE_STICKY_KINDS,\n HOST_STICKY_KINDS,\n type BoardEdge,\n type BoardElement,\n type DrawingStrokeStyle,\n type NoteAlignHorizontal,\n type NoteAlignVertical,\n} from '@miragon/event-storming-schema-model';\n\n/**\n * diagram-js runtime model with Event Storming extensions.\n *\n * The positional truth while editing is the diagram-js pixel geometry (`x`/`y`/`width`/`height`)\n * — there is no second coordinate system. `businessObject` is the identity/metadata backref to\n * the original model element; every editable field lives as a flat DI property.\n */\n\n/** ID of the diagram-js root element of the Event Storming board. */\nexport const ROOT_ID = 'event-storming-root';\n\nexport type EventStormingShapeType =\n | 'event'\n | 'command'\n | 'actor'\n | 'aggregate'\n | 'policy'\n | 'readmodel'\n | 'external'\n | 'hotspot'\n | 'note'\n | 'drawing';\n\nexport type EventStormingConnectionType = 'arrow';\n\nexport interface EventStormingShape extends Shape {\n eventStormingType: EventStormingShapeType;\n /** Display text (separate from diagram-js `label`, which references a label element). */\n eventStormingLabel: string;\n /** drawing only: points in px RELATIVE to the shape's x/y (moving the shape moves them all). */\n drawingPoints?: Array<{ x: number; y: number }>;\n /** drawing only: closed polygon vs. open polyline. */\n closed?: boolean;\n /** drawing only. */\n strokeStyle?: DrawingStrokeStyle;\n /** Optional color override (CSS color/hex from the swatch palette) — any element type. */\n color?: string;\n /** note only: horizontal text alignment, mirrored from `NoteElement.align` — absent = 'left'. */\n alignHorizontal?: NoteAlignHorizontal;\n /** note only: vertical text-block anchoring, mirrored from `NoteElement.align` — absent = 'top'. */\n alignVertical?: NoteAlignVertical;\n /**\n * Blank append sticky awaiting its kind (chosen in the change-type popup after placing).\n * Renderer-only: never exported, never copied, never persisted — cleared by the retype.\n */\n provisional?: boolean;\n businessObject?: BoardElement;\n}\n\nexport interface EventStormingConnection extends Connection {\n eventStormingType: EventStormingConnectionType;\n /** Arrow annotation text after `;` (e.g. \"async\"). */\n linkLabel?: string;\n businessObject?: BoardEdge;\n}\n\nfunction isObject(el: unknown): el is Record<string, unknown> {\n return typeof el === 'object' && el !== null;\n}\n\n/** Shapes and connections both carry `eventStormingType` — only connections have waypoints. */\nexport function isEventStormingShape(el: unknown): el is EventStormingShape {\n return isObject(el) && typeof el['eventStormingType'] === 'string' && !('waypoints' in el);\n}\n\nexport function isEventStormingConnection(el: unknown): el is EventStormingConnection {\n return isObject(el) && typeof el['eventStormingType'] === 'string' && 'waypoints' in el;\n}\n\n/** The eight sticky kinds — connectable, retypeable, always fixed-size (not note/drawing). */\nexport const STICKY_KINDS = [\n 'event',\n 'command',\n 'actor',\n 'aggregate',\n 'policy',\n 'readmodel',\n 'external',\n 'hotspot',\n] as const;\n\nexport type StickyKind = (typeof STICKY_KINDS)[number];\n\nexport function isStickyKind(type: string): type is StickyKind {\n return (STICKY_KINDS as readonly string[]).includes(type);\n}\n\nexport function isSticky(el: unknown): el is EventStormingShape {\n return isEventStormingShape(el) && isStickyKind(el.eventStormingType);\n}\n\n/** Pinnable kinds (actor/hotspot/note): can be dropped onto a host sticky and then move with it. */\nexport function isAttachableKind(type: string): boolean {\n return (ATTACHABLE_STICKY_KINDS as readonly string[]).includes(type);\n}\n\n/** Host kinds: can carry pinned attachers. Disjoint from the attachable kinds — no chains. */\nexport function isHostKind(type: string): boolean {\n return (HOST_STICKY_KINDS as readonly string[]).includes(type);\n}\n\nexport function isAttachableSticky(el: unknown): el is EventStormingShape {\n return isEventStormingShape(el) && isAttachableKind(el.eventStormingType);\n}\n\nexport function isHostSticky(el: unknown): el is EventStormingShape {\n return isEventStormingShape(el) && isHostKind(el.eventStormingType);\n}\n\nexport function isDrawing(el: unknown): el is EventStormingShape {\n return isEventStormingShape(el) && el.eventStormingType === 'drawing';\n}\n\nexport function isNote(el: unknown): el is EventStormingShape {\n return isEventStormingShape(el) && el.eventStormingType === 'note';\n}\n","import type ElementFactory from 'diagram-js/lib/core/ElementFactory';\nimport type ElementRegistry from 'diagram-js/lib/core/ElementRegistry';\nimport type {\n BoardEdge,\n BoardElement,\n DrawingElement,\n NoteElement,\n} from '@miragon/event-storming-schema-model';\nimport { STICKY_STYLES, noteMetrics } from '../draw/styles.js';\nimport {\n isStickyKind,\n type EventStormingConnection,\n type EventStormingShape,\n type EventStormingShapeType,\n} from './di-types.js';\n\n/**\n * Id prefixes matching the DSL parser's allocator (event_/cmd_/…) plus note/drawing — ids can\n * surface in the `.storm` text (`(id …)` suffix, `#id` references) once labels are duplicated,\n * so interactively created elements must not carry diagram-js `shape_N` ids.\n */\nconst ID_PREFIXES: Readonly<Record<EventStormingShapeType, string>> = {\n event: 'event',\n command: 'cmd',\n actor: 'actor',\n aggregate: 'agg',\n policy: 'policy',\n readmodel: 'read',\n external: 'ext',\n hotspot: 'hot',\n note: 'note',\n drawing: 'draw',\n};\n\n/**\n * Creates diagram-js runtime elements with Event Storming markers. Schema positions are element\n * CENTERS in board pixels — converted to diagram-js top-left via the per-kind width/height.\n */\nexport default class EventStormingElementFactory {\n static $inject = ['elementFactory', 'elementRegistry'];\n\n constructor(\n private readonly elementFactory: ElementFactory,\n private readonly elementRegistry: ElementRegistry,\n ) {}\n\n /**\n * Returns a unique label: `base`, otherwise `base 2`, `base 3`, … Duplicate labels are legal\n * (the DSL disambiguates via ids) — the numbering is pure UX so consecutive palette creates\n * read \"Domain Event 2\" instead of piling up identical defaults.\n */\n uniqueLabel(base: string): string {\n const taken = new Set<string>();\n for (const el of this.elementRegistry.getAll()) {\n const lbl = (el as { eventStormingLabel?: unknown }).eventStormingLabel;\n if (typeof lbl === 'string') taken.add(lbl);\n }\n if (!taken.has(base)) return base;\n let i = 2;\n while (taken.has(`${base} ${i}`)) i++;\n return `${base} ${i}`;\n }\n\n /**\n * DSL-style id `<kind-prefix>_<n>` for interactively created elements, collision-checked\n * against the elementRegistry. `reserved` covers ids handed out for the same batch before\n * anything is placed (e.g. a multi-shape paste — the clones are not in the registry yet).\n */\n allocateId(type: EventStormingShapeType, reserved?: ReadonlySet<string>): string {\n const prefix = ID_PREFIXES[type];\n for (let i = 1; ; i++) {\n const id = `${prefix}_${i}`;\n if (!this.elementRegistry.get(id) && !reserved?.has(id)) return id;\n }\n }\n\n /** Builds a fixed-size sticky from a schema element (position = center). */\n createSticky(el: BoardElement): EventStormingShape {\n if (!isStickyKind(el.elementType)) {\n throw new Error(`not a sticky kind: ${el.elementType}`);\n }\n const { width, height } = STICKY_STYLES[el.elementType];\n const shape = this.elementFactory.createShape({\n id: el.id,\n x: el.position.x - width / 2,\n y: el.position.y - height / 2,\n width,\n height,\n eventStormingType: el.elementType,\n eventStormingLabel: el.label,\n businessObject: el,\n ...(el.color ? { color: el.color } : {}),\n });\n return shape as unknown as EventStormingShape;\n }\n\n createNote(el: NoteElement): EventStormingShape {\n // Note box grows with the (possibly multiline) text -> move/click hitbox covers the text.\n // A manual `size` (the user resized the note by hand) wins over the text metrics.\n // Centered on the position (consistent with the center back-calculation on export).\n const { width, height } = el.size ?? noteMetrics(el.label);\n // Alignment DI props stay canonical: default axes (left/top) are absent, mirroring the\n // model's canonical form — so the exporter emits `align` only for real deviations.\n const horizontal = el.align?.horizontal;\n const vertical = el.align?.vertical;\n const shape = this.elementFactory.createShape({\n id: el.id,\n x: el.position.x - width / 2,\n y: el.position.y - height / 2,\n width,\n height,\n eventStormingType: 'note',\n eventStormingLabel: el.label,\n businessObject: el,\n ...(el.color ? { color: el.color } : {}),\n ...(horizontal && horizontal !== 'left' ? { alignHorizontal: horizontal } : {}),\n ...(vertical && vertical !== 'top' ? { alignVertical: vertical } : {}),\n });\n return shape as unknown as EventStormingShape;\n }\n\n createDrawing(el: DrawingElement): EventStormingShape {\n return this.drawingFromCanvasPoints([...el.points], {\n id: el.id,\n ...(el.closed ? { closed: true } : {}),\n ...(el.strokeStyle ? { strokeStyle: el.strokeStyle } : {}),\n ...(el.color ? { color: el.color } : {}),\n businessObject: el,\n });\n }\n\n /** Builds a drawing shape from ABSOLUTE canvas points (bbox shape + relative points). */\n drawingFromCanvasPoints(\n canvasPoints: ReadonlyArray<{ x: number; y: number }>,\n extra: {\n id?: string;\n closed?: boolean;\n strokeStyle?: DrawingElement['strokeStyle'];\n color?: string;\n businessObject?: DrawingElement;\n } = {},\n ): EventStormingShape {\n const xs = canvasPoints.map((p) => p.x);\n const ys = canvasPoints.map((p) => p.y);\n const x = Math.min(...xs);\n const y = Math.min(...ys);\n const width = Math.max(Math.max(...xs) - x, 4);\n const height = Math.max(Math.max(...ys) - y, 4);\n const shape = this.elementFactory.createShape({\n id: extra.id ?? this.allocateId('drawing'),\n x,\n y,\n width,\n height,\n eventStormingType: 'drawing',\n eventStormingLabel: '',\n drawingPoints: canvasPoints.map((p) => ({ x: p.x - x, y: p.y - y })),\n ...(extra.closed ? { closed: true } : {}),\n ...(extra.strokeStyle ? { strokeStyle: extra.strokeStyle } : {}),\n ...(extra.color ? { color: extra.color } : {}),\n ...(extra.businessObject ? { businessObject: extra.businessObject } : {}),\n });\n return shape as unknown as EventStormingShape;\n }\n\n /** Palette/keyboard create: sized per kind, position comes from the drop point. */\n createNew(type: EventStormingShapeType, rawLabel: string): EventStormingShape {\n // Numbered default labels (\"Domain Event 2\") are pure UX — see uniqueLabel.\n const label = this.uniqueLabel(rawLabel);\n const { width, height } = isStickyKind(type) ? STICKY_STYLES[type] : noteMetrics(label);\n const shape = this.elementFactory.createShape({\n id: this.allocateId(type),\n width,\n height,\n eventStormingType: type,\n eventStormingLabel: label,\n });\n return shape as unknown as EventStormingShape;\n }\n\n /**\n * Blank append create: the kind is chosen AFTER placing (change-type popup). The placeholder\n * kind 'event' keeps the model valid; the empty label plus the renderer-only `provisional`\n * DI prop make the sticky render blank until the choice lands (which clears the prop).\n */\n createProvisional(): EventStormingShape {\n const { width, height } = STICKY_STYLES.event;\n const shape = this.elementFactory.createShape({\n id: this.allocateId('event'),\n width,\n height,\n eventStormingType: 'event',\n eventStormingLabel: '',\n provisional: true,\n });\n return shape as unknown as EventStormingShape;\n }\n\n createArrow(\n edge: BoardEdge,\n source: EventStormingShape,\n target: EventStormingShape,\n ): EventStormingConnection {\n const conn = this.elementFactory.createConnection({\n id: edge.id,\n source,\n target,\n waypoints: [centerOf(source), centerOf(target)],\n eventStormingType: 'arrow',\n ...(edge.label ? { linkLabel: edge.label } : {}),\n businessObject: edge,\n });\n return conn as unknown as EventStormingConnection;\n }\n}\n\nfunction centerOf(shape: EventStormingShape): { x: number; y: number } {\n return { x: shape.x + shape.width / 2, y: shape.y + shape.height / 2 };\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingElementFactory from './EventStormingElementFactory.js';\n\n/** Custom ElementFactory with Event Storming sticky defaults. */\nexport const eventStormingModelModule: ModuleDeclaration = {\n eventStormingElementFactory: ['type', EventStormingElementFactory],\n};\n\nexport { default as EventStormingElementFactory } from './EventStormingElementFactory.js';\nexport * from './di-types.js';\n","import type ElementRegistry from 'diagram-js/lib/core/ElementRegistry';\nimport { DEFAULT_BOARD_SIZE } from '@miragon/event-storming-schema-model';\nimport { ROOT_ID } from '../model/di-types.js';\n\nexport interface Bounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface ShapeLikeElement {\n id: string;\n x?: unknown;\n y?: unknown;\n width?: unknown;\n height?: unknown;\n waypoints?: unknown;\n}\n\nfunction isPositionedShape(\n el: ShapeLikeElement,\n): el is ShapeLikeElement & { x: number; y: number; width: number; height: number } {\n return (\n el.id !== ROOT_ID &&\n !el.waypoints &&\n typeof el.x === 'number' &&\n typeof el.y === 'number' &&\n typeof el.width === 'number' &&\n typeof el.height === 'number'\n );\n}\n\n/**\n * Content bounds of the free Event Storming canvas — no rendering, no constraint. The single\n * bounds source for the SVG export viewBox and the apps' fitView (connections always run\n * between shapes, so the shape bbox covers everything).\n */\nexport default class BoardBounds {\n static $inject = ['elementRegistry'];\n\n constructor(private readonly elementRegistry: ElementRegistry) {}\n\n /**\n * Bounding box over all elements, padded on every side. An empty board falls back to the\n * schema-model default framing so fitView/export behave sensibly before the first sticky.\n */\n contentBounds(padding = 120): Bounds {\n const shapes = (this.elementRegistry.getAll() as ShapeLikeElement[]).filter(isPositionedShape);\n if (!shapes.length) return { x: 0, y: 0, ...DEFAULT_BOARD_SIZE };\n\n const minX = Math.min(...shapes.map((s) => s.x));\n const minY = Math.min(...shapes.map((s) => s.y));\n const maxX = Math.max(...shapes.map((s) => s.x + s.width));\n const maxY = Math.max(...shapes.map((s) => s.y + s.height));\n return {\n x: minX - padding,\n y: minY - padding,\n width: maxX - minX + 2 * padding,\n height: maxY - minY + 2 * padding,\n };\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport BoardBounds from './BoardBounds.js';\n\n/** Content-bbox bounds service (fitView + SVG export framing). */\nexport const boardBoundsModule: ModuleDeclaration = {\n boardBounds: ['type', BoardBounds],\n};\n\nexport { default as BoardBounds } from './BoardBounds.js';\nexport type { Bounds } from './BoardBounds.js';\n","import type EventBus from 'diagram-js/lib/core/EventBus';\nimport type ElementRegistry from 'diagram-js/lib/core/ElementRegistry';\nimport { isSticky } from '../model/di-types.js';\n\n/** Fired whenever a view preference changes (payload: `{ typeCaptionsVisible }`). */\nexport const VIEW_OPTIONS_CHANGED_EVENT = 'eventStorming.viewOptions.changed';\n\n/**\n * Per-viewer VIEW preferences — NOT board content: no schema/DSL field, no command-stack\n * entry (toggling is not undoable) and no import/export involvement. Consumers persist a\n * choice themselves (e.g. localStorage) and re-apply it right after creating the viewer.\n */\nexport default class EventStormingViewOptions {\n static $inject = ['eventBus', 'elementRegistry'];\n\n /** Captions default to ON — a fresh board explains the sticky color grammar by itself. */\n private _typeCaptionsVisible = true;\n\n constructor(\n private readonly eventBus: EventBus,\n private readonly elementRegistry: ElementRegistry,\n ) {}\n\n typeCaptionsVisible(): boolean {\n return this._typeCaptionsVisible;\n }\n\n setTypeCaptionsVisible(visible: boolean): void {\n if (visible === this._typeCaptionsVisible) return;\n this._typeCaptionsVisible = visible;\n this.eventBus.fire(VIEW_OPTIONS_CHANGED_EVENT, { typeCaptionsVisible: visible });\n // Only stickies carry a caption — mark exactly those changed; the stock change support\n // then clears and redraws each one, and the renderer reads the flag per drawShape.\n const stickies = this.elementRegistry.filter(isSticky);\n if (stickies.length) this.eventBus.fire('elements.changed', { elements: stickies });\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport ChangeSupportModule from 'diagram-js/lib/features/change-support';\nimport EventStormingViewOptions from './EventStormingViewOptions.js';\n\n/**\n * View preferences (e.g. type captions). Depends on change support so that toggling\n * re-renders even in plain Viewers, which do not pull in the modeling stack.\n */\nexport const eventStormingViewOptionsModule: ModuleDeclaration = {\n __depends__: [ChangeSupportModule],\n eventStormingViewOptions: ['type', EventStormingViewOptions],\n};\n\nexport { default as EventStormingViewOptions } from './EventStormingViewOptions.js';\nexport { VIEW_OPTIONS_CHANGED_EVENT } from './EventStormingViewOptions.js';\n","import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer';\nimport { append as svgAppend, create as svgCreate, attr as svgAttr } from 'tiny-svg';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type { ElementLike, ShapeLike, ConnectionLike } from 'diagram-js/lib/model/Types';\nimport type { Point } from 'diagram-js/lib/util/Types';\nimport {\n COLORS,\n DRAWING_INK,\n FONT,\n NOTE_BULLET_INDENT,\n NOTE_STYLE,\n STICKY_CHAR_WIDTH,\n STICKY_LINE_HEIGHT,\n STICKY_PADDING,\n STICKY_RADIUS,\n STICKY_STYLES,\n} from './styles.js';\nimport { parseNoteMarkdown, type NoteLine, type NoteRun } from './note-markdown.js';\nimport {\n isEventStormingConnection,\n isEventStormingShape,\n isStickyKind,\n type EventStormingConnection,\n type EventStormingShape,\n} from '../model/di-types.js';\nimport type EventStormingViewOptions from '../view-options/EventStormingViewOptions.js';\n\n/** BaseRenderer default is 1000; 1500 wins the render.shape/render.connection event. */\nconst RENDER_PRIORITY = 1500;\n\n/** Hotspots stand out with a slight tilt (rotated around the sticky center). */\nconst HOTSPOT_ROTATION_DEG = -3;\n\n/** Class of the small kind caption at a sticky's bottom (selector contract for tests/e2e). */\nexport const KIND_CAPTION_CLASS = 'event-storming-kind-caption';\n\n/** Caption typography: small and light so it never competes with the user's label. */\nconst CAPTION_FONT_SIZE = 9;\nconst CAPTION_FONT_WEIGHT = 300;\nconst CAPTION_FILL = '#606060';\n/** Caption baseline sits this many px above the sticky's bottom edge. */\nconst CAPTION_BOTTOM_OFFSET = 7;\n\n/** Provisional (blank append) sticky: neutral paper with a dashed hint border, no kind yet. */\nconst PROVISIONAL_FILL = '#FBFBFB';\nconst PROVISIONAL_STROKE = '#B9B9B9';\nconst PROVISIONAL_DASH = '6 4';\n\n/** Soft drop shadow that makes stickies read as paper on the board (defs id, per canvas SVG). */\nexport const STICKY_SHADOW_FILTER_ID = 'event-storming-sticky-shadow';\n\n/**\n * Installs the shadow filter into the owning SVG's defs (once per SVG — the export clones the\n * whole SVG, so the defs travel into saved files). Returns false while the visual group is not\n * attached yet: a `filter=\"url(#…)\"` pointing at a missing def would make the element invisible,\n * so callers must only reference the filter when this succeeded.\n */\nfunction ensureStickyShadowFilter(visuals: SVGElement): boolean {\n const svg = visuals.closest('svg');\n if (!svg) return false;\n if (svg.querySelector(`#${STICKY_SHADOW_FILTER_ID}`)) return true;\n const drop = svgAttr(svgCreate('feDropShadow'), {\n dx: 0,\n dy: 5,\n stdDeviation: 5,\n 'flood-color': '#000000',\n 'flood-opacity': 0.2,\n });\n // Widened filter region: the default -10%/120% box would clip the soft blur below the sticky.\n const filter = svgAttr(svgCreate('filter'), {\n id: STICKY_SHADOW_FILTER_ID,\n x: '-40%',\n y: '-40%',\n width: '180%',\n height: '180%',\n });\n svgAppend(filter, drop);\n const defs = svgCreate('defs');\n svgAppend(defs, filter);\n svg.insertBefore(defs, svg.firstChild);\n return true;\n}\n\ntype Attrs = Record<string, string | number>;\n\nexport default class EventStormingRenderer extends BaseRenderer {\n static $inject = ['eventBus', 'eventStormingViewOptions'];\n\n constructor(\n eventBus: EventBus,\n private readonly viewOptions: EventStormingViewOptions,\n ) {\n super(eventBus, RENDER_PRIORITY);\n }\n\n override canRender(element: ElementLike): boolean {\n return isEventStormingShape(element) || isEventStormingConnection(element);\n }\n\n override drawShape(visuals: SVGElement, element: ShapeLike): SVGElement {\n const shape = element as unknown as EventStormingShape;\n if (shape.eventStormingType === 'drawing') return this.drawDrawing(visuals, shape);\n return this.drawSticky(visuals, shape);\n }\n\n /** Freeform drawing: polyline/polygon from relative points (see EventStormingDrawTool). */\n private drawDrawing(visuals: SVGElement, shape: EventStormingShape): SVGElement {\n const pts = shape.drawingPoints ?? [];\n const dash =\n shape.strokeStyle === 'dashed' ? '8 5' : shape.strokeStyle === 'dotted' ? '2 4' : undefined;\n const path = svgAttr(svgCreate(shape.closed ? 'polygon' : 'polyline'), {\n points: pts.map((p) => `${p.x},${p.y}`).join(' '),\n fill: 'none',\n stroke: shape.color ?? DRAWING_INK,\n 'stroke-width': 2,\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n ...(dash ? { 'stroke-dasharray': dash } : {}),\n });\n svgAppend(visuals, path);\n return path;\n }\n\n /**\n * Every sticky (and the free note) is a rounded rectangle with centered, wrapped dark text\n * inside — the label lives IN the sticky, never beside it. A user-picked `color` overrides\n * the kind's fill; the border stays the kind's own (so the type remains recognizable).\n */\n private drawSticky(visuals: SVGElement, shape: EventStormingShape): SVGElement {\n const kind = shape.eventStormingType;\n const style = isStickyKind(kind) ? STICKY_STYLES[kind] : NOTE_STYLE;\n // A provisional (blank append) sticky renders as a neutral dashed shell — its placeholder\n // kind must not leak: no kind colors, no caption, no text (the label is empty anyway).\n const provisional = shape.provisional === true;\n\n // Hotspots are tilted like a hastily slapped-on sticky; rotate the whole visual group\n // around the center so rect and text stay together.\n let parent = visuals;\n if (kind === 'hotspot') {\n const group = svgAttr(svgCreate('g'), {\n transform: `rotate(${HOTSPOT_ROTATION_DEG} ${shape.width / 2} ${shape.height / 2})`,\n });\n svgAppend(visuals, group);\n parent = group;\n }\n\n const rect = svgAttr(svgCreate('rect'), {\n x: 0,\n y: 0,\n width: Math.max(shape.width, 1),\n height: Math.max(shape.height, 1),\n rx: STICKY_RADIUS,\n fill: provisional ? PROVISIONAL_FILL : (shape.color ?? style.fill),\n stroke: provisional ? PROVISIONAL_STROKE : style.stroke,\n 'stroke-width': 1.5,\n ...(provisional ? { 'stroke-dasharray': PROVISIONAL_DASH } : {}),\n });\n // Attribute (not tiny-svg attr, which routes `filter` into inline style) so exports carry it.\n if (ensureStickyShadowFilter(visuals)) {\n rect.setAttribute('filter', `url(#${STICKY_SHADOW_FILTER_ID})`);\n }\n svgAppend(parent, rect);\n\n if (provisional) return rect;\n\n if (kind === 'note') drawNoteText(parent, shape);\n else drawStickyText(parent, shape);\n\n // Small kind caption at the bottom — the 8 sticky kinds only (a note explains itself,\n // drawings never reach this method). Appended to `parent` so it tilts with a hotspot.\n if (isStickyKind(kind) && this.viewOptions.typeCaptionsVisible()) {\n const caption = label(\n STICKY_STYLES[kind].label,\n shape.width / 2,\n shape.height - CAPTION_BOTTOM_OFFSET,\n {\n 'text-anchor': 'middle',\n 'font-size': CAPTION_FONT_SIZE,\n fill: CAPTION_FILL,\n },\n );\n // Plain attributes (tiny-svg attr routes `font-weight` into inline style): the class is\n // the test/e2e selector contract, and exports must carry both as-is.\n caption.setAttribute('class', KIND_CAPTION_CLASS);\n caption.setAttribute('font-weight', String(CAPTION_FONT_WEIGHT));\n svgAppend(parent, caption);\n }\n return rect;\n }\n\n override drawConnection(visuals: SVGElement, element: ConnectionLike): SVGElement {\n const conn = element as unknown as EventStormingConnection;\n const [start, end] = endpoints(conn);\n\n const path = svgAttr(svgCreate('polyline'), {\n points: `${start.x},${start.y} ${end.x},${end.y}`,\n fill: 'none',\n stroke: COLORS.arrow,\n 'stroke-width': 1.5,\n 'stroke-linecap': 'round',\n });\n svgAppend(visuals, path);\n svgAppend(visuals, connectionArrow(start, end, COLORS.arrow, 11, 5));\n\n // Arrow annotation (`; …`) at the midpoint.\n if (conn.linkLabel) {\n const mx = (start.x + end.x) / 2;\n const my = (start.y + end.y) / 2;\n svgAppend(\n visuals,\n label(conn.linkLabel, mx, my - 5, {\n 'text-anchor': 'middle',\n 'font-size': 11,\n 'font-style': 'italic',\n fill: COLORS.inkSoft,\n }),\n );\n }\n return path;\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 [first, ...rest] = connection.waypoints;\n if (!first) return '';\n return `M${first.x},${first.y}` + rest.map((p: Point) => `L${p.x},${p.y}`).join('');\n }\n}\n\n/** Word-wraps one paragraph to `maxChars` (estimated monospace-ish width, like noteMetrics). */\nfunction wrapParagraph(paragraph: string, maxChars: number): string[] {\n const words = paragraph.split(/\\s+/).filter((w) => w.length);\n if (!words.length) return [''];\n const lines: string[] = [];\n let current = '';\n for (const word of words) {\n // Hard-break unbreakable over-long words (e.g. PascalCase identifiers) into maxChars chunks —\n // an over-wide single line would spill outside the fixed sticky box.\n if (word.length > maxChars) {\n if (current) lines.push(current);\n let rest = word;\n while (rest.length > maxChars) {\n lines.push(rest.slice(0, maxChars));\n rest = rest.slice(maxChars);\n }\n current = rest;\n continue;\n }\n const candidate = current ? `${current} ${word}` : word;\n if (candidate.length <= maxChars || !current) current = candidate;\n else {\n lines.push(current);\n current = word;\n }\n }\n lines.push(current);\n return lines;\n}\n\n/**\n * Centered multi-line text inside the sticky: explicit line breaks are honored, long lines are\n * word-wrapped into the padded box, and overflowing lines are clipped (fixed-size stickies never\n * grow). Notes render via `drawNoteText` instead.\n */\nfunction drawStickyText(parent: SVGElement, shape: EventStormingShape): void {\n const innerWidth = shape.width - 2 * STICKY_PADDING;\n const maxChars = Math.max(1, Math.floor(innerWidth / STICKY_CHAR_WIDTH));\n const maxLines = Math.max(\n 1,\n Math.floor((shape.height - 2 * STICKY_PADDING) / STICKY_LINE_HEIGHT),\n );\n\n const lines = (shape.eventStormingLabel ?? '')\n .split('\\n')\n .flatMap((paragraph) => wrapParagraph(paragraph, maxChars))\n .slice(0, maxLines);\n\n const cx = shape.width / 2;\n // Center the block of lines vertically in the box (+4 ~ baseline offset for 13px).\n const y0 = shape.height / 2 - ((lines.length - 1) * STICKY_LINE_HEIGHT) / 2 + 4;\n lines.forEach((line, i) => {\n svgAppend(\n parent,\n label(line, cx, y0 + i * STICKY_LINE_HEIGHT, {\n 'text-anchor': 'middle',\n fill: COLORS.stickyText,\n }),\n );\n });\n}\n\n/**\n * Chars the '• ' prefix occupies in the estimate — matches `plainNoteText`, so the wrap budget\n * stays consistent with the `noteMetrics` box.\n */\nconst BULLET_PREFIX_CHARS = 2;\n\n/**\n * Baseline offset within a line row — chosen so a middle-anchored block sits exactly where the\n * old centered note layout put it (`height/2 - (n-1)*LH/2 + 4`).\n */\nconst NOTE_ROW_BASELINE = STICKY_LINE_HEIGHT / 2 + 4;\n\ninterface NoteRow {\n readonly runs: NoteRun[];\n /** First row of a bullet line — rendered with the leading '• ' marker. */\n readonly marker: boolean;\n /** Wrapped continuation row of a bullet line — keeps the hanging indent (left alignment). */\n readonly indent: boolean;\n}\n\n/**\n * Note text is a small document, not a centered label: markdown runs (bold/italic tspans) and\n * bullet lines with a '•' hanging indent, laid out per the note's alignment — horizontal per\n * line (anchor at padding / center / width-minus-padding), vertical anchoring the whole block\n * top/middle/bottom inside `STICKY_PADDING`. Defaults: left/top. Wrapping (hand-shrunken boxes)\n * splits runs at the wrap point so styling survives; overflowing rows are clipped like stickies.\n */\nfunction drawNoteText(parent: SVGElement, shape: EventStormingShape): void {\n const innerWidth = shape.width - 2 * STICKY_PADDING;\n const maxChars = Math.max(1, Math.floor(innerWidth / STICKY_CHAR_WIDTH));\n const maxLines = Math.max(\n 1,\n Math.floor((shape.height - 2 * STICKY_PADDING) / STICKY_LINE_HEIGHT),\n );\n\n const rows = parseNoteMarkdown(shape.eventStormingLabel ?? '')\n .flatMap((line) => wrapNoteLine(line, maxChars))\n .slice(0, maxLines);\n\n const horizontal = shape.alignHorizontal ?? 'left';\n const vertical = shape.alignVertical ?? 'top';\n const anchor = horizontal === 'left' ? 'start' : horizontal === 'center' ? 'middle' : 'end';\n const blockHeight = rows.length * STICKY_LINE_HEIGHT;\n const blockTop =\n vertical === 'top'\n ? STICKY_PADDING\n : vertical === 'middle'\n ? (shape.height - blockHeight) / 2\n : shape.height - STICKY_PADDING - blockHeight;\n\n rows.forEach((row, i) => {\n // The hanging indent only exists as an x-offset when lines share a left edge; centered/right\n // rows are anchored like any other line (the '• ' marker still sticks to its row's start).\n const x =\n horizontal === 'left'\n ? STICKY_PADDING + (row.indent ? NOTE_BULLET_INDENT : 0)\n : horizontal === 'center'\n ? shape.width / 2\n : shape.width - STICKY_PADDING;\n const text = svgAttr(svgCreate('text'), {\n x,\n y: blockTop + i * STICKY_LINE_HEIGHT + NOTE_ROW_BASELINE,\n 'font-family': FONT.family,\n 'font-size': FONT.label,\n fill: COLORS.stickyText,\n 'text-anchor': anchor,\n });\n const runs: NoteRun[] = row.marker\n ? [{ text: '• ', bold: false, italic: false }, ...row.runs]\n : row.runs;\n for (const run of runs) {\n const tspan = svgCreate('tspan');\n tspan.textContent = run.text;\n // Plain attributes (like the kind caption): exports and e2e selectors see them directly.\n if (run.bold) tspan.setAttribute('font-weight', '600');\n if (run.italic) tspan.setAttribute('font-style', 'italic');\n svgAppend(text, tspan);\n }\n svgAppend(parent, text);\n });\n}\n\n/** Wraps one markdown line into rows; bullet rows reserve the '• ' prefix in their budget. */\nfunction wrapNoteLine(line: NoteLine, maxChars: number): NoteRow[] {\n const budget = Math.max(1, maxChars - (line.bullet ? BULLET_PREFIX_CHARS : 0));\n return wrapRuns(line.runs, budget).map((runs, i) => ({\n runs,\n marker: line.bullet && i === 0,\n indent: line.bullet && i > 0,\n }));\n}\n\n/**\n * Word-wraps styled runs by wrapping their concatenated plain text into index ranges and\n * slicing the runs along them — a run split by the wrap point keeps its styling on both rows.\n * A line that fits stays verbatim (auto-sized boxes always hit this path via noteMetrics).\n */\nfunction wrapRuns(runs: NoteRun[], maxChars: number): NoteRun[][] {\n const plain = runs.map((run) => run.text).join('');\n if (plain.length <= maxChars) return [runs];\n return wrapRanges(plain, maxChars).map(([start, end]) => sliceRuns(runs, start, end));\n}\n\n/**\n * Greedy word wrap as index ranges over the original string (same semantics as\n * `wrapParagraph`, incl. hard-breaking over-long words) — whitespace only collapses AT the\n * wrap points, so run offsets stay valid.\n */\nfunction wrapRanges(plain: string, maxChars: number): Array<[number, number]> {\n const words = [...plain.matchAll(/\\S+/g)];\n if (!words.length) return [[0, 0]];\n const rows: Array<[number, number]> = [];\n let start = -1;\n let end = -1;\n const flush = () => {\n if (start >= 0) rows.push([start, end]);\n start = end = -1;\n };\n for (const match of words) {\n let wordStart = match.index;\n const wordEnd = wordStart + match[0].length;\n if (match[0].length > maxChars) {\n flush();\n while (wordEnd - wordStart > maxChars) {\n rows.push([wordStart, wordStart + maxChars]);\n wordStart += maxChars;\n }\n start = wordStart;\n end = wordEnd;\n continue;\n }\n if (start < 0 || wordEnd - start <= maxChars) {\n if (start < 0) start = wordStart;\n end = wordEnd;\n continue;\n }\n flush();\n start = wordStart;\n end = wordEnd;\n }\n flush();\n return rows;\n}\n\n/** The runs overlapping [start, end) of the concatenated plain text, cut at the boundaries. */\nfunction sliceRuns(runs: NoteRun[], start: number, end: number): NoteRun[] {\n const out: NoteRun[] = [];\n let offset = 0;\n for (const run of runs) {\n const runStart = offset;\n offset += run.text.length;\n const from = Math.max(start, runStart);\n const to = Math.min(end, offset);\n if (from >= to) continue;\n out.push({\n text: run.text.slice(from - runStart, to - runStart),\n bold: run.bold,\n italic: run.italic,\n });\n }\n return out;\n}\n\nfunction label(content: string, x: number, y: number, attrs: Attrs = {}): SVGElement {\n const el = svgAttr(svgCreate('text'), {\n x,\n y,\n 'font-family': FONT.family,\n 'font-size': FONT.label,\n fill: COLORS.ink,\n ...attrs,\n });\n el.textContent = content;\n return el;\n}\n\nfunction connectionArrow(from: Point, to: Point, color: string, len = 10, w = 5): SVGElement {\n const angle = Math.atan2(to.y - from.y, to.x - from.x);\n const bx = to.x - len * Math.cos(angle);\n const by = to.y - len * Math.sin(angle);\n const points =\n `${to.x},${to.y} ` +\n `${bx - w * Math.sin(angle)},${by + w * Math.cos(angle)} ` +\n `${bx + w * Math.sin(angle)},${by - w * Math.cos(angle)}`;\n return svgAttr(svgCreate('polygon'), { points, fill: color });\n}\n\nfunction centerOf(s: EventStormingShape): Point {\n return { x: s.x + s.width / 2, y: s.y + s.height / 2 };\n}\n\n/** Point where the ray from the rect center towards `to` exits the (slightly padded) rect. */\nfunction rectBoundaryPoint(s: EventStormingShape, to: Point): Point {\n const c = centerOf(s);\n const dx = to.x - c.x;\n const dy = to.y - c.y;\n if (dx === 0 && dy === 0) return c;\n const halfW = s.width / 2 + 2;\n const halfH = s.height / 2 + 2;\n const t = Math.min(\n dx !== 0 ? halfW / Math.abs(dx) : Infinity,\n dy !== 0 ? halfH / Math.abs(dy) : Infinity,\n );\n return { x: c.x + dx * t, y: c.y + dy * t };\n}\n\n/**\n * Connection endpoints from the CURRENT shape centers, cropped at the rectangle boundary\n * (line ends at the sticky's edge, arrowhead visible — independent of z-order, and correct\n * after moving, since recomputed on every render).\n */\nfunction endpoints(conn: EventStormingConnection): [Point, Point] {\n const s = conn.source as unknown as EventStormingShape | undefined;\n const t = conn.target as unknown as EventStormingShape | undefined;\n const wp = conn.waypoints;\n if (!s || !t) {\n const a = wp[0] ?? { x: 0, y: 0 };\n return [a, wp[wp.length - 1] ?? a];\n }\n const sc = centerOf(s);\n const tc = centerOf(t);\n const start = rectBoundaryPoint(s, tc);\n const end = rectBoundaryPoint(t, sc);\n // Overlapping stickies: fall back to the raw centers instead of crossed-over crop points.\n const along = (tc.x - sc.x) * (end.x - start.x) + (tc.y - sc.y) * (end.y - start.y);\n if (along <= 0) return [sc, tc];\n return [start, end];\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingRenderer from './EventStormingRenderer.js';\nimport { eventStormingViewOptionsModule } from '../view-options/index.js';\n\n/** SVG rendering of all Event Storming stickies (BaseRenderer subclass, priority 1500). */\nexport const eventStormingDrawModule: ModuleDeclaration = {\n // The renderer reads the caption toggle — carry the providing module along for consumers\n // that wire the draw module standalone (didi dedupes it against the Viewer's own entry).\n __depends__: [eventStormingViewOptionsModule],\n __init__: ['eventStormingRenderer'],\n eventStormingRenderer: ['type', EventStormingRenderer],\n};\n\nexport { default as EventStormingRenderer } from './EventStormingRenderer.js';\nexport {\n parseNoteMarkdown,\n serializeNoteMarkdown,\n plainNoteText,\n type NoteLine,\n type NoteRun,\n} from './note-markdown.js';\n","import 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 { BoardElement, EventStormingBoard } from '@miragon/event-storming-schema-model';\nimport type BoardBounds from '../board-bounds/BoardBounds.js';\nimport type EventStormingElementFactory from '../model/EventStormingElementFactory.js';\nimport { isHostSticky, type EventStormingShape } from '../model/di-types.js';\nimport { ROOT_ID, type ImportWarning, type RootBusinessObject } from './types.js';\n\n/**\n * Z-order of the shapes among themselves: smaller number = further back. Drawings encircle\n * sticky clusters and must never swallow their clicks, so they sit at the very back; the\n * connections are inserted between drawings and stickies via parentIndex. Stickies and notes\n * share the top band in document order — the interactive ordering provider appends both, so a\n * separate note band would make the stacking flip between a session and the re-imported board.\n */\nconst TYPE_ORDER: Record<string, number> = {\n drawing: 0,\n};\n\n/**\n * Bridges the EventStormingBoard model into the diagram-js canvas. Deliberately bypasses the\n * commandStack (import path): no undo, no dirty.\n */\nexport default class EventStormingImporter {\n static $inject = [\n 'canvas',\n 'elementFactory',\n 'eventStormingElementFactory',\n 'boardBounds',\n 'eventBus',\n 'elementRegistry',\n ];\n\n constructor(\n private readonly canvas: Canvas,\n private readonly elementFactory: ElementFactory,\n private readonly factory: EventStormingElementFactory,\n private readonly boardBounds: BoardBounds,\n private readonly eventBus: EventBus,\n private readonly elementRegistry: ElementRegistry,\n ) {}\n\n import(board: EventStormingBoard): ImportWarning[] {\n const warnings: ImportWarning[] = [];\n this.eventBus.fire('import.render.start', { board });\n\n const meta: RootBusinessObject = {\n config: board.config,\n ...(board.rawPassthrough ? { rawPassthrough: board.rawPassthrough } : {}),\n };\n\n // Reuse the existing root (re-import), otherwise create a new one.\n let existing: (Root & { businessObject?: RootBusinessObject }) | undefined;\n try {\n existing = this.canvas.getRootElement() as Root & { businessObject?: RootBusinessObject };\n } catch {\n existing = undefined;\n }\n let root: Root & { businessObject?: RootBusinessObject };\n if (existing && existing.id === ROOT_ID) {\n root = existing;\n } else {\n root = this.elementFactory.createRoot({ id: ROOT_ID }) as Root & {\n businessObject?: RootBusinessObject;\n };\n this.canvas.setRootElement(root);\n }\n root.businessObject = meta;\n\n const shapeById = new Map<string, EventStormingShape>();\n const ordered = [...board.elements].sort(\n (a, b) => (TYPE_ORDER[a.elementType] ?? 9) - (TYPE_ORDER[b.elementType] ?? 9),\n );\n\n // Z-order (back -> front): drawings -> connections -> stickies/notes. Drawings and nodes\n // must be registered before the connections; the connections are then inserted via\n // parentIndex BEHIND the nodes (but after the drawings).\n const drawings = ordered.filter((el) => el.elementType === 'drawing');\n const nodes = ordered.filter((el) => el.elementType !== 'drawing');\n\n for (const el of drawings) {\n const shape = this.createShape(el);\n this.canvas.addShape(shape, root);\n shapeById.set(el.id, shape);\n }\n for (const el of nodes) {\n const shape = this.createShape(el);\n this.canvas.addShape(shape, root);\n shapeById.set(el.id, shape);\n }\n\n // Pinning is wired only once ALL shapes exist — a host may appear later in document order\n // than its attacher. The diagram-js bi-directional refs keep `host.attachers` in sync;\n // positions stay the elements' own absolute centers (attachedTo adds behavior, not geometry).\n for (const el of nodes) {\n const attachedTo = 'attachedTo' in el ? el.attachedTo : undefined;\n if (!attachedTo) continue;\n const host = shapeById.get(attachedTo);\n if (!host || !isHostSticky(host)) {\n warnings.push({\n message: `Element ${el.id}: attachedTo host \"${attachedTo}\" missing.`,\n elementId: el.id,\n });\n continue;\n }\n shapeById.get(el.id)!.host = host;\n }\n\n for (const edge of board.edges) {\n const source = shapeById.get(edge.from);\n const target = shapeById.get(edge.to);\n if (!source || !target) {\n warnings.push({ message: `Edge ${edge.id}: endpoint missing.`, elementId: edge.id });\n continue;\n }\n const conn = this.factory.createArrow(edge, source, target);\n // Insert directly behind the drawings, before all nodes.\n this.canvas.addConnection(conn, root, drawings.length);\n }\n\n this.canvas.viewbox(this.boardBounds.contentBounds());\n this.eventBus.fire('import.render.done', { warnings });\n return warnings;\n }\n\n private createShape(el: BoardElement): EventStormingShape {\n switch (el.elementType) {\n case 'note':\n return this.factory.createNote(el);\n case 'drawing':\n return this.factory.createDrawing(el);\n default:\n return this.factory.createSticky(el);\n }\n }\n\n clear(): void {\n for (const el of [...this.elementRegistry.getAll()]) {\n const e = el as { waypoints?: unknown; id: string };\n if (e.id === ROOT_ID) continue;\n try {\n if (e.waypoints) this.canvas.removeConnection(e.id);\n else this.canvas.removeShape(e.id);\n } catch {\n // already removed (e.g. edge on a removed shape) — ignore\n }\n }\n }\n}\n","import type Canvas from 'diagram-js/lib/core/Canvas';\nimport type ElementRegistry from 'diagram-js/lib/core/ElementRegistry';\nimport type { Root } from 'diagram-js/lib/model/Types';\nimport {\n validateBoard,\n CURRENT_SCHEMA_VERSION,\n type BoardConfig,\n type BoardEdge,\n type BoardElement,\n type EventStormingBoard,\n type NoteAlign,\n} from '@miragon/event-storming-schema-model';\nimport {\n isEventStormingConnection,\n isEventStormingShape,\n type EventStormingShape,\n} from '../model/di-types.js';\nimport { isManualNoteBox } from '../draw/styles.js';\nimport { ROOT_ID, type RootBusinessObject } from './types.js';\n\n/**\n * Reconstructs an EventStormingBoard from the diagram-js runtime model. The DI properties are\n * the single source of truth — position is the shape CENTER back-calculated from the pixel\n * geometry; the `businessObject` only serves as identity backref and is not consulted for data.\n */\nexport default class EventStormingExporter {\n static $inject = ['elementRegistry', 'canvas'];\n\n constructor(\n private readonly elementRegistry: ElementRegistry,\n private readonly canvas: Canvas,\n ) {}\n\n export(): EventStormingBoard {\n const root = this.canvas.getRootElement() as Root & { businessObject?: RootBusinessObject };\n const meta = root.businessObject;\n const config: BoardConfig = meta?.config ?? { title: 'Untitled Board' };\n\n const elements: BoardElement[] = [];\n const edges: BoardEdge[] = [];\n\n for (const el of this.elementRegistry.getAll()) {\n if (el.id === ROOT_ID) continue;\n if (isEventStormingConnection(el)) {\n edges.push({\n id: el.id,\n edgeType: 'arrow',\n from: el.source?.id ?? '',\n to: el.target?.id ?? '',\n ...(el.linkLabel ? { label: el.linkLabel } : {}),\n });\n } else if (isEventStormingShape(el)) {\n const built = this.buildElement(el);\n if (built) elements.push(built);\n }\n }\n\n const board: EventStormingBoard = {\n schemaVersion: CURRENT_SCHEMA_VERSION,\n config,\n elements,\n edges,\n ...(meta?.rawPassthrough ? { rawPassthrough: meta.rawPassthrough } : {}),\n };\n\n return validateBoard(board);\n }\n\n /** Builds a BoardElement from the DI properties; position = shape center. */\n private buildElement(el: EventStormingShape): BoardElement | undefined {\n if (el.eventStormingType === 'drawing') {\n // Points are stored relative to the shape in px — convert back to absolute board px.\n const points = (el.drawingPoints ?? []).map((p) => ({ x: el.x + p.x, y: el.y + p.y }));\n if (points.length < 2) return undefined;\n return {\n id: el.id,\n elementType: 'drawing',\n label: '',\n position: points[0]!,\n points,\n ...(el.closed ? { closed: true } : {}),\n ...(el.strokeStyle ? { strokeStyle: el.strokeStyle } : {}),\n ...(el.color ? { color: el.color } : {}),\n };\n }\n // Auto-vs-manual: `size` is emitted ONLY when the note box differs from its text metrics —\n // auto-sized notes stay absent-size, keeping existing boards byte-identical on round-trip.\n const manualSize =\n el.eventStormingType === 'note' && isManualNoteBox(el.eventStormingLabel, el)\n ? { width: el.width, height: el.height }\n : undefined;\n const align = el.eventStormingType === 'note' ? noteAlignOf(el) : undefined;\n return {\n id: el.id,\n elementType: el.eventStormingType,\n label: el.eventStormingLabel,\n position: { x: el.x + el.width / 2, y: el.y + el.height / 2 },\n ...(el.color ? { color: el.color } : {}),\n ...(manualSize ? { size: manualSize } : {}),\n ...(align ? { align } : {}),\n // Pinning lives in the diagram-js host/attachers refs — only actor/hotspot/note ever\n // carry a host (attach rule), matching the schema's attachedTo placement.\n ...(el.host ? { attachedTo: el.host.id } : {}),\n };\n }\n}\n\n/**\n * Canonical model alignment from the DI props: default axes (left/top) collapse to absent —\n * even when a caller wrote them explicitly — so unaligned boards keep serializing\n * byte-identically (the DSL emits `(align …)` only when this returns a value).\n */\nfunction noteAlignOf(el: EventStormingShape): NoteAlign | undefined {\n const horizontal =\n el.alignHorizontal && el.alignHorizontal !== 'left' ? el.alignHorizontal : undefined;\n const vertical = el.alignVertical && el.alignVertical !== 'top' ? el.alignVertical : undefined;\n if (!horizontal && !vertical) return undefined;\n return { ...(horizontal ? { horizontal } : {}), ...(vertical ? { vertical } : {}) };\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingImporter from './EventStormingImporter.js';\nimport EventStormingExporter from './EventStormingExporter.js';\n\nexport const ioModule: ModuleDeclaration = {\n eventStormingImporter: ['type', EventStormingImporter],\n eventStormingExporter: ['type', EventStormingExporter],\n};\n\nexport { default as EventStormingImporter } from './EventStormingImporter.js';\nexport { default as EventStormingExporter } from './EventStormingExporter.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 { EventStormingBaseViewer } from './EventStormingBaseViewer.js';\nimport { eventStormingModelModule } from './model/index.js';\nimport { boardBoundsModule } from './board-bounds/index.js';\nimport { eventStormingViewOptionsModule } from './view-options/index.js';\nimport { eventStormingDrawModule } from './draw/index.js';\nimport { ioModule } from './io/index.js';\n\nexport class Viewer extends EventStormingBaseViewer {\n protected _getModules(): ModuleDeclaration[] {\n return [\n eventStormingModelModule,\n boardBoundsModule,\n eventStormingViewOptionsModule,\n eventStormingDrawModule,\n ioModule,\n ];\n }\n}\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 KeyboardModule from 'diagram-js/lib/features/keyboard';\nimport { Viewer } from './Viewer.js';\n\n/**\n * `keyboard-move-selection` depends on `modeling` and therefore belongs in the (later) Modeler,\n * not in the read-only NavigatedViewer. Panning is unconstrained — the canvas is free.\n */\nexport class NavigatedViewer extends Viewer {\n protected override _getModules(): ModuleDeclaration[] {\n return [\n ...super._getModules(),\n SelectionModule,\n ZoomScrollModule,\n MoveCanvasModule,\n KeyboardModule,\n ];\n }\n}\n","import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type Modeling from 'diagram-js/lib/features/modeling/Modeling';\nimport type { Shape } from 'diagram-js/lib/model/Types';\nimport { isAttachableKind, isHostKind } from '../model/di-types.js';\nimport type { UpdatePropertiesContext } from '../modeling/cmd/UpdatePropertiesHandler.js';\n\n/**\n * Keeps pinning consistent under RETYPE (`setStickyKind` via the popup): only attachable kinds\n * (actor/hotspot/note) may carry a `host` and only host kinds may carry attachers — a stale link\n * would make the exporter's `validateBoard` throw. Drag/drop, host-delete and move-together are\n * covered by the stock diagram-js AttachSupport; retype mutates in place (no `shape.replace`),\n * so it needs this hook. Notes themselves cannot be retyped (`setStickyKind` rejects them), but\n * a HOST retyped to a non-host kind sheds its note attachers like any other attacher here.\n * Runs in `preExecute` of the SAME command -> detach joins the retype as one undo step.\n */\nexport default class EventStormingAttachBehavior extends CommandInterceptor {\n static override $inject = ['eventBus', 'modeling'];\n\n constructor(eventBus: EventBus, modeling: Modeling) {\n super(eventBus);\n\n this.preExecute('element.updateProperties', (event: { context: UpdatePropertiesContext }) => {\n const { element, properties } = event.context;\n const newType = properties['eventStormingType'];\n if (typeof newType !== 'string') return;\n const shape = element as unknown as Shape;\n if (shape.host && !isAttachableKind(newType)) {\n modeling.updateAttachment(shape, undefined);\n }\n if (shape.attachers?.length && !isHostKind(newType)) {\n for (const attacher of [...shape.attachers]) {\n modeling.updateAttachment(attacher, undefined);\n }\n }\n });\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport AttachSupportModule from 'diagram-js/lib/features/attach-support';\nimport EventStormingAttachBehavior from './EventStormingAttachBehavior.js';\n\n/**\n * Pinning of actor/hotspot stickies and notes: the stock diagram-js AttachSupport\n * (host/attachers move-together, delete-together — the bpmn-js boundary-event machinery) plus\n * the Event Storming retype consistency behavior.\n */\nexport const eventStormingAttachModule: ModuleDeclaration = {\n __depends__: [AttachSupportModule],\n __init__: ['eventStormingAttachBehavior'],\n eventStormingAttachBehavior: ['type', EventStormingAttachBehavior],\n};\n\nexport { default as EventStormingAttachBehavior } from './EventStormingAttachBehavior.js';\n","import 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\nconst GEOMETRY_KEYS = ['x', 'y', 'width', 'height'];\n\n/**\n * Geometry changes (e.g. `setStickyKind` resizing the box) move the rectangle the attached\n * arrows are cropped against at render time — the connections must be marked dirty too, or\n * they keep pointing at the old boundary until something else forces a re-render.\n */\nfunction dirtyElements(element: ElementLike, changedKeys: string[]): ElementLike[] {\n if (!changedKeys.some((key) => GEOMETRY_KEYS.includes(key))) return [element];\n const el = element as { incoming?: ElementLike[]; outgoing?: ElementLike[] };\n return [element, ...(el.incoming ?? []), ...(el.outgoing ?? [])];\n}\n\n/**\n * Generic, undoable command handler for setting arbitrary Event Storming properties\n * (eventStormingLabel, eventStormingType, color, strokeStyle, ...). Returns the changed element\n * -> CommandStack fires `elements.changed` -> re-render.\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 dirtyElements(element, Object.keys(properties));\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 dirtyElements(element, Object.keys(oldProperties ?? {}));\n }\n}\n","import 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 { Root } from 'diagram-js/lib/model/Types';\nimport {\n DEFAULT_BOARD_LEVEL,\n type BoardLevel,\n type DrawingStrokeStyle,\n} from '@miragon/event-storming-schema-model';\nimport {\n isStickyKind,\n ROOT_ID,\n type EventStormingConnection,\n type EventStormingShape,\n type StickyKind,\n} from '../model/di-types.js';\nimport type { RootBusinessObject } from '../io/types.js';\nimport { STICKY_STYLES, isManualNoteBox, noteMetrics } from '../draw/styles.js';\nimport UpdatePropertiesHandler from './cmd/UpdatePropertiesHandler.js';\n\nconst UPDATE_PROPERTIES = 'element.updateProperties';\n\n/**\n * High-level mutations on Event Storming elements that run through the commandStack (undo/redo).\n * Registers the generic UpdatePropertiesHandler at bootstrap.\n */\nexport default class EventStormingModeling {\n static $inject = ['commandStack', 'canvas', 'elementRegistry'];\n\n constructor(\n private readonly commandStack: CommandStack,\n private readonly canvas: Canvas,\n private readonly elementRegistry: ElementRegistry,\n ) {\n commandStack.registerHandler(UPDATE_PROPERTIES, UpdatePropertiesHandler);\n }\n\n updateProperties(\n element: EventStormingShape | EventStormingConnection,\n properties: Record<string, unknown>,\n ): void {\n this.commandStack.execute(UPDATE_PROPERTIES, { element, properties });\n }\n\n updateLabel(element: EventStormingShape, label: string): void {\n // AUTO-sized notes: resize the box (and thus the move/click hitbox) to the new text, keeping\n // the center. A MANUAL box (differs from the text metrics) was the user's choice — keep it,\n // the text reflows/clips inside.\n if (\n element.eventStormingType === 'note' &&\n !isManualNoteBox(element.eventStormingLabel, element)\n ) {\n const { width, height } = noteMetrics(label);\n const cx = element.x + element.width / 2;\n const cy = element.y + element.height / 2;\n this.updateProperties(element, {\n eventStormingLabel: label,\n width,\n height,\n x: cx - width / 2,\n y: cy - height / 2,\n });\n return;\n }\n this.updateProperties(element, { eventStormingLabel: label });\n }\n\n /**\n * Retypes a sticky among the eight sticky kinds, keeping id/label/position/color. The box is\n * resized to the new kind's size around the current center; the changed element re-renders.\n * On a provisional (blank append) sticky the SAME single command also clears the provisional\n * marker — picking its placeholder kind again is a real confirmation, not a no-op.\n */\n setStickyKind(element: EventStormingShape, elementType: StickyKind): void {\n if (!isStickyKind(element.eventStormingType) || !isStickyKind(elementType)) {\n throw new Error(`setStickyKind: only sticky kinds can be retyped`);\n }\n if (element.eventStormingType === elementType && !element.provisional) return;\n const { width, height } = STICKY_STYLES[elementType];\n const cx = element.x + element.width / 2;\n const cy = element.y + element.height / 2;\n this.updateProperties(element, {\n eventStormingType: elementType,\n ...(element.provisional ? { provisional: undefined } : {}),\n width,\n height,\n x: cx - width / 2,\n y: cy - height / 2,\n });\n }\n\n /** Sets the element color (CSS color/hex) or removes it (`undefined` = the kind's default). */\n setColor(element: EventStormingShape, color: string | undefined): void {\n this.updateProperties(element, { color });\n }\n\n /** Sets a drawing's stroke style (`undefined` = solid). */\n setStrokeStyle(element: EventStormingShape, strokeStyle: DrawingStrokeStyle | undefined): void {\n this.updateProperties(element, { strokeStyle });\n }\n\n /**\n * Current effective workshop level (root `config.level`; absent means design). Reads via the\n * element registry — NOT `canvas.getRootElement()`, which would CREATE an implicit root as a\n * side effect (the palette asks for the level at bootstrap, before any board is imported, and\n * a stale implicit root crashes the importer's root swap after `clear()`).\n */\n getLevel(): BoardLevel {\n const root = this.elementRegistry.get(ROOT_ID) as\n (Root & { businessObject?: RootBusinessObject }) | undefined;\n return root?.businessObject?.config.level ?? DEFAULT_BOARD_LEVEL;\n }\n\n /**\n * Sets the workshop level on the root config — undoable like any element mutation. The\n * businessObject is replaced as a whole (not mutated) so the generic property handler can\n * snapshot/restore it and the exporter picks the change up from the root config.\n */\n setLevel(level: BoardLevel): void {\n if (this.getLevel() === level) return;\n const root = this.root();\n const meta = root.businessObject ?? { config: { title: 'Untitled Board' } };\n this.commandStack.execute(UPDATE_PROPERTIES, {\n element: root,\n properties: { businessObject: { ...meta, config: { ...meta.config, level } } },\n });\n }\n\n private root(): Root & { businessObject?: RootBusinessObject } {\n return (this.elementRegistry.get(ROOT_ID) ?? this.canvas.getRootElement()) as Root & {\n businessObject?: RootBusinessObject;\n };\n }\n}\n","import type ElementFactory from 'diagram-js/lib/core/ElementFactory';\nimport type Canvas from 'diagram-js/lib/core/Canvas';\nimport type Create from 'diagram-js/lib/features/create/Create';\nimport type Modeling from 'diagram-js/lib/features/modeling/Modeling';\nimport type Mouse from 'diagram-js/lib/features/mouse/Mouse';\nimport type Selection from 'diagram-js/lib/features/selection/Selection';\nimport type { Element, Shape } from 'diagram-js/lib/model/Types';\nimport {\n isEventStormingConnection,\n isEventStormingShape,\n type EventStormingConnection,\n type EventStormingShape,\n type EventStormingShapeType,\n} from '../model/di-types.js';\nimport type EventStormingElementFactory from '../model/EventStormingElementFactory.js';\n\n/** Offset (px) accumulated per paste operation. */\nconst PASTE_OFFSET = 24;\n\ninterface ShapeSnapshot {\n readonly props: Record<string, unknown>;\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n readonly label: string;\n /** Pinning: index of the copied HOST within the batch — absent if the host was not copied. */\n readonly hostIdx?: number;\n}\ninterface ConnectionSnapshot {\n readonly sourceIdx: number;\n readonly targetIdx: number;\n readonly props: Record<string, unknown>;\n}\n\n/** Event Storming properties carried along when copying (geometry handled separately). */\nconst SHAPE_PROPS = [\n 'eventStormingType',\n 'color',\n 'drawingPoints',\n 'closed',\n 'strokeStyle',\n 'alignHorizontal',\n 'alignVertical',\n] as const;\nconst CONNECTION_PROPS = ['eventStormingType', 'linkLabel'] as const;\n\nfunction snapshotProps(\n el: Record<string, unknown>,\n keys: readonly string[],\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of keys) {\n const value = el[key];\n if (value !== undefined) out[key] = structuredClone(value);\n }\n return out;\n}\n\n/**\n * Custom copy/paste for Event Storming elements: copies the selection including the connections\n * BETWEEN selected shapes. Clones keep their labels verbatim — duplicate labels are legal, the\n * DSL disambiguates via `(id …)`/`#id` — and get fresh DSL-style ids.\n * Paste attaches the clones to the cursor like palette create (live preview, click places,\n * Escape cancels); duplicate inserts immediately with an offset. Either way the insert is ONE\n * undoable `elements.create` command.\n */\nexport default class EventStormingCopyPaste {\n static $inject = [\n 'selection',\n 'modeling',\n 'elementFactory',\n 'eventStormingElementFactory',\n 'canvas',\n 'create',\n 'mouse',\n ];\n\n private clipboard: { shapes: ShapeSnapshot[]; connections: ConnectionSnapshot[] } | null = null;\n private pasteCount = 0;\n\n constructor(\n private readonly selection: Selection,\n private readonly modeling: Modeling,\n private readonly elementFactory: ElementFactory,\n private readonly esFactory: EventStormingElementFactory,\n private readonly canvas: Canvas,\n private readonly create: Create,\n private readonly mouse: Mouse,\n ) {}\n\n /** Copies the current selection. Returns false if nothing copyable is selected. */\n copy(): boolean {\n const selected = this.selection.get() as Element[];\n const shapes = selected.filter((el) => isEventStormingShape(el)) as EventStormingShape[];\n if (!shapes.length) return false;\n\n const indexOf = new Map<EventStormingShape, number>(shapes.map((s, i) => [s, i]));\n const connections: ConnectionSnapshot[] = [];\n const seen = new Set<EventStormingConnection>();\n for (const shape of shapes) {\n for (const conn of [...(shape.incoming ?? []), ...(shape.outgoing ?? [])]) {\n if (!isEventStormingConnection(conn) || seen.has(conn)) continue;\n const sourceIdx = indexOf.get(conn.source as unknown as EventStormingShape);\n const targetIdx = indexOf.get(conn.target as unknown as EventStormingShape);\n if (sourceIdx === undefined || targetIdx === undefined) continue;\n seen.add(conn);\n connections.push({\n sourceIdx,\n targetIdx,\n props: snapshotProps(conn as unknown as Record<string, unknown>, CONNECTION_PROPS),\n });\n }\n }\n\n this.clipboard = {\n shapes: shapes.map((s) => {\n // Attachment survives the copy only when the HOST is copied along (like the internal\n // connections); a lone attacher pastes detached.\n const hostIdx = s.host ? indexOf.get(s.host as unknown as EventStormingShape) : undefined;\n return {\n props: snapshotProps(s as unknown as Record<string, unknown>, SHAPE_PROPS),\n x: s.x,\n y: s.y,\n width: s.width,\n height: s.height,\n label: s.eventStormingLabel ?? '',\n ...(hostIdx !== undefined ? { hostIdx } : {}),\n };\n }),\n connections,\n };\n this.pasteCount = 0;\n return true;\n }\n\n /**\n * Paste with placement preview: the clones attach to the cursor exactly like palette create —\n * click places them, Escape cancels. Falls back to an offset insert when the mouse position\n * is unknown (e.g. paste before the pointer ever entered the canvas).\n */\n paste(): boolean {\n if (!this.clipboard?.shapes.length) return false;\n const clones = this.buildClones();\n const lastMove = this.mouse.getLastMoveEvent();\n if (lastMove) {\n this.create.start(lastMove, [...clones.shapes, ...clones.connections] as Element[]);\n return true;\n }\n return this.insertWithOffset(clones);\n }\n\n /** Copy + immediate offset insert of the selection (Ctrl+D) — no placement step. */\n duplicate(): boolean {\n if (!this.copy()) return false;\n return this.insertWithOffset(this.buildClones());\n }\n\n /** Builds fresh clone elements (fresh ids, labels kept, internal connections rewired). */\n private buildClones(): { shapes: Shape[]; connections: Element[] } {\n const clipboard = this.clipboard!;\n // Labels are kept verbatim, so the snapshot geometry stays correct for every note (an AUTO\n // box IS the label's text metrics, a MANUAL box was the user's choice). The fresh ids may\n // surface in the DSL as `(id …)` — allocate them DSL-style, reserving within the batch\n // (the clones only enter the registry once placed).\n const reserved = new Set<string>();\n const shapes = clipboard.shapes.map((snap) => {\n const id = this.esFactory.allocateId(\n snap.props['eventStormingType'] as EventStormingShapeType,\n reserved,\n );\n reserved.add(id);\n return this.elementFactory.createShape({\n ...structuredClone(snap.props),\n id,\n x: snap.x,\n y: snap.y,\n width: snap.width,\n height: snap.height,\n eventStormingLabel: snap.label,\n });\n });\n // Re-pin clones onto their clone hosts — the diagram-js bi-directional refs keep\n // `host.attachers` in sync, and AttachSupport moves/deletes them together after insert.\n clipboard.shapes.forEach((snap, i) => {\n if (snap.hostIdx !== undefined) shapes[i]!.host = shapes[snap.hostIdx]!;\n });\n const connections = clipboard.connections.map((c) =>\n this.elementFactory.createConnection({\n ...structuredClone(c.props),\n source: shapes[c.sourceIdx]!,\n target: shapes[c.targetIdx]!,\n waypoints: [center(shapes[c.sourceIdx]!), center(shapes[c.targetIdx]!)],\n }),\n );\n return { shapes, connections: connections as Element[] };\n }\n\n /** One `elements.create` command = one undo step; position = group center + offset. */\n private insertWithOffset(clones: { shapes: Shape[]; connections: Element[] }): boolean {\n this.pasteCount++;\n const offset = PASTE_OFFSET * this.pasteCount;\n const bbox = groupBBox(clones.shapes);\n const created = this.modeling.createElements(\n [...clones.shapes, ...clones.connections] as Element[],\n { x: bbox.cx + offset, y: bbox.cy + offset },\n this.canvas.getRootElement() as Shape,\n );\n this.selection.select(created as Element[]);\n return true;\n }\n}\n\nfunction center(s: { x: number; y: number; width: number; height: number }): {\n x: number;\n y: number;\n} {\n return { x: s.x + s.width / 2, y: s.y + s.height / 2 };\n}\n\nfunction groupBBox(shapes: Array<{ x: number; y: number; width: number; height: number }>): {\n cx: number;\n cy: number;\n} {\n const minX = Math.min(...shapes.map((s) => s.x));\n const minY = Math.min(...shapes.map((s) => s.y));\n const maxX = Math.max(...shapes.map((s) => s.x + s.width));\n const maxY = Math.max(...shapes.map((s) => s.y + s.height));\n return { cx: (minX + maxX) / 2, cy: (minY + maxY) / 2 };\n}\n","import type { ModuleDeclaration } from 'didi';\nimport MouseModule from 'diagram-js/lib/features/mouse';\nimport CreateModule from 'diagram-js/lib/features/create';\nimport EventStormingModeling from './EventStormingModeling.js';\nimport EventStormingCopyPaste from './EventStormingCopyPaste.js';\n\n/** High-level Event Storming mutations + registration of the custom command handlers. */\nexport const eventStormingModelingModule: ModuleDeclaration = {\n // Mouse/Create are needed by the paste preview (clones attach to the cursor).\n __depends__: [MouseModule, CreateModule],\n __init__: ['eventStormingModeling'],\n eventStormingModeling: ['type', EventStormingModeling],\n eventStormingCopyPaste: ['type', EventStormingCopyPaste],\n};\n\nexport { default as EventStormingModeling } from './EventStormingModeling.js';\nexport { default as EventStormingCopyPaste } from './EventStormingCopyPaste.js';\n","import type EventBus from 'diagram-js/lib/core/EventBus';\nimport type Canvas from 'diagram-js/lib/core/Canvas';\nimport type LassoTool from 'diagram-js/lib/features/lasso-tool/LassoTool';\n\ninterface ElementMouseEvent {\n element?: unknown;\n originalEvent?: MouseEvent;\n}\n\n/**\n * Activates the diagram-js lasso via Shift+drag on the empty canvas.\n * Plain drag stays canvas pan (MoveCanvas); Shift+click on elements stays multi-select.\n */\nexport default class EventStormingLassoBehavior {\n static $inject = ['eventBus', 'canvas', 'lassoTool'];\n\n constructor(eventBus: EventBus, canvas: Canvas, lassoTool: LassoTool) {\n eventBus.on('element.mousedown', 1500, (event: ElementMouseEvent) => {\n const original = event.originalEvent;\n if (!original?.shiftKey) return undefined;\n let root: unknown;\n try {\n root = canvas.getRootElement();\n } catch {\n return undefined;\n }\n if (event.element !== root) return undefined;\n lassoTool.activateLasso(original);\n // Returning false stops lower-priority listeners (canvas pan).\n return false;\n });\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport LassoToolModule from 'diagram-js/lib/features/lasso-tool';\nimport EventStormingLassoBehavior from './EventStormingLassoBehavior.js';\n\n/** Lasso multi-select: diagram-js lasso-tool plus Shift+drag activation on an empty canvas. */\nexport const eventStormingLassoModule: ModuleDeclaration = {\n __depends__: [LassoToolModule],\n __init__: ['eventStormingLassoBehavior'],\n eventStormingLassoBehavior: ['type', EventStormingLassoBehavior],\n};\n\nexport { default as EventStormingLassoBehavior } from './EventStormingLassoBehavior.js';\n","import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport {\n isAttachableSticky,\n isHostSticky,\n isNote,\n isSticky,\n type EventStormingShape,\n} from '../model/di-types.js';\nimport { NOTE_MIN_RESIZE } from '../draw/styles.js';\n\n/**\n * Is there already an arrow from `source` to `target` in this SAME direction? Arrows are\n * directional — the reverse arrow (B -> A alongside A -> B) is a distinct DSL line that imports\n * and round-trips, so it must stay drawable.\n */\nfunction alreadyConnected(source: EventStormingShape, target: EventStormingShape): boolean {\n return (source.outgoing ?? []).some((c) => c.target === (target as unknown));\n}\n\n/**\n * Pinning (bpmn-js boundary-event pattern): a SINGLE actor/hotspot/note dragged over a host-kind\n * sticky yields the diagram-js 'attach' verdict — the drop then sets `host` while the parent\n * stays the root. Host kinds exclude the attachable kinds, so attach chains cannot form. Notes\n * join via the shared attachable-kinds constant WITHOUT becoming connectable — the connection\n * rules gate on the eight sticky kinds, which exclude notes.\n */\nfunction canAttach(shapes: readonly unknown[], target: unknown): 'attach' | false {\n if (shapes.length !== 1) return false;\n if (!isAttachableSticky(shapes[0])) return false;\n if (!isHostSticky(target)) return false;\n return 'attach';\n}\n\n/**\n * Allowed edit operations. On success the `connection.create` rule returns the new connection's\n * attributes. Arrows connect the eight sticky kinds; notes and drawings are annotation-only and\n * never edge endpoints (they are also exempt from unique labels for the same reason).\n */\nexport default class EventStormingRules extends RuleProvider {\n static override $inject = ['eventBus'];\n\n constructor(eventBus: EventBus) {\n super(eventBus);\n }\n\n override init(): void {\n this.addRule('connection.start', (context: { source?: unknown }) => isSticky(context.source));\n\n this.addRule('connection.create', (context: { source?: unknown; target?: unknown }) => {\n const { source, target } = context;\n if (!isSticky(source) || !isSticky(target)) return false;\n if (source === target) return false;\n // Same-direction duplicate arrows are never meaningful (and indistinguishable in the\n // DSL) — prevent them instead of silently stacking.\n if (alreadyConnected(source, target)) return false;\n return { eventStormingType: 'arrow' };\n });\n\n // Moving is always allowed; dropping on a non-root target never nests (the ordering\n // provider retargets the parent to the root) — except for the 'attach' verdict, which\n // pins the dragged sticky to the hovered host instead.\n this.addRule(\n ['shape.move', 'elements.move'],\n (context: { shapes?: unknown[]; shape?: unknown; target?: unknown }) => {\n const shapes = context.shapes ?? (context.shape ? [context.shape] : []);\n return canAttach(shapes, context.target) || true;\n },\n );\n this.addRule('shape.create', () => true);\n // Group create (paste preview): diagram-js Create checks this rule for element arrays.\n this.addRule('elements.create', () => true);\n // Only notes are freely resizable: stickies have fixed per-kind sizes, drawings are\n // reshaped via their vertex handles. During a drag diagram-js re-checks with `newBounds`\n // (already clamped to the resize.start `minDimensions`) — the explicit minimum here also\n // keeps programmatic resizes from producing sub-minimum boxes.\n this.addRule(\n 'shape.resize',\n (context: { shape?: unknown; newBounds?: { width: number; height: number } }) => {\n if (!isNote(context.shape)) return false;\n const { newBounds } = context;\n if (!newBounds) return true;\n return (\n newBounds.width >= NOTE_MIN_RESIZE.width && newBounds.height >= NOTE_MIN_RESIZE.height\n );\n },\n );\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingRules from './EventStormingRules.js';\n\n/** Allowed Event Storming operations (RuleProvider). */\nexport const eventStormingRulesModule: ModuleDeclaration = {\n __init__: ['eventStormingRules'],\n eventStormingRules: ['type', EventStormingRules],\n};\n\nexport { default as EventStormingRules } from './EventStormingRules.js';\n","import type EventBus from 'diagram-js/lib/core/EventBus';\nimport type ElementRegistry from 'diagram-js/lib/core/ElementRegistry';\nimport { isEventStormingShape, type EventStormingShape } from '../model/di-types.js';\n\nconst SNAP_TOLERANCE = 8;\n\ninterface DragMoveEvent {\n x?: number;\n y?: number;\n /** Delta since drag start — diagram-js move/create works ONLY with dx/dy, never with x/y. */\n dx?: number;\n dy?: number;\n originalEvent?: { shiftKey?: boolean };\n context?: {\n shape?: { id?: string; x: number; y: number; width: number; height: number };\n shapes?: Array<{ id?: string }>;\n };\n}\n\ninterface Point {\n x: number;\n y: number;\n}\n\n/**\n * Snaps a sticky's CENTER to nearby stickies' center x/y while moving or creating, so event\n * chains line up into clean timeline rows/columns without a grid. Each axis snaps independently\n * to the closest candidate within the tolerance. Disabled while the Shift key is held.\n * Important: the coordinate and its delta must be adjusted TOGETHER (like diagram-js'\n * `setSnapped`) — move takes the final position from `dx`/`dy`, so a mutated `x` alone would\n * have no effect.\n */\nexport default class ElementSnapping {\n static $inject = ['eventBus', 'elementRegistry'];\n\n constructor(eventBus: EventBus, elementRegistry: ElementRegistry) {\n const candidateCenters = (excludeIds: ReadonlySet<string>): Point[] =>\n elementRegistry\n .getAll()\n .filter(\n (el): el is EventStormingShape =>\n isEventStormingShape(el) &&\n el.eventStormingType !== 'drawing' &&\n !excludeIds.has(el.id),\n )\n .map((s) => ({ x: s.x + s.width / 2, y: s.y + s.height / 2 }));\n\n const closest = (value: number, candidates: number[]): number | undefined => {\n let best: number | undefined;\n let bestDist = SNAP_TOLERANCE + 1;\n for (const c of candidates) {\n const dist = Math.abs(c - value);\n if (dist <= SNAP_TOLERANCE && dist < bestDist) {\n best = c;\n bestDist = dist;\n }\n }\n return best;\n };\n\n // Move: snap the SHAPE MIDPOINT (not the cursor) — the user rarely grabs the sticky\n // exactly at its centre.\n eventBus.on(['shape.move.move', 'shape.move.end'], 1500, (event: DragMoveEvent) => {\n if (event.originalEvent?.shiftKey) return;\n if (\n typeof event.x !== 'number' ||\n typeof event.dx !== 'number' ||\n typeof event.y !== 'number' ||\n typeof event.dy !== 'number'\n )\n return;\n const shape = event.context?.shape;\n if (!shape) return;\n const moving = new Set<string>(\n (event.context?.shapes ?? [shape]).map((s) => s.id ?? '').filter(Boolean),\n );\n const centers = candidateCenters(moving);\n const midX = shape.x + shape.width / 2 + event.dx;\n const midY = shape.y + shape.height / 2 + event.dy;\n\n const snapX = closest(\n midX,\n centers.map((c) => c.x),\n );\n if (snapX !== undefined) {\n const d = snapX - midX;\n event.dx += d;\n event.x += d;\n }\n const snapY = closest(\n midY,\n centers.map((c) => c.y),\n );\n if (snapY !== undefined) {\n const d = snapY - midY;\n event.dy += d;\n event.y += d;\n }\n });\n\n // Create (cursor = shape midpoint): snap the cursor to nearby sticky centers.\n eventBus.on(['create.move', 'create.end'], 1500, (event: DragMoveEvent) => {\n if (event.originalEvent?.shiftKey) return;\n const centers = candidateCenters(new Set());\n if (typeof event.x === 'number') {\n const snapX = closest(\n event.x,\n centers.map((c) => c.x),\n );\n if (snapX !== undefined) {\n if (typeof event.dx === 'number') event.dx += snapX - event.x;\n event.x = snapX;\n }\n }\n if (typeof event.y === 'number') {\n const snapY = closest(\n event.y,\n centers.map((c) => c.y),\n );\n if (snapY !== undefined) {\n if (typeof event.dy === 'number') event.dy += snapY - event.y;\n event.y = snapY;\n }\n }\n });\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport ElementSnapping from './ElementSnapping.js';\n\n/** Center-to-center sticky snapping while moving/creating (editor-only). */\nexport const elementSnappingModule: ModuleDeclaration = {\n __init__: ['elementSnapping'],\n elementSnapping: ['type', ElementSnapping],\n};\n\nexport { default as ElementSnapping } from './ElementSnapping.js';\n","import { COLORS, NOTE_STYLE, STICKY_STYLES } from './styles.js';\nimport { STICKY_KINDS } from '../model/di-types.js';\n\n/**\n * Palette icons as a mini preview of the ACTUAL canvas rendering (WYSIWYG) — the same colored\n * rounded squares the EventStormingRenderer draws, so the palette shows what will be created.\n */\n\nconst wrap = (inner: string): string =>\n `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" class=\"event-storming-palette-svg\">${inner}</svg>`;\n\nconst stickySquare = (fill: string, stroke: string, tilt = 0): string =>\n wrap(\n `<rect x=\"4\" y=\"5\" width=\"16\" height=\"14\" fill=\"${fill}\" stroke=\"${stroke}\" stroke-width=\"1.5\"${\n tilt ? ` transform=\"rotate(${tilt} 12 12)\"` : ''\n }/>`,\n );\n\nexport const PALETTE_ICONS: Record<string, string> = {\n // Draw tool: open zigzag polyline with the start point marked.\n draw: wrap(\n `<polyline points=\"3,18 8.5,7 14,14 21,4\" fill=\"none\" stroke=\"${COLORS.ink}\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>` +\n `<circle cx=\"3\" cy=\"18\" r=\"2.2\" fill=\"${COLORS.surface}\" stroke=\"${COLORS.ink}\" stroke-width=\"1.4\"/>`,\n ),\n // Selection tool: dashed lasso rectangle with a cursor arrow.\n lasso: wrap(\n `<rect x=\"3\" y=\"3\" width=\"13\" height=\"13\" rx=\"2\" fill=\"none\" stroke=\"${COLORS.ink}\" stroke-width=\"1.5\" stroke-dasharray=\"3 2.5\"/>` +\n `<path d=\"M13.5 13.5l7 2.7-3 1.3-1.3 3z\" fill=\"${COLORS.ink}\"/>`,\n ),\n note: stickySquare(NOTE_STYLE.fill, NOTE_STYLE.stroke),\n};\n\n// One colored square per sticky kind — the hotspot preview carries the canvas tilt.\nfor (const kind of STICKY_KINDS) {\n const style = STICKY_STYLES[kind];\n PALETTE_ICONS[kind] = stickySquare(style.fill, style.stroke, kind === 'hotspot' ? -6 : 0);\n}\n\n/** Small colored square for the change-type popup menu entries. */\nexport function kindSquare(fill: string, stroke: string): string {\n return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" class=\"event-storming-palette-svg\"><rect x=\"1\" y=\"1\" width=\"12\" height=\"12\" fill=\"${fill}\" stroke=\"${stroke}\" stroke-width=\"1\"/></svg>`;\n}\n","import type Palette from 'diagram-js/lib/features/palette/Palette';\nimport type Create from 'diagram-js/lib/features/create/Create';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type LassoTool from 'diagram-js/lib/features/lasso-tool/LassoTool';\nimport type EventStormingDrawTool from '../draw-tool/EventStormingDrawTool.js';\nimport type {\n PaletteEntries,\n PaletteEntry,\n default as PaletteProvider,\n} from 'diagram-js/lib/features/palette/PaletteProvider';\nimport { LEVEL_STICKY_KINDS } from '@miragon/event-storming-schema-model';\nimport type EventStormingElementFactory from '../model/EventStormingElementFactory.js';\nimport type EventStormingModeling from '../modeling/EventStormingModeling.js';\nimport { ROOT_ID, type EventStormingShapeType } from '../model/di-types.js';\nimport { NOTE_STYLE, STICKY_STYLES } from '../draw/styles.js';\nimport { PALETTE_ICONS } from '../draw/palette-icons.js';\n\ninterface PaletteSpec {\n key: string;\n type: EventStormingShapeType;\n label: string;\n title: string;\n group: string;\n}\n\n// Group IDs with a prefix number -> stable, visible ordering of the palette groups.\nconst GROUP_STICKIES_1 = 'stickies-1';\nconst GROUP_STICKIES_2 = 'stickies-2';\nconst GROUP_STICKIES_3 = 'stickies-3';\n\nconst SPECS: readonly PaletteSpec[] = [\n {\n key: 'event',\n type: 'event',\n label: STICKY_STYLES.event.label,\n title: 'Domain Event — E',\n group: GROUP_STICKIES_1,\n },\n {\n key: 'command',\n type: 'command',\n label: STICKY_STYLES.command.label,\n title: 'Command — C',\n group: GROUP_STICKIES_1,\n },\n {\n key: 'actor',\n type: 'actor',\n label: STICKY_STYLES.actor.label,\n title: 'Actor',\n group: GROUP_STICKIES_1,\n },\n {\n key: 'aggregate',\n type: 'aggregate',\n label: STICKY_STYLES.aggregate.label,\n title: 'Aggregate',\n group: GROUP_STICKIES_1,\n },\n {\n key: 'policy',\n type: 'policy',\n label: STICKY_STYLES.policy.label,\n title: 'Policy',\n group: GROUP_STICKIES_2,\n },\n {\n key: 'readmodel',\n type: 'readmodel',\n label: STICKY_STYLES.readmodel.label,\n title: 'Read Model',\n group: GROUP_STICKIES_2,\n },\n {\n key: 'external',\n type: 'external',\n label: STICKY_STYLES.external.label,\n title: 'External System',\n group: GROUP_STICKIES_2,\n },\n {\n key: 'hotspot',\n type: 'hotspot',\n label: STICKY_STYLES.hotspot.label,\n title: 'Hotspot',\n group: GROUP_STICKIES_3,\n },\n {\n key: 'note',\n type: 'note',\n label: NOTE_STYLE.label,\n title: 'Note',\n group: GROUP_STICKIES_3,\n },\n];\n\nexport default class EventStormingPaletteProvider implements PaletteProvider {\n static $inject = [\n 'palette',\n 'create',\n 'eventStormingElementFactory',\n 'lassoTool',\n 'eventStormingDrawTool',\n 'eventStormingModeling',\n 'eventBus',\n ];\n\n constructor(\n palette: Palette,\n private readonly create: Create,\n private readonly factory: EventStormingElementFactory,\n private readonly lassoTool: LassoTool,\n private readonly drawTool: EventStormingDrawTool,\n private readonly eventStormingModeling: EventStormingModeling,\n eventBus: EventBus,\n ) {\n palette.registerProvider(this);\n\n // The level filters the entries, but diagram-js renders the palette once — re-query the\n // providers whenever the effective level may have changed: a (re)imported board and\n // setLevel incl. its undo/redo (= any updateProperties on the root, where config lives).\n // `_rebuild` is the internal diagram-js refresh; it guards against pre-init calls.\n const rebuild = () => (palette as unknown as { _rebuild(): void })._rebuild();\n eventBus.on('import.done', rebuild);\n eventBus.on(\n [\n 'commandStack.element.updateProperties.postExecuted',\n 'commandStack.element.updateProperties.reverted',\n ],\n (event: { context: { element: { id: string } } }) => {\n if (event.context.element.id === ROOT_ID) rebuild();\n },\n );\n }\n\n getPaletteEntries(): PaletteEntries {\n const entries: Record<string, PaletteEntry> = {};\n\n // Selection tool first. Group MUST be called \"tools\" and the key end in \"-tool\" — that is\n // what diagram-js' palette uses to highlight the active tool (tool-manager.update).\n entries['lasso-tool'] = {\n group: 'tools',\n title: 'Selection tool — L (or Shift+drag)',\n html: `<div class=\"entry event-storming-palette-entry\" title=\"Selection tool — L (or Shift+drag)\">${PALETTE_ICONS.lasso}</div>`,\n action: {\n click: (event: Event) => this.lassoTool.activateSelection(event as MouseEvent),\n },\n };\n\n entries['draw-tool'] = {\n group: 'tools',\n title:\n 'Draw — click point by point, double-click/Enter finishes, click the start point to close',\n html: `<div class=\"entry event-storming-palette-entry\" title=\"Draw — click point by point, double-click/Enter finishes, click the start point to close\">${PALETTE_ICONS.draw}</div>`,\n action: {\n click: () => this.drawTool.toggle(),\n },\n };\n\n // Sticky kinds are filtered by the workshop level; notes are annotations and always stay.\n const allowed = LEVEL_STICKY_KINDS[this.eventStormingModeling.getLevel()];\n for (const spec of SPECS) {\n if (spec.type !== 'note' && !allowed.includes(spec.type)) continue;\n const start = (event: Event) => {\n const shape = this.factory.createNew(spec.type, spec.label);\n this.create.start(event, shape);\n };\n entries[`create.${spec.key}`] = {\n group: spec.group,\n title: spec.title,\n html: `<div class=\"entry event-storming-palette-entry\" draggable=\"true\" title=\"${spec.title}\">${PALETTE_ICONS[spec.key]}</div>`,\n action: { dragstart: start, click: start },\n };\n }\n return entries;\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingPaletteProvider from './EventStormingPaletteProvider.js';\n\n/** Tool palette (drag-to-create). */\nexport const eventStormingPaletteModule: ModuleDeclaration = {\n __init__: ['eventStormingPaletteProvider'],\n eventStormingPaletteProvider: ['type', EventStormingPaletteProvider],\n};\n\nexport { default as EventStormingPaletteProvider } from './EventStormingPaletteProvider.js';\n","import type PopupMenu from 'diagram-js/lib/features/popup-menu/PopupMenu';\nimport type { PopupMenuTarget } from 'diagram-js/lib/features/popup-menu/PopupMenu';\nimport type {\n PopupMenuEntries,\n default as PopupMenuProvider,\n} from 'diagram-js/lib/features/popup-menu/PopupMenuProvider';\nimport { LEVEL_STICKY_KINDS } from '@miragon/event-storming-schema-model';\nimport {\n STICKY_KINDS,\n isSticky,\n type EventStormingShape,\n type StickyKind,\n} from '../model/di-types.js';\nimport { STICKY_STYLES } from '../draw/styles.js';\nimport { kindSquare } from '../draw/palette-icons.js';\nimport type EventStormingModeling from '../modeling/EventStormingModeling.js';\n\nexport const POPUP_PROVIDER_ID = 'event-storming-element-settings';\n\nconst KIND_GROUP = { id: 'kind', name: 'Change type' };\n\nfunction mark(active: boolean, label: string): string {\n return active ? `✓ ${label}` : label;\n}\n\n/**\n * Popup submenu (opened via the context pad) for retyping a sticky among the eight kinds —\n * colored-square icon per kind, checkmark on the current one. All actions go through\n * `eventStormingModeling.setStickyKind` (undo/redo).\n */\nexport default class EventStormingElementSettingsProvider implements PopupMenuProvider {\n static $inject = ['popupMenu', 'eventStormingModeling'];\n\n constructor(\n popupMenu: PopupMenu,\n private readonly modeling: EventStormingModeling,\n ) {\n popupMenu.registerProvider(POPUP_PROVIDER_ID, this);\n }\n\n getPopupMenuEntries(target: PopupMenuTarget): PopupMenuEntries {\n const shape = (Array.isArray(target) ? target[0] : target) as EventStormingShape | undefined;\n if (!isSticky(shape)) return {};\n return this.kindEntries(shape);\n }\n\n private kindEntries(shape: EventStormingShape): PopupMenuEntries {\n const entries: PopupMenuEntries = {};\n // A provisional (blank append) sticky has no current type yet: its placeholder kind must\n // neither show a checkmark nor bypass the level filter.\n const provisional = shape.provisional === true;\n // The workshop level filters the offered kinds; the element's CURRENT kind always shows,\n // so an out-of-level sticky (levels are not validation) still displays its type checked.\n const allowed = LEVEL_STICKY_KINDS[this.modeling.getLevel()];\n for (const kind of STICKY_KINDS) {\n if (!allowed.includes(kind) && (provisional || kind !== shape.eventStormingType)) continue;\n const style = STICKY_STYLES[kind];\n entries[`kind-${kind}`] = {\n label: provisional ? style.label : mark(shape.eventStormingType === kind, style.label),\n imageHtml: kindSquare(style.fill, style.stroke),\n group: KIND_GROUP,\n action: () => this.modeling.setStickyKind(shape, kind as StickyKind),\n };\n }\n return entries;\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingElementSettingsProvider from './EventStormingElementSettingsProvider.js';\n\n/** Popup submenu for retyping a sticky (\"Change type\"). */\nexport const eventStormingPopupModule: ModuleDeclaration = {\n __init__: ['eventStormingElementSettings'],\n eventStormingElementSettings: ['type', EventStormingElementSettingsProvider],\n};\n\nexport {\n default as EventStormingElementSettingsProvider,\n POPUP_PROVIDER_ID,\n} from './EventStormingElementSettingsProvider.js';\n","/**\n * Embedded icon paths from Google Material Icons (Apache-2.0, © Google).\n * 24x24-viewBox paths. `iconMarkup` renders them as an HTML string (palette/context pad/buttons)\n * with `fill: currentColor` (color controllable via CSS).\n * Source: https://github.com/google/material-design-icons (Apache License 2.0).\n */\n\nexport const ICON_PERSON =\n 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z';\nexport const ICON_ARROW_FORWARD = 'M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z';\nexport const ICON_EDIT =\n 'M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z';\nexport const ICON_DELETE =\n 'M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z';\nexport const ICON_UNDO =\n 'M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z';\nexport const ICON_REDO =\n 'M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z';\n/** data_object — JSON. */\nexport const ICON_DATA_OBJECT =\n 'M4 7v2c0 .55-.45 1-1 1H2v2h1c.55 0 1 .45 1 1v2c0 1.65 1.35 3 3 3h1v-2H7c-.55 0-1-.45-1-1v-2c0-.84-.35-1.61-.92-2.18L4.85 12l.23-.82C5.65 10.61 6 9.84 6 9V7c0-.55.45-1 1-1h1V4H7C5.35 4 4 5.35 4 7zm16 3c-.55 0-1-.45-1-1V7c0-1.65-1.35-3-3-3h-1v2h1c.55 0 1 .45 1 1v2c0 .84.35 1.61.92 2.18l.23.82-.23.82c-.57.57-.92 1.34-.92 2.18v2c0 .55-.45 1-1 1h-1v2h1c1.65 0 3-1.35 3-3v-2c0-.55.45-1 1-1h1v-2h-1z';\n/** code — DSL. */\nexport const ICON_CODE =\n 'M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z';\n/** download — Export. */\nexport const ICON_DOWNLOAD = 'M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z';\n/** share — share link. */\nexport const ICON_SHARE =\n 'M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z';\n/** folder_open — open file. */\nexport const ICON_FOLDER_OPEN =\n 'M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z';\n/** image — PNG/image. */\nexport const ICON_IMAGE =\n 'M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z';\n/** note_add — new / clear. */\nexport const ICON_NEW =\n 'M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 14h-3v3h-2v-3H8v-2h3v-3h2v3h3v2zm-3-7V3.5L18.5 9H13z';\n/** palette — sticky color. */\nexport const ICON_PALETTE =\n 'M12 2C6.49 2 2 6.49 2 12s4.49 10 10 10c1.38 0 2.5-1.12 2.5-2.5 0-.61-.23-1.2-.64-1.67-.08-.1-.13-.21-.13-.33 0-.28.22-.5.5-.5H16c3.31 0 6-2.69 6-6 0-4.96-4.49-9-10-9zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 8 6.5 8 8 8.67 8 9.5 7.33 11 6.5 11zm3-4C8.67 7 8 6.33 8 5.5S8.67 4 9.5 4s1.5.67 1.5 1.5S10.33 7 9.5 7zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 4 14.5 4s1.5.67 1.5 1.5S15.33 7 14.5 7zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 8 17.5 8s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z';\n/** swap_horiz — cycle the drawing stroke style. */\nexport const ICON_SWAP_HORIZ =\n 'M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v3H10v2h7.01v3L21 9z';\n/** autorenew — change the sticky kind. */\nexport const ICON_AUTORENEW =\n 'M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z';\n/** menu — hamburger (main menu). */\nexport const ICON_MENU = 'M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z';\n/** add — append sticky. */\nexport const ICON_ADD = 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z';\n/** aspect_ratio — fit the board into the viewport. */\nexport const ICON_FIT =\n 'M19 12h-2v3h-3v2h5v-5zM7 9h3V7H5v5h2V9zm14-6H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z';\n/** remove_red_eye — show example. */\nexport const ICON_EYE =\n 'M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z';\n\n/** Returns an icon as an HTML SVG string (for palette/context pad/buttons), color = currentColor. */\nexport function iconMarkup(path: string, size = 18): string {\n return `<svg viewBox=\"0 0 24 24\" width=\"${size}\" height=\"${size}\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"${path}\"/></svg>`;\n}\n","import type ContextPad from 'diagram-js/lib/features/context-pad/ContextPad';\nimport type Modeling from 'diagram-js/lib/features/modeling/Modeling';\nimport type Connect from 'diagram-js/lib/features/connect/Connect';\nimport type Create from 'diagram-js/lib/features/create/Create';\nimport type PopupMenu from 'diagram-js/lib/features/popup-menu/PopupMenu';\nimport type {\n ContextPadEntries,\n default as ContextPadProvider,\n} from 'diagram-js/lib/features/context-pad/ContextPadProvider';\nimport type { Element } from 'diagram-js/lib/model/Types';\nimport {\n isEventStormingShape,\n isEventStormingConnection,\n isStickyKind,\n type EventStormingShape,\n} from '../model/di-types.js';\nimport type EventStormingModeling from '../modeling/EventStormingModeling.js';\nimport type EventStormingLabelEditing from '../label-editing/EventStormingLabelEditing.js';\nimport type EventStormingElementFactory from '../model/EventStormingElementFactory.js';\nimport type EventStormingColorPicker from '../color-picker/EventStormingColorPicker.js';\nimport { POPUP_PROVIDER_ID } from '../popup/index.js';\nimport {\n iconMarkup,\n ICON_ADD,\n ICON_ARROW_FORWARD,\n ICON_AUTORENEW,\n ICON_DELETE,\n ICON_EDIT,\n ICON_PALETTE,\n ICON_SWAP_HORIZ,\n} from '../draw/icons.js';\n\n/** Title of the single append entry — the kind is chosen in the popup, not in the pad. */\nconst APPEND_TITLE = 'Append sticky (auto-connect, choose the type after placing)';\n\n/**\n * ContextPad entry as HTML with a Material icon. `draggable=true` is mandatory for entries with a\n * `dragstart` action — otherwise diagram-js does not fire the drag.\n */\nfunction cpHtml(icon: string, title: string, draggable = false): string {\n return `<div class=\"entry event-storming-cp-entry\"${draggable ? ' draggable=\"true\"' : ''} title=\"${title}\">${iconMarkup(icon)}</div>`;\n}\n\n/** Context actions per element. */\nexport default class EventStormingContextPadProvider implements ContextPadProvider {\n static $inject = [\n 'contextPad',\n 'modeling',\n 'connect',\n 'create',\n 'popupMenu',\n 'eventStormingModeling',\n 'eventStormingLabelEditing',\n 'eventStormingElementFactory',\n 'eventStormingColorPicker',\n ];\n\n constructor(\n contextPad: ContextPad,\n private readonly modeling: Modeling,\n private readonly connect: Connect,\n private readonly create: Create,\n private readonly popupMenu: PopupMenu,\n private readonly eventStormingModeling: EventStormingModeling,\n private readonly labelEditing: EventStormingLabelEditing,\n private readonly factory: EventStormingElementFactory,\n private readonly colorPicker: EventStormingColorPicker,\n ) {\n contextPad.registerProvider(this);\n }\n\n getContextPadEntries(element: Element): ContextPadEntries {\n // Connections: edit the arrow annotation + delete.\n if (isEventStormingConnection(element)) {\n const conn = element;\n return {\n 'edit-label': {\n group: 'edit',\n title: 'Edit arrow label',\n html: cpHtml(ICON_EDIT, 'Edit arrow label'),\n action: { click: () => this.labelEditing.activateConnection(conn) },\n },\n delete: {\n group: 'edit',\n title: 'Delete connection',\n html: cpHtml(ICON_DELETE, 'Delete connection'),\n action: { click: () => this.modeling.removeElements([element]) },\n },\n };\n }\n if (!isEventStormingShape(element)) return {};\n const shape = element as EventStormingShape;\n const entries: ContextPadEntries = {};\n const kind = shape.eventStormingType;\n\n if (isStickyKind(kind)) {\n // Append: drags out a BLANK sticky and creates the arrow automatically (diagram-js Create\n // with `source` -> modeling.appendShape). The kind is chosen in the change-type popup that\n // opens on placement (see EventStormingAppendBehavior), so ONE entry suffices and it is\n // available on every workshop level — the popup applies the level filter.\n const startAppend = (event: Event) => {\n const next = this.factory.createProvisional();\n this.create.start(event as MouseEvent, next as unknown as Element, {\n source: shape as unknown as Element,\n });\n };\n entries['append'] = {\n group: 'append',\n title: APPEND_TITLE,\n html: cpHtml(ICON_ADD, APPEND_TITLE, true),\n action: { click: startAppend, dragstart: startAppend },\n };\n\n const startConnect = (event: Event) => {\n this.connect.start(event as MouseEvent, shape as unknown as Element);\n };\n entries['connect'] = {\n group: 'edit',\n title: 'Connect to existing sticky',\n html: cpHtml(ICON_ARROW_FORWARD, 'Connect to existing sticky', true),\n action: { click: startConnect, dragstart: startConnect },\n };\n\n entries['change-kind'] = {\n group: 'sticky',\n title: 'Change type',\n html: cpHtml(ICON_AUTORENEW, 'Change type'),\n action: {\n click: (event: Event) => {\n const e = event as MouseEvent;\n this.popupMenu.open(shape as unknown as Element, POPUP_PROVIDER_ID, {\n x: e.clientX,\n y: e.clientY,\n });\n },\n },\n };\n }\n\n // Drawings: cycle the stroke style (solid -> dashed -> dotted).\n if (kind === 'drawing') {\n const next =\n shape.strokeStyle === 'dashed'\n ? 'dotted'\n : shape.strokeStyle === 'dotted'\n ? undefined\n : 'dashed';\n const title = `Line style: ${shape.strokeStyle ?? 'solid'} (click to change)`;\n entries['stroke-style'] = {\n group: 'sticky',\n title,\n html: cpHtml(ICON_SWAP_HORIZ, title),\n action: {\n click: () => this.eventStormingModeling.setStrokeStyle(shape, next),\n },\n };\n }\n\n // Recoloring is offered for DRAWINGS only — stickies and notes carry their notation color\n // (the model-wide `color` override and the DSL `(color ...)` suffix still round-trip, there\n // is just no pad action for them).\n if (kind === 'drawing') {\n entries['color'] = {\n group: 'sticky',\n title: 'Color',\n html: cpHtml(ICON_PALETTE, 'Color'),\n action: {\n click: (event: Event) => {\n const e = event as MouseEvent;\n this.colorPicker.open(shape, e.clientX, e.clientY);\n },\n },\n };\n }\n\n // Drawings have no label (pure geometry).\n if (kind !== 'drawing') {\n entries['edit-label'] = {\n group: 'edit',\n title: 'Edit label',\n html: cpHtml(ICON_EDIT, 'Edit label'),\n action: { click: () => this.labelEditing.activate(shape) },\n };\n }\n\n entries['delete'] = {\n group: 'edit',\n title: 'Delete',\n html: cpHtml(ICON_DELETE, 'Delete'),\n action: { click: () => this.modeling.removeElements([shape as unknown as Element]) },\n };\n\n return entries;\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingContextPadProvider from './EventStormingContextPadProvider.js';\n\n/** Context actions per element. */\nexport const eventStormingContextPadModule: ModuleDeclaration = {\n __init__: ['eventStormingContextPadProvider'],\n eventStormingContextPadProvider: ['type', EventStormingContextPadProvider],\n};\n\nexport { default as EventStormingContextPadProvider } from './EventStormingContextPadProvider.js';\n","import type { NoteAlignHorizontal, NoteAlignVertical } from '@miragon/event-storming-schema-model';\nimport { parseNoteMarkdown, serializeNoteMarkdown } from '../draw/index.js';\nimport { iconMarkup } from '../draw/icons.js';\n\n/**\n * DOM half of the WYSIWYG note editor: the model stores a note label as ONE markdown-subset\n * string (see draw/note-markdown.ts), the contenteditable overlay speaks live DOM. This module\n * translates between the two — markdown→DOM on open, DOM→markdown on commit — and hosts the\n * selection/bullet/toolbar helpers that only exist because of contenteditable quirks.\n */\n\n/** Class on line `<div>`s carrying the `- ` bullet marker (the '•' itself renders via CSS). */\nexport const NOTE_BULLET_CLASS = 'bullet';\n\nexport type NoteToolbarAction =\n 'note-bold' | 'note-italic' | 'note-bullet' | 'note-align-horizontal' | 'note-align-vertical';\n\nexport interface NoteAlignState {\n horizontal: NoteAlignHorizontal;\n vertical: NoteAlignVertical;\n}\n\nexport const HORIZONTAL_CYCLE: readonly NoteAlignHorizontal[] = ['left', 'center', 'right'];\nexport const VERTICAL_CYCLE: readonly NoteAlignVertical[] = ['top', 'middle', 'bottom'];\n\nexport function nextInCycle<T>(cycle: readonly T[], value: T): T {\n return cycle[(cycle.indexOf(value) + 1) % cycle.length]!;\n}\n\n/** One `<div>` per markdown line: `<b>`/`<i>` for the runs, `.bullet` rows for `- ` lines. */\nexport function noteMarkdownToDom(root: HTMLElement, label: string): void {\n const doc = root.ownerDocument;\n root.textContent = '';\n for (const line of parseNoteMarkdown(label)) {\n const div = doc.createElement('div');\n if (line.bullet) div.className = NOTE_BULLET_CLASS;\n for (const run of line.runs) {\n let node: Node = doc.createTextNode(run.text);\n if (run.italic) node = wrapIn(doc, 'i', node);\n if (run.bold) node = wrapIn(doc, 'b', node);\n div.appendChild(node);\n }\n // An empty line div would collapse to zero height — the <br> placeholder keeps it visible\n // and editable (the same trick contenteditable browsers use themselves).\n if (line.runs.length === 0) div.appendChild(doc.createElement('br'));\n root.appendChild(div);\n }\n}\n\nfunction wrapIn(doc: Document, tag: string, node: Node): Node {\n const el = doc.createElement(tag);\n el.appendChild(node);\n return el;\n}\n\ninterface EditorLine {\n bullet: boolean;\n runs: Array<{ text: string; bold: boolean; italic: boolean }>;\n}\n\n/**\n * Reads the contenteditable back into the CANONICAL markdown string (via the pinned\n * note-markdown serializer — never hand-emitted markers). Lenient on input: it understands the\n * DOM this module writes AND the browser-flavored structures `execCommand`/typing produce\n * (strong/em, styled spans, bare first-line text, `<br>` breaks, raw '\\n' from plain-text\n * paste), so a commit never loses text.\n */\nexport function domToNoteMarkdown(root: HTMLElement): string {\n const lines: EditorLine[] = [];\n let current: EditorLine | null = null;\n const open = (bullet: boolean): EditorLine => {\n current = { bullet, runs: [] };\n lines.push(current);\n return current;\n };\n\n const visitInline = (node: Node, bold: boolean, italic: boolean): void => {\n if (node.nodeType === Node.TEXT_NODE) {\n // Plain-text paste can leave raw '\\n' inside one text node (rendered as breaks by\n // `white-space: pre-wrap`) — every segment after a '\\n' is its own line.\n (node.nodeValue ?? '').split('\\n').forEach((segment, i) => {\n if (i > 0) open(false);\n (current ?? open(false)).runs.push({ text: segment, bold, italic });\n });\n return;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n const el = node as HTMLElement;\n if (el.tagName === 'BR') {\n // A trailing <br> is the invisible placeholder browsers keep in lines — only a <br>\n // with content after it is a real line break.\n if (el.nextSibling) open(false);\n return;\n }\n if (isBlockTag(el.tagName)) {\n visitBlock(el);\n return;\n }\n const style = styledAs(el, bold, italic);\n for (const child of el.childNodes) visitInline(child, style.bold, style.italic);\n };\n\n const visitBlock = (el: HTMLElement): void => {\n open(el.classList.contains(NOTE_BULLET_CLASS) || el.tagName === 'LI');\n for (const child of el.childNodes) visitInline(child, false, false);\n // Blocks always break: content after a closed block starts a fresh line.\n current = null;\n };\n\n for (const child of root.childNodes) visitInline(child, false, false);\n return serializeNoteMarkdown(lines);\n}\n\nfunction isBlockTag(tag: string): boolean {\n return tag === 'DIV' || tag === 'P' || tag === 'LI';\n}\n\n/**\n * Effective bold/italic of an element within its inherited context: the semantic tags this\n * module writes (b/i) plus the browser-flavored `execCommand` output (strong/em, spans with\n * inline font-weight/font-style — including the `normal` values Chrome uses to UN-format\n * inside a styled ancestor).\n */\nfunction styledAs(\n el: HTMLElement,\n bold: boolean,\n italic: boolean,\n): { bold: boolean; italic: boolean } {\n const tag = el.tagName;\n if (tag === 'B' || tag === 'STRONG') bold = true;\n if (tag === 'I' || tag === 'EM') italic = true;\n const weight = el.style.fontWeight;\n if (weight) bold = weight === 'bold' || weight === 'bolder' || Number.parseInt(weight, 10) >= 600;\n const slant = el.style.fontStyle;\n if (slant) italic = slant === 'italic' || slant === 'oblique';\n return { bold, italic };\n}\n\n/** Mirrors `field.select()` of the textarea path: the editor opens with everything selected. */\nexport function selectAllContent(el: HTMLElement): void {\n const doc = el.ownerDocument;\n const selection = doc.getSelection();\n if (!selection) return;\n const range = doc.createRange();\n range.selectNodeContents(el);\n selection.removeAllRanges();\n selection.addRange(range);\n}\n\n/**\n * Replaces the current selection with PLAIN text — the paste path: foreign HTML must never\n * enter the DOM the commit reads back. `insertText` (where implemented) keeps the browser's\n * native undo stack; the manual Range fallback covers jsdom.\n */\nexport function insertPlainText(root: HTMLElement, text: string): void {\n const doc = root.ownerDocument;\n if (typeof doc.execCommand === 'function' && doc.execCommand('insertText', false, text)) return;\n const selection = doc.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (!root.contains(range.commonAncestorContainer)) return;\n range.deleteContents();\n const node = doc.createTextNode(text);\n range.insertNode(node);\n range.setStartAfter(node);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n}\n\n/** Line `<div>`s the current selection touches (empty when the selection is elsewhere). */\nexport function selectedLineDivs(root: HTMLElement): HTMLElement[] {\n const selection = root.ownerDocument.getSelection();\n if (!selection || selection.rangeCount === 0) return [];\n const range = selection.getRangeAt(0);\n if (!root.contains(range.commonAncestorContainer)) return [];\n return Array.from(root.children).filter((child) => range.intersectsNode(child)) as HTMLElement[];\n}\n\n/**\n * Toggles the bullet marker on every line the selection touches — mixed selections become\n * all-bullet first, a second click removes them (Miro semantics). Root-level inline content\n * (browsers leave the first line bare) is wrapped into line divs first so there is always an\n * element to mark.\n */\nexport function toggleBulletLines(root: HTMLElement): void {\n ensureLineDivs(root);\n const lines = selectedLineDivs(root);\n if (lines.length === 0) return;\n const allBullets = lines.every((line) => line.classList.contains(NOTE_BULLET_CLASS));\n for (const line of lines) line.classList.toggle(NOTE_BULLET_CLASS, !allBullets);\n}\n\n/** Wraps stray root-level inline nodes into line `<div>`s (selection survives the move). */\nexport function ensureLineDivs(root: HTMLElement): void {\n const doc = root.ownerDocument;\n let wrapper: HTMLElement | null = null;\n for (const node of Array.from(root.childNodes)) {\n if (node.nodeType === Node.ELEMENT_NODE && isBlockTag((node as Element).tagName)) {\n wrapper = null;\n continue;\n }\n if (!wrapper) {\n wrapper = doc.createElement('div');\n root.insertBefore(wrapper, node);\n }\n wrapper.appendChild(node);\n }\n}\n\n/**\n * Alignment icon paths from Google Material Icons (Apache-2.0, © Google) — same source and\n * conventions as draw/icons.ts.\n */\nconst ALIGN_ICONS: Record<'horizontal' | 'vertical', Record<string, string>> = {\n horizontal: {\n left: 'M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z',\n center: 'M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z',\n right: 'M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z',\n },\n vertical: {\n top: 'M8 11h3v10h2V11h3l-4-4-4 4zM4 3v2h16V3H4z',\n middle: 'M8 19h3v4h2v-4h3l-4-4-4 4zm8-14h-3V1h-2v4H8l4 4 4-4zM4 11v2h16v-2H4z',\n bottom: 'M16 13h-3V3h-2v10H8l4 4 4-4zM4 19v2h16v-2H4z',\n },\n};\n\n/**\n * The floating formatting toolbar above the note editor. Buttons are addressed via\n * `data-action`; the two align CYCLE buttons start empty — `updateAlignButton` stamps the icon\n * of the CURRENT value (and re-stamps it after every cycle click).\n */\nexport function createNoteToolbar(\n doc: Document,\n onAction: (action: NoteToolbarAction) => void,\n): HTMLElement {\n const toolbar = doc.createElement('div');\n toolbar.className = 'event-storming-note-toolbar';\n const add = (action: NoteToolbarAction, title: string, html: string): void => {\n const button = doc.createElement('button');\n button.type = 'button';\n button.setAttribute('data-action', action);\n button.title = title;\n button.innerHTML = html;\n // Keep the editor's focus/selection: formatting applies to the CURRENT selection, and a\n // focus loss would commit-close the editor before the click even lands.\n button.addEventListener('mousedown', (e) => e.preventDefault());\n button.addEventListener('click', () => onAction(action));\n toolbar.appendChild(button);\n };\n add('note-bold', 'Bold (Cmd/Ctrl+B)', '<b>B</b>');\n add('note-italic', 'Italic (Cmd/Ctrl+I)', '<i>I</i>');\n add('note-bullet', 'Bullet list', '•');\n const separator = doc.createElement('span');\n separator.className = 'event-storming-note-toolbar-separator';\n toolbar.appendChild(separator);\n add('note-align-horizontal', 'Horizontal alignment (click to cycle)', '');\n add('note-align-vertical', 'Vertical alignment (click to cycle)', '');\n return toolbar;\n}\n\n/** Stamps a cycle button with the icon/tooltip of the CURRENT alignment value. */\nexport function updateAlignButton(\n button: HTMLElement,\n axis: 'horizontal' | 'vertical',\n value: NoteAlignHorizontal | NoteAlignVertical,\n): void {\n button.innerHTML = iconMarkup(ALIGN_ICONS[axis][value] ?? '', 16);\n button.title =\n axis === 'horizontal'\n ? `Horizontal alignment: ${value} (click to cycle)`\n : `Vertical alignment: ${value} (click to cycle)`;\n}\n\n/** Live preview of the note alignment on the contenteditable (flex column mirrors the canvas). */\nexport function applyAlignPreview(editor: HTMLElement, align: NoteAlignState): void {\n editor.style.textAlign = align.horizontal;\n editor.style.justifyContent =\n align.vertical === 'top' ? 'flex-start' : align.vertical === 'middle' ? 'center' : 'flex-end';\n}\n","import type Canvas from 'diagram-js/lib/core/Canvas';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport {\n isEventStormingConnection,\n isEventStormingShape,\n type EventStormingConnection,\n type EventStormingShape,\n} from '../model/di-types.js';\nimport type EventStormingModeling from '../modeling/EventStormingModeling.js';\nimport { isManualNoteBox, noteMetrics } from '../draw/styles.js';\nimport {\n NOTE_BULLET_CLASS,\n HORIZONTAL_CYCLE,\n VERTICAL_CYCLE,\n applyAlignPreview,\n createNoteToolbar,\n domToNoteMarkdown,\n insertPlainText,\n nextInCycle,\n noteMarkdownToDom,\n selectAllContent,\n selectedLineDivs,\n toggleBulletLines,\n updateAlignButton,\n type NoteAlignState,\n type NoteToolbarAction,\n} from './note-editor-dom.js';\n\ninterface ActiveEdit {\n field: HTMLElement;\n /** Saves the current value and closes (for Enter, blur, click outside). */\n commit: () => void;\n /** Discards and closes (only for Escape). */\n cleanup: () => void;\n}\n\n/**\n * Defuses DSL metacharacters in labels: in the `.storm` DSL, names double as references —\n * `->`, `;`, square brackets and comment starters would corrupt arrow/coordinate lines on\n * re-import. The comment defusing mirrors the DSL serializer's `escapeText` exactly (division\n * slash U+2215, `://` URLs exempt), so what the user sees on canvas is byte-identical to what a\n * save/reload produces. Newlines stay: the DSL escapes them (`\\n`) for stickies and notes alike.\n */\nexport function sanitizeLabel(raw: string): string {\n return raw\n .replace(/(?<!:)\\/\\//g, '∕∕') // // starts a line comment (URL `://` stays intact)\n .replace(/\\/\\*/g, '∕*') // /* starts a block comment\n .replace(/->/g, '→') // -> would be the arrow operator\n .replace(/;/g, ',') // ; separates arrow annotations\n .replace(/\\[/g, '(') // [..] would be a coordinate tuple\n .replace(/\\]/g, ')')\n .trim();\n}\n\n/**\n * Custom inline label editing as an HTML overlay (deliberately not diagram-js direct-editing).\n * Commit goes through `eventStormingModeling` -> commandStack (undo). Sticky text is\n * multi-line, so stickies are edited in a `<textarea>` (Enter = line break, Cmd/Ctrl+Enter or\n * click outside = save); connection labels use a single-line `<input>` (Enter = save). NOTES\n * get the WYSIWYG contenteditable overlay instead (see `activateNote`) — same commit/cancel\n * semantics, plus live bold/italic/bullet formatting and the floating alignment toolbar.\n */\nexport default class EventStormingLabelEditing {\n static $inject = ['eventBus', 'canvas', 'eventStormingModeling'];\n\n private active: ActiveEdit | null = null;\n\n constructor(\n eventBus: EventBus,\n private readonly canvas: Canvas,\n private readonly modeling: EventStormingModeling,\n ) {\n eventBus.on('element.dblclick', (event: { element?: unknown }) => {\n if (isEventStormingShape(event.element)) this.activate(event.element);\n else if (isEventStormingConnection(event.element)) this.activateConnection(event.element);\n });\n // Click/drag/pan outside the field = SAVE (not discard). Only Escape discards.\n eventBus.on(['element.mousedown', 'drag.init', 'canvas.viewbox.changing'], () =>\n this.active?.commit(),\n );\n }\n\n activate(element: EventStormingShape): void {\n this.active?.commit();\n if (element.eventStormingType === 'drawing') return; // pure geometry, no label\n if (element.eventStormingType === 'note') {\n this.activateNote(element);\n return;\n }\n\n const container = this.canvas.getContainer();\n const scale = this.canvas.zoom();\n const vb = this.canvas.viewbox();\n // Overlay the editor centered ON the sticky (the text lives inside it — WYSIWYG); this also\n // keeps the field visible for stickies at the viewport edge.\n const left = (element.x + element.width / 2 - vb.x) * scale;\n const top = (element.y + element.height / 2 - vb.y) * scale;\n\n const field = document.createElement('textarea');\n field.className = 'event-storming-label-input event-storming-label-textarea';\n field.value = element.eventStormingLabel ?? '';\n field.rows = Math.max(2, field.value.split('\\n').length);\n field.wrap = 'off';\n field.style.position = 'absolute';\n field.style.left = `${left}px`;\n field.style.top = `${top}px`;\n field.style.transform = 'translate(-50%, -50%)';\n field.style.width = `${element.width * scale}px`;\n container.appendChild(field);\n field.focus();\n field.select();\n\n let done = false;\n const cleanup = () => {\n if (done) return;\n done = true;\n field.removeEventListener('keydown', onKey as EventListener);\n field.removeEventListener('blur', onBlur);\n field.remove();\n this.active = null;\n };\n const commit = () => {\n if (done) return;\n // Enforce metacharacter protection also on RENAME — the DSL references elements by their\n // name; unescaped `->`, `;` or brackets would corrupt arrow/coordinate lines on re-import.\n const value = sanitizeLabel(field.value);\n const changed = value && value !== element.eventStormingLabel;\n cleanup();\n if (!changed) return;\n // Renaming to an EXISTING label is allowed — duplicate labels are legal, the DSL\n // disambiguates via `(id …)` suffixes and `#id` references.\n this.modeling.updateLabel(element, value);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n cleanup();\n return;\n }\n if (e.key === 'Enter') {\n // Save only with Cmd/Ctrl -> plain Enter inserts a line break (sticky text is multi-line).\n if (!(e.metaKey || e.ctrlKey)) return;\n e.preventDefault();\n commit();\n }\n };\n const onBlur = () => commit();\n field.addEventListener('keydown', onKey as EventListener);\n field.addEventListener('blur', onBlur);\n\n this.active = { field, commit, cleanup };\n }\n\n /**\n * WYSIWYG editing for notes: a contenteditable overlay rendering the markdown subset live\n * (bold/italic/bullets) plus the floating format/alignment toolbar. Commit/cancel semantics\n * are identical to the textarea path (click outside / Cmd-Ctrl+Enter save, Escape discards,\n * plain Enter breaks the line); the committed value is the canonical markdown string run\n * through the same `sanitizeLabel`, and label + alignment land in ONE updateProperties.\n */\n private activateNote(element: EventStormingShape): void {\n const container = this.canvas.getContainer();\n const scale = this.canvas.zoom();\n const vb = this.canvas.viewbox();\n const left = (element.x + element.width / 2 - vb.x) * scale;\n const top = (element.y + element.height / 2 - vb.y) * scale;\n\n const editor = document.createElement('div');\n editor.className = 'event-storming-label-input event-storming-note-editor';\n editor.contentEditable = 'true';\n editor.style.position = 'absolute';\n editor.style.left = `${left}px`;\n editor.style.top = `${top}px`;\n editor.style.transform = 'translate(-50%, -50%)';\n // min- (not fixed) box: the editor covers the note's footprint but grows with new lines.\n editor.style.minWidth = `${element.width * scale}px`;\n editor.style.minHeight = `${element.height * scale}px`;\n noteMarkdownToDom(editor, element.eventStormingLabel ?? '');\n\n const align: NoteAlignState = {\n horizontal: element.alignHorizontal ?? 'left',\n vertical: element.alignVertical ?? 'top',\n };\n applyAlignPreview(editor, align);\n\n const toolbar = createNoteToolbar(document, (action) => onAction(action));\n // Floats just above the note's top edge, x-centered like the editor.\n toolbar.style.left = `${left}px`;\n toolbar.style.top = `${(element.y - vb.y) * scale - 8}px`;\n toolbar.style.transform = 'translate(-50%, -100%)';\n\n container.appendChild(editor);\n container.appendChild(toolbar);\n editor.focus();\n selectAllContent(editor);\n\n const buttonOf = (action: NoteToolbarAction) =>\n toolbar.querySelector<HTMLElement>(`[data-action=\"${action}\"]`);\n const setActive = (action: NoteToolbarAction, on: boolean) => {\n const button = buttonOf(action);\n button?.classList.toggle('active', on);\n button?.setAttribute('aria-pressed', String(on));\n };\n const refreshToolbar = () => {\n setActive('note-bold', queryCommandState('bold'));\n setActive('note-italic', queryCommandState('italic'));\n const lines = selectedLineDivs(editor);\n setActive(\n 'note-bullet',\n lines.length > 0 && lines.every((line) => line.classList.contains(NOTE_BULLET_CLASS)),\n );\n const horizontal = buttonOf('note-align-horizontal');\n if (horizontal) updateAlignButton(horizontal, 'horizontal', align.horizontal);\n const vertical = buttonOf('note-align-vertical');\n if (vertical) updateAlignButton(vertical, 'vertical', align.vertical);\n };\n const exec = (command: 'bold' | 'italic') => {\n // Deprecated but still the only dependency-free selection-formatting primitive for\n // contenteditable; absent in jsdom, hence the guard.\n if (typeof document.execCommand === 'function') document.execCommand(command, false);\n refreshToolbar();\n };\n const cycle = (axis: 'horizontal' | 'vertical') => {\n if (axis === 'horizontal') align.horizontal = nextInCycle(HORIZONTAL_CYCLE, align.horizontal);\n else align.vertical = nextInCycle(VERTICAL_CYCLE, align.vertical);\n applyAlignPreview(editor, align);\n refreshToolbar();\n };\n const onAction = (action: NoteToolbarAction) => {\n if (action === 'note-bold') exec('bold');\n else if (action === 'note-italic') exec('italic');\n else if (action === 'note-bullet') {\n toggleBulletLines(editor);\n refreshToolbar();\n } else cycle(action === 'note-align-horizontal' ? 'horizontal' : 'vertical');\n };\n // Bold/italic active states follow the caret, not just toolbar clicks.\n const onSelectionChange = () => refreshToolbar();\n document.addEventListener('selectionchange', onSelectionChange);\n\n let done = false;\n const cleanup = () => {\n if (done) return;\n done = true;\n document.removeEventListener('selectionchange', onSelectionChange);\n editor.removeEventListener('keydown', onKey as EventListener);\n editor.removeEventListener('blur', onBlur as EventListener);\n editor.removeEventListener('paste', onPaste as EventListener);\n editor.remove();\n toolbar.remove();\n this.active = null;\n };\n const commit = () => {\n if (done) return;\n // Same metacharacter defusing as the textarea path, applied to the COMMITTED markdown.\n const value = sanitizeLabel(domToNoteMarkdown(editor));\n const properties = noteCommitProperties(element, value, align);\n cleanup();\n if (properties) this.modeling.updateProperties(element, properties);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n cleanup();\n return;\n }\n if (e.key === 'Enter') {\n // Save only with Cmd/Ctrl -> plain Enter inserts a line break (notes are multi-line).\n if (!(e.metaKey || e.ctrlKey)) return;\n e.preventDefault();\n commit();\n return;\n }\n const key = e.key.toLowerCase();\n if ((e.metaKey || e.ctrlKey) && (key === 'b' || key === 'i')) {\n e.preventDefault();\n exec(key === 'b' ? 'bold' : 'italic');\n }\n };\n const onBlur = (e: FocusEvent) => {\n // Focus moving INTO the toolbar is not \"outside\" (its mousedown is prevented, but be\n // safe for keyboard focus and engines that blur anyway).\n if (e.relatedTarget instanceof Node && toolbar.contains(e.relatedTarget)) return;\n commit();\n };\n const onPaste = (e: ClipboardEvent) => {\n // PLAIN text only — foreign HTML must never enter the DOM the commit reads back.\n e.preventDefault();\n const text = e.clipboardData?.getData('text/plain') ?? '';\n if (text) insertPlainText(editor, text);\n };\n editor.addEventListener('keydown', onKey as EventListener);\n editor.addEventListener('blur', onBlur as EventListener);\n editor.addEventListener('paste', onPaste as EventListener);\n\n refreshToolbar();\n this.active = { field: editor, commit, cleanup };\n }\n\n /**\n * Inline editing for connections: the arrow's `; annotation` text. An empty input clears the\n * field. Undo-safe via updateProperties.\n */\n activateConnection(conn: EventStormingConnection): void {\n this.active?.commit();\n\n const container = this.canvas.getContainer();\n const scale = this.canvas.zoom();\n const vb = this.canvas.viewbox();\n const first = conn.waypoints[0];\n const last = conn.waypoints[conn.waypoints.length - 1];\n if (!first || !last) return;\n\n const field = document.createElement('input');\n field.type = 'text';\n field.className = 'event-storming-label-input';\n field.placeholder = 'arrow label';\n field.value = conn.linkLabel ?? '';\n field.style.position = 'absolute';\n field.style.left = `${((first.x + last.x) / 2 - 60 - vb.x) * scale}px`;\n field.style.top = `${((first.y + last.y) / 2 - 26 - vb.y) * scale}px`;\n container.appendChild(field);\n field.focus();\n field.select();\n\n let done = false;\n const cleanup = () => {\n if (done) return;\n done = true;\n field.removeEventListener('keydown', onKey as EventListener);\n field.removeEventListener('blur', onBlur);\n field.remove();\n this.active = null;\n };\n const commit = () => {\n if (done) return;\n // Same metacharacter protection as sticky labels: an unescaped `[..]` tuple in the\n // serialized arrow line would be misread as a declaration, silently losing the edge.\n const value = sanitizeLabel(field.value);\n const current = conn.linkLabel ?? '';\n cleanup();\n if (value === current) return;\n this.modeling.updateProperties(conn, { linkLabel: value || undefined });\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n cleanup();\n } else if (e.key === 'Enter') {\n e.preventDefault();\n commit();\n }\n };\n const onBlur = () => commit();\n field.addEventListener('keydown', onKey as EventListener);\n field.addEventListener('blur', onBlur);\n\n this.active = { field, commit, cleanup };\n }\n\n cancel(): void {\n this.active?.cleanup();\n }\n}\n\n/**\n * Everything a note commit changes, as ONE updateProperties payload — label, (for auto-sized\n * boxes) the recentered metrics box, and the align DI props: a single command, a single undo\n * step. Returns null when nothing changed. The auto-resize mirrors\n * `EventStormingModeling.updateLabel`'s manual-vs-auto rule; it is inlined here because the\n * alignment must land in the SAME command as the label.\n */\nfunction noteCommitProperties(\n element: EventStormingShape,\n value: string,\n align: NoteAlignState,\n): Record<string, unknown> | null {\n const labelChanged = !!value && value !== element.eventStormingLabel;\n const alignChanged =\n align.horizontal !== (element.alignHorizontal ?? 'left') ||\n align.vertical !== (element.alignVertical ?? 'top');\n if (!labelChanged && !alignChanged) return null;\n const properties: Record<string, unknown> = {};\n if (labelChanged) {\n properties.eventStormingLabel = value;\n if (!isManualNoteBox(element.eventStormingLabel, element)) {\n const { width, height } = noteMetrics(value);\n properties.width = width;\n properties.height = height;\n properties.x = element.x + element.width / 2 - width / 2;\n properties.y = element.y + element.height / 2 - height / 2;\n }\n }\n if (alignChanged) {\n // Default axes collapse to ABSENT DI props (undefined deletes) — the exporter/factory\n // contract that keeps unaligned boards serializing byte-identically.\n properties.alignHorizontal = align.horizontal === 'left' ? undefined : align.horizontal;\n properties.alignVertical = align.vertical === 'top' ? undefined : align.vertical;\n }\n return properties;\n}\n\n/** Bold/italic state at the caret — absent in jsdom (the button simply never shows active). */\nfunction queryCommandState(command: string): boolean {\n if (typeof document.queryCommandState !== 'function') return false;\n try {\n return document.queryCommandState(command);\n } catch {\n return false;\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingLabelEditing from './EventStormingLabelEditing.js';\n\n/** Custom inline label editing (HTML overlay). */\nexport const labelEditingModule: ModuleDeclaration = {\n __init__: ['eventStormingLabelEditing'],\n eventStormingLabelEditing: ['type', EventStormingLabelEditing],\n};\n\nexport { default as EventStormingLabelEditing } from './EventStormingLabelEditing.js';\nexport {\n noteMarkdownToDom,\n domToNoteMarkdown,\n createNoteToolbar,\n updateAlignButton,\n applyAlignPreview,\n toggleBulletLines,\n insertPlainText,\n NOTE_BULLET_CLASS,\n} from './note-editor-dom.js';\nexport type { NoteToolbarAction, NoteAlignState } from './note-editor-dom.js';\n","import type Canvas from 'diagram-js/lib/core/Canvas';\nimport type CommandStack from 'diagram-js/lib/command/CommandStack';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type Create from 'diagram-js/lib/features/create/Create';\nimport type LassoTool from 'diagram-js/lib/features/lasso-tool/LassoTool';\nimport type Mouse from 'diagram-js/lib/features/mouse/Mouse';\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 type EventStormingCopyPaste from '../modeling/EventStormingCopyPaste.js';\nimport type EventStormingElementFactory from '../model/EventStormingElementFactory.js';\nimport { STICKY_STYLES } from '../draw/styles.js';\n\n/** Arrow-key nudge in diagram px (Shift = coarse). */\nconst NUDGE_STEP = 2;\nconst NUDGE_STEP_COARSE = 10;\n\nconst ARROW_DELTAS: Record<string, { x: number; y: number }> = {\n arrowleft: { x: -1, y: 0 },\n arrowright: { x: 1, y: 0 },\n arrowup: { x: 0, y: -1 },\n arrowdown: { x: 0, y: 1 },\n};\n\n/**\n * Minimal keyboard binding on the canvas container: undo/redo, delete, copy/paste/duplicate,\n * arrow-key nudge of the selection, plus the single-key tools E (domain event), C (command) and\n * L (lasso). Deliberately a DOM listener (no diagram-js keyboard-service binding needed).\n */\nexport default class EventStormingKeyboard {\n static $inject = [\n 'canvas',\n 'commandStack',\n 'selection',\n 'modeling',\n 'eventStormingCopyPaste',\n 'eventStormingElementFactory',\n 'create',\n 'mouse',\n 'lassoTool',\n 'eventBus',\n ];\n\n constructor(\n canvas: Canvas,\n commandStack: CommandStack,\n selection: Selection,\n modeling: Modeling,\n copyPaste: EventStormingCopyPaste,\n factory: EventStormingElementFactory,\n create: Create,\n mouse: Mouse,\n lassoTool: LassoTool,\n eventBus: EventBus,\n ) {\n const container = canvas.getContainer();\n if (!container.hasAttribute('tabindex')) container.setAttribute('tabindex', '0');\n\n // Bind on the DOCUMENT (not the canvas container): single-key tools (E/C/L) must work\n // without the canvas having focus first — same trade-off bpmn-js makes for its keyboard.\n const onKeydown = (e: KeyboardEvent) => {\n // If the user is currently typing in an input field, do NOT intercept: inline label editing\n // (EventStormingLabelEditing) attaches its <textarea> to the canvas container, and the\n // web-app chrome has its own fields. Without the guard, Backspace/Delete would delete the\n // selected element (instead of a character) and Cmd+Z would reset the diagram.\n if (isEditableTarget(e.target)) return;\n\n const cmd = e.ctrlKey || e.metaKey;\n const key = e.key.toLowerCase();\n\n if (cmd && key === 'z' && !e.shiftKey) {\n e.preventDefault();\n commandStack.undo();\n } else if ((cmd && key === 'z' && e.shiftKey) || (cmd && key === 'y')) {\n e.preventDefault();\n commandStack.redo();\n } else if (cmd && key === 'c') {\n if (copyPaste.copy()) e.preventDefault();\n } else if (cmd && key === 'v') {\n if (copyPaste.paste()) e.preventDefault();\n } else if (cmd && key === 'd') {\n e.preventDefault();\n copyPaste.duplicate();\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 } else if (!cmd && !e.altKey && (key === 'e' || key === 'c')) {\n // Quick create: the new sticky attaches to the cursor (like palette create).\n const lastMove = mouse.getLastMoveEvent();\n if (lastMove) {\n e.preventDefault();\n const shape =\n key === 'e'\n ? factory.createNew('event', STICKY_STYLES.event.label)\n : factory.createNew('command', STICKY_STYLES.command.label);\n create.start(lastMove, shape as unknown as Element);\n }\n } else if (!cmd && !e.altKey && key === 'l') {\n e.preventDefault();\n const lastMove = mouse.getLastMoveEvent();\n lassoTool.activateSelection((lastMove ?? e) as MouseEvent, !!lastMove);\n } else if (key in ARROW_DELTAS && !cmd) {\n const sel = selection.get() as Element[];\n if (sel.length) {\n e.preventDefault();\n const step = e.shiftKey ? NUDGE_STEP_COARSE : NUDGE_STEP;\n const d = ARROW_DELTAS[key]!;\n modeling.moveElements(sel, { x: d.x * step, y: d.y * step });\n }\n }\n };\n\n document.addEventListener('keydown', onKeydown);\n eventBus.on('diagram.destroy', () => document.removeEventListener('keydown', onKeydown));\n }\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable;\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingKeyboard from './EventStormingKeyboard.js';\n\n/** Undo/redo/delete via keyboard on the canvas container. */\nexport const eventStormingKeyboardModule: ModuleDeclaration = {\n __init__: ['eventStormingKeyboard'],\n eventStormingKeyboard: ['type', EventStormingKeyboard],\n};\n\nexport { default as EventStormingKeyboard } from './EventStormingKeyboard.js';\n","import type EventBus from 'diagram-js/lib/core/EventBus';\nimport type { Injector } from 'didi';\nimport { POPUP_PROVIDER_ID } from '../popup/index.js';\n\ninterface ConnectionPreviewLike {\n drawPreview(context: object, canConnect: unknown, hints: object): void;\n cleanUp(context: object): void;\n}\n\ninterface LabelEditingLike {\n activate(element: object): void;\n}\n\ninterface PopupMenuLike {\n open(target: object, providerId: string, position: { x: number; y: number }): void;\n isOpen(): boolean;\n}\n\ninterface ModelingLike {\n removeElements(elements: object[]): void;\n}\n\ninterface CanvasLike {\n getAbsoluteBBox(element: object): { x: number; y: number; width: number; height: number };\n getContainer(): HTMLElement;\n}\n\ninterface SourceShape {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface CreatedShape {\n /** Blank append sticky awaiting its kind — see EventStormingElementFactory.createProvisional. */\n provisional?: boolean;\n /** Unset again once the shape leaves the canvas (e.g. undo of the create). */\n parent?: object | null;\n}\n\ninterface CreateEvent {\n x: number;\n y: number;\n context: {\n source?: SourceShape;\n shape?: CreatedShape;\n canExecute?: { connect?: unknown } | false | null;\n };\n}\n\n// diagram-js runs listeners in descending priority order; the default create.end handler (creation)\n// sits at 1000 -> with < 1000 we run AFTERWARDS, once the shape already exists.\nconst AFTER_CREATE = 500;\n\n/** Gap (px) between the placed sticky's bottom edge and the kind-chooser popup. */\nconst CHOOSER_GAP = 6;\n\n/**\n * Behavior for \"append sticky\" (`create.start` with `context.source`):\n * 1. LIVE arrow preview from the source to the cursor (analogous to diagram-js ConnectPreview,\n * but in the create flow) — requires the `connectionPreview` service (ConnectionPreviewModule).\n * 2. After creation of the provisional (blank) sticky, opens the change-type popup on it so the\n * user picks the kind first; the retype then hands over to the label editor (step 2 of the\n * chain). Dismissing the popup without choosing removes the blank sticky (and thereby its\n * auto-arrow) again.\n * Both only when `context.source` is set; ordinary palette-create stays untouched.\n */\nexport default class EventStormingAppendBehavior {\n static $inject = ['injector', 'eventBus'];\n\n constructor(injector: Injector, eventBus: EventBus) {\n const connectionPreview = injector.get(\n 'connectionPreview',\n false,\n ) as ConnectionPreviewLike | null;\n const labelEditing = injector.get(\n 'eventStormingLabelEditing',\n false,\n ) as LabelEditingLike | null;\n const popupMenu = injector.get('popupMenu', false) as PopupMenuLike | null;\n const modeling = injector.get('modeling', false) as ModelingLike | null;\n const canvas = injector.get('canvas', false) as CanvasLike | null;\n\n // The chain steps run deferred (setTimeout) — after a teardown they must become no-ops\n // instead of executing commands on a destroyed diagram.\n let destroyed = false;\n eventBus.on('diagram.destroy', () => {\n destroyed = true;\n });\n\n // (1) arrow preview\n if (connectionPreview) {\n eventBus.on('create.move', (event: CreateEvent) => {\n const { context } = event;\n const source = context.source;\n if (!source) return;\n const canConnect =\n context.canExecute && (context.canExecute as { connect?: unknown }).connect;\n connectionPreview.drawPreview(context, canConnect ?? false, {\n source,\n connectionStart: { x: source.x + source.width / 2, y: source.y + source.height / 2 },\n connectionEnd: { x: event.x, y: event.y },\n });\n });\n\n eventBus.on(\n ['create.end', 'create.cancel', 'create.cleanup'],\n (event: { context: object }) => {\n connectionPreview.cleanUp(event.context);\n },\n );\n }\n\n /**\n * Kind chooser on the freshly placed blank sticky. Choose vs dismiss is decided AT close\n * time: picking a kind runs the retype action — which clears `provisional` and auto-closes\n * the popup via `commandStack.changed` — BEFORE the close event, so a shape still\n * provisional on close means nothing was chosen.\n */\n const openKindChooser = (shape: CreatedShape) => {\n if (destroyed || !shape.parent || !popupMenu || !modeling || !canvas) return;\n // Anchor right below the placed sticky (client coords — the popup is position: fixed).\n const bbox = canvas.getAbsoluteBBox(shape);\n const container = canvas.getContainer().getBoundingClientRect();\n popupMenu.open(shape, POPUP_PROVIDER_ID, {\n x: container.left + bbox.x,\n y: container.top + bbox.y + bbox.height + CHOOSER_GAP,\n });\n if (!popupMenu.isOpen()) {\n // No chooser came up (e.g. a vetoed open): a blank sticky without one is unusable.\n modeling.removeElements([shape]);\n return;\n }\n eventBus.once('popupMenu.close', () => {\n // Deferred: the close event fires INSIDE PopupMenu.close() — executing a command here\n // would re-enter close() via its auto-close binding, and the label editor would lose\n // focus to the popup teardown's focus restore.\n setTimeout(() => {\n if (destroyed) return;\n if (shape.provisional) {\n // Dismissed without choosing: the blank sticky goes away, its auto-arrow with it —\n // unless something else (e.g. undo of the create) already removed it.\n if (shape.parent) modeling.removeElements([shape]);\n return;\n }\n labelEditing?.activate(shape);\n }, 0);\n });\n };\n\n // (2) post-placement chain: provisional stickies get the kind chooser first (label editing\n // follows the retype); a non-provisional append opens the label editor directly.\n eventBus.on('create.end', AFTER_CREATE, (event: CreateEvent) => {\n const { context } = event;\n if (!context.source || !context.canExecute || !context.shape) return;\n const shape = context.shape;\n if (shape.provisional && popupMenu && modeling && canvas) {\n // Open only after render/cleanup — like the label edit below, plus the create's own\n // commandStack.changed would auto-close a popup opened synchronously.\n const original = (event as { originalEvent?: Event }).originalEvent;\n if (original?.type === 'mousedown') {\n // Click-to-place: the create ends on MOUSEDOWN, so the gesture's trailing click is\n // still pending — it would hit the freshly opened popup as an outside click and\n // dismiss it (removing the blank sticky right away). Open after that click passed;\n // the timeout covers gestures whose click never fires (e.g. mouseup off-window).\n const openAfterClick = () => {\n document.removeEventListener('click', openAfterClick, true);\n clearTimeout(fallback);\n setTimeout(() => openKindChooser(shape), 0);\n };\n document.addEventListener('click', openAfterClick, true);\n const fallback = setTimeout(openAfterClick, 300);\n return;\n }\n setTimeout(() => openKindChooser(shape), 0);\n return;\n }\n if (!labelEditing) return;\n // Activate only after render/cleanup so the editor is positioned correctly.\n setTimeout(() => labelEditing.activate(shape), 0);\n });\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport ConnectionPreviewModule from 'diagram-js/lib/features/connection-preview';\nimport EventStormingAppendBehavior from './EventStormingAppendBehavior.js';\n\n/**\n * \"Append sticky\": pulls in the `connectionPreview` service (thereby also enabling the connect\n * tool's arrow preview) and registers the append behavior (live arrow preview + automatically\n * opening the label editor after creation).\n */\nexport const eventStormingAppendModule: ModuleDeclaration = {\n __depends__: [ConnectionPreviewModule],\n __init__: ['eventStormingAppendBehavior'],\n eventStormingAppendBehavior: ['type', EventStormingAppendBehavior],\n};\n\nexport { default as EventStormingAppendBehavior } from './EventStormingAppendBehavior.js';\n","import type Canvas from 'diagram-js/lib/core/Canvas';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type EventStormingModeling from '../modeling/EventStormingModeling.js';\nimport { STICKY_KINDS, type EventStormingShape } from '../model/di-types.js';\nimport { STICKY_STYLES } from '../draw/styles.js';\n\n/** The 8 swatches = the 8 sticky fills (recolor any element into another kind's tone). */\nconst SWATCHES: ReadonlyArray<{ value: string; title: string }> = STICKY_KINDS.map((kind) => ({\n value: STICKY_STYLES[kind].fill,\n title: STICKY_STYLES[kind].label,\n}));\n\n/**\n * Compact color picker (bpmn.io-style): a 3x3 grid of small color squares (no text), opened from\n * an element's context pad. Uses its own popover (instead of diagram-js PopupMenu) so the swatch\n * grid can be rendered exactly and without text. Sets the color override via\n * `eventStormingModeling` (undo/redo). First cell = \"no color\" (back to the kind's default).\n */\nexport default class EventStormingColorPicker {\n static $inject = ['canvas', 'eventBus', 'eventStormingModeling'];\n\n private popover: HTMLElement | undefined;\n\n private readonly onDocPointer = (e: MouseEvent): void => {\n if (this.popover && !this.popover.contains(e.target as Node)) this.close();\n };\n private readonly onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') this.close();\n };\n\n constructor(\n private readonly canvas: Canvas,\n eventBus: EventBus,\n private readonly modeling: EventStormingModeling,\n ) {\n // Close on pan/zoom, drag or re-import (otherwise the popover ends up misplaced).\n eventBus.on(['canvas.viewbox.changing', 'drag.init', 'diagram.clear'], () => this.close());\n }\n\n /** Opens the swatch grid for `shape` at the click position (viewport coordinates). */\n open(shape: EventStormingShape, clientX: number, clientY: number): void {\n this.close();\n const container = this.canvas.getContainer();\n const rect = container.getBoundingClientRect();\n\n const pop = document.createElement('div');\n pop.className = 'event-storming-color-picker';\n\n const swatches: ReadonlyArray<{ value: string | undefined; title: string; cls: string }> = [\n { value: undefined, title: 'No color', cls: 'event-storming-cp-none' },\n ...SWATCHES.map((c) => ({ value: c.value as string, title: c.title, cls: '' })),\n ];\n for (const s of swatches) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = `event-storming-cp-swatch ${s.cls}`.trim();\n btn.title = s.title;\n if (s.value) btn.style.background = s.value;\n if ((shape.color ?? undefined) === s.value) btn.classList.add('event-storming-cp-active');\n btn.addEventListener('click', (ev) => {\n ev.stopPropagation();\n this.modeling.setColor(shape, s.value);\n this.close();\n });\n pop.append(btn);\n }\n\n container.appendChild(pop);\n\n // Keep it within the (overflow:hidden) container.\n const cw = container.clientWidth;\n const ch = container.clientHeight;\n const pw = pop.offsetWidth;\n const ph = pop.offsetHeight;\n const left = Math.max(4, Math.min(clientX - rect.left, cw - pw - 4));\n const top = Math.max(4, Math.min(clientY - rect.top, ch - ph - 4));\n pop.style.left = `${left}px`;\n pop.style.top = `${top}px`;\n\n this.popover = pop;\n // Attach listeners with a delay so the opening click does not immediately close the popover.\n setTimeout(() => {\n document.addEventListener('click', this.onDocPointer, true);\n document.addEventListener('keydown', this.onKey, true);\n }, 0);\n }\n\n close(): void {\n if (!this.popover) return;\n this.popover.remove();\n this.popover = undefined;\n document.removeEventListener('click', this.onDocPointer, true);\n document.removeEventListener('keydown', this.onKey, true);\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingColorPicker from './EventStormingColorPicker.js';\n\n/** Sticky color picker (3x3 swatch popover). */\nexport const eventStormingColorPickerModule: ModuleDeclaration = {\n __init__: ['eventStormingColorPicker'],\n eventStormingColorPicker: ['type', EventStormingColorPicker],\n};\n\nexport { default as EventStormingColorPicker } from './EventStormingColorPicker.js';\n","import OrderingProvider from 'diagram-js/lib/features/ordering/OrderingProvider';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type { ElementLike, ShapeLike } from 'diagram-js/lib/model/Types';\nimport { isDrawing, isEventStormingConnection } from '../model/di-types.js';\n\n/**\n * Keeps the z-order stable for INTERACTIVELY created/moved elements, matching the import order:\n * drawings at the back, connections in the middle, stickies/notes on top. Without this,\n * connections drawn in the editor would land above the stickies (unlike imported ones).\n */\nexport default class EventStormingOrderingProvider extends OrderingProvider {\n static override $inject = ['eventBus'];\n\n constructor(eventBus: EventBus) {\n super(eventBus);\n }\n\n override getOrdering(\n element: ElementLike,\n newParent: ShapeLike,\n ): { parent: ShapeLike; index?: number } {\n // The board is flat — everything lives directly under the root. diagram-js Create/Move pass\n // the hovered element as drop target; without retargeting, releasing a sticky over another\n // one would nest it as a child (cascade move/delete). The returned parent overrides the\n // command context on both shape.create and shape.move.\n while (newParent.parent) newParent = newParent.parent as ShapeLike;\n const siblings = (newParent.children ?? []) as ElementLike[];\n if (isEventStormingConnection(element)) {\n // Behind the stickies: after all drawings and existing connections.\n const index = siblings.filter(\n (c) => c !== element && (isDrawing(c) || isEventStormingConnection(c)),\n ).length;\n return { parent: newParent, index };\n }\n if (isDrawing(element)) {\n // All the way to the back (after the other drawings).\n const index = siblings.filter((c) => c !== element && isDrawing(c)).length;\n return { parent: newParent, index };\n }\n // Stickies/notes: on top (append).\n return { parent: newParent };\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingOrderingProvider from './EventStormingOrderingProvider.js';\n\n/** Z-order for interactive edits: drawings -> connections -> stickies (like the import). */\nexport const eventStormingOrderingModule: ModuleDeclaration = {\n __init__: ['eventStormingOrderingProvider'],\n eventStormingOrderingProvider: ['type', EventStormingOrderingProvider],\n};\n\nexport { default as EventStormingOrderingProvider } from './EventStormingOrderingProvider.js';\n","import {\n append as svgAppend,\n attr as svgAttr,\n create as svgCreate,\n remove as svgRemove,\n} from 'tiny-svg';\nimport type Canvas from 'diagram-js/lib/core/Canvas';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type Modeling from 'diagram-js/lib/features/modeling/Modeling';\nimport type Selection from 'diagram-js/lib/features/selection/Selection';\nimport type { Element, Shape } from 'diagram-js/lib/model/Types';\nimport { COLORS, DRAWING_INK } from '../draw/styles.js';\nimport type EventStormingElementFactory from '../model/EventStormingElementFactory.js';\n\ninterface Point {\n x: number;\n y: number;\n}\n\n/** Clicking this close (px, canvas coords) to the FIRST/LAST point finishes/closes. */\nconst CLOSE_RADIUS = 12;\n\n/**\n * Excalidraw-style polyline tool: activate, click point by point (rubber-band preview).\n * Finishing (like Excalidraw): click the LAST point again, double-click, Enter or Escape\n * commits the open line; clicking the FIRST point closes the shape. Escape with fewer than\n * two points cancels. The result is ONE undoable `drawing` shape that moves as a whole.\n */\nexport default class EventStormingDrawTool {\n static $inject = ['canvas', 'eventBus', 'modeling', 'selection', 'eventStormingElementFactory'];\n\n private active = false;\n private points: Point[] = [];\n private cursor: Point | null = null;\n private layer: SVGElement | null = null;\n\n constructor(\n private readonly canvas: Canvas,\n private readonly eventBus: EventBus,\n private readonly modeling: Modeling,\n private readonly selection: Selection,\n private readonly factory: EventStormingElementFactory,\n ) {\n eventBus.on('diagram.destroy', () => this.cancel());\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n toggle(): void {\n if (this.active) this.cancel();\n else this.activate();\n }\n\n /**\n * The OUTER viewer container — getContainer() returns the inner .djs-container, but the\n * mode class must sit on .event-storming-container for the crosshair/empty-state CSS to match.\n */\n private outerContainer(): HTMLElement {\n const container = this.canvas.getContainer();\n return (container.closest('.event-storming-container') as HTMLElement | null) ?? container;\n }\n\n activate(): void {\n if (this.active) return;\n this.active = true;\n this.points = [];\n this.cursor = null;\n const container = this.canvas.getContainer();\n this.outerContainer().classList.add('event-storming-draw-mode');\n // Capture phase: while drawing, clicks must NOT select/move elements underneath.\n container.addEventListener('mousedown', this.onMouseDown, true);\n container.addEventListener('dblclick', this.onDblClick, true);\n container.addEventListener('mousemove', this.onMouseMove, true);\n document.addEventListener('keydown', this.onKeyDown, true);\n // Light up the palette entry (same channel the tool manager uses).\n this.eventBus.fire('tool-manager.update', { tool: 'draw' });\n }\n\n /** Finishes the current polyline (>= 2 points) and deactivates the tool. */\n finish(): void {\n const pts = [...this.points];\n this.deactivate();\n if (pts.length < 2) return;\n const shape = this.factory.drawingFromCanvasPoints(pts);\n const created = this.modeling.createShape(\n shape as unknown as Shape,\n { x: shape.x + shape.width / 2, y: shape.y + shape.height / 2 },\n this.canvas.getRootElement() as Shape,\n );\n this.selection.select(created as unknown as Element);\n }\n\n /** Closes the shape (polygon) using the collected points. */\n private finishClosed(): void {\n const pts = [...this.points];\n this.deactivate();\n if (pts.length < 3) return;\n const shape = this.factory.drawingFromCanvasPoints(pts, { closed: true });\n const created = this.modeling.createShape(\n shape as unknown as Shape,\n { x: shape.x + shape.width / 2, y: shape.y + shape.height / 2 },\n this.canvas.getRootElement() as Shape,\n );\n this.selection.select(created as unknown as Element);\n }\n\n cancel(): void {\n this.deactivate();\n }\n\n private deactivate(): void {\n if (!this.active) return;\n this.active = false;\n const container = this.canvas.getContainer();\n this.outerContainer().classList.remove('event-storming-draw-mode');\n container.removeEventListener('mousedown', this.onMouseDown, true);\n container.removeEventListener('dblclick', this.onDblClick, true);\n container.removeEventListener('mousemove', this.onMouseMove, true);\n document.removeEventListener('keydown', this.onKeyDown, true);\n this.points = [];\n this.cursor = null;\n this.clearPreview();\n this.eventBus.fire('tool-manager.update', { tool: null });\n }\n\n private toCanvasPoint(e: MouseEvent): Point {\n const rect = this.canvas.getContainer().getBoundingClientRect();\n const vb = this.canvas.viewbox();\n const scale = this.canvas.zoom();\n return {\n x: (e.clientX - rect.left) / scale + vb.x,\n y: (e.clientY - rect.top) / scale + vb.y,\n };\n }\n\n /** Palette/context-pad/menus live INSIDE the container — let their clicks through. */\n private isChromeTarget(e: MouseEvent): boolean {\n const target = e.target as HTMLElement | null;\n return !!target?.closest('.djs-palette, .djs-context-pad, .event-storming-color-picker');\n }\n\n private readonly onMouseDown = (e: MouseEvent): void => {\n if (e.button !== 0 || this.isChromeTarget(e)) return;\n e.preventDefault();\n e.stopPropagation();\n const p = this.toCanvasPoint(e);\n const first = this.points[0];\n if (first && this.points.length >= 3 && distance(p, first) <= CLOSE_RADIUS) {\n this.finishClosed();\n return;\n }\n // Clicking the LAST point again finishes the open line (Excalidraw behavior) — this is\n // the discoverable way out; double-click/Enter/Escape work as well.\n const last = this.points[this.points.length - 1];\n if (last && distance(p, last) <= CLOSE_RADIUS) {\n if (this.points.length >= 2) this.finish();\n return;\n }\n this.points.push(p);\n this.renderPreview();\n };\n\n private readonly onDblClick = (e: MouseEvent): void => {\n if (this.isChromeTarget(e)) return;\n e.preventDefault();\n e.stopPropagation();\n this.finish();\n };\n\n private readonly onMouseMove = (e: MouseEvent): void => {\n if (!this.points.length) return;\n this.cursor = this.toCanvasPoint(e);\n this.renderPreview();\n };\n\n private readonly onKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n // Excalidraw semantics: Escape COMMITS what is there (undo removes it); it only\n // cancels while no line exists yet.\n if (this.points.length >= 2) this.finish();\n else this.cancel();\n } else if (e.key === 'Enter') {\n e.preventDefault();\n e.stopPropagation();\n this.finish();\n }\n };\n\n private renderPreview(): void {\n this.clearPreview();\n if (!this.points.length) return;\n const layer = this.canvas.getLayer('event-storming-draw-preview', 1000);\n const group = svgCreate('g');\n const pts = this.cursor ? [...this.points, this.cursor] : this.points;\n svgAppend(\n group,\n svgAttr(svgCreate('polyline'), {\n points: pts.map((p) => `${p.x},${p.y}`).join(' '),\n fill: 'none',\n stroke: DRAWING_INK,\n 'stroke-width': 2,\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-dasharray': '5 4',\n }),\n );\n // First point = \"close the shape here\", last point = \"finish the line here\".\n const first = this.points[0]!;\n svgAppend(\n group,\n svgAttr(svgCreate('circle'), {\n cx: first.x,\n cy: first.y,\n r: this.points.length >= 3 ? 5 : 3,\n fill: COLORS.paper,\n stroke: DRAWING_INK,\n 'stroke-width': 1.5,\n }),\n );\n if (this.points.length >= 2) {\n const last = this.points[this.points.length - 1]!;\n svgAppend(\n group,\n svgAttr(svgCreate('circle'), {\n cx: last.x,\n cy: last.y,\n r: 5,\n fill: COLORS.paper,\n stroke: DRAWING_INK,\n 'stroke-width': 1.5,\n }),\n );\n }\n svgAppend(layer, group);\n this.layer = group;\n }\n\n private clearPreview(): void {\n if (this.layer) {\n svgRemove(this.layer);\n this.layer = null;\n }\n }\n}\n\nfunction distance(a: Point, b: Point): number {\n return Math.hypot(a.x - b.x, a.y - b.y);\n}\n","import {\n append as svgAppend,\n attr as svgAttr,\n create as svgCreate,\n remove as svgRemove,\n} from 'tiny-svg';\nimport type Canvas from 'diagram-js/lib/core/Canvas';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport { COLORS } from '../draw/styles.js';\nimport { isDrawing, type EventStormingShape } from '../model/di-types.js';\nimport type EventStormingModeling from '../modeling/EventStormingModeling.js';\n\ninterface Point {\n x: number;\n y: number;\n}\n\n/**\n * Vertex handles for drawings: when exactly one drawing is selected, every point gets a small\n * draggable handle. Dragging shows a live preview; releasing commits the new geometry (points +\n * recomputed bbox) as ONE undoable command.\n */\nexport default class EventStormingDrawingHandles {\n static $inject = ['eventBus', 'canvas', 'eventStormingModeling'];\n\n private shape: EventStormingShape | null = null;\n private group: SVGElement | null = null;\n private dragPreview: SVGElement | null = null;\n\n constructor(\n private readonly eventBus: EventBus,\n private readonly canvas: Canvas,\n private readonly modeling: EventStormingModeling,\n ) {\n eventBus.on('selection.changed', (event: { newSelection?: unknown[] }) => {\n const sel = event.newSelection ?? [];\n const only = sel.length === 1 ? sel[0] : null;\n this.attach(isDrawing(only) ? (only as EventStormingShape) : null);\n });\n // Keep the handles glued to the shape while it is moved/changed.\n eventBus.on('element.changed', (event: { element?: unknown }) => {\n if (this.shape && event.element === this.shape) this.render();\n });\n eventBus.on(['diagram.clear', 'diagram.destroy'], () => this.attach(null));\n }\n\n private attach(shape: EventStormingShape | null): void {\n this.shape = shape;\n this.render();\n }\n\n private absolutePoints(): Point[] {\n const s = this.shape!;\n return (s.drawingPoints ?? []).map((p) => ({ x: s.x + p.x, y: s.y + p.y }));\n }\n\n private render(): void {\n this.clear();\n if (!this.shape) return;\n const layer = this.canvas.getLayer('event-storming-drawing-handles', 1100);\n const group = svgCreate('g');\n this.absolutePoints().forEach((p, index) => {\n const handle = svgAttr(svgCreate('circle'), {\n cx: p.x,\n cy: p.y,\n r: 5,\n fill: COLORS.paper,\n stroke: COLORS.ink,\n 'stroke-width': 1.5,\n class: 'event-storming-drawing-handle',\n });\n handle.addEventListener('mousedown', (e) => this.startDrag(e as MouseEvent, index));\n svgAppend(group, handle);\n });\n svgAppend(layer, group);\n this.group = group;\n }\n\n private startDrag(e: MouseEvent, index: number): void {\n if (e.button !== 0 || !this.shape) return;\n e.preventDefault();\n e.stopPropagation();\n const shape = this.shape;\n const points = this.absolutePoints();\n\n const onMove = (ev: MouseEvent): void => {\n points[index] = this.toCanvasPoint(ev);\n this.renderDragPreview(points, !!shape.closed);\n };\n const onUp = (ev: MouseEvent): void => {\n document.removeEventListener('mousemove', onMove, true);\n document.removeEventListener('mouseup', onUp, true);\n points[index] = this.toCanvasPoint(ev);\n this.clearDragPreview();\n this.commit(shape, points);\n };\n document.addEventListener('mousemove', onMove, true);\n document.addEventListener('mouseup', onUp, true);\n }\n\n /** New bbox + relative points — ONE undoable updateProperties command. */\n private commit(shape: EventStormingShape, points: Point[]): void {\n const xs = points.map((p) => p.x);\n const ys = points.map((p) => p.y);\n const x = Math.min(...xs);\n const y = Math.min(...ys);\n this.modeling.updateProperties(shape, {\n x,\n y,\n width: Math.max(Math.max(...xs) - x, 4),\n height: Math.max(Math.max(...ys) - y, 4),\n drawingPoints: points.map((p) => ({ x: p.x - x, y: p.y - y })),\n });\n this.render();\n }\n\n private renderDragPreview(points: Point[], closed: boolean): void {\n this.clearDragPreview();\n const layer = this.canvas.getLayer('event-storming-drawing-handles', 1100);\n const preview = svgAttr(svgCreate(closed ? 'polygon' : 'polyline'), {\n points: points.map((p) => `${p.x},${p.y}`).join(' '),\n fill: 'none',\n stroke: COLORS.ink,\n 'stroke-width': 1.5,\n 'stroke-dasharray': '5 4',\n 'pointer-events': 'none',\n });\n svgAppend(layer, preview);\n this.dragPreview = preview;\n }\n\n private clearDragPreview(): void {\n if (this.dragPreview) {\n svgRemove(this.dragPreview);\n this.dragPreview = null;\n }\n }\n\n private clear(): void {\n this.clearDragPreview();\n if (this.group) {\n svgRemove(this.group);\n this.group = null;\n }\n }\n\n private toCanvasPoint(e: MouseEvent): Point {\n const rect = this.canvas.getContainer().getBoundingClientRect();\n const vb = this.canvas.viewbox();\n const scale = this.canvas.zoom();\n return {\n x: (e.clientX - rect.left) / scale + vb.x,\n y: (e.clientY - rect.top) / scale + vb.y,\n };\n }\n}\n","import { append as svgAppend, attr as svgAttr, create as svgCreate } from 'tiny-svg';\nimport type EventBus from 'diagram-js/lib/core/EventBus';\nimport type InteractionEvents from 'diagram-js/lib/features/interaction-events/InteractionEvents';\nimport { isDrawing, type EventStormingShape } from '../model/di-types.js';\n\n/**\n * Drawings get a hit zone along their STROKE only (generous 15px band, like the default\n * stroke hit) instead of the default full-bbox hit — a shape drawn AROUND sticky clusters must\n * not swallow the clicks for everything inside it. The interior stays click-through; the drawing\n * itself is selected/moved by grabbing its line.\n */\nexport default class EventStormingDrawingHitProvider {\n static $inject = ['eventBus', 'interactionEvents'];\n\n constructor(eventBus: EventBus, interactionEvents: InteractionEvents) {\n // The diagram-js default (box hit) listens on LOW_PRIORITY — returning false here\n // suppresses it (same pattern bpmn-js uses for its custom hits).\n eventBus.on('interactionEvents.createHit', (event: { element?: unknown; gfx?: SVGElement }) => {\n if (!isDrawing(event.element) || !event.gfx) return;\n createStrokeHit(event.element, event.gfx);\n return false;\n });\n eventBus.on('interactionEvents.updateHit', (event: { element?: unknown; gfx?: SVGElement }) => {\n if (!isDrawing(event.element) || !event.gfx) return;\n interactionEvents.removeHits(event.gfx);\n createStrokeHit(event.element, event.gfx);\n return false;\n });\n }\n}\n\nfunction createStrokeHit(shape: EventStormingShape, gfx: SVGElement): void {\n const points = shape.drawingPoints ?? [];\n const hit = svgCreate(shape.closed ? 'polygon' : 'polyline');\n svgAttr(hit, {\n points: points.map((p) => `${p.x},${p.y}`).join(' '),\n class: 'djs-hit djs-hit-stroke',\n fill: 'none',\n stroke: 'white',\n 'stroke-width': 15,\n // diagram-js makes hits invisible via this INLINE attribute (its \"no-border\" trait),\n // not via CSS — without it the 15px white band is visible.\n 'stroke-opacity': 0,\n });\n svgAppend(gfx, hit);\n}\n","import type { ModuleDeclaration } from 'didi';\nimport EventStormingDrawTool from './EventStormingDrawTool.js';\nimport EventStormingDrawingHandles from './EventStormingDrawingHandles.js';\nimport EventStormingDrawingHitProvider from './EventStormingDrawingHitProvider.js';\n\nexport const eventStormingDrawToolModule: ModuleDeclaration = {\n __init__: [\n 'eventStormingDrawTool',\n 'eventStormingDrawingHandles',\n 'eventStormingDrawingHitProvider',\n ],\n eventStormingDrawTool: ['type', EventStormingDrawTool],\n eventStormingDrawingHandles: ['type', EventStormingDrawingHandles],\n eventStormingDrawingHitProvider: ['type', EventStormingDrawingHitProvider],\n};\n\nexport { default as EventStormingDrawTool } from './EventStormingDrawTool.js';\nexport { default as EventStormingDrawingHandles } from './EventStormingDrawingHandles.js';\nexport { default as EventStormingDrawingHitProvider } from './EventStormingDrawingHitProvider.js';\n","import type EventBus from 'diagram-js/lib/core/EventBus';\nimport { isNote } from '../model/di-types.js';\nimport { NOTE_MIN_RESIZE } from '../draw/styles.js';\n\ninterface ResizeStartEvent {\n context: {\n shape?: unknown;\n minDimensions?: { width: number; height: number };\n };\n}\n\n/**\n * Clamps interactive note resizing to `NOTE_MIN_RESIZE` the way diagram-js Resize consumes it:\n * a `resize.start` interceptor ABOVE the stock handler (default priority 1000) sets\n * `context.minDimensions`, which the drag then enforces as hard constraints — the preview stops\n * at the minimum instead of entering a not-allowed state (the bpmn-js ResizeBehavior pattern).\n */\nexport default class EventStormingResizeBehavior {\n static $inject = ['eventBus'];\n\n constructor(eventBus: EventBus) {\n eventBus.on('resize.start', 1500, (event: ResizeStartEvent) => {\n const context = event.context;\n if (isNote(context.shape)) {\n context.minDimensions = NOTE_MIN_RESIZE;\n }\n });\n }\n}\n","import type { ModuleDeclaration } from 'didi';\nimport ResizeModule from 'diagram-js/lib/features/resize';\nimport EventStormingResizeBehavior from './EventStormingResizeBehavior.js';\n\n/**\n * Free note resizing: the stock diagram-js Resize feature (handles, preview, rules check,\n * undoable `shape.resize` command) plus the Event Storming minimum-bounds clamp. Which shapes\n * get handles is decided by the `shape.resize` rule — notes only.\n */\nexport const eventStormingResizeModule: ModuleDeclaration = {\n __depends__: [ResizeModule],\n __init__: ['eventStormingResizeBehavior'],\n eventStormingResizeBehavior: ['type', EventStormingResizeBehavior],\n};\n\nexport { default as EventStormingResizeBehavior } from './EventStormingResizeBehavior.js';\n","import type { ModuleDeclaration } from 'didi';\nimport type CommandStack from 'diagram-js/lib/command/CommandStack';\n\nimport ModelingModule from 'diagram-js/lib/features/modeling';\nimport MoveModule from 'diagram-js/lib/features/move';\nimport CreateModule from 'diagram-js/lib/features/create';\nimport ConnectModule from 'diagram-js/lib/features/connect';\nimport ContextPadModule from 'diagram-js/lib/features/context-pad';\nimport PaletteModule from 'diagram-js/lib/features/palette';\nimport RulesModule from 'diagram-js/lib/features/rules';\nimport OutlineModule from 'diagram-js/lib/features/outline';\nimport PopupMenuModule from 'diagram-js/lib/features/popup-menu';\n\nimport { NavigatedViewer } from './NavigatedViewer.js';\nimport { eventStormingAttachModule } from './attach/index.js';\nimport { eventStormingModelingModule } from './modeling/index.js';\nimport { eventStormingLassoModule } from './lasso/index.js';\nimport { eventStormingRulesModule } from './rules/index.js';\nimport { elementSnappingModule } from './snapping/index.js';\nimport { eventStormingPaletteModule } from './palette/index.js';\nimport { eventStormingContextPadModule } from './context-pad/index.js';\nimport { labelEditingModule } from './label-editing/index.js';\nimport { eventStormingKeyboardModule } from './keyboard/index.js';\nimport { eventStormingPopupModule } from './popup/index.js';\nimport { eventStormingAppendModule } from './append/index.js';\nimport { eventStormingColorPickerModule } from './color-picker/index.js';\nimport { eventStormingOrderingModule } from './ordering/index.js';\nimport { eventStormingDrawToolModule } from './draw-tool/index.js';\nimport { eventStormingResizeModule } from './resize/index.js';\n\n/**\n * Full Event Storming editor: palette/create, free move with sticky-center snapping, connect\n * with rules, context pad, inline label editing, undo/redo, pinning of actor/hotspot stickies,\n * free resizing of notes.\n */\nexport class Modeler extends NavigatedViewer {\n protected override _getModules(): ModuleDeclaration[] {\n return [\n ...super._getModules(),\n ModelingModule,\n RulesModule,\n MoveModule,\n CreateModule,\n ConnectModule,\n ContextPadModule,\n PaletteModule,\n OutlineModule,\n PopupMenuModule,\n eventStormingModelingModule,\n eventStormingAttachModule,\n eventStormingRulesModule,\n elementSnappingModule,\n eventStormingPaletteModule,\n eventStormingContextPadModule,\n labelEditingModule,\n eventStormingKeyboardModule,\n eventStormingPopupModule,\n eventStormingAppendModule,\n eventStormingColorPickerModule,\n eventStormingLassoModule,\n eventStormingOrderingModule,\n eventStormingDrawToolModule,\n eventStormingResizeModule,\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"],"mappings":"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"}