@memberjunction/ng-whiteboard 0.0.1 → 5.41.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 (62) hide show
  1. package/README.md +302 -28
  2. package/dist/lib/whiteboard-agent-sees-popover.component.d.ts +31 -0
  3. package/dist/lib/whiteboard-agent-sees-popover.component.d.ts.map +1 -0
  4. package/dist/lib/whiteboard-agent-sees-popover.component.js +132 -0
  5. package/dist/lib/whiteboard-agent-sees-popover.component.js.map +1 -0
  6. package/dist/lib/whiteboard-board.component.d.ts +458 -0
  7. package/dist/lib/whiteboard-board.component.d.ts.map +1 -0
  8. package/dist/lib/whiteboard-board.component.js +2357 -0
  9. package/dist/lib/whiteboard-board.component.js.map +1 -0
  10. package/dist/lib/whiteboard-context-menu.d.ts +57 -0
  11. package/dist/lib/whiteboard-context-menu.d.ts.map +1 -0
  12. package/dist/lib/whiteboard-context-menu.js +69 -0
  13. package/dist/lib/whiteboard-context-menu.js.map +1 -0
  14. package/dist/lib/whiteboard-export.d.ts +94 -0
  15. package/dist/lib/whiteboard-export.d.ts.map +1 -0
  16. package/dist/lib/whiteboard-export.js +592 -0
  17. package/dist/lib/whiteboard-export.js.map +1 -0
  18. package/dist/lib/whiteboard-host.component.d.ts +174 -0
  19. package/dist/lib/whiteboard-host.component.d.ts.map +1 -0
  20. package/dist/lib/whiteboard-host.component.js +758 -0
  21. package/dist/lib/whiteboard-host.component.js.map +1 -0
  22. package/dist/lib/whiteboard-pages.component.d.ts +83 -0
  23. package/dist/lib/whiteboard-pages.component.d.ts.map +1 -0
  24. package/dist/lib/whiteboard-pages.component.js +211 -0
  25. package/dist/lib/whiteboard-pages.component.js.map +1 -0
  26. package/dist/lib/whiteboard-snapshot.component.d.ts +30 -0
  27. package/dist/lib/whiteboard-snapshot.component.d.ts.map +1 -0
  28. package/dist/lib/whiteboard-snapshot.component.js +91 -0
  29. package/dist/lib/whiteboard-snapshot.component.js.map +1 -0
  30. package/dist/lib/whiteboard-srcdoc.pipe.d.ts +60 -0
  31. package/dist/lib/whiteboard-srcdoc.pipe.d.ts.map +1 -0
  32. package/dist/lib/whiteboard-srcdoc.pipe.js +75 -0
  33. package/dist/lib/whiteboard-srcdoc.pipe.js.map +1 -0
  34. package/dist/lib/whiteboard-state.d.ts +1113 -0
  35. package/dist/lib/whiteboard-state.d.ts.map +1 -0
  36. package/dist/lib/whiteboard-state.js +1396 -0
  37. package/dist/lib/whiteboard-state.js.map +1 -0
  38. package/dist/lib/whiteboard-toolbar.component.d.ts +95 -0
  39. package/dist/lib/whiteboard-toolbar.component.d.ts.map +1 -0
  40. package/dist/lib/whiteboard-toolbar.component.js +344 -0
  41. package/dist/lib/whiteboard-toolbar.component.js.map +1 -0
  42. package/dist/lib/whiteboard-tools.d.ts +103 -0
  43. package/dist/lib/whiteboard-tools.d.ts.map +1 -0
  44. package/dist/lib/whiteboard-tools.js +748 -0
  45. package/dist/lib/whiteboard-tools.js.map +1 -0
  46. package/dist/lib/whiteboard-widget-bridge.d.ts +217 -0
  47. package/dist/lib/whiteboard-widget-bridge.d.ts.map +1 -0
  48. package/dist/lib/whiteboard-widget-bridge.js +254 -0
  49. package/dist/lib/whiteboard-widget-bridge.js.map +1 -0
  50. package/dist/lib/whiteboard-zoom.component.d.ts +55 -0
  51. package/dist/lib/whiteboard-zoom.component.d.ts.map +1 -0
  52. package/dist/lib/whiteboard-zoom.component.js +139 -0
  53. package/dist/lib/whiteboard-zoom.component.js.map +1 -0
  54. package/dist/lib/whiteboard.module.d.ts +29 -0
  55. package/dist/lib/whiteboard.module.d.ts.map +1 -0
  56. package/dist/lib/whiteboard.module.js +78 -0
  57. package/dist/lib/whiteboard.module.js.map +1 -0
  58. package/dist/public-api.d.ts +49 -0
  59. package/dist/public-api.d.ts.map +1 -0
  60. package/dist/public-api.js +59 -0
  61. package/dist/public-api.js.map +1 -0
  62. package/package.json +43 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whiteboard-host.component.js","sourceRoot":"","sources":["../../src/lib/whiteboard-host.component.ts","../../src/lib/whiteboard-host.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n ChangeDetectorRef, Component, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output,\n ViewChild, inject\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Subscription } from 'rxjs';\nimport {\n WhiteboardFontFamily, WhiteboardItemAddedEventArgs, WhiteboardItemAddingEventArgs,\n WhiteboardItemRemovedEventArgs, WhiteboardItemRemovingEventArgs,\n WhiteboardItemUpdatedEventArgs, WhiteboardItemUpdatingEventArgs, WhiteboardState\n} from './whiteboard-state';\nimport {\n BuildWhiteboardExportHtml, BuildWhiteboardExportHtmlAllPages, BuildWhiteboardExportSvg,\n BuildWhiteboardExportSvgPages\n} from './whiteboard-export';\nimport { ApplyWhiteboardAgentTool, WHITEBOARD_TOOL_NAMES, WhiteboardToolResult } from './whiteboard-tools';\nimport {\n RealtimeWhiteboardBoardComponent, WhiteboardAgentPresence,\n WhiteboardContentAppliedEventArgs, WhiteboardContentApplyingEventArgs\n} from './whiteboard-board.component';\nimport {\n WhiteboardWidgetInteractionEvent, WhiteboardWidgetSubmitEvent, WhiteboardWidgetSubmittingEventArgs\n} from './whiteboard-widget-bridge';\nimport { RealtimeWhiteboardToolbarComponent, WhiteboardTool, WHITEBOARD_PEN_COLORS } from './whiteboard-toolbar.component';\nimport { RealtimeWhiteboardZoomComponent } from './whiteboard-zoom.component';\nimport { RealtimeWhiteboardAgentSeesPopoverComponent } from './whiteboard-agent-sees-popover.component';\n\n/** Debounce window for the perception feed (the popover's \"debounce 750 ms\" stat). */\nconst SCENE_DELTA_DEBOUNCE_MS = 750;\n/** How long the agent-action toast stays up (coalescing further actions while visible). */\nconst TOAST_MS = 6000;\n/** How long the presence cursor lingers after the agent's last board action. */\nconst PRESENCE_MS = 4200;\n\n/**\n * LIVE WHITEBOARD host (`mj-realtime-whiteboard-host`): board header (title / saved chip /\n * ownership legend / \"What [Agent] sees\" popover / Focus toggle), the board surface with its\n * floating toolbar + zoom cluster, the agent action toast with Undo, and the status footer —\n * everything EXCEPT the overlay/tab chrome, which the session shell owns.\n *\n * Integration contract:\n * - `State` is created by the integration layer (channel state of record) and passed in;\n * - `SceneDelta` emits the debounced (750 ms), coalesced scene-delta JSON on user changes —\n * the perception feed the integration pipes into the live agent context;\n * - `ApplyAgentTool(toolName, argsJson)` executes one agent channel tool\n * (`Whiteboard_AddNote` … see `WHITEBOARD_TOOL_DEFINITIONS`) with the violet pop-in,\n * toast and presence-cursor garnish, returning the result JSON for the tool round-trip;\n * - `AgentUndo` fires when the user clicks Undo on the agent-action toast;\n * - `FocusModeChange` asks the shell to collapse/restore the call rail (\"Focus board\").\n *\n * Extensibility (before/after events): the host mirrors the engine's cancelable\n * BEFORE / AFTER mutation pairs as outputs (`ItemAdding`/`ItemAdded`,\n * `ItemUpdating`/`ItemUpdated`, `ItemRemoving`/`ItemRemoved`) and forwards the board's\n * editor + widget pairs (`ContentApplying`/`ContentApplied`,\n * `WidgetSubmitting`/`WidgetSubmitted`). All BEFORE events honor `Cancel = true` set\n * synchronously by a handler.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-whiteboard-host',\n imports: [\n CommonModule,\n RealtimeWhiteboardBoardComponent,\n RealtimeWhiteboardToolbarComponent,\n RealtimeWhiteboardZoomComponent,\n RealtimeWhiteboardAgentSeesPopoverComponent\n ],\n templateUrl: './whiteboard-host.component.html',\n styleUrl: './whiteboard-host.component.css'\n})\nexport class RealtimeWhiteboardHostComponent implements OnInit, OnDestroy {\n /** Shared board state engine, owned by the integration layer. */\n @Input({ required: true }) State!: WhiteboardState;\n /** Display name of the session's agent (legend, chips, popover, toast). */\n @Input() AgentName = 'Agent';\n /** Board title shown in the header. */\n @Input() BoardTitle = 'Whiteboard';\n /** Persistence chip text (e.g. \"Saved to session · v14\"). */\n @Input() SavedLabel = 'Saved to session';\n\n /** Debounced (750 ms), coalesced scene-delta JSON — the live perception feed. */\n @Output() SceneDelta = new EventEmitter<string>();\n /** The user clicked Undo on the agent-action toast (the undo itself already applied). */\n @Output() AgentUndo = new EventEmitter<void>();\n /** Focus-board toggle — the session shell collapses/restores the call rail. */\n @Output() FocusModeChange = new EventEmitter<boolean>();\n /** Emitted when the user picks \"Save to artifacts\" — the channel plugin persists via its host context. */\n @Output() SaveToArtifactsRequested = new EventEmitter<void>();\n /**\n * Cancelable BEFORE event (forwarded from the board): a sandboxed HTML widget submitted\n * input via `MJWhiteboard.submit` and it passed validation. Set `Cancel = true`\n * synchronously to drop it before {@link WidgetSubmitted} fires.\n */\n @Output() WidgetSubmitting = new EventEmitter<WhiteboardWidgetSubmittingEventArgs>();\n /**\n * AFTER event: a sandboxed HTML widget submitted user input via `MJWhiteboard.submit`\n * (validated + size-capped by the board, not canceled). Integration layers forward it\n * to their agent runtime — e.g. MJ's channel plugin sends a `[whiteboard]` context note.\n */\n @Output() WidgetSubmitted = new EventEmitter<WhiteboardWidgetSubmitEvent>();\n /**\n * AMBIENT widget telemetry (forwarded from the board): the injected recorder observed\n * passive form activity (clicks / changes / typing / focus) inside a sandboxed HTML\n * widget, validated + pre-summarized. Integration layers forward it to their agent\n * runtime as throttled, low-priority background context — e.g. MJ's channel plugin sends\n * an \"ambient activity\" `[whiteboard]` note at most once per widget per few seconds.\n */\n @Output() WidgetInteraction = new EventEmitter<WhiteboardWidgetInteractionEvent>();\n /**\n * Cancelable BEFORE event (forwarded from the board): an in-board editor commit is\n * about to write to the state engine. Set `Cancel = true` synchronously to discard it.\n */\n @Output() ContentApplying = new EventEmitter<WhiteboardContentApplyingEventArgs>();\n /** AFTER event (forwarded from the board): an editor commit applied. */\n @Output() ContentApplied = new EventEmitter<WhiteboardContentAppliedEventArgs>();\n\n // Engine mutation mirrors — the same before/after events {@link WhiteboardState} raises,\n // re-emitted as component outputs so template-driven consumers can bind them without\n // subscribing to the engine directly. Emission is synchronous, so cancelable BEFORE\n // mirrors (`ItemAdding` / `ItemUpdating` / `ItemRemoving`) honor `Cancel = true` set by\n // a template handler exactly like a direct engine subscription would.\n\n /** Cancelable BEFORE mirror of {@link WhiteboardState.ItemAdding$}. */\n @Output() ItemAdding = new EventEmitter<WhiteboardItemAddingEventArgs>();\n /** AFTER mirror of {@link WhiteboardState.ItemAdded$}. */\n @Output() ItemAdded = new EventEmitter<WhiteboardItemAddedEventArgs>();\n /** Cancelable BEFORE mirror of {@link WhiteboardState.ItemUpdating$} (update / move / reorder). */\n @Output() ItemUpdating = new EventEmitter<WhiteboardItemUpdatingEventArgs>();\n /** AFTER mirror of {@link WhiteboardState.ItemUpdated$}. */\n @Output() ItemUpdated = new EventEmitter<WhiteboardItemUpdatedEventArgs>();\n /** Cancelable BEFORE mirror of {@link WhiteboardState.ItemRemoving$}. */\n @Output() ItemRemoving = new EventEmitter<WhiteboardItemRemovingEventArgs>();\n /** AFTER mirror of {@link WhiteboardState.ItemRemoved$}. */\n @Output() ItemRemoved = new EventEmitter<WhiteboardItemRemovedEventArgs>();\n\n @ViewChild(RealtimeWhiteboardBoardComponent) public Board?: RealtimeWhiteboardBoardComponent;\n\n // tool state (host-owned; toolbar + keyboard drive it, board consumes it)\n public Tool: WhiteboardTool = 'select';\n public PenColor: string = WHITEBOARD_PEN_COLORS[0];\n public PenWidth = 4;\n public ShapeKind: 'rect' | 'ellipse' | 'diamond' = 'rect';\n public TextSize = 12;\n public TextFamily: WhiteboardFontFamily = 'sans';\n public TextBold = true;\n public TextColor: string | null = null;\n\n // header state\n public SeesOpen = false;\n public FocusMode = false;\n public ExportOpen = false;\n\n // agent garnish state\n public AgentPresence: WhiteboardAgentPresence | null = null;\n public ToastText: string | null = null;\n private toastPhrases: string[] = [];\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\n private presenceTimer: ReturnType<typeof setTimeout> | null = null;\n\n // perception feed state\n public LastDeltaJson = '';\n private lastDeltaToken = 0;\n private lastDeltaAt: number | null = null;\n private deltaTimer: ReturnType<typeof setTimeout> | null = null;\n\n // \"synced n s ago\" ticker\n public NowTick = Date.now();\n private ticker: ReturnType<typeof setInterval> | null = null;\n\n private changedSub?: Subscription;\n private mirrorSubs: Subscription[] = [];\n private cdr = inject(ChangeDetectorRef);\n\n ngOnInit(): void {\n this.changedSub = this.State.Changed$.subscribe((change) => {\n // perception feed: user edits (and scene replacements like undo) schedule a delta\n if (change.Author === 'user' || change.Op === 'replace') {\n this.scheduleSceneDelta();\n }\n this.cdr.markForCheck();\n });\n // Mirror the engine's before/after mutation events as component outputs. The re-emit\n // runs synchronously inside the engine's emit, so Cancel set by an output handler\n // still vetoes the mutation.\n this.mirrorSubs.push(\n this.State.ItemAdding$.subscribe((e) => this.ItemAdding.emit(e)),\n this.State.ItemAdded$.subscribe((e) => this.ItemAdded.emit(e)),\n this.State.ItemUpdating$.subscribe((e) => this.ItemUpdating.emit(e)),\n this.State.ItemUpdated$.subscribe((e) => this.ItemUpdated.emit(e)),\n this.State.ItemRemoving$.subscribe((e) => this.ItemRemoving.emit(e)),\n this.State.ItemRemoved$.subscribe((e) => this.ItemRemoved.emit(e))\n );\n this.ticker = setInterval(() => {\n this.NowTick = Date.now();\n this.cdr.markForCheck();\n }, 1000);\n }\n\n ngOnDestroy(): void {\n this.changedSub?.unsubscribe();\n for (const sub of this.mirrorSubs) {\n sub.unsubscribe();\n }\n this.mirrorSubs = [];\n if (this.deltaTimer) {\n clearTimeout(this.deltaTimer);\n }\n if (this.toastTimer) {\n clearTimeout(this.toastTimer);\n }\n if (this.presenceTimer) {\n clearTimeout(this.presenceTimer);\n }\n if (this.ticker) {\n clearInterval(this.ticker);\n }\n }\n\n // ────────────────────────────────────────────── AGENT tool entry point\n\n /**\n * Execute one agent whiteboard tool (author `'agent'`, one undo batch), with the UI\n * garnish: presence cursor glides to the mutation point, the new item pops in violet,\n * and the action toast (with Undo) appears. Returns the result JSON string that the\n * integration layer feeds back to the realtime model as the `tool_response`.\n */\n public ApplyAgentTool(toolName: string, argsJson: string): string {\n const resultJson = ApplyWhiteboardAgentTool(this.State, toolName, argsJson);\n let result: WhiteboardToolResult | null = null;\n try {\n result = JSON.parse(resultJson) as WhiteboardToolResult;\n }\n catch {\n result = null;\n }\n if (result?.success) {\n this.showAgentPresence(result.itemId);\n this.pushToastPhrase(RealtimeWhiteboardHostComponent.toolPhrase(toolName));\n }\n this.cdr.markForCheck();\n return resultJson;\n }\n\n // ────────────────────────────────────────────── header actions\n\n public ToggleSees(event: Event): void {\n event.stopPropagation();\n this.SeesOpen = !this.SeesOpen;\n }\n\n @HostListener('document:click')\n public CloseSees(): void {\n if (this.SeesOpen) {\n this.SeesOpen = false;\n }\n }\n\n public ToggleFocus(): void {\n this.FocusMode = !this.FocusMode;\n this.FocusModeChange.emit(this.FocusMode);\n }\n\n // ────────────────────────────────────────────── export menu\n\n public ToggleExport(event: Event): void {\n event.stopPropagation();\n this.ExportOpen = !this.ExportOpen;\n }\n\n @HostListener('document:click')\n public CloseExport(): void {\n if (this.ExportOpen) {\n this.ExportOpen = false;\n }\n }\n\n /** Download the board as one self-contained HTML document. */\n /** Request a first-class artifact snapshot of the board (handled by the channel plugin). */\n public ExportSaveToArtifacts(): void {\n this.ExportOpen = false;\n this.SaveToArtifactsRequested.emit();\n }\n\n public ExportDownloadHtml(): void {\n this.downloadBlob(this.buildExportHtml(), 'text/html', `whiteboard-${RealtimeWhiteboardHostComponent.exportDateStamp()}.html`);\n this.ExportOpen = false;\n }\n\n /** Download ONE self-contained HTML document containing EVERY page (titled sections). */\n public ExportDownloadHtmlAllPages(): void {\n const html = BuildWhiteboardExportHtmlAllPages(this.State, this.exportOptions());\n this.downloadBlob(html, 'text/html', `whiteboard-all-pages-${RealtimeWhiteboardHostComponent.exportDateStamp()}.html`);\n this.ExportOpen = false;\n }\n\n /** Download the ACTIVE page as a standalone SVG document. */\n public ExportDownloadSvg(): void {\n this.downloadBlob(BuildWhiteboardExportSvg(this.State), 'image/svg+xml', `whiteboard-${RealtimeWhiteboardHostComponent.exportDateStamp()}.svg`);\n this.ExportOpen = false;\n }\n\n /**\n * Download EVERY page as its own standalone SVG document (SVG is single-image, so\n * \"all pages\" is one file per page, downloaded sequentially with the page name\n * slug-suffixed into each filename).\n */\n public ExportDownloadSvgAllPages(): void {\n const stamp = RealtimeWhiteboardHostComponent.exportDateStamp();\n for (const page of BuildWhiteboardExportSvgPages(this.State)) {\n const slug = RealtimeWhiteboardHostComponent.fileNameSlug(page.PageName) || page.PageID;\n this.downloadBlob(page.Content, 'image/svg+xml', `whiteboard-${stamp}-${slug}.svg`);\n }\n this.ExportOpen = false;\n }\n\n /** Whether the board has more than one page (gates the \"all pages\" export entries). */\n public get HasMultiplePages(): boolean {\n return this.State.Pages.length > 1;\n }\n\n /**\n * Print the board: open a blank window, write the self-contained export document and\n * invoke the print dialog (same precedent as the artifact viewer's print path). When the\n * popup is blocked this is a logged no-op — nothing breaks, the user can retry.\n */\n public ExportPrint(): void {\n this.ExportOpen = false;\n const printWindow = window.open('about:blank', '_blank');\n if (!printWindow) {\n console.warn('Whiteboard print: popup was blocked — allow popups for this site and retry.');\n return;\n }\n printWindow.document.write(this.buildExportHtml());\n printWindow.document.close();\n printWindow.focus();\n // let the document lay out before invoking the dialog (artifact-viewer precedent)\n setTimeout(() => printWindow.print(), 250);\n }\n\n private buildExportHtml(): string {\n return BuildWhiteboardExportHtml(this.State, this.exportOptions());\n }\n\n /** Shared options for the HTML export builders (single page + all pages). */\n private exportOptions(): { Title: string; AgentName: string; GeneratedAt: string } {\n return {\n Title: this.BoardTitle,\n AgentName: this.AgentName,\n GeneratedAt: new Date().toLocaleString()\n };\n }\n\n /** Safe filename fragment from a page name (lowercased, non-alphanumerics collapse to '-'). */\n private static fileNameSlug(name: string): string {\n return (name ?? '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40);\n }\n\n private downloadBlob(content: string, mimeType: string, fileName: string): void {\n const url = URL.createObjectURL(new Blob([content], { type: mimeType }));\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = fileName;\n anchor.click();\n URL.revokeObjectURL(url);\n }\n\n private static exportDateStamp(): string {\n return new Date().toISOString().slice(0, 10);\n }\n\n // ────────────────────────────────────────────── toast\n\n public OnToastUndo(event: Event): void {\n event.stopPropagation();\n // The agent's tool call ran as ONE undo batch, so a single Undo reverts it whole.\n this.State.Undo();\n this.hideToast();\n this.AgentUndo.emit();\n }\n\n // ────────────────────────────────────────────── keyboard shortcuts\n\n @HostListener('document:keydown', ['$event'])\n public OnKeydown(event: KeyboardEvent): void {\n const target = event.target as HTMLElement | null;\n if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)) {\n return;\n }\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'z') {\n event.preventDefault();\n if (event.shiftKey) {\n this.State.Redo();\n }\n else {\n this.State.Undo();\n }\n return;\n }\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'y') {\n event.preventDefault();\n this.State.Redo();\n return;\n }\n if (event.metaKey || event.ctrlKey || event.altKey) {\n return;\n }\n switch (event.key) {\n case 'Escape':\n this.Tool = 'select';\n this.Board?.CancelTransient();\n this.State.Select(null);\n break;\n case 'Delete':\n case 'Backspace':\n if (this.State.SelectedIDs.length > 0) {\n event.preventDefault();\n // removes the WHOLE (single or multi) selection as one undo step\n this.State.RemoveSelected('user');\n }\n break;\n default: {\n const tool = RealtimeWhiteboardHostComponent.toolForKey(event.key);\n if (tool) {\n this.Tool = tool;\n }\n break;\n }\n }\n }\n\n // ────────────────────────────────────────────── status footer / popover bindings\n\n public get ElementCount(): number {\n return this.State.ElementCount;\n }\n\n public get UserCount(): number {\n return this.State.CountByAuthor('user');\n }\n\n public get AgentCount(): number {\n return this.State.CountByAuthor('agent');\n }\n\n public get CurrentSeq(): number {\n return this.State.CurrentSeq;\n }\n\n /** \"2 s ago\" style age of the last emitted delta (the ticker keeps it fresh). */\n public get LastDeltaLabel(): string {\n if (this.lastDeltaAt == null) {\n return '—';\n }\n const seconds = Math.max(0, Math.round((this.NowTick - this.lastDeltaAt) / 1000));\n if (seconds < 60) {\n return `${seconds} s ago`;\n }\n return `${Math.floor(seconds / 60)} min ago`;\n }\n\n public get SceneDeltaDebounceMs(): number {\n return SCENE_DELTA_DEBOUNCE_MS;\n }\n\n // ────────────────────────────────────────────── internals\n\n private scheduleSceneDelta(): void {\n if (this.deltaTimer) {\n clearTimeout(this.deltaTimer);\n }\n this.deltaTimer = setTimeout(() => {\n this.deltaTimer = null;\n this.emitSceneDelta();\n }, SCENE_DELTA_DEBOUNCE_MS);\n }\n\n private emitSceneDelta(): void {\n const delta = this.State.BuildSceneDelta(this.lastDeltaToken);\n this.lastDeltaToken = this.State.CurrentSeq;\n this.lastDeltaAt = Date.now();\n this.LastDeltaJson = JSON.stringify(delta, null, 2);\n this.SceneDelta.emit(JSON.stringify(delta));\n this.cdr.markForCheck();\n }\n\n private showAgentPresence(itemId: string | undefined): void {\n let x = 480;\n let y = 220;\n const item = itemId ? this.State.GetItem(itemId) : undefined;\n if (item) {\n const b = this.State.ItemBounds(item);\n x = b.X + b.W + 14;\n y = b.Y + b.H / 2 - 13;\n }\n this.AgentPresence = { Active: true, X: x, Y: y, Label: `${this.AgentName} is drawing…` };\n if (this.presenceTimer) {\n clearTimeout(this.presenceTimer);\n }\n this.presenceTimer = setTimeout(() => {\n this.AgentPresence = null;\n this.cdr.markForCheck();\n }, PRESENCE_MS);\n }\n\n private pushToastPhrase(phrase: string): void {\n if (!this.ToastText) {\n this.toastPhrases = [];\n }\n if (!this.toastPhrases.includes(phrase)) {\n this.toastPhrases.push(phrase);\n }\n const joined = this.toastPhrases.length > 1\n ? `${this.toastPhrases.slice(0, -1).join(', ')} & ${this.toastPhrases[this.toastPhrases.length - 1]}`\n : this.toastPhrases[0];\n this.ToastText = `${this.AgentName} ${joined} · just now`;\n if (this.toastTimer) {\n clearTimeout(this.toastTimer);\n }\n this.toastTimer = setTimeout(() => this.hideToast(), TOAST_MS);\n }\n\n private hideToast(): void {\n this.ToastText = null;\n this.toastPhrases = [];\n if (this.toastTimer) {\n clearTimeout(this.toastTimer);\n this.toastTimer = null;\n }\n this.cdr.markForCheck();\n }\n\n private static toolPhrase(toolName: string): string {\n switch (toolName) {\n case WHITEBOARD_TOOL_NAMES.AddNote: return 'added a note';\n case WHITEBOARD_TOOL_NAMES.AddShape: return 'added a shape';\n case WHITEBOARD_TOOL_NAMES.AddText: return 'added a label';\n case WHITEBOARD_TOOL_NAMES.AddMarkdown: return 'added a markdown panel';\n case WHITEBOARD_TOOL_NAMES.AddHtml: return 'added an HTML widget';\n case WHITEBOARD_TOOL_NAMES.UpdateContent: return 'edited an item';\n case WHITEBOARD_TOOL_NAMES.DrawConnector: return 'added a connector';\n case WHITEBOARD_TOOL_NAMES.Highlight: return 'highlighted a region';\n case WHITEBOARD_TOOL_NAMES.MoveItem: return 'moved an item';\n case WHITEBOARD_TOOL_NAMES.RemoveItem: return 'removed an item';\n case WHITEBOARD_TOOL_NAMES.StyleItem: return 'restyled an item';\n case WHITEBOARD_TOOL_NAMES.AddPage: return 'created a page';\n case WHITEBOARD_TOOL_NAMES.SwitchPage: return 'switched pages';\n case WHITEBOARD_TOOL_NAMES.RenamePage: return 'renamed a page';\n default: return 'updated the board';\n }\n }\n\n private static toolForKey(key: string): WhiteboardTool | null {\n switch (key.toLowerCase()) {\n case 'v': return 'select';\n case 'h': return 'pan';\n case 'p': return 'pen';\n case 'r': return 'shape';\n case 's': return 'sticky';\n case 't': return 'text';\n case 'm': return 'markdown';\n case 'w': return 'html';\n case 'i': return 'image';\n case 'c': return 'connector';\n case 'e': return 'eraser';\n default: return null;\n }\n }\n}\n","<!-- board header -->\n<div class=\"board-head\">\n <span class=\"bt\"><i class=\"fa-solid fa-chalkboard\"></i> {{ BoardTitle }}</span>\n <span class=\"board-save\"><i class=\"fa-solid fa-circle-check\"></i> {{ SavedLabel }}</span>\n <span class=\"board-legend\">\n <span><span class=\"sw sw--you\"></span>You</span>\n <span><span class=\"sw sw--sage\"></span>{{ AgentName }} <i class=\"fa-solid fa-feather legend-feather\"></i></span>\n </span>\n <div class=\"head-end\">\n <button type=\"button\" class=\"head-btn head-btn--sees\" [class.on]=\"SeesOpen\" (click)=\"ToggleSees($event)\">\n <span class=\"eye-pulse\"></span><i class=\"fa-regular fa-eye\"></i> What {{ AgentName }} sees\n @if (SeesOpen) {\n <mj-realtime-whiteboard-agent-sees-popover\n [AgentName]=\"AgentName\"\n [DeltaJson]=\"LastDeltaJson\"\n [DebounceMs]=\"SceneDeltaDebounceMs\"\n [ElementCount]=\"ElementCount\"\n [LastDeltaLabel]=\"LastDeltaLabel\"/>\n }\n </button>\n <span class=\"export-wrap\">\n <button type=\"button\" class=\"head-btn\" [class.on]=\"ExportOpen\" (click)=\"ToggleExport($event)\">\n <i class=\"fa-solid fa-file-export\"></i> Export\n </button>\n @if (ExportOpen) {\n <div class=\"export-menu\">\n <button type=\"button\" class=\"export-item\" (click)=\"ExportDownloadHtml()\">\n <i class=\"fa-solid fa-file-code\"></i> Download HTML\n </button>\n @if (HasMultiplePages) {\n <button type=\"button\" class=\"export-item\" (click)=\"ExportDownloadHtmlAllPages()\">\n <i class=\"fa-solid fa-file-code\"></i> Download HTML — all pages\n </button>\n }\n <button type=\"button\" class=\"export-item\" (click)=\"ExportDownloadSvg()\">\n <i class=\"fa-solid fa-bezier-curve\"></i> Download SVG\n </button>\n @if (HasMultiplePages) {\n <button type=\"button\" class=\"export-item\" title=\"One SVG file per page\"\n (click)=\"ExportDownloadSvgAllPages()\">\n <i class=\"fa-solid fa-bezier-curve\"></i> Download SVG — all pages\n </button>\n }\n <button type=\"button\" class=\"export-item\" (click)=\"ExportPrint()\">\n <i class=\"fa-solid fa-print\"></i> Print\n </button>\n <button type=\"button\" class=\"export-item\" (click)=\"ExportSaveToArtifacts()\">\n <i class=\"fa-solid fa-box-archive\"></i> Save to artifacts\n </button>\n </div>\n }\n </span>\n <button type=\"button\" class=\"head-btn\" [class.on]=\"FocusMode\" (click)=\"ToggleFocus()\">\n <i [class]=\"FocusMode ? 'fa-solid fa-compress' : 'fa-solid fa-expand'\"></i>\n {{ FocusMode ? 'Show thread' : 'Focus board' }}\n </button>\n <button type=\"button\" class=\"head-btn head-btn--more\" title=\"More\"><i class=\"fa-solid fa-ellipsis\"></i></button>\n </div>\n</div>\n\n<!-- the board -->\n<div class=\"board-wrap\">\n <mj-realtime-whiteboard #board\n [State]=\"State\"\n [AgentName]=\"AgentName\"\n [Tool]=\"Tool\"\n [PenColor]=\"PenColor\"\n [PenWidth]=\"PenWidth\"\n [ShapeKind]=\"ShapeKind\"\n [TextSize]=\"TextSize\"\n [TextFamily]=\"TextFamily\"\n [TextBold]=\"TextBold\"\n [TextColor]=\"TextColor\"\n [AgentPresence]=\"AgentPresence\"\n (ToolChangeRequest)=\"Tool = $event\"\n (WidgetSubmitting)=\"WidgetSubmitting.emit($event)\"\n (WidgetSubmitted)=\"WidgetSubmitted.emit($event)\"\n (WidgetInteraction)=\"WidgetInteraction.emit($event)\"\n (ContentApplying)=\"ContentApplying.emit($event)\"\n (ContentApplied)=\"ContentApplied.emit($event)\"/>\n\n <mj-realtime-whiteboard-toolbar\n [ActiveTool]=\"Tool\"\n [PenColor]=\"PenColor\"\n [PenWidth]=\"PenWidth\"\n [ShapeKind]=\"ShapeKind\"\n [TextSize]=\"TextSize\"\n [TextFamily]=\"TextFamily\"\n [TextBold]=\"TextBold\"\n [TextColor]=\"TextColor\"\n [CanUndo]=\"State.CanUndo\"\n [CanRedo]=\"State.CanRedo\"\n [AgentName]=\"AgentName\"\n (ToolChange)=\"Tool = $event\"\n (PenColorChange)=\"PenColor = $event\"\n (PenWidthChange)=\"PenWidth = $event\"\n (ShapeKindChange)=\"ShapeKind = $event\"\n (TextSizeChange)=\"TextSize = $event\"\n (TextFamilyChange)=\"TextFamily = $event\"\n (TextBoldChange)=\"TextBold = $event\"\n (TextColorChange)=\"TextColor = $event\"\n (StyleSelection)=\"board.ApplyTextStyleToSelection($event)\"\n (Undo)=\"State.Undo()\"\n (Redo)=\"State.Redo()\"/>\n\n <mj-realtime-whiteboard-zoom\n [ZoomPercent]=\"board.ZoomPercent\"\n [MinimapOpen]=\"board.MinimapOpen\"\n (ZoomOut)=\"board.ZoomOut()\"\n (ZoomIn)=\"board.ZoomIn()\"\n (ZoomBy)=\"board.ZoomByFactor($event)\"\n (Fit)=\"board.FitToContent()\"\n (ToggleMinimap)=\"board.ToggleMinimap()\"/>\n\n <!-- agent action toast -->\n @if (ToastText) {\n <div class=\"board-toast\">\n <i class=\"fa-solid fa-feather\"></i>\n <span class=\"board-toast__text\">{{ ToastText }}</span>\n <span class=\"undo\" (click)=\"OnToastUndo($event)\"><i class=\"fa-solid fa-rotate-left\"></i> Undo</span>\n </div>\n }\n</div>\n\n<!-- board status footer: ONE row, never wraps — items ellipsize, and the long\n persistence prose collapses to an icon chip (full text on its tooltip) when\n the host is narrow (container query on the host width). -->\n<div class=\"board-status\">\n <span class=\"stat\"><b>{{ ElementCount }}</b> elements</span>\n <span class=\"stat\">you <b>{{ UserCount }}</b> · {{ AgentName }} <b>{{ AgentCount }}</b></span>\n <span class=\"stat\">synced <b>{{ LastDeltaLabel }}</b> · seq <b>{{ CurrentSeq }}</b></span>\n <span class=\"seg-r\">\n <span class=\"stat ctx-live\" [title]=\"AgentName + '’s live context: current'\">\n <span class=\"d\"></span><span class=\"ctx-live__text\"> {{ AgentName }}'s live context: current</span>\n </span>\n <span class=\"stat persist\" title=\"Persists as a session artifact when the call ends\">\n <i class=\"fa-solid fa-box-archive\" aria-hidden=\"true\"></i>\n <span class=\"persist__long\">persists as <b>session artifact</b> when the call ends</span>\n <span class=\"persist__short\">session artifact</span>\n </span>\n </span>\n</div>\n"]}
@@ -0,0 +1,83 @@
1
+ import { AfterViewChecked, EventEmitter } from '@angular/core';
2
+ import { WhiteboardPageInfo, WhiteboardState } from './whiteboard-state';
3
+ import * as i0 from "@angular/core";
4
+ /** Payload of {@link RealtimeWhiteboardPagesComponent.ChipContextMenu} — a right-clicked page chip. */
5
+ export interface WhiteboardPageChipContextMenuEvent {
6
+ /** The original mouse event (for menu positioning; default menu already suppressed). */
7
+ Event: MouseEvent;
8
+ /** The page whose chip was right-clicked. */
9
+ Page: WhiteboardPageInfo;
10
+ }
11
+ /**
12
+ * The PAGE STRIP (`mj-realtime-whiteboard-pages`) — a compact, OneNote-style floating
13
+ * row of page chips on the board's bottom-left, hosted by the board surface so every
14
+ * consumer (live host, read-only snapshot viewer) gets page navigation for free.
15
+ *
16
+ * Interactions:
17
+ * - click a chip → {@link WhiteboardState.SwitchPage};
18
+ * - double-click a chip → inline rename (input swap; Enter commits via
19
+ * {@link WhiteboardState.RenamePage}, Esc cancels);
20
+ * - right-click a chip → {@link ChipContextMenu} fires and the BOARD renders its
21
+ * standard context menu with Rename / Delete entries (rename routes back into the
22
+ * strip's inline editor via {@link BeginRename});
23
+ * - the per-chip "×" (shown on hover when more than one page exists) →
24
+ * {@link WhiteboardState.RemovePage};
25
+ * - the trailing "+" → {@link WhiteboardState.AddPage} (auto-named "Page N").
26
+ *
27
+ * Agent-created pages (the `Whiteboard_AddPage` tool) carry the package's delegated
28
+ * violet authorship garnish on their chip — a small violet dot plus a violet ring —
29
+ * consistent with the violet treatment on agent-authored items.
30
+ *
31
+ * ReadOnly mode (artifact viewer / session review): chips still SWITCH pages — flipping
32
+ * through a saved board is navigation, not mutation — but add / rename / delete are
33
+ * hidden/disabled. All mutations go through the shared {@link WhiteboardState} engine,
34
+ * so the cancelable Page* before/after events and undo behave exactly as for the agent's
35
+ * page tools.
36
+ */
37
+ export declare class RealtimeWhiteboardPagesComponent implements AfterViewChecked {
38
+ /** Shared board state engine (owned by the integration layer, passed via the board). */
39
+ State: WhiteboardState;
40
+ /** Read-only mode: page switching stays available; add / rename / delete do not. */
41
+ ReadOnly: boolean;
42
+ /**
43
+ * A page chip was right-clicked (never fires in ReadOnly). The hosting board renders
44
+ * its standard context menu from this — see `BuildWhiteboardPageContextMenu`.
45
+ */
46
+ ChipContextMenu: EventEmitter<WhiteboardPageChipContextMenuEvent>;
47
+ /** ID of the page being renamed inline, or null when no rename is in flight. */
48
+ RenamingID: string | null;
49
+ private pendingFocus;
50
+ private elementRef;
51
+ /** The board's ordered page list (re-read every CD pass — cheap snapshots). */
52
+ get Pages(): WhiteboardPageInfo[];
53
+ /** Whether the delete affordance renders (never on the last page, never read-only). */
54
+ get CanDelete(): boolean;
55
+ ngAfterViewChecked(): void;
56
+ /** Click a chip → switch to that page (no-op when it is already active). */
57
+ OnChipClick(page: WhiteboardPageInfo): void;
58
+ /** Double-click a chip → swap it for the inline rename input (not in read-only). */
59
+ OnChipDblClick(event: Event, page: WhiteboardPageInfo): void;
60
+ /**
61
+ * Open the strip's inline-rename editor for a page (the same editor the dblclick
62
+ * path uses). Public so the board's context-menu "Rename page" action can route here.
63
+ * No-op in ReadOnly.
64
+ */
65
+ BeginRename(pageId: string): void;
66
+ /**
67
+ * Right-click a chip → suppress the native menu and hand the event to the board
68
+ * (which renders the page Rename / Delete context menu). Silent in ReadOnly — no
69
+ * board menu is offered on a read-only strip.
70
+ */
71
+ OnChipContextMenu(event: MouseEvent, page: WhiteboardPageInfo): void;
72
+ /** Enter commits the rename, Esc cancels; keys never leak to the board shortcuts. */
73
+ OnRenameKeydown(event: KeyboardEvent, value: string): void;
74
+ /** Commit the inline rename (blur or Enter). Empty input keeps the previous name. */
75
+ CommitRename(value: string): void;
76
+ /** The "+" button → add an auto-named page (the engine switches to it). */
77
+ OnAddPage(): void;
78
+ /** The per-chip "×" → remove the page (the engine guards the last page). */
79
+ OnDeletePage(event: Event, page: WhiteboardPageInfo): void;
80
+ static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeWhiteboardPagesComponent, never>;
81
+ static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeWhiteboardPagesComponent, "mj-realtime-whiteboard-pages", never, { "State": { "alias": "State"; "required": true; }; "ReadOnly": { "alias": "ReadOnly"; "required": false; }; }, { "ChipContextMenu": "ChipContextMenu"; }, never, never, true, never>;
82
+ }
83
+ //# sourceMappingURL=whiteboard-pages.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whiteboard-pages.component.d.ts","sourceRoot":"","sources":["../../src/lib/whiteboard-pages.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAyB,YAAY,EAAyB,MAAM,eAAe,CAAC;AAE7G,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;;AAEzE,uGAAuG;AACvG,MAAM,WAAW,kCAAkC;IACjD,wFAAwF;IACxF,KAAK,EAAE,UAAU,CAAC;IAClB,6CAA6C;IAC7C,IAAI,EAAE,kBAAkB,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAOa,gCAAiC,YAAW,gBAAgB;IACvE,wFAAwF;IAC7D,KAAK,EAAG,eAAe,CAAC;IACnD,oFAAoF;IAC3E,QAAQ,UAAS;IAE1B;;;OAGG;IACO,eAAe,mDAA0D;IAEnF,gFAAgF;IACzE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAA+C;IAEjE,+EAA+E;IAC/E,IAAW,KAAK,IAAI,kBAAkB,EAAE,CAEvC;IAED,uFAAuF;IACvF,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,kBAAkB,IAAI,IAAI;IAS1B,4EAA4E;IACrE,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAMlD,oFAAoF;IAC7E,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAKnE;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQxC;;;;OAIG;IACI,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAQ3E,qFAAqF;IAC9E,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAYjE,qFAAqF;IAC9E,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQxC,2EAA2E;IACpE,SAAS,IAAI,IAAI;IAMxB,4EAA4E;IACrE,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;yCA1GtD,gCAAgC;2CAAhC,gCAAgC;CAgH5C"}
@@ -0,0 +1,211 @@
1
+ import { Component, ElementRef, EventEmitter, Input, Output, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { WhiteboardState } from './whiteboard-state';
4
+ import * as i0 from "@angular/core";
5
+ const _forTrack0 = ($index, $item) => $item.ID;
6
+ function RealtimeWhiteboardPagesComponent_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
7
+ const _r1 = i0.ɵɵgetCurrentView();
8
+ i0.ɵɵdomElementStart(0, "input", 5, 0);
9
+ i0.ɵɵdomListener("keydown", function RealtimeWhiteboardPagesComponent_For_2_Conditional_0_Template_input_keydown_0_listener($event) { i0.ɵɵrestoreView(_r1); const rename_r2 = i0.ɵɵreference(1); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OnRenameKeydown($event, rename_r2.value)); })("blur", function RealtimeWhiteboardPagesComponent_For_2_Conditional_0_Template_input_blur_0_listener() { i0.ɵɵrestoreView(_r1); const rename_r2 = i0.ɵɵreference(1); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.CommitRename(rename_r2.value)); });
10
+ i0.ɵɵdomElementEnd();
11
+ } if (rf & 2) {
12
+ const page_r4 = i0.ɵɵnextContext().$implicit;
13
+ i0.ɵɵdomProperty("value", page_r4.Name);
14
+ } }
15
+ function RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
16
+ i0.ɵɵdomElement(0, "span", 7);
17
+ } }
18
+ function RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
19
+ const _r6 = i0.ɵɵgetCurrentView();
20
+ i0.ɵɵdomElementStart(0, "span", 10);
21
+ i0.ɵɵdomListener("click", function RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Conditional_4_Template_span_click_0_listener($event) { i0.ɵɵrestoreView(_r6); const page_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnDeletePage($event, page_r4)); });
22
+ i0.ɵɵdomElement(1, "i", 11);
23
+ i0.ɵɵdomElementEnd();
24
+ } }
25
+ function RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
26
+ const _r5 = i0.ɵɵgetCurrentView();
27
+ i0.ɵɵdomElementStart(0, "button", 6);
28
+ i0.ɵɵdomListener("click", function RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const page_r4 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnChipClick(page_r4)); })("dblclick", function RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Template_button_dblclick_0_listener($event) { i0.ɵɵrestoreView(_r5); const page_r4 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnChipDblClick($event, page_r4)); })("contextmenu", function RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Template_button_contextmenu_0_listener($event) { i0.ɵɵrestoreView(_r5); const page_r4 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnChipContextMenu($event, page_r4)); });
29
+ i0.ɵɵconditionalCreate(1, RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Conditional_1_Template, 1, 0, "span", 7);
30
+ i0.ɵɵdomElementStart(2, "span", 8);
31
+ i0.ɵɵtext(3);
32
+ i0.ɵɵdomElementEnd();
33
+ i0.ɵɵconditionalCreate(4, RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Conditional_4_Template, 2, 0, "span", 9);
34
+ i0.ɵɵdomElementEnd();
35
+ } if (rf & 2) {
36
+ const page_r4 = i0.ɵɵnextContext().$implicit;
37
+ const ctx_r2 = i0.ɵɵnextContext();
38
+ i0.ɵɵclassProp("active", page_r4.Active)("wb-page-chip--agent", page_r4.Author === "agent");
39
+ i0.ɵɵdomProperty("title", page_r4.Name + " \u00B7 " + page_r4.ItemCount + (page_r4.ItemCount === 1 ? " item" : " items") + (page_r4.Author === "agent" ? " \u00B7 created by the agent" : "") + (ctx_r2.ReadOnly ? "" : " \u2014 double-click to rename"));
40
+ i0.ɵɵadvance();
41
+ i0.ɵɵconditional(page_r4.Author === "agent" ? 1 : -1);
42
+ i0.ɵɵadvance(2);
43
+ i0.ɵɵtextInterpolate(page_r4.Name);
44
+ i0.ɵɵadvance();
45
+ i0.ɵɵconditional(ctx_r2.CanDelete ? 4 : -1);
46
+ } }
47
+ function RealtimeWhiteboardPagesComponent_For_2_Template(rf, ctx) { if (rf & 1) {
48
+ i0.ɵɵconditionalCreate(0, RealtimeWhiteboardPagesComponent_For_2_Conditional_0_Template, 2, 1, "input", 3)(1, RealtimeWhiteboardPagesComponent_For_2_Conditional_1_Template, 5, 8, "button", 4);
49
+ } if (rf & 2) {
50
+ const page_r4 = ctx.$implicit;
51
+ const ctx_r2 = i0.ɵɵnextContext();
52
+ i0.ɵɵconditional(ctx_r2.RenamingID === page_r4.ID ? 0 : 1);
53
+ } }
54
+ function RealtimeWhiteboardPagesComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
55
+ const _r7 = i0.ɵɵgetCurrentView();
56
+ i0.ɵɵdomElementStart(0, "button", 12);
57
+ i0.ɵɵdomListener("click", function RealtimeWhiteboardPagesComponent_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OnAddPage()); });
58
+ i0.ɵɵdomElement(1, "i", 13);
59
+ i0.ɵɵdomElementEnd();
60
+ } }
61
+ /**
62
+ * The PAGE STRIP (`mj-realtime-whiteboard-pages`) — a compact, OneNote-style floating
63
+ * row of page chips on the board's bottom-left, hosted by the board surface so every
64
+ * consumer (live host, read-only snapshot viewer) gets page navigation for free.
65
+ *
66
+ * Interactions:
67
+ * - click a chip → {@link WhiteboardState.SwitchPage};
68
+ * - double-click a chip → inline rename (input swap; Enter commits via
69
+ * {@link WhiteboardState.RenamePage}, Esc cancels);
70
+ * - right-click a chip → {@link ChipContextMenu} fires and the BOARD renders its
71
+ * standard context menu with Rename / Delete entries (rename routes back into the
72
+ * strip's inline editor via {@link BeginRename});
73
+ * - the per-chip "×" (shown on hover when more than one page exists) →
74
+ * {@link WhiteboardState.RemovePage};
75
+ * - the trailing "+" → {@link WhiteboardState.AddPage} (auto-named "Page N").
76
+ *
77
+ * Agent-created pages (the `Whiteboard_AddPage` tool) carry the package's delegated
78
+ * violet authorship garnish on their chip — a small violet dot plus a violet ring —
79
+ * consistent with the violet treatment on agent-authored items.
80
+ *
81
+ * ReadOnly mode (artifact viewer / session review): chips still SWITCH pages — flipping
82
+ * through a saved board is navigation, not mutation — but add / rename / delete are
83
+ * hidden/disabled. All mutations go through the shared {@link WhiteboardState} engine,
84
+ * so the cancelable Page* before/after events and undo behave exactly as for the agent's
85
+ * page tools.
86
+ */
87
+ export class RealtimeWhiteboardPagesComponent {
88
+ constructor() {
89
+ /** Read-only mode: page switching stays available; add / rename / delete do not. */
90
+ this.ReadOnly = false;
91
+ /**
92
+ * A page chip was right-clicked (never fires in ReadOnly). The hosting board renders
93
+ * its standard context menu from this — see `BuildWhiteboardPageContextMenu`.
94
+ */
95
+ this.ChipContextMenu = new EventEmitter();
96
+ /** ID of the page being renamed inline, or null when no rename is in flight. */
97
+ this.RenamingID = null;
98
+ this.pendingFocus = false;
99
+ this.elementRef = inject(ElementRef);
100
+ }
101
+ /** The board's ordered page list (re-read every CD pass — cheap snapshots). */
102
+ get Pages() {
103
+ return this.State.Pages;
104
+ }
105
+ /** Whether the delete affordance renders (never on the last page, never read-only). */
106
+ get CanDelete() {
107
+ return !this.ReadOnly && this.State.Pages.length > 1;
108
+ }
109
+ ngAfterViewChecked() {
110
+ if (this.pendingFocus) {
111
+ this.pendingFocus = false;
112
+ const input = this.elementRef.nativeElement.querySelector('.wb-page-rename');
113
+ input?.focus();
114
+ input?.select();
115
+ }
116
+ }
117
+ /** Click a chip → switch to that page (no-op when it is already active). */
118
+ OnChipClick(page) {
119
+ if (!page.Active) {
120
+ this.State.SwitchPage(page.ID, 'user');
121
+ }
122
+ }
123
+ /** Double-click a chip → swap it for the inline rename input (not in read-only). */
124
+ OnChipDblClick(event, page) {
125
+ event.stopPropagation();
126
+ this.BeginRename(page.ID);
127
+ }
128
+ /**
129
+ * Open the strip's inline-rename editor for a page (the same editor the dblclick
130
+ * path uses). Public so the board's context-menu "Rename page" action can route here.
131
+ * No-op in ReadOnly.
132
+ */
133
+ BeginRename(pageId) {
134
+ if (this.ReadOnly) {
135
+ return;
136
+ }
137
+ this.RenamingID = pageId;
138
+ this.pendingFocus = true;
139
+ }
140
+ /**
141
+ * Right-click a chip → suppress the native menu and hand the event to the board
142
+ * (which renders the page Rename / Delete context menu). Silent in ReadOnly — no
143
+ * board menu is offered on a read-only strip.
144
+ */
145
+ OnChipContextMenu(event, page) {
146
+ event.preventDefault();
147
+ event.stopPropagation();
148
+ if (!this.ReadOnly) {
149
+ this.ChipContextMenu.emit({ Event: event, Page: page });
150
+ }
151
+ }
152
+ /** Enter commits the rename, Esc cancels; keys never leak to the board shortcuts. */
153
+ OnRenameKeydown(event, value) {
154
+ event.stopPropagation();
155
+ if (event.key === 'Enter') {
156
+ event.preventDefault();
157
+ this.CommitRename(value);
158
+ }
159
+ else if (event.key === 'Escape') {
160
+ event.preventDefault();
161
+ this.RenamingID = null; // cancel — the input unmounts; its blur finds no rename in flight
162
+ }
163
+ }
164
+ /** Commit the inline rename (blur or Enter). Empty input keeps the previous name. */
165
+ CommitRename(value) {
166
+ const id = this.RenamingID;
167
+ this.RenamingID = null;
168
+ if (id && value.trim().length > 0) {
169
+ this.State.RenamePage(id, value, 'user');
170
+ }
171
+ }
172
+ /** The "+" button → add an auto-named page (the engine switches to it). */
173
+ OnAddPage() {
174
+ if (!this.ReadOnly) {
175
+ this.State.AddPage(undefined, 'user');
176
+ }
177
+ }
178
+ /** The per-chip "×" → remove the page (the engine guards the last page). */
179
+ OnDeletePage(event, page) {
180
+ event.stopPropagation();
181
+ if (!this.ReadOnly) {
182
+ this.State.RemovePage(page.ID, 'user');
183
+ }
184
+ }
185
+ static { this.ɵfac = function RealtimeWhiteboardPagesComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeWhiteboardPagesComponent)(); }; }
186
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeWhiteboardPagesComponent, selectors: [["mj-realtime-whiteboard-pages"]], inputs: { State: "State", ReadOnly: "ReadOnly" }, outputs: { ChipContextMenu: "ChipContextMenu" }, decls: 4, vars: 1, consts: [["rename", ""], [1, "wb-pages", 3, "pointerdown", "dblclick", "wheel", "contextmenu"], ["type", "button", "title", "Add page", 1, "wb-page-add"], ["type", "text", 1, "wb-page-rename", 3, "value"], ["type", "button", 1, "wb-page-chip", 3, "active", "wb-page-chip--agent", "title"], ["type", "text", 1, "wb-page-rename", 3, "keydown", "blur", "value"], ["type", "button", 1, "wb-page-chip", 3, "click", "dblclick", "contextmenu", "title"], ["aria-hidden", "true", 1, "wb-page-chip__agent-dot"], [1, "wb-page-chip__name"], ["role", "button", "title", "Delete page", 1, "wb-page-chip__close"], ["role", "button", "title", "Delete page", 1, "wb-page-chip__close", 3, "click"], [1, "fa-solid", "fa-xmark"], ["type", "button", "title", "Add page", 1, "wb-page-add", 3, "click"], [1, "fa-solid", "fa-plus"]], template: function RealtimeWhiteboardPagesComponent_Template(rf, ctx) { if (rf & 1) {
187
+ i0.ɵɵdomElementStart(0, "div", 1);
188
+ i0.ɵɵdomListener("pointerdown", function RealtimeWhiteboardPagesComponent_Template_div_pointerdown_0_listener($event) { return $event.stopPropagation(); })("dblclick", function RealtimeWhiteboardPagesComponent_Template_div_dblclick_0_listener($event) { return $event.stopPropagation(); })("wheel", function RealtimeWhiteboardPagesComponent_Template_div_wheel_0_listener($event) { return $event.stopPropagation(); })("contextmenu", function RealtimeWhiteboardPagesComponent_Template_div_contextmenu_0_listener($event) { $event.stopPropagation(); return $event.preventDefault(); });
189
+ i0.ɵɵrepeaterCreate(1, RealtimeWhiteboardPagesComponent_For_2_Template, 2, 1, null, null, _forTrack0);
190
+ i0.ɵɵconditionalCreate(3, RealtimeWhiteboardPagesComponent_Conditional_3_Template, 2, 0, "button", 2);
191
+ i0.ɵɵdomElementEnd();
192
+ } if (rf & 2) {
193
+ i0.ɵɵadvance();
194
+ i0.ɵɵrepeater(ctx.Pages);
195
+ i0.ɵɵadvance(2);
196
+ i0.ɵɵconditional(!ctx.ReadOnly ? 3 : -1);
197
+ } }, dependencies: [CommonModule], styles: ["\n\n\n\n[_nghost-%COMP%] {\n display: block;\n position: absolute;\n left: 14px;\n bottom: 14px;\n z-index: 10;\n \n\n max-width: calc(100% - 240px);\n \n\n --sage: var(--mj-color-violet-400, #a78bfa);\n}\n\n.wb-pages[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 4px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n box-shadow: var(--mj-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.3));\n overflow-x: auto;\n scrollbar-width: none;\n}\n.wb-pages[_ngcontent-%COMP%]::-webkit-scrollbar {\n display: none;\n}\n\n.wb-page-chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n height: 26px;\n padding: 0 10px;\n border: 0;\n border-radius: var(--mj-radius-full, 9999px);\n background: transparent;\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n white-space: nowrap;\n cursor: pointer;\n transition: background 120ms ease, color 120ms ease;\n}\n.wb-page-chip[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.wb-page-chip.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n\n.wb-page-chip__name[_ngcontent-%COMP%] {\n max-width: 140px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n\n\n.wb-page-chip--agent[_ngcontent-%COMP%] {\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sage) 45%, transparent);\n}\n.wb-page-chip__agent-dot[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n}\n.wb-page-chip.active.wb-page-chip--agent[_ngcontent-%COMP%] {\n \n\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mj-color-violet-300, #c4b5fd) 80%, transparent);\n}\n.wb-page-chip.active[_ngcontent-%COMP%] .wb-page-chip__agent-dot[_ngcontent-%COMP%] {\n background: var(--mj-color-violet-300, #c4b5fd);\n}\n\n.wb-page-chip__close[_ngcontent-%COMP%] {\n display: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n font-size: 9px;\n line-height: 14px;\n text-align: center;\n color: inherit;\n opacity: 0.75;\n}\n.wb-page-chip[_ngcontent-%COMP%]:hover .wb-page-chip__close[_ngcontent-%COMP%] {\n display: inline-block;\n}\n.wb-page-chip__close[_ngcontent-%COMP%]:hover {\n opacity: 1;\n background: color-mix(in srgb, var(--mj-status-error) 22%, transparent);\n color: var(--mj-status-error-text, var(--mj-status-error));\n}\n.wb-page-chip.active[_ngcontent-%COMP%] .wb-page-chip__close[_ngcontent-%COMP%]:hover {\n \n\n color: var(--mj-text-inverse, #fff);\n}\n\n.wb-page-rename[_ngcontent-%COMP%] {\n height: 26px;\n width: 124px;\n padding: 0 9px;\n border: 1px solid var(--mj-border-focus, var(--mj-brand-primary));\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n outline: none;\n}\n\n.wb-page-add[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n width: 26px;\n height: 26px;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 11px;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-family: inherit;\n}\n.wb-page-add[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}"] }); }
198
+ }
199
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeWhiteboardPagesComponent, [{
200
+ type: Component,
201
+ args: [{ standalone: true, selector: 'mj-realtime-whiteboard-pages', imports: [CommonModule], template: "<!-- The strip swallows pointer/dblclick/contextmenu so board tools never fire under it. -->\n<div class=\"wb-pages\"\n (pointerdown)=\"$event.stopPropagation()\"\n (dblclick)=\"$event.stopPropagation()\"\n (wheel)=\"$event.stopPropagation()\"\n (contextmenu)=\"$event.stopPropagation(); $event.preventDefault()\">\n @for (page of Pages; track page.ID) {\n @if (RenamingID === page.ID) {\n <input class=\"wb-page-rename\" type=\"text\" #rename\n [value]=\"page.Name\"\n (keydown)=\"OnRenameKeydown($event, rename.value)\"\n (blur)=\"CommitRename(rename.value)\"/>\n } @else {\n <button type=\"button\" class=\"wb-page-chip\"\n [class.active]=\"page.Active\"\n [class.wb-page-chip--agent]=\"page.Author === 'agent'\"\n [title]=\"page.Name + ' \u00B7 ' + page.ItemCount + (page.ItemCount === 1 ? ' item' : ' items') + (page.Author === 'agent' ? ' \u00B7 created by the agent' : '') + (ReadOnly ? '' : ' \u2014 double-click to rename')\"\n (click)=\"OnChipClick(page)\"\n (dblclick)=\"OnChipDblClick($event, page)\"\n (contextmenu)=\"OnChipContextMenu($event, page)\">\n @if (page.Author === 'agent') {\n <span class=\"wb-page-chip__agent-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"wb-page-chip__name\">{{ page.Name }}</span>\n @if (CanDelete) {\n <span class=\"wb-page-chip__close\" role=\"button\" title=\"Delete page\"\n (click)=\"OnDeletePage($event, page)\"><i class=\"fa-solid fa-xmark\"></i></span>\n }\n </button>\n }\n }\n @if (!ReadOnly) {\n <button type=\"button\" class=\"wb-page-add\" title=\"Add page\" (click)=\"OnAddPage()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n</div>\n", styles: ["/* Bottom-left floating page strip \u2014 OneNote-style tabs, styled with the same\n token vocabulary as the zoom cluster (whiteboard-zoom.component.css). */\n\n:host {\n display: block;\n position: absolute;\n left: 14px;\n bottom: 14px;\n z-index: 10;\n /* leave room for the bottom-right zoom cluster */\n max-width: calc(100% - 240px);\n /* agent (violet) accent \u2014 same derivation as the board's item-level treatment */\n --sage: var(--mj-color-violet-400, #a78bfa);\n}\n\n.wb-pages {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 4px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n box-shadow: var(--mj-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.3));\n overflow-x: auto;\n scrollbar-width: none;\n}\n.wb-pages::-webkit-scrollbar {\n display: none;\n}\n\n.wb-page-chip {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n height: 26px;\n padding: 0 10px;\n border: 0;\n border-radius: var(--mj-radius-full, 9999px);\n background: transparent;\n color: var(--mj-text-secondary);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n white-space: nowrap;\n cursor: pointer;\n transition: background 120ms ease, color 120ms ease;\n}\n.wb-page-chip:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.wb-page-chip.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n}\n\n.wb-page-chip__name {\n max-width: 140px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Delegated-violet garnish for AGENT-created pages: a violet dot + a soft violet ring,\n mirroring the violet authorship treatment on agent-authored board items. */\n.wb-page-chip--agent {\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sage) 45%, transparent);\n}\n.wb-page-chip__agent-dot {\n flex: 0 0 auto;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n}\n.wb-page-chip.active.wb-page-chip--agent {\n /* keep the garnish legible on the filled active chip */\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mj-color-violet-300, #c4b5fd) 80%, transparent);\n}\n.wb-page-chip.active .wb-page-chip__agent-dot {\n background: var(--mj-color-violet-300, #c4b5fd);\n}\n\n.wb-page-chip__close {\n display: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n font-size: 9px;\n line-height: 14px;\n text-align: center;\n color: inherit;\n opacity: 0.75;\n}\n.wb-page-chip:hover .wb-page-chip__close {\n display: inline-block;\n}\n.wb-page-chip__close:hover {\n opacity: 1;\n background: color-mix(in srgb, var(--mj-status-error) 22%, transparent);\n color: var(--mj-status-error-text, var(--mj-status-error));\n}\n.wb-page-chip.active .wb-page-chip__close:hover {\n /* on the filled active chip, keep the glyph legible against the brand fill */\n color: var(--mj-text-inverse, #fff);\n}\n\n.wb-page-rename {\n height: 26px;\n width: 124px;\n padding: 0 9px;\n border: 1px solid var(--mj-border-focus, var(--mj-brand-primary));\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n outline: none;\n}\n\n.wb-page-add {\n flex: 0 0 auto;\n width: 26px;\n height: 26px;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 11px;\n display: grid;\n place-items: center;\n cursor: pointer;\n font-family: inherit;\n}\n.wb-page-add:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n"] }]
202
+ }], null, { State: [{
203
+ type: Input,
204
+ args: [{ required: true }]
205
+ }], ReadOnly: [{
206
+ type: Input
207
+ }], ChipContextMenu: [{
208
+ type: Output
209
+ }] }); })();
210
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeWhiteboardPagesComponent, { className: "RealtimeWhiteboardPagesComponent", filePath: "src/lib/whiteboard-pages.component.ts", lineNumber: 46 }); })();
211
+ //# sourceMappingURL=whiteboard-pages.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whiteboard-pages.component.js","sourceRoot":"","sources":["../../src/lib/whiteboard-pages.component.ts","../../src/lib/whiteboard-pages.component.html"],"names":[],"mappings":"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","sourcesContent":["import { AfterViewChecked, Component, ElementRef, EventEmitter, Input, Output, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { WhiteboardPageInfo, WhiteboardState } from './whiteboard-state';\n\n/** Payload of {@link RealtimeWhiteboardPagesComponent.ChipContextMenu} — a right-clicked page chip. */\nexport interface WhiteboardPageChipContextMenuEvent {\n /** The original mouse event (for menu positioning; default menu already suppressed). */\n Event: MouseEvent;\n /** The page whose chip was right-clicked. */\n Page: WhiteboardPageInfo;\n}\n\n/**\n * The PAGE STRIP (`mj-realtime-whiteboard-pages`) — a compact, OneNote-style floating\n * row of page chips on the board's bottom-left, hosted by the board surface so every\n * consumer (live host, read-only snapshot viewer) gets page navigation for free.\n *\n * Interactions:\n * - click a chip → {@link WhiteboardState.SwitchPage};\n * - double-click a chip → inline rename (input swap; Enter commits via\n * {@link WhiteboardState.RenamePage}, Esc cancels);\n * - right-click a chip → {@link ChipContextMenu} fires and the BOARD renders its\n * standard context menu with Rename / Delete entries (rename routes back into the\n * strip's inline editor via {@link BeginRename});\n * - the per-chip \"×\" (shown on hover when more than one page exists) →\n * {@link WhiteboardState.RemovePage};\n * - the trailing \"+\" → {@link WhiteboardState.AddPage} (auto-named \"Page N\").\n *\n * Agent-created pages (the `Whiteboard_AddPage` tool) carry the package's delegated\n * violet authorship garnish on their chip — a small violet dot plus a violet ring —\n * consistent with the violet treatment on agent-authored items.\n *\n * ReadOnly mode (artifact viewer / session review): chips still SWITCH pages — flipping\n * through a saved board is navigation, not mutation — but add / rename / delete are\n * hidden/disabled. All mutations go through the shared {@link WhiteboardState} engine,\n * so the cancelable Page* before/after events and undo behave exactly as for the agent's\n * page tools.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-whiteboard-pages',\n imports: [CommonModule],\n templateUrl: './whiteboard-pages.component.html',\n styleUrl: './whiteboard-pages.component.css'\n})\nexport class RealtimeWhiteboardPagesComponent implements AfterViewChecked {\n /** Shared board state engine (owned by the integration layer, passed via the board). */\n @Input({ required: true }) State!: WhiteboardState;\n /** Read-only mode: page switching stays available; add / rename / delete do not. */\n @Input() ReadOnly = false;\n\n /**\n * A page chip was right-clicked (never fires in ReadOnly). The hosting board renders\n * its standard context menu from this — see `BuildWhiteboardPageContextMenu`.\n */\n @Output() ChipContextMenu = new EventEmitter<WhiteboardPageChipContextMenuEvent>();\n\n /** ID of the page being renamed inline, or null when no rename is in flight. */\n public RenamingID: string | null = null;\n\n private pendingFocus = false;\n private elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /** The board's ordered page list (re-read every CD pass — cheap snapshots). */\n public get Pages(): WhiteboardPageInfo[] {\n return this.State.Pages;\n }\n\n /** Whether the delete affordance renders (never on the last page, never read-only). */\n public get CanDelete(): boolean {\n return !this.ReadOnly && this.State.Pages.length > 1;\n }\n\n ngAfterViewChecked(): void {\n if (this.pendingFocus) {\n this.pendingFocus = false;\n const input = this.elementRef.nativeElement.querySelector<HTMLInputElement>('.wb-page-rename');\n input?.focus();\n input?.select();\n }\n }\n\n /** Click a chip → switch to that page (no-op when it is already active). */\n public OnChipClick(page: WhiteboardPageInfo): void {\n if (!page.Active) {\n this.State.SwitchPage(page.ID, 'user');\n }\n }\n\n /** Double-click a chip → swap it for the inline rename input (not in read-only). */\n public OnChipDblClick(event: Event, page: WhiteboardPageInfo): void {\n event.stopPropagation();\n this.BeginRename(page.ID);\n }\n\n /**\n * Open the strip's inline-rename editor for a page (the same editor the dblclick\n * path uses). Public so the board's context-menu \"Rename page\" action can route here.\n * No-op in ReadOnly.\n */\n public BeginRename(pageId: string): void {\n if (this.ReadOnly) {\n return;\n }\n this.RenamingID = pageId;\n this.pendingFocus = true;\n }\n\n /**\n * Right-click a chip → suppress the native menu and hand the event to the board\n * (which renders the page Rename / Delete context menu). Silent in ReadOnly — no\n * board menu is offered on a read-only strip.\n */\n public OnChipContextMenu(event: MouseEvent, page: WhiteboardPageInfo): void {\n event.preventDefault();\n event.stopPropagation();\n if (!this.ReadOnly) {\n this.ChipContextMenu.emit({ Event: event, Page: page });\n }\n }\n\n /** Enter commits the rename, Esc cancels; keys never leak to the board shortcuts. */\n public OnRenameKeydown(event: KeyboardEvent, value: string): void {\n event.stopPropagation();\n if (event.key === 'Enter') {\n event.preventDefault();\n this.CommitRename(value);\n }\n else if (event.key === 'Escape') {\n event.preventDefault();\n this.RenamingID = null; // cancel — the input unmounts; its blur finds no rename in flight\n }\n }\n\n /** Commit the inline rename (blur or Enter). Empty input keeps the previous name. */\n public CommitRename(value: string): void {\n const id = this.RenamingID;\n this.RenamingID = null;\n if (id && value.trim().length > 0) {\n this.State.RenamePage(id, value, 'user');\n }\n }\n\n /** The \"+\" button → add an auto-named page (the engine switches to it). */\n public OnAddPage(): void {\n if (!this.ReadOnly) {\n this.State.AddPage(undefined, 'user');\n }\n }\n\n /** The per-chip \"×\" → remove the page (the engine guards the last page). */\n public OnDeletePage(event: Event, page: WhiteboardPageInfo): void {\n event.stopPropagation();\n if (!this.ReadOnly) {\n this.State.RemovePage(page.ID, 'user');\n }\n }\n}\n","<!-- The strip swallows pointer/dblclick/contextmenu so board tools never fire under it. -->\n<div class=\"wb-pages\"\n (pointerdown)=\"$event.stopPropagation()\"\n (dblclick)=\"$event.stopPropagation()\"\n (wheel)=\"$event.stopPropagation()\"\n (contextmenu)=\"$event.stopPropagation(); $event.preventDefault()\">\n @for (page of Pages; track page.ID) {\n @if (RenamingID === page.ID) {\n <input class=\"wb-page-rename\" type=\"text\" #rename\n [value]=\"page.Name\"\n (keydown)=\"OnRenameKeydown($event, rename.value)\"\n (blur)=\"CommitRename(rename.value)\"/>\n } @else {\n <button type=\"button\" class=\"wb-page-chip\"\n [class.active]=\"page.Active\"\n [class.wb-page-chip--agent]=\"page.Author === 'agent'\"\n [title]=\"page.Name + ' · ' + page.ItemCount + (page.ItemCount === 1 ? ' item' : ' items') + (page.Author === 'agent' ? ' · created by the agent' : '') + (ReadOnly ? '' : ' — double-click to rename')\"\n (click)=\"OnChipClick(page)\"\n (dblclick)=\"OnChipDblClick($event, page)\"\n (contextmenu)=\"OnChipContextMenu($event, page)\">\n @if (page.Author === 'agent') {\n <span class=\"wb-page-chip__agent-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"wb-page-chip__name\">{{ page.Name }}</span>\n @if (CanDelete) {\n <span class=\"wb-page-chip__close\" role=\"button\" title=\"Delete page\"\n (click)=\"OnDeletePage($event, page)\"><i class=\"fa-solid fa-xmark\"></i></span>\n }\n </button>\n }\n }\n @if (!ReadOnly) {\n <button type=\"button\" class=\"wb-page-add\" title=\"Add page\" (click)=\"OnAddPage()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n }\n</div>\n"]}
@@ -0,0 +1,30 @@
1
+ import { WhiteboardState } from './whiteboard-state';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Parse a persisted whiteboard payload ({@link WhiteboardState.ToJSON} output) into a
5
+ * rehydrated engine instance. PURE + TOLERANT: any malformed input (empty, non-JSON,
6
+ * JSON of the wrong shape) returns `null` instead of throwing — callers render an
7
+ * empty state rather than breaking the surface they're embedded in.
8
+ */
9
+ export declare function ParseBoardStateJson(json: string | null | undefined): WhiteboardState | null;
10
+ /**
11
+ * READ-ONLY SNAPSHOT of a whiteboard — renders a persisted board payload (the
12
+ * session-channel artifact JSON) through the real board component in `ReadOnly` mode,
13
+ * so a saved board looks exactly like the live one: same chips, shapes, ink and
14
+ * connectors, with pan + zoom still available for navigation but every mutating
15
+ * interaction disabled. Used by the whiteboard artifact viewer plugin and any
16
+ * session-review surface that wants to show a board without an engine wired to tools.
17
+ */
18
+ export declare class WhiteboardSnapshotComponent {
19
+ private _stateJson;
20
+ /** Rehydrated board engine (null when the payload is empty/malformed). */
21
+ State: WhiteboardState | null;
22
+ /** Persisted board payload — setter-driven so a new artifact version re-parses. */
23
+ set StateJson(value: string);
24
+ get StateJson(): string;
25
+ /** Display name of the session's agent — ownership chips on the rendered board. */
26
+ AgentName: string;
27
+ static ɵfac: i0.ɵɵFactoryDeclaration<WhiteboardSnapshotComponent, never>;
28
+ static ɵcmp: i0.ɵɵComponentDeclaration<WhiteboardSnapshotComponent, "mj-whiteboard-snapshot", never, { "StateJson": { "alias": "StateJson"; "required": false; }; "AgentName": { "alias": "AgentName"; "required": false; }; }, {}, never, never, true, never>;
29
+ }
30
+ //# sourceMappingURL=whiteboard-snapshot.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whiteboard-snapshot.component.d.ts","sourceRoot":"","sources":["../../src/lib/whiteboard-snapshot.component.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;;AAErD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,eAAe,GAAG,IAAI,CAS3F;AAED;;;;;;;GAOG;AACH,qBAgDa,2BAA2B;IACtC,OAAO,CAAC,UAAU,CAAM;IAExB,0EAA0E;IACnE,KAAK,EAAE,eAAe,GAAG,IAAI,CAAQ;IAE5C,mFAAmF;IACnF,IACI,SAAS,CAAC,KAAK,EAAE,MAAM,EAK1B;IACD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,mFAAmF;IAC1E,SAAS,SAAW;yCAnBlB,2BAA2B;2CAA3B,2BAA2B;CAoBvC"}
@@ -0,0 +1,91 @@
1
+ import { Component, Input } from '@angular/core';
2
+ import { RealtimeWhiteboardBoardComponent } from './whiteboard-board.component';
3
+ import { WhiteboardState } from './whiteboard-state';
4
+ import * as i0 from "@angular/core";
5
+ function WhiteboardSnapshotComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
6
+ i0.ɵɵelementStart(0, "div", 0);
7
+ i0.ɵɵelement(1, "mj-realtime-whiteboard", 2);
8
+ i0.ɵɵelementEnd();
9
+ } if (rf & 2) {
10
+ const ctx_r0 = i0.ɵɵnextContext();
11
+ i0.ɵɵadvance();
12
+ i0.ɵɵproperty("State", ctx_r0.State)("AgentName", ctx_r0.AgentName)("ReadOnly", true)("Tool", "pan");
13
+ } }
14
+ function WhiteboardSnapshotComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
15
+ i0.ɵɵelementStart(0, "div", 1);
16
+ i0.ɵɵelement(1, "i", 3);
17
+ i0.ɵɵelementStart(2, "span");
18
+ i0.ɵɵtext(3, "No board content");
19
+ i0.ɵɵelementEnd()();
20
+ } }
21
+ /**
22
+ * Parse a persisted whiteboard payload ({@link WhiteboardState.ToJSON} output) into a
23
+ * rehydrated engine instance. PURE + TOLERANT: any malformed input (empty, non-JSON,
24
+ * JSON of the wrong shape) returns `null` instead of throwing — callers render an
25
+ * empty state rather than breaking the surface they're embedded in.
26
+ */
27
+ export function ParseBoardStateJson(json) {
28
+ if (!json || json.trim().length === 0) {
29
+ return null;
30
+ }
31
+ try {
32
+ return WhiteboardState.FromJSON(json);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ /**
39
+ * READ-ONLY SNAPSHOT of a whiteboard — renders a persisted board payload (the
40
+ * session-channel artifact JSON) through the real board component in `ReadOnly` mode,
41
+ * so a saved board looks exactly like the live one: same chips, shapes, ink and
42
+ * connectors, with pan + zoom still available for navigation but every mutating
43
+ * interaction disabled. Used by the whiteboard artifact viewer plugin and any
44
+ * session-review surface that wants to show a board without an engine wired to tools.
45
+ */
46
+ export class WhiteboardSnapshotComponent {
47
+ constructor() {
48
+ this._stateJson = '';
49
+ /** Rehydrated board engine (null when the payload is empty/malformed). */
50
+ this.State = null;
51
+ /** Display name of the session's agent — ownership chips on the rendered board. */
52
+ this.AgentName = 'Agent';
53
+ }
54
+ /** Persisted board payload — setter-driven so a new artifact version re-parses. */
55
+ set StateJson(value) {
56
+ if (value !== this._stateJson) {
57
+ this._stateJson = value;
58
+ this.State = ParseBoardStateJson(value);
59
+ }
60
+ }
61
+ get StateJson() {
62
+ return this._stateJson;
63
+ }
64
+ static { this.ɵfac = function WhiteboardSnapshotComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WhiteboardSnapshotComponent)(); }; }
65
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: WhiteboardSnapshotComponent, selectors: [["mj-whiteboard-snapshot"]], inputs: { StateJson: "StateJson", AgentName: "AgentName" }, decls: 2, vars: 1, consts: [[1, "wb-snapshot-board"], [1, "wb-snapshot-empty"], [3, "State", "AgentName", "ReadOnly", "Tool"], ["aria-hidden", "true", 1, "fa-solid", "fa-chalkboard"]], template: function WhiteboardSnapshotComponent_Template(rf, ctx) { if (rf & 1) {
66
+ i0.ɵɵconditionalCreate(0, WhiteboardSnapshotComponent_Conditional_0_Template, 2, 4, "div", 0)(1, WhiteboardSnapshotComponent_Conditional_1_Template, 4, 0, "div", 1);
67
+ } if (rf & 2) {
68
+ i0.ɵɵconditional(ctx.State ? 0 : 1);
69
+ } }, dependencies: [RealtimeWhiteboardBoardComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n height: 100%;\n min-height: 320px;\n }\n \n\n .wb-snapshot-board[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-height: 0;\n }\n .wb-snapshot-empty[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md, 6px);\n font-size: 13px;\n }\n .wb-snapshot-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 22px;\n color: var(--mj-text-disabled);\n }"] }); }
70
+ }
71
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(WhiteboardSnapshotComponent, [{
72
+ type: Component,
73
+ args: [{ standalone: true, selector: 'mj-whiteboard-snapshot', imports: [RealtimeWhiteboardBoardComponent], template: `
74
+ @if (State) {
75
+ <div class="wb-snapshot-board">
76
+ <mj-realtime-whiteboard [State]="State" [AgentName]="AgentName" [ReadOnly]="true" [Tool]="'pan'" />
77
+ </div>
78
+ } @else {
79
+ <div class="wb-snapshot-empty">
80
+ <i class="fa-solid fa-chalkboard" aria-hidden="true"></i>
81
+ <span>No board content</span>
82
+ </div>
83
+ }
84
+ `, styles: ["\n :host {\n display: flex;\n flex-direction: column;\n flex: 1;\n height: 100%;\n min-height: 320px;\n }\n /* the board component positions itself absolute, so give it a relative frame */\n .wb-snapshot-board {\n position: relative;\n flex: 1;\n min-height: 0;\n }\n .wb-snapshot-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md, 6px);\n font-size: 13px;\n }\n .wb-snapshot-empty i {\n font-size: 22px;\n color: var(--mj-text-disabled);\n }\n "] }]
85
+ }], null, { StateJson: [{
86
+ type: Input
87
+ }], AgentName: [{
88
+ type: Input
89
+ }] }); })();
90
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(WhiteboardSnapshotComponent, { className: "WhiteboardSnapshotComponent", filePath: "src/lib/whiteboard-snapshot.component.ts", lineNumber: 78 }); })();
91
+ //# sourceMappingURL=whiteboard-snapshot.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whiteboard-snapshot.component.js","sourceRoot":"","sources":["../../src/lib/whiteboard-snapshot.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;;;IAiC/C,8BAA+B;IAC7B,4CAAmG;IACrG,iBAAM;;;IADoB,cAAe;IAA2C,AAAlB,AAAxB,AAAhB,oCAAe,+BAAwB,kBAAkB,eAAe;;;IAGlG,8BAA+B;IAC7B,uBAAyD;IACzD,4BAAM;IAAA,gCAAgB;IACxB,AADwB,iBAAO,EACzB;;AAtCZ;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAA+B;IACjE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AAiDH,MAAM,OAAO,2BAA2B;IAhDxC;QAiDU,eAAU,GAAG,EAAE,CAAC;QAExB,0EAA0E;QACnE,UAAK,GAA2B,IAAI,CAAC;QAc5C,mFAAmF;QAC1E,cAAS,GAAG,OAAO,CAAC;KAC9B;IAdC,mFAAmF;IACnF,IACI,SAAS,CAAC,KAAa;QACzB,IAAI,KAAK,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YAC9B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;4HAhBU,2BAA2B;oEAA3B,2BAA2B;YAvClC,AAJF,6FAAa,uEAIJ;;YAJT,mCASC;4BAXO,gCAAgC;;iFA6C/B,2BAA2B;cAhDvC,SAAS;6BACI,IAAI,YACN,wBAAwB,WACzB,CAAC,gCAAgC,CAAC,YACjC;;;;;;;;;;;GAWT;;kBAwCA,KAAK;;kBAYL,KAAK;;kFAnBK,2BAA2B","sourcesContent":["import { Component, Input } from '@angular/core';\nimport { RealtimeWhiteboardBoardComponent } from './whiteboard-board.component';\nimport { WhiteboardState } from './whiteboard-state';\n\n/**\n * Parse a persisted whiteboard payload ({@link WhiteboardState.ToJSON} output) into a\n * rehydrated engine instance. PURE + TOLERANT: any malformed input (empty, non-JSON,\n * JSON of the wrong shape) returns `null` instead of throwing — callers render an\n * empty state rather than breaking the surface they're embedded in.\n */\nexport function ParseBoardStateJson(json: string | null | undefined): WhiteboardState | null {\n if (!json || json.trim().length === 0) {\n return null;\n }\n try {\n return WhiteboardState.FromJSON(json);\n } catch {\n return null;\n }\n}\n\n/**\n * READ-ONLY SNAPSHOT of a whiteboard — renders a persisted board payload (the\n * session-channel artifact JSON) through the real board component in `ReadOnly` mode,\n * so a saved board looks exactly like the live one: same chips, shapes, ink and\n * connectors, with pan + zoom still available for navigation but every mutating\n * interaction disabled. Used by the whiteboard artifact viewer plugin and any\n * session-review surface that wants to show a board without an engine wired to tools.\n */\n@Component({\n standalone: true,\n selector: 'mj-whiteboard-snapshot',\n imports: [RealtimeWhiteboardBoardComponent],\n template: `\n @if (State) {\n <div class=\"wb-snapshot-board\">\n <mj-realtime-whiteboard [State]=\"State\" [AgentName]=\"AgentName\" [ReadOnly]=\"true\" [Tool]=\"'pan'\" />\n </div>\n } @else {\n <div class=\"wb-snapshot-empty\">\n <i class=\"fa-solid fa-chalkboard\" aria-hidden=\"true\"></i>\n <span>No board content</span>\n </div>\n }\n `,\n styles: [`\n :host {\n display: flex;\n flex-direction: column;\n flex: 1;\n height: 100%;\n min-height: 320px;\n }\n /* the board component positions itself absolute, so give it a relative frame */\n .wb-snapshot-board {\n position: relative;\n flex: 1;\n min-height: 0;\n }\n .wb-snapshot-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md, 6px);\n font-size: 13px;\n }\n .wb-snapshot-empty i {\n font-size: 22px;\n color: var(--mj-text-disabled);\n }\n `]\n})\nexport class WhiteboardSnapshotComponent {\n private _stateJson = '';\n\n /** Rehydrated board engine (null when the payload is empty/malformed). */\n public State: WhiteboardState | null = null;\n\n /** Persisted board payload — setter-driven so a new artifact version re-parses. */\n @Input()\n set StateJson(value: string) {\n if (value !== this._stateJson) {\n this._stateJson = value;\n this.State = ParseBoardStateJson(value);\n }\n }\n get StateJson(): string {\n return this._stateJson;\n }\n\n /** Display name of the session's agent — ownership chips on the rendered board. */\n @Input() AgentName = 'Agent';\n}\n"]}