@memberjunction/ng-whiteboard 5.51.1 → 5.51.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/lib/whiteboard-board.component.d.ts +11 -3
- package/dist/lib/whiteboard-board.component.d.ts.map +1 -1
- package/dist/lib/whiteboard-board.component.js +12 -3
- package/dist/lib/whiteboard-board.component.js.map +1 -1
- package/dist/lib/whiteboard-context-menu.d.ts +2 -1
- package/dist/lib/whiteboard-context-menu.d.ts.map +1 -1
- package/dist/lib/whiteboard-context-menu.js +11 -7
- package/dist/lib/whiteboard-context-menu.js.map +1 -1
- package/dist/lib/whiteboard-host.component.d.ts +72 -3
- package/dist/lib/whiteboard-host.component.d.ts.map +1 -1
- package/dist/lib/whiteboard-host.component.dom.test.d.ts +2 -0
- package/dist/lib/whiteboard-host.component.dom.test.d.ts.map +1 -0
- package/dist/lib/whiteboard-host.component.dom.test.js +187 -0
- package/dist/lib/whiteboard-host.component.dom.test.js.map +1 -0
- package/dist/lib/whiteboard-host.component.js +132 -12
- package/dist/lib/whiteboard-host.component.js.map +1 -1
- package/dist/lib/whiteboard-tool-roster.d.ts +55 -0
- package/dist/lib/whiteboard-tool-roster.d.ts.map +1 -0
- package/dist/lib/whiteboard-tool-roster.js +58 -0
- package/dist/lib/whiteboard-tool-roster.js.map +1 -0
- package/dist/lib/whiteboard-toolbar.component.d.ts +11 -4
- package/dist/lib/whiteboard-toolbar.component.d.ts.map +1 -1
- package/dist/lib/whiteboard-toolbar.component.dom.test.js +13 -0
- package/dist/lib/whiteboard-toolbar.component.dom.test.js.map +1 -1
- package/dist/lib/whiteboard-toolbar.component.js +18 -3
- package/dist/lib/whiteboard-toolbar.component.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +2 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +6 -6
|
@@ -1 +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"]}
|
|
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, ElementRef, EventEmitter, HostBinding, HostListener, Input,\n OnDestroy, OnInit, Output, 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 { WhiteboardTool, WhiteboardToolRoster, ClampToolToRoster, IsToolAllowed } from './whiteboard-tool-roster';\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, 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 * Opt back in to DOCUMENT-WIDE keyboard shortcuts.\n *\n * The host binds eleven bare single-character tool shortcuts (v h p r s t m w i c e). While\n * those listened on `document` unconditionally they fired wherever the user was on the page,\n * which fails WCAG 2.1.4 (Character Key Shortcuts): a speech-input user saying an ordinary\n * word, or anyone typing in a non-input control elsewhere, silently switched the board tool.\n * They are now scoped to focus being inside this host, which satisfies the criterion's\n * \"active only on focus\" branch.\n *\n * Scoping covers the host's ENTIRE keydown handler, not only the letters: undo/redo\n * (Cmd/Ctrl+Z, +Y), Escape and Delete/Backspace are focus-gated as well.\n *\n * Set `true` only for a surface where the whiteboard is the entire page AND the 2.1.4\n * exposure has been accepted — it is an accessibility regression, not a convenience flag.\n */\n @Input() EnableGlobalShortcuts = false;\n\n /**\n * Which tools this surface offers. `null` (default) is all eleven: today's rendering.\n *\n * The roster governs which tools are AVAILABLE, closing every door to a tool it leaves out:\n * the toolbar button, the single-letter shortcut, and the canvas \"add … here\" action. It is\n * deliberately not a content policy — it does not restrict what already exists on the board,\n * what the agent places, or authoring on existing items (Restyle, Duplicate, paste). An empty\n * roster narrows the palette to nothing; it does NOT make the board read-only, which is a\n * separate input.\n *\n * A setter rather than `ngOnChanges` (packages/Angular/CLAUDE.md): a realtime channel's\n * `BindSurface` assigns this property directly on a dynamically-created component, and\n * Angular fires no `ngOnChanges` for a plain assignment, so a clamp implemented there would\n * silently never run on the path real consumers use.\n */\n @Input()\n set ToolRoster(value: WhiteboardToolRoster) {\n const next = value ?? null;\n // Identity compare, per the Angular rule: a consumer binding a freshly-built array literal\n // re-fires this setter every change-detection pass, and re-running the clamp on every pass\n // would fight the user for the active tool.\n if (next === this._toolRoster) {\n return;\n }\n this._toolRoster = next;\n // Re-validate the CURRENT tool through the same chokepoint every other write uses.\n this.Tool = this._tool;\n }\n get ToolRoster(): WhiteboardToolRoster {\n return this._toolRoster;\n }\n private _toolRoster: WhiteboardToolRoster = null;\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 /**\n * The active tool, and the ONE place the roster invariant is enforced on a write.\n *\n * \"The active tool is always one the roster allows\" is a property of every write, not of the\n * handful of call sites that exist today (the roster setter, Escape, the key map, and the two\n * template `Tool = $event` bindings). Guarding each of those would leave the next writer —\n * a new shortcut, a gesture, a host API — to remember the rule. Guarding here closes them all\n * by construction, and makes assignment order irrelevant: setting `ToolRoster` and `Tool` in\n * either order still lands on an allowed tool.\n *\n * A DISALLOWED request is ignored rather than clamped: pressing Escape under `['pen','eraser']`\n * should leave you on pen, not bounce you to the roster's fallback. The clamp is only for the\n * case where the tool you are already holding stopped being allowed.\n */\n public get Tool(): WhiteboardTool {\n return this._tool;\n }\n public set Tool(value: WhiteboardTool) {\n this._tool = IsToolAllowed(this._toolRoster, value)\n ? value\n : ClampToolToRoster(this._tool, this._toolRoster);\n }\n private _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 /**\n * The board is made focusable so its shortcuts have a focus scope to be bound to. `-1`, not\n * `0`: the canvas has no keyboard interaction model yet (see the whiteboard keyboard-\n * operability work), so adding a real Tab stop would put a stop in the page that a keyboard\n * user can reach and do nothing with. Click focuses it; that is the whole contract today.\n */\n @HostBinding('attr.tabindex') readonly HostTabIndex = '-1';\n\n private readonly host: ElementRef<HTMLElement> = inject(ElementRef);\n\n /**\n * Clicking the board takes focus, so the shortcuts below apply. The browser would usually do\n * this on its own by focusing the nearest focusable ancestor, but the board's pointer\n * pipeline is elaborate enough (drag, marquee, handles, transient shapes) that relying on\n * that default is fragile — one `preventDefault()` added later would silently kill every\n * shortcut. This makes it explicit.\n */\n @HostListener('pointerdown')\n public OnHostPointerDown(): void {\n if (!this.hasFocusWithin()) {\n this.host.nativeElement.focus({ preventScroll: true });\n }\n }\n\n /** Whether focus currently sits on, or inside, this whiteboard host. */\n private hasFocusWithin(): boolean {\n const el = this.host.nativeElement;\n const active = document.activeElement;\n return !!active && (active === el || el.contains(active));\n }\n\n @HostListener('document:keydown', ['$event'])\n public OnKeydown(event: KeyboardEvent): void {\n // WCAG 2.1.4: only live while focus is on the board. NOTE this gates the WHOLE handler,\n // not just the single-character tool keys that 2.1.4 is about — undo/redo (Cmd/Ctrl+Z,\n // +Y), Escape and Delete/Backspace are scoped too. That is deliberate: a board that\n // swallows the document's Cmd+Z from anywhere on the page is its own bug, and \"the board\n // responds to keys when you are on the board\" is the only model that stays predictable.\n // See {@link EnableGlobalShortcuts} for the (discouraged) opt-out.\n if (!this.EnableGlobalShortcuts && !this.hasFocusWithin()) {\n return;\n }\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 // No roster check here: the Tool setter ignores a disallowed write, so a key for a\n // hidden tool is a no-op by construction rather than by a remembered guard.\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 [ToolRoster]=\"ToolRoster\"\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 [ToolRoster]=\"ToolRoster\"\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,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every tool the board knows, in the toolbar's own display order. This is the runtime
|
|
3
|
+
* companion to {@link WhiteboardTool}: the clamp needs to tell a real tool from a typo, and a
|
|
4
|
+
* union alone cannot do that once it has been erased.
|
|
5
|
+
*
|
|
6
|
+
* It lives HERE rather than beside the toolbar because the roster is the only thing that has
|
|
7
|
+
* to reason about tools as data. The toolbar imports the type back; it must not re-export it,
|
|
8
|
+
* because `public-api.ts` `export *`s both modules and two modules exporting one name that way
|
|
9
|
+
* is a TS2308 ambiguity.
|
|
10
|
+
*/
|
|
11
|
+
export declare const WHITEBOARD_TOOLS: readonly ["select", "pan", "pen", "shape", "sticky", "text", "markdown", "html", "image", "connector", "eraser"];
|
|
12
|
+
/** A user-selectable board tool. */
|
|
13
|
+
export type WhiteboardTool = typeof WHITEBOARD_TOOLS[number];
|
|
14
|
+
/** Whether `name` is one of the board's tools — the guard the clamp uses to skip typos. */
|
|
15
|
+
export declare function IsKnownTool(name: string): name is WhiteboardTool;
|
|
16
|
+
/**
|
|
17
|
+
* A host-supplied subset of the board's tools. `null` means "all of them" (today's behaviour).
|
|
18
|
+
*
|
|
19
|
+
* The roster is ONE fact read in three places, so a tool a host hides is hidden everywhere a
|
|
20
|
+
* user could reach it: the floating toolbar, the single-letter keyboard shortcuts, and the
|
|
21
|
+
* right-click "add … here" actions. Hiding only the toolbar button (CSS) leaves the other two
|
|
22
|
+
* doors open, which is how a consumer ended up with learners able to press `w` and place an
|
|
23
|
+
* HTML widget on a board whose toolbar showed no such tool.
|
|
24
|
+
*/
|
|
25
|
+
export type WhiteboardToolRoster = readonly WhiteboardTool[] | null;
|
|
26
|
+
/**
|
|
27
|
+
* May `tool` be offered under `roster`? A `null` roster allows everything.
|
|
28
|
+
*
|
|
29
|
+
* `== null` deliberately, not `=== null`: the package compiles with `strictNullChecks: false`,
|
|
30
|
+
* so the type does not stop a consumer handing us `undefined`, and an undefined roster must
|
|
31
|
+
* read as "no roster" rather than throw on `.includes`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function IsToolAllowed(roster: WhiteboardToolRoster, tool: WhiteboardTool): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Filter a tool list by the roster, preserving the LIST's order (never the roster's) and
|
|
36
|
+
* ignoring roster entries that name no tool, so a consumer cannot reorder the palette or
|
|
37
|
+
* conjure a button by misspelling.
|
|
38
|
+
*/
|
|
39
|
+
export declare function VisibleToolbarEntries<T extends {
|
|
40
|
+
Tool: WhiteboardTool;
|
|
41
|
+
}>(entries: readonly T[], roster: WhiteboardToolRoster): T[];
|
|
42
|
+
/**
|
|
43
|
+
* The tool the host should hold when `current` is no longer allowed: `select` when the roster
|
|
44
|
+
* offers it, else the roster's first KNOWN entry, else `current` unchanged.
|
|
45
|
+
*
|
|
46
|
+
* Why `select` first rather than `roster[0]`: roster order is documented as meaningless for
|
|
47
|
+
* rendering ({@link VisibleToolbarEntries} always uses list order), so it must not quietly
|
|
48
|
+
* become load-bearing here. `select` is the neutral tool; falling back to roster order instead
|
|
49
|
+
* would let a host land the user on the eraser by writing the roster in an innocuous order.
|
|
50
|
+
*
|
|
51
|
+
* An empty or all-typo roster returns `current`, so the board never has "no tool" — narrowing
|
|
52
|
+
* the palette to nothing is not the same as making the board read-only.
|
|
53
|
+
*/
|
|
54
|
+
export declare function ClampToolToRoster(current: WhiteboardTool, roster: WhiteboardToolRoster): WhiteboardTool;
|
|
55
|
+
//# sourceMappingURL=whiteboard-tool-roster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whiteboard-tool-roster.d.ts","sourceRoot":"","sources":["../../src/lib/whiteboard-tool-roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,kHAEnB,CAAC;AAEX,oCAAoC;AACpC,MAAM,MAAM,cAAc,GAAG,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE7D,2FAA2F;AAC3F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,cAAc,CAEhE;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAAG,SAAS,cAAc,EAAE,GAAG,IAAI,CAAC;AAEpE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAEzF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,oBAAoB,GAAG,CAAC,EAAE,CAElI;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,oBAAoB,GAAG,cAAc,CASvG"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every tool the board knows, in the toolbar's own display order. This is the runtime
|
|
3
|
+
* companion to {@link WhiteboardTool}: the clamp needs to tell a real tool from a typo, and a
|
|
4
|
+
* union alone cannot do that once it has been erased.
|
|
5
|
+
*
|
|
6
|
+
* It lives HERE rather than beside the toolbar because the roster is the only thing that has
|
|
7
|
+
* to reason about tools as data. The toolbar imports the type back; it must not re-export it,
|
|
8
|
+
* because `public-api.ts` `export *`s both modules and two modules exporting one name that way
|
|
9
|
+
* is a TS2308 ambiguity.
|
|
10
|
+
*/
|
|
11
|
+
export const WHITEBOARD_TOOLS = [
|
|
12
|
+
'select', 'pan', 'pen', 'shape', 'sticky', 'text', 'markdown', 'html', 'image', 'connector', 'eraser'
|
|
13
|
+
];
|
|
14
|
+
/** Whether `name` is one of the board's tools — the guard the clamp uses to skip typos. */
|
|
15
|
+
export function IsKnownTool(name) {
|
|
16
|
+
return WHITEBOARD_TOOLS.includes(name);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* May `tool` be offered under `roster`? A `null` roster allows everything.
|
|
20
|
+
*
|
|
21
|
+
* `== null` deliberately, not `=== null`: the package compiles with `strictNullChecks: false`,
|
|
22
|
+
* so the type does not stop a consumer handing us `undefined`, and an undefined roster must
|
|
23
|
+
* read as "no roster" rather than throw on `.includes`.
|
|
24
|
+
*/
|
|
25
|
+
export function IsToolAllowed(roster, tool) {
|
|
26
|
+
return roster == null || roster.includes(tool);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Filter a tool list by the roster, preserving the LIST's order (never the roster's) and
|
|
30
|
+
* ignoring roster entries that name no tool, so a consumer cannot reorder the palette or
|
|
31
|
+
* conjure a button by misspelling.
|
|
32
|
+
*/
|
|
33
|
+
export function VisibleToolbarEntries(entries, roster) {
|
|
34
|
+
return entries.filter((e) => IsToolAllowed(roster, e.Tool));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The tool the host should hold when `current` is no longer allowed: `select` when the roster
|
|
38
|
+
* offers it, else the roster's first KNOWN entry, else `current` unchanged.
|
|
39
|
+
*
|
|
40
|
+
* Why `select` first rather than `roster[0]`: roster order is documented as meaningless for
|
|
41
|
+
* rendering ({@link VisibleToolbarEntries} always uses list order), so it must not quietly
|
|
42
|
+
* become load-bearing here. `select` is the neutral tool; falling back to roster order instead
|
|
43
|
+
* would let a host land the user on the eraser by writing the roster in an innocuous order.
|
|
44
|
+
*
|
|
45
|
+
* An empty or all-typo roster returns `current`, so the board never has "no tool" — narrowing
|
|
46
|
+
* the palette to nothing is not the same as making the board read-only.
|
|
47
|
+
*/
|
|
48
|
+
export function ClampToolToRoster(current, roster) {
|
|
49
|
+
if (IsToolAllowed(roster, current)) {
|
|
50
|
+
return current;
|
|
51
|
+
}
|
|
52
|
+
const known = (roster ?? []).filter(IsKnownTool);
|
|
53
|
+
if (known.length === 0) {
|
|
54
|
+
return current;
|
|
55
|
+
}
|
|
56
|
+
return known.includes('select') ? 'select' : known[0];
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=whiteboard-tool-roster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whiteboard-tool-roster.js","sourceRoot":"","sources":["../../src/lib/whiteboard-tool-roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ;CAC7F,CAAC;AAKX,2FAA2F;AAC3F,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAQ,gBAAsC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAChE,CAAC;AAaD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,MAA4B,EAAE,IAAoB;IAC9E,OAAO,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAqC,OAAqB,EAAE,MAA4B;IAC3H,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAuB,EAAE,MAA4B;IACrF,IAAI,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACjD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC","sourcesContent":["/**\n * Every tool the board knows, in the toolbar's own display order. This is the runtime\n * companion to {@link WhiteboardTool}: the clamp needs to tell a real tool from a typo, and a\n * union alone cannot do that once it has been erased.\n *\n * It lives HERE rather than beside the toolbar because the roster is the only thing that has\n * to reason about tools as data. The toolbar imports the type back; it must not re-export it,\n * because `public-api.ts` `export *`s both modules and two modules exporting one name that way\n * is a TS2308 ambiguity.\n */\nexport const WHITEBOARD_TOOLS = [\n 'select', 'pan', 'pen', 'shape', 'sticky', 'text', 'markdown', 'html', 'image', 'connector', 'eraser'\n] as const;\n\n/** A user-selectable board tool. */\nexport type WhiteboardTool = typeof WHITEBOARD_TOOLS[number];\n\n/** Whether `name` is one of the board's tools — the guard the clamp uses to skip typos. */\nexport function IsKnownTool(name: string): name is WhiteboardTool {\n return (WHITEBOARD_TOOLS as readonly string[]).includes(name);\n}\n\n/**\n * A host-supplied subset of the board's tools. `null` means \"all of them\" (today's behaviour).\n *\n * The roster is ONE fact read in three places, so a tool a host hides is hidden everywhere a\n * user could reach it: the floating toolbar, the single-letter keyboard shortcuts, and the\n * right-click \"add … here\" actions. Hiding only the toolbar button (CSS) leaves the other two\n * doors open, which is how a consumer ended up with learners able to press `w` and place an\n * HTML widget on a board whose toolbar showed no such tool.\n */\nexport type WhiteboardToolRoster = readonly WhiteboardTool[] | null;\n\n/**\n * May `tool` be offered under `roster`? A `null` roster allows everything.\n *\n * `== null` deliberately, not `=== null`: the package compiles with `strictNullChecks: false`,\n * so the type does not stop a consumer handing us `undefined`, and an undefined roster must\n * read as \"no roster\" rather than throw on `.includes`.\n */\nexport function IsToolAllowed(roster: WhiteboardToolRoster, tool: WhiteboardTool): boolean {\n return roster == null || roster.includes(tool);\n}\n\n/**\n * Filter a tool list by the roster, preserving the LIST's order (never the roster's) and\n * ignoring roster entries that name no tool, so a consumer cannot reorder the palette or\n * conjure a button by misspelling.\n */\nexport function VisibleToolbarEntries<T extends { Tool: WhiteboardTool }>(entries: readonly T[], roster: WhiteboardToolRoster): T[] {\n return entries.filter((e) => IsToolAllowed(roster, e.Tool));\n}\n\n/**\n * The tool the host should hold when `current` is no longer allowed: `select` when the roster\n * offers it, else the roster's first KNOWN entry, else `current` unchanged.\n *\n * Why `select` first rather than `roster[0]`: roster order is documented as meaningless for\n * rendering ({@link VisibleToolbarEntries} always uses list order), so it must not quietly\n * become load-bearing here. `select` is the neutral tool; falling back to roster order instead\n * would let a host land the user on the eraser by writing the roster in an innocuous order.\n *\n * An empty or all-typo roster returns `current`, so the board never has \"no tool\" — narrowing\n * the palette to nothing is not the same as making the board read-only.\n */\nexport function ClampToolToRoster(current: WhiteboardTool, roster: WhiteboardToolRoster): WhiteboardTool {\n if (IsToolAllowed(roster, current)) {\n return current;\n }\n const known = (roster ?? []).filter(IsKnownTool);\n if (known.length === 0) {\n return current;\n }\n return known.includes('select') ? 'select' : known[0];\n}\n"]}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from '@angular/core';
|
|
2
2
|
import { WhiteboardFontFamily, WhiteboardShapeKind } from './whiteboard-state';
|
|
3
|
+
import { WhiteboardTool, WhiteboardToolRoster } from './whiteboard-tool-roster';
|
|
3
4
|
import * as i0 from "@angular/core";
|
|
4
|
-
/** A user-selectable board tool. */
|
|
5
|
-
export type WhiteboardTool = 'select' | 'pan' | 'pen' | 'shape' | 'sticky' | 'text' | 'markdown' | 'html' | 'image' | 'connector' | 'eraser';
|
|
6
5
|
/** One entry in the floating toolbar. */
|
|
7
6
|
interface ToolbarEntry {
|
|
8
7
|
Tool: WhiteboardTool;
|
|
@@ -41,6 +40,12 @@ interface FontFamilyEntry {
|
|
|
41
40
|
export declare class RealtimeWhiteboardToolbarComponent {
|
|
42
41
|
/** The currently active tool. */
|
|
43
42
|
ActiveTool: WhiteboardTool;
|
|
43
|
+
/**
|
|
44
|
+
* Which tools the palette offers. `null` (default) is all eleven, today's rendering. A host
|
|
45
|
+
* that narrows this also narrows the keyboard shortcuts and the canvas context menu, because
|
|
46
|
+
* the same roster is threaded to all three (see `whiteboard-tool-roster.ts`).
|
|
47
|
+
*/
|
|
48
|
+
ToolRoster: WhiteboardToolRoster;
|
|
44
49
|
/** Selected pen ink color (from {@link WHITEBOARD_PEN_COLORS}). */
|
|
45
50
|
PenColor: string;
|
|
46
51
|
/** Selected pen stroke width. */
|
|
@@ -60,7 +65,7 @@ export declare class RealtimeWhiteboardToolbarComponent {
|
|
|
60
65
|
CanRedo: boolean;
|
|
61
66
|
/** Display name of the session's agent (the pen flyout note: "violet = Sage's"). */
|
|
62
67
|
AgentName: string;
|
|
63
|
-
ToolChange: EventEmitter<
|
|
68
|
+
ToolChange: EventEmitter<"sticky" | "shape" | "text" | "image" | "connector" | "markdown" | "html" | "select" | "pan" | "pen" | "eraser">;
|
|
64
69
|
PenColorChange: EventEmitter<string>;
|
|
65
70
|
PenWidthChange: EventEmitter<number>;
|
|
66
71
|
ShapeKindChange: EventEmitter<WhiteboardShapeKind>;
|
|
@@ -73,6 +78,8 @@ export declare class RealtimeWhiteboardToolbarComponent {
|
|
|
73
78
|
Undo: EventEmitter<void>;
|
|
74
79
|
Redo: EventEmitter<void>;
|
|
75
80
|
readonly Tools: ToolbarEntry[];
|
|
81
|
+
/** `Tools` narrowed by `ToolRoster`, in `Tools` order. The template loops over this. */
|
|
82
|
+
get VisibleTools(): ToolbarEntry[];
|
|
76
83
|
readonly PenColors: readonly string[];
|
|
77
84
|
readonly PenWidths: readonly number[];
|
|
78
85
|
readonly ShapeKinds: {
|
|
@@ -89,7 +96,7 @@ export declare class RealtimeWhiteboardToolbarComponent {
|
|
|
89
96
|
PickTextColor(color: string): void;
|
|
90
97
|
TrackTool(index: number, entry: ToolbarEntry): WhiteboardTool;
|
|
91
98
|
static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeWhiteboardToolbarComponent, never>;
|
|
92
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeWhiteboardToolbarComponent, "mj-realtime-whiteboard-toolbar", never, { "ActiveTool": { "alias": "ActiveTool"; "required": false; }; "PenColor": { "alias": "PenColor"; "required": false; }; "PenWidth": { "alias": "PenWidth"; "required": false; }; "ShapeKind": { "alias": "ShapeKind"; "required": false; }; "TextSize": { "alias": "TextSize"; "required": false; }; "TextFamily": { "alias": "TextFamily"; "required": false; }; "TextBold": { "alias": "TextBold"; "required": false; }; "TextColor": { "alias": "TextColor"; "required": false; }; "CanUndo": { "alias": "CanUndo"; "required": false; }; "CanRedo": { "alias": "CanRedo"; "required": false; }; "AgentName": { "alias": "AgentName"; "required": false; }; }, { "ToolChange": "ToolChange"; "PenColorChange": "PenColorChange"; "PenWidthChange": "PenWidthChange"; "ShapeKindChange": "ShapeKindChange"; "TextSizeChange": "TextSizeChange"; "TextFamilyChange": "TextFamilyChange"; "TextBoldChange": "TextBoldChange"; "TextColorChange": "TextColorChange"; "StyleSelection": "StyleSelection"; "Undo": "Undo"; "Redo": "Redo"; }, never, never, true, never>;
|
|
99
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeWhiteboardToolbarComponent, "mj-realtime-whiteboard-toolbar", never, { "ActiveTool": { "alias": "ActiveTool"; "required": false; }; "ToolRoster": { "alias": "ToolRoster"; "required": false; }; "PenColor": { "alias": "PenColor"; "required": false; }; "PenWidth": { "alias": "PenWidth"; "required": false; }; "ShapeKind": { "alias": "ShapeKind"; "required": false; }; "TextSize": { "alias": "TextSize"; "required": false; }; "TextFamily": { "alias": "TextFamily"; "required": false; }; "TextBold": { "alias": "TextBold"; "required": false; }; "TextColor": { "alias": "TextColor"; "required": false; }; "CanUndo": { "alias": "CanUndo"; "required": false; }; "CanRedo": { "alias": "CanRedo"; "required": false; }; "AgentName": { "alias": "AgentName"; "required": false; }; }, { "ToolChange": "ToolChange"; "PenColorChange": "PenColorChange"; "PenWidthChange": "PenWidthChange"; "ShapeKindChange": "ShapeKindChange"; "TextSizeChange": "TextSizeChange"; "TextFamilyChange": "TextFamilyChange"; "TextBoldChange": "TextBoldChange"; "TextColorChange": "TextColorChange"; "StyleSelection": "StyleSelection"; "Undo": "Undo"; "Redo": "Redo"; }, never, never, true, never>;
|
|
93
100
|
}
|
|
94
101
|
export {};
|
|
95
102
|
//# sourceMappingURL=whiteboard-toolbar.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whiteboard-toolbar.component.d.ts","sourceRoot":"","sources":["../../src/lib/whiteboard-toolbar.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAyB,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC
|
|
1
|
+
{"version":3,"file":"whiteboard-toolbar.component.d.ts","sourceRoot":"","sources":["../../src/lib/whiteboard-toolbar.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AAEvE,OAAO,EAAyB,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGtG,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAyB,MAAM,0BAA0B,CAAC;;AAEvG,yCAAyC;AACzC,UAAU,YAAY;IACpB,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAA4D,CAAC;AAEhH,wCAAwC;AACxC,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAc,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,6EAA6E;AAC7E,UAAU,eAAe;IACvB,GAAG,EAAE,oBAAoB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,qBAOa,kCAAkC;IAC7C,iCAAiC;IACxB,UAAU,EAAE,cAAc,CAAY;IAC/C;;;;OAIG;IACM,UAAU,EAAE,oBAAoB,CAAQ;IACjD,mEAAmE;IAC1D,QAAQ,EAAE,MAAM,CAA4B;IACrD,iCAAiC;IACxB,QAAQ,SAAK;IACtB,2CAA2C;IAClC,SAAS,EAAE,mBAAmB,CAAU;IACjD,2EAA2E;IAClE,QAAQ,SAAM;IACvB,iCAAiC;IACxB,UAAU,EAAE,oBAAoB,CAAU;IACnD,gEAAgE;IACvD,QAAQ,UAAQ;IACzB,2FAA2F;IAClF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IACzC,qFAAqF;IAC5E,OAAO,UAAS;IAChB,OAAO,UAAS;IACzB,oFAAoF;IAC3E,SAAS,SAAW;IAEnB,UAAU,gIAAsC;IAChD,cAAc,uBAA8B;IAC5C,cAAc,uBAA8B;IAC5C,eAAe,oCAA2C;IAC1D,cAAc,uBAA8B;IAC5C,gBAAgB,qCAA4C;IAC5D,cAAc,wBAA+B;IAC7C,eAAe,uBAA8B;IACvD,gGAAgG;IACtF,cAAc,yCAAgD;IAC9D,IAAI,qBAA4B;IAChC,IAAI,qBAA4B;IAE1C,SAAgB,KAAK,EAAE,YAAY,EAAE,CAYnC;IAEF,wFAAwF;IACxF,IAAW,YAAY,IAAI,YAAY,EAAE,CAExC;IAED,SAAgB,SAAS,oBAAyB;IAClD,SAAgB,SAAS,oBAAyB;IAClD,SAAgB,UAAU,EAAE;QAAE,IAAI,EAAE,mBAAmB,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAItF;IACF,SAAgB,SAAS,oBAAyB;IAClD,SAAgB,YAAY,EAAE,eAAe,EAAE,CAI7C;IAEK,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAMtC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKhC,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAKlD,cAAc,IAAI,IAAI;IAMtB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKlC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,cAAc;yCAtGzD,kCAAkC;2CAAlC,kCAAkC;CAyG9C"}
|
|
@@ -15,6 +15,19 @@ describe('RealtimeWhiteboardToolbarComponent (DOM)', () => {
|
|
|
15
15
|
// 11 tools + undo + redo = 13 .tool buttons
|
|
16
16
|
expect(toolButtons(f).length).toBe(f.componentInstance.Tools.length + 2);
|
|
17
17
|
});
|
|
18
|
+
it('narrows the palette to the ToolRoster (plus undo + redo), in Tools order', () => {
|
|
19
|
+
const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ToolRoster: ['eraser', 'select', 'pen'] } });
|
|
20
|
+
const titles = toolButtons(f).map((b) => b.getAttribute('title'));
|
|
21
|
+
// 3 roster tools + undo + redo
|
|
22
|
+
expect(toolButtons(f).length).toBe(5);
|
|
23
|
+
expect(titles.slice(0, 3)).toEqual(['Select / move', 'Pen', 'Eraser']);
|
|
24
|
+
});
|
|
25
|
+
it('a roster entry that names no tool is ignored, and a null roster is the full palette', () => {
|
|
26
|
+
const typo = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ToolRoster: ['pen', 'lasso'] } });
|
|
27
|
+
expect(toolButtons(typo).length).toBe(1 + 2);
|
|
28
|
+
const all = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ToolRoster: null } });
|
|
29
|
+
expect(toolButtons(all).length).toBe(all.componentInstance.Tools.length + 2);
|
|
30
|
+
});
|
|
18
31
|
it('marks the active tool button with the .active class and only that one', () => {
|
|
19
32
|
const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'pen' } });
|
|
20
33
|
const active = toolButtons(f).filter((b) => b.classList.contains('active'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whiteboard-toolbar.component.dom.test.js","sourceRoot":"","sources":["../../src/lib/whiteboard-toolbar.component.dom.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, vi } from 'vitest';\nimport { renderComponentFixture } from '@memberjunction/ng-test-utils';\nimport { RealtimeWhiteboardToolbarComponent } from './whiteboard-toolbar.component';\n\n/**\n * DOM spec for <mj-realtime-whiteboard-toolbar> — the floating left-edge tool palette.\n * Covers the @for tool rendering, [class.active] on the active tool, the @if pen/text/\n * shape flyouts that only render when their tool is active, the undo/redo [disabled]\n * gating, and the @Output emissions (tool change, pen color/width, undo/redo, and the\n * compound text-style picks that emit BOTH a *Change and StyleSelection).\n */\ndescribe('RealtimeWhiteboardToolbarComponent (DOM)', () => {\n type Fix = ReturnType<typeof renderComponentFixture<RealtimeWhiteboardToolbarComponent>>;\n const toolButtons = (f: Fix) => Array.from(f.nativeElement.querySelectorAll('button.tool')) as HTMLButtonElement[];\n\n it('renders one tool button per entry in Tools (plus undo + redo)', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent);\n // 11 tools + undo + redo = 13 .tool buttons\n expect(toolButtons(f).length).toBe(f.componentInstance.Tools.length + 2);\n });\n\n it('marks the active tool button with the .active class and only that one', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'pen' } });\n const active = toolButtons(f).filter((b) => b.classList.contains('active'));\n expect(active.length).toBe(1);\n expect(active[0].getAttribute('title')).toBe('Pen');\n });\n\n it('does not render the pen flyout when pen is not the active tool', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'select' } });\n expect(f.nativeElement.querySelector('.pen-flyout')).toBeNull();\n });\n\n it('renders the pen flyout (with one swatch per pen color) when pen is active', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'pen' } });\n const flyout = f.nativeElement.querySelector('.pen-flyout');\n expect(flyout).not.toBeNull();\n expect(flyout!.querySelectorAll('.pen-c').length).toBe(f.componentInstance.PenColors.length);\n });\n\n it('shows the agent name in the pen-flyout violet note', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'pen', AgentName: 'Sage' } });\n expect(f.nativeElement.querySelector('.pen-note')?.textContent).toContain(\"violet = Sage's\");\n });\n\n it('renders the text-style flyout only when text is the active tool', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'text' } });\n expect(f.nativeElement.querySelector('.text-flyout')).not.toBeNull();\n });\n\n it('renders the shape flyout only when shape is the active tool', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'shape' } });\n const flyout = f.nativeElement.querySelector('.shape-flyout');\n expect(flyout).not.toBeNull();\n expect(flyout!.querySelectorAll('.shape-c').length).toBe(f.componentInstance.ShapeKinds.length);\n });\n\n it('disables undo/redo by default and enables them when CanUndo/CanRedo are true', () => {\n const disabled = renderComponentFixture(RealtimeWhiteboardToolbarComponent);\n const undoD = disabled.nativeElement.querySelector('button[title=\"Undo\"]') as HTMLButtonElement;\n const redoD = disabled.nativeElement.querySelector('button[title=\"Redo\"]') as HTMLButtonElement;\n expect(undoD.disabled).toBe(true);\n expect(redoD.disabled).toBe(true);\n\n const enabled = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { CanUndo: true, CanRedo: true } });\n expect((enabled.nativeElement.querySelector('button[title=\"Undo\"]') as HTMLButtonElement).disabled).toBe(false);\n expect((enabled.nativeElement.querySelector('button[title=\"Redo\"]') as HTMLButtonElement).disabled).toBe(false);\n });\n\n it('emits ToolChange with the clicked tool', () => {\n const spy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { setup: (c) => c.ToolChange.subscribe(spy) });\n // the pen tool button (3rd entry, index 2)\n const penBtn = f.nativeElement.querySelector('button[title=\"Pen\"]') as HTMLButtonElement;\n penBtn.click();\n expect(spy).toHaveBeenCalledWith('pen');\n });\n\n it('emits PenColorChange when a pen swatch is clicked', () => {\n const spy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, {\n inputs: { ActiveTool: 'pen' },\n setup: (c) => c.PenColorChange.subscribe(spy),\n });\n const swatch = f.nativeElement.querySelector('.pen-flyout .pen-c') as HTMLElement;\n swatch.click();\n expect(spy).toHaveBeenCalledWith(f.componentInstance.PenColors[0]);\n });\n\n it('emits BOTH TextSizeChange and StyleSelection when a text size is picked', () => {\n const sizeSpy = vi.fn();\n const styleSpy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, {\n inputs: { ActiveTool: 'text' },\n setup: (c) => {\n c.TextSizeChange.subscribe(sizeSpy);\n c.StyleSelection.subscribe(styleSpy);\n },\n });\n const sizeEl = f.nativeElement.querySelector('.text-flyout .txt-s') as HTMLElement;\n sizeEl.click();\n const firstSize = f.componentInstance.TextSizes[0];\n expect(sizeSpy).toHaveBeenCalledWith(firstSize);\n expect(styleSpy).toHaveBeenCalledWith({ FontSize: firstSize });\n });\n\n it('emits Undo / Redo when those buttons are enabled and clicked', () => {\n const undoSpy = vi.fn();\n const redoSpy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, {\n inputs: { CanUndo: true, CanRedo: true },\n setup: (c) => {\n c.Undo.subscribe(undoSpy);\n c.Redo.subscribe(redoSpy);\n },\n });\n (f.nativeElement.querySelector('button[title=\"Undo\"]') as HTMLButtonElement).click();\n (f.nativeElement.querySelector('button[title=\"Redo\"]') as HTMLButtonElement).click();\n expect(undoSpy).toHaveBeenCalledTimes(1);\n expect(redoSpy).toHaveBeenCalledTimes(1);\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"whiteboard-toolbar.component.dom.test.js","sourceRoot":"","sources":["../../src/lib/whiteboard-toolbar.component.dom.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, vi } from 'vitest';\nimport { renderComponentFixture } from '@memberjunction/ng-test-utils';\nimport { RealtimeWhiteboardToolbarComponent } from './whiteboard-toolbar.component';\n\n/**\n * DOM spec for <mj-realtime-whiteboard-toolbar> — the floating left-edge tool palette.\n * Covers the @for tool rendering, [class.active] on the active tool, the @if pen/text/\n * shape flyouts that only render when their tool is active, the undo/redo [disabled]\n * gating, and the @Output emissions (tool change, pen color/width, undo/redo, and the\n * compound text-style picks that emit BOTH a *Change and StyleSelection).\n */\ndescribe('RealtimeWhiteboardToolbarComponent (DOM)', () => {\n type Fix = ReturnType<typeof renderComponentFixture<RealtimeWhiteboardToolbarComponent>>;\n const toolButtons = (f: Fix) => Array.from(f.nativeElement.querySelectorAll('button.tool')) as HTMLButtonElement[];\n\n it('renders one tool button per entry in Tools (plus undo + redo)', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent);\n // 11 tools + undo + redo = 13 .tool buttons\n expect(toolButtons(f).length).toBe(f.componentInstance.Tools.length + 2);\n });\n\n it('narrows the palette to the ToolRoster (plus undo + redo), in Tools order', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ToolRoster: ['eraser', 'select', 'pen'] } });\n const titles = toolButtons(f).map((b) => b.getAttribute('title'));\n // 3 roster tools + undo + redo\n expect(toolButtons(f).length).toBe(5);\n expect(titles.slice(0, 3)).toEqual(['Select / move', 'Pen', 'Eraser']);\n });\n\n it('a roster entry that names no tool is ignored, and a null roster is the full palette', () => {\n const typo = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ToolRoster: ['pen', 'lasso'] } });\n expect(toolButtons(typo).length).toBe(1 + 2);\n const all = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ToolRoster: null } });\n expect(toolButtons(all).length).toBe(all.componentInstance.Tools.length + 2);\n });\n\n it('marks the active tool button with the .active class and only that one', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'pen' } });\n const active = toolButtons(f).filter((b) => b.classList.contains('active'));\n expect(active.length).toBe(1);\n expect(active[0].getAttribute('title')).toBe('Pen');\n });\n\n it('does not render the pen flyout when pen is not the active tool', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'select' } });\n expect(f.nativeElement.querySelector('.pen-flyout')).toBeNull();\n });\n\n it('renders the pen flyout (with one swatch per pen color) when pen is active', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'pen' } });\n const flyout = f.nativeElement.querySelector('.pen-flyout');\n expect(flyout).not.toBeNull();\n expect(flyout!.querySelectorAll('.pen-c').length).toBe(f.componentInstance.PenColors.length);\n });\n\n it('shows the agent name in the pen-flyout violet note', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'pen', AgentName: 'Sage' } });\n expect(f.nativeElement.querySelector('.pen-note')?.textContent).toContain(\"violet = Sage's\");\n });\n\n it('renders the text-style flyout only when text is the active tool', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'text' } });\n expect(f.nativeElement.querySelector('.text-flyout')).not.toBeNull();\n });\n\n it('renders the shape flyout only when shape is the active tool', () => {\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { ActiveTool: 'shape' } });\n const flyout = f.nativeElement.querySelector('.shape-flyout');\n expect(flyout).not.toBeNull();\n expect(flyout!.querySelectorAll('.shape-c').length).toBe(f.componentInstance.ShapeKinds.length);\n });\n\n it('disables undo/redo by default and enables them when CanUndo/CanRedo are true', () => {\n const disabled = renderComponentFixture(RealtimeWhiteboardToolbarComponent);\n const undoD = disabled.nativeElement.querySelector('button[title=\"Undo\"]') as HTMLButtonElement;\n const redoD = disabled.nativeElement.querySelector('button[title=\"Redo\"]') as HTMLButtonElement;\n expect(undoD.disabled).toBe(true);\n expect(redoD.disabled).toBe(true);\n\n const enabled = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { inputs: { CanUndo: true, CanRedo: true } });\n expect((enabled.nativeElement.querySelector('button[title=\"Undo\"]') as HTMLButtonElement).disabled).toBe(false);\n expect((enabled.nativeElement.querySelector('button[title=\"Redo\"]') as HTMLButtonElement).disabled).toBe(false);\n });\n\n it('emits ToolChange with the clicked tool', () => {\n const spy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, { setup: (c) => c.ToolChange.subscribe(spy) });\n // the pen tool button (3rd entry, index 2)\n const penBtn = f.nativeElement.querySelector('button[title=\"Pen\"]') as HTMLButtonElement;\n penBtn.click();\n expect(spy).toHaveBeenCalledWith('pen');\n });\n\n it('emits PenColorChange when a pen swatch is clicked', () => {\n const spy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, {\n inputs: { ActiveTool: 'pen' },\n setup: (c) => c.PenColorChange.subscribe(spy),\n });\n const swatch = f.nativeElement.querySelector('.pen-flyout .pen-c') as HTMLElement;\n swatch.click();\n expect(spy).toHaveBeenCalledWith(f.componentInstance.PenColors[0]);\n });\n\n it('emits BOTH TextSizeChange and StyleSelection when a text size is picked', () => {\n const sizeSpy = vi.fn();\n const styleSpy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, {\n inputs: { ActiveTool: 'text' },\n setup: (c) => {\n c.TextSizeChange.subscribe(sizeSpy);\n c.StyleSelection.subscribe(styleSpy);\n },\n });\n const sizeEl = f.nativeElement.querySelector('.text-flyout .txt-s') as HTMLElement;\n sizeEl.click();\n const firstSize = f.componentInstance.TextSizes[0];\n expect(sizeSpy).toHaveBeenCalledWith(firstSize);\n expect(styleSpy).toHaveBeenCalledWith({ FontSize: firstSize });\n });\n\n it('emits Undo / Redo when those buttons are enabled and clicked', () => {\n const undoSpy = vi.fn();\n const redoSpy = vi.fn();\n const f = renderComponentFixture(RealtimeWhiteboardToolbarComponent, {\n inputs: { CanUndo: true, CanRedo: true },\n setup: (c) => {\n c.Undo.subscribe(undoSpy);\n c.Redo.subscribe(redoSpy);\n },\n });\n (f.nativeElement.querySelector('button[title=\"Undo\"]') as HTMLButtonElement).click();\n (f.nativeElement.querySelector('button[title=\"Redo\"]') as HTMLButtonElement).click();\n expect(undoSpy).toHaveBeenCalledTimes(1);\n expect(redoSpy).toHaveBeenCalledTimes(1);\n });\n});\n"]}
|