@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.
Files changed (32) hide show
  1. package/README.md +5 -0
  2. package/dist/lib/whiteboard-board.component.d.ts +11 -3
  3. package/dist/lib/whiteboard-board.component.d.ts.map +1 -1
  4. package/dist/lib/whiteboard-board.component.js +12 -3
  5. package/dist/lib/whiteboard-board.component.js.map +1 -1
  6. package/dist/lib/whiteboard-context-menu.d.ts +2 -1
  7. package/dist/lib/whiteboard-context-menu.d.ts.map +1 -1
  8. package/dist/lib/whiteboard-context-menu.js +11 -7
  9. package/dist/lib/whiteboard-context-menu.js.map +1 -1
  10. package/dist/lib/whiteboard-host.component.d.ts +72 -3
  11. package/dist/lib/whiteboard-host.component.d.ts.map +1 -1
  12. package/dist/lib/whiteboard-host.component.dom.test.d.ts +2 -0
  13. package/dist/lib/whiteboard-host.component.dom.test.d.ts.map +1 -0
  14. package/dist/lib/whiteboard-host.component.dom.test.js +187 -0
  15. package/dist/lib/whiteboard-host.component.dom.test.js.map +1 -0
  16. package/dist/lib/whiteboard-host.component.js +132 -12
  17. package/dist/lib/whiteboard-host.component.js.map +1 -1
  18. package/dist/lib/whiteboard-tool-roster.d.ts +55 -0
  19. package/dist/lib/whiteboard-tool-roster.d.ts.map +1 -0
  20. package/dist/lib/whiteboard-tool-roster.js +58 -0
  21. package/dist/lib/whiteboard-tool-roster.js.map +1 -0
  22. package/dist/lib/whiteboard-toolbar.component.d.ts +11 -4
  23. package/dist/lib/whiteboard-toolbar.component.d.ts.map +1 -1
  24. package/dist/lib/whiteboard-toolbar.component.dom.test.js +13 -0
  25. package/dist/lib/whiteboard-toolbar.component.dom.test.js.map +1 -1
  26. package/dist/lib/whiteboard-toolbar.component.js +18 -3
  27. package/dist/lib/whiteboard-toolbar.component.js.map +1 -1
  28. package/dist/public-api.d.ts +1 -0
  29. package/dist/public-api.d.ts.map +1 -1
  30. package/dist/public-api.js +2 -0
  31. package/dist/public-api.js.map +1 -1
  32. package/package.json +6 -6
@@ -1,6 +1,9 @@
1
1
  import { Component, EventEmitter, Input, Output } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { WHITEBOARD_FONT_SIZES } from './whiteboard-state';
4
+ // WhiteboardTool is imported, never re-exported: public-api.ts `export *`s this file and the
5
+ // roster module, and two modules exporting the same name that way is a TS2308 ambiguity.
6
+ import { VisibleToolbarEntries } from './whiteboard-tool-roster';
4
7
  import * as i0 from "@angular/core";
5
8
  const _forTrack0 = ($index, $item) => $item.Tool;
6
9
  const _forTrack1 = ($index, $item) => $item.Key;
@@ -187,6 +190,12 @@ export class RealtimeWhiteboardToolbarComponent {
187
190
  constructor() {
188
191
  /** The currently active tool. */
189
192
  this.ActiveTool = 'select';
193
+ /**
194
+ * Which tools the palette offers. `null` (default) is all eleven, today's rendering. A host
195
+ * that narrows this also narrows the keyboard shortcuts and the canvas context menu, because
196
+ * the same roster is threaded to all three (see `whiteboard-tool-roster.ts`).
197
+ */
198
+ this.ToolRoster = null;
190
199
  /** Selected pen ink color (from {@link WHITEBOARD_PEN_COLORS}). */
191
200
  this.PenColor = WHITEBOARD_PEN_COLORS[0];
192
201
  /** Selected pen stroke width. */
@@ -245,6 +254,10 @@ export class RealtimeWhiteboardToolbarComponent {
245
254
  { Key: 'mono', Title: 'Monospace', Stack: 'var(--mj-font-mono, ui-monospace, "SF Mono", Menlo, monospace)' }
246
255
  ];
247
256
  }
257
+ /** `Tools` narrowed by `ToolRoster`, in `Tools` order. The template loops over this. */
258
+ get VisibleTools() {
259
+ return VisibleToolbarEntries(this.Tools, this.ToolRoster);
260
+ }
248
261
  SelectTool(tool) {
249
262
  this.ToolChange.emit(tool);
250
263
  }
@@ -271,7 +284,7 @@ export class RealtimeWhiteboardToolbarComponent {
271
284
  return entry.Tool;
272
285
  }
273
286
  static { this.ɵfac = function RealtimeWhiteboardToolbarComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeWhiteboardToolbarComponent)(); }; }
274
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeWhiteboardToolbarComponent, selectors: [["mj-realtime-whiteboard-toolbar"]], inputs: { ActiveTool: "ActiveTool", PenColor: "PenColor", PenWidth: "PenWidth", ShapeKind: "ShapeKind", TextSize: "TextSize", TextFamily: "TextFamily", TextBold: "TextBold", TextColor: "TextColor", CanUndo: "CanUndo", CanRedo: "CanRedo", AgentName: "AgentName" }, outputs: { ToolChange: "ToolChange", PenColorChange: "PenColorChange", PenWidthChange: "PenWidthChange", ShapeKindChange: "ShapeKindChange", TextSizeChange: "TextSizeChange", TextFamilyChange: "TextFamilyChange", TextBoldChange: "TextBoldChange", TextColorChange: "TextColorChange", StyleSelection: "StyleSelection", Undo: "Undo", Redo: "Redo" }, decls: 8, vars: 2, consts: [[1, "board-toolbar"], ["type", "button", 1, "tool", 3, "active", "title"], [1, "tool-sep"], ["type", "button", "title", "Undo", 1, "tool", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-left"], ["type", "button", "title", "Redo", 1, "tool", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-right"], ["type", "button", 1, "tool", 3, "click", "title"], [1, "kbd"], [1, "pen-flyout"], [1, "pen-flyout", "text-flyout"], [1, "pen-flyout", "shape-flyout"], [1, "pen-flyout", 3, "click"], [1, "pen-c", 3, "sel", "background"], [1, "pen-w"], [3, "class", "sel"], [1, "pen-note"], [1, "pen-c", 3, "click"], [3, "click"], [1, "pen-flyout", "text-flyout", 3, "click"], [1, "txt-s", 3, "sel", "title"], [1, "txt-fams"], [1, "txt-f", 3, "sel", "title", "fontFamily"], ["title", "Bold", 1, "txt-f", "txt-b", 3, "click"], [1, "fa-solid", "fa-bold"], [1, "txt-colors"], [1, "txt-s", 3, "click", "title"], [1, "txt-f", 3, "click", "title"], [1, "pen-flyout", "shape-flyout", 3, "click"], [1, "shape-c", 3, "sel", "title"], [1, "shape-c", 3, "click", "title"]], template: function RealtimeWhiteboardToolbarComponent_Template(rf, ctx) { if (rf & 1) {
287
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeWhiteboardToolbarComponent, selectors: [["mj-realtime-whiteboard-toolbar"]], inputs: { ActiveTool: "ActiveTool", ToolRoster: "ToolRoster", PenColor: "PenColor", PenWidth: "PenWidth", ShapeKind: "ShapeKind", TextSize: "TextSize", TextFamily: "TextFamily", TextBold: "TextBold", TextColor: "TextColor", CanUndo: "CanUndo", CanRedo: "CanRedo", AgentName: "AgentName" }, outputs: { ToolChange: "ToolChange", PenColorChange: "PenColorChange", PenWidthChange: "PenWidthChange", ShapeKindChange: "ShapeKindChange", TextSizeChange: "TextSizeChange", TextFamilyChange: "TextFamilyChange", TextBoldChange: "TextBoldChange", TextColorChange: "TextColorChange", StyleSelection: "StyleSelection", Undo: "Undo", Redo: "Redo" }, decls: 8, vars: 2, consts: [[1, "board-toolbar"], ["type", "button", 1, "tool", 3, "active", "title"], [1, "tool-sep"], ["type", "button", "title", "Undo", 1, "tool", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-left"], ["type", "button", "title", "Redo", 1, "tool", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-right"], ["type", "button", 1, "tool", 3, "click", "title"], [1, "kbd"], [1, "pen-flyout"], [1, "pen-flyout", "text-flyout"], [1, "pen-flyout", "shape-flyout"], [1, "pen-flyout", 3, "click"], [1, "pen-c", 3, "sel", "background"], [1, "pen-w"], [3, "class", "sel"], [1, "pen-note"], [1, "pen-c", 3, "click"], [3, "click"], [1, "pen-flyout", "text-flyout", 3, "click"], [1, "txt-s", 3, "sel", "title"], [1, "txt-fams"], [1, "txt-f", 3, "sel", "title", "fontFamily"], ["title", "Bold", 1, "txt-f", "txt-b", 3, "click"], [1, "fa-solid", "fa-bold"], [1, "txt-colors"], [1, "txt-s", 3, "click", "title"], [1, "txt-f", 3, "click", "title"], [1, "pen-flyout", "shape-flyout", 3, "click"], [1, "shape-c", 3, "sel", "title"], [1, "shape-c", 3, "click", "title"]], template: function RealtimeWhiteboardToolbarComponent_Template(rf, ctx) { if (rf & 1) {
275
288
  i0.ɵɵdomElementStart(0, "div", 0);
276
289
  i0.ɵɵrepeaterCreate(1, RealtimeWhiteboardToolbarComponent_For_2_Template, 7, 9, "button", 1, _forTrack0);
277
290
  i0.ɵɵdomElement(3, "div", 2);
@@ -285,7 +298,7 @@ export class RealtimeWhiteboardToolbarComponent {
285
298
  i0.ɵɵdomElementEnd()();
286
299
  } if (rf & 2) {
287
300
  i0.ɵɵadvance();
288
- i0.ɵɵrepeater(ctx.Tools);
301
+ i0.ɵɵrepeater(ctx.VisibleTools);
289
302
  i0.ɵɵadvance(3);
290
303
  i0.ɵɵdomProperty("disabled", !ctx.CanUndo);
291
304
  i0.ɵɵadvance(2);
@@ -294,9 +307,11 @@ export class RealtimeWhiteboardToolbarComponent {
294
307
  }
295
308
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeWhiteboardToolbarComponent, [{
296
309
  type: Component,
297
- args: [{ standalone: true, selector: 'mj-realtime-whiteboard-toolbar', imports: [CommonModule], template: "<div class=\"board-toolbar\">\n @for (entry of Tools; track entry.Tool) {\n <button type=\"button\"\n class=\"tool\"\n [class.active]=\"ActiveTool === entry.Tool\"\n [title]=\"entry.Title\"\n (click)=\"SelectTool(entry.Tool)\">\n <i [class]=\"entry.Icon\"></i><span class=\"kbd\">{{ entry.Kbd }}</span>\n\n @if (entry.Tool === 'pen' && ActiveTool === 'pen') {\n <span class=\"pen-flyout\" (click)=\"$event.stopPropagation()\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"PenColor === color\"\n [style.background]=\"color\"\n (click)=\"PenColorChange.emit(color)\"></span>\n }\n <span class=\"pen-w\">\n @for (width of PenWidths; track width; let i = $index) {\n <span [class]=\"'w' + (i + 1)\"\n [class.sel]=\"PenWidth === width\"\n (click)=\"PenWidthChange.emit(width)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'text' && ActiveTool === 'text') {\n <span class=\"pen-flyout text-flyout\" (click)=\"$event.stopPropagation()\">\n @for (size of TextSizes; track size) {\n <span class=\"txt-s\"\n [class.sel]=\"TextSize === size\"\n [title]=\"size + ' px'\"\n (click)=\"PickTextSize(size)\">{{ size }}</span>\n }\n <span class=\"txt-fams\">\n @for (fam of TextFamilies; track fam.Key) {\n <span class=\"txt-f\"\n [class.sel]=\"TextFamily === fam.Key\"\n [title]=\"fam.Title\"\n [style.fontFamily]=\"fam.Stack\"\n (click)=\"PickTextFamily(fam.Key)\">Ag</span>\n }\n <span class=\"txt-f txt-b\"\n [class.sel]=\"TextBold\"\n title=\"Bold\"\n (click)=\"ToggleTextBold()\"><i class=\"fa-solid fa-bold\"></i></span>\n </span>\n <span class=\"txt-colors\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"TextColor === color\"\n [style.background]=\"color\"\n (click)=\"PickTextColor(color)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'shape' && ActiveTool === 'shape') {\n <span class=\"pen-flyout shape-flyout\" (click)=\"$event.stopPropagation()\">\n @for (shape of ShapeKinds; track shape.Kind) {\n <span class=\"shape-c\"\n [class.sel]=\"ShapeKind === shape.Kind\"\n [title]=\"shape.Title\"\n (click)=\"ShapeKindChange.emit(shape.Kind)\"><i [class]=\"shape.Icon\"></i></span>\n }\n <span class=\"pen-note\">drag to draw</span>\n </span>\n }\n </button>\n }\n\n <div class=\"tool-sep\"></div>\n <button type=\"button\" class=\"tool\" title=\"Undo\" [disabled]=\"!CanUndo\" (click)=\"Undo.emit()\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n </button>\n <button type=\"button\" class=\"tool\" title=\"Redo\" [disabled]=\"!CanRedo\" (click)=\"Redo.emit()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n </button>\n</div>\n", styles: ["/* Floating left-edge board toolbar \u2014 ported pixel-faithfully from\n plans/realtime/mockups/whiteboard.html (.board-toolbar / .tool / .pen-flyout). */\n\n:host {\n display: block;\n position: absolute;\n left: 14px;\n top: 14px;\n z-index: 10;\n}\n\n.board-toolbar {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 6px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 12px);\n box-shadow: var(--mj-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.3));\n}\n\n.tool {\n position: relative;\n width: 36px;\n height: 36px;\n border-radius: var(--mj-radius-md, 8px);\n border: 0;\n cursor: pointer;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 13.5px;\n display: grid;\n place-items: center;\n transition: all 130ms ease;\n font-family: inherit;\n}\n.tool:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.tool.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n box-shadow: var(--mj-shadow-brand, 0 4px 14px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent));\n}\n.tool:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.tool:disabled:hover {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n.tool .kbd {\n position: absolute;\n bottom: 1px;\n right: 3px;\n font-size: 7px;\n font-weight: 700;\n color: currentColor;\n opacity: 0.55;\n}\n\n.tool-sep {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 4px;\n}\n\n/* ---------- pen / shape flyout ---------- */\n.pen-flyout {\n position: absolute;\n left: calc(100% + 10px);\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 8px 11px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n box-shadow: var(--mj-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.3));\n white-space: nowrap;\n cursor: default;\n}\n.pen-flyout::before {\n content: \"\";\n position: absolute;\n left: -5px;\n top: calc(50% - 5px);\n width: 9px;\n height: 9px;\n transform: rotate(45deg);\n background: var(--mj-bg-surface-card);\n border-left: 1px solid var(--mj-border-default);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.pen-c {\n width: 17px;\n height: 17px;\n border-radius: 50%;\n cursor: pointer;\n border: 2px solid transparent;\n}\n.pen-c.sel {\n border-color: var(--mj-text-inverse, #fff);\n box-shadow: 0 0 0 2px var(--mj-brand-primary);\n}\n\n.pen-w {\n display: flex;\n align-items: center;\n gap: 7px;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n.pen-w span {\n border-radius: 99px;\n background: var(--mj-text-secondary);\n cursor: pointer;\n}\n.pen-w .w1 { width: 14px; height: 2px; }\n.pen-w .w2 { width: 14px; height: 4px; }\n.pen-w .w3 { width: 14px; height: 7px; }\n.pen-w span.sel {\n background: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 2px;\n}\n\n.pen-note {\n font-size: 9.5px;\n color: var(--mj-text-muted);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n\n/* shape flyout reuses pen-flyout chrome */\n.shape-c {\n width: 22px;\n height: 22px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n.shape-c:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n.shape-c.sel {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 1px;\n}\n.shape-c i.wb-diamond {\n transform: rotate(45deg);\n font-size: 10px;\n}\n\n/* ---------- text-style flyout (reuses pen-flyout chrome) ---------- */\n.text-flyout {\n gap: 6px;\n}\n.txt-s {\n min-width: 20px;\n height: 20px;\n padding: 0 3px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 10px;\n font-weight: 700;\n}\n.txt-s:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n.txt-s.sel {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 1px;\n}\n\n.txt-fams {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n.txt-f {\n width: 22px;\n height: 22px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 11px;\n font-weight: 600;\n}\n.txt-f:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n.txt-f.sel {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 1px;\n}\n.txt-b {\n font-size: 10px;\n}\n\n.txt-colors {\n display: flex;\n align-items: center;\n gap: 9px;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n"] }]
310
+ args: [{ standalone: true, selector: 'mj-realtime-whiteboard-toolbar', imports: [CommonModule], template: "<div class=\"board-toolbar\">\n @for (entry of VisibleTools; track entry.Tool) {\n <button type=\"button\"\n class=\"tool\"\n [class.active]=\"ActiveTool === entry.Tool\"\n [title]=\"entry.Title\"\n (click)=\"SelectTool(entry.Tool)\">\n <i [class]=\"entry.Icon\"></i><span class=\"kbd\">{{ entry.Kbd }}</span>\n\n @if (entry.Tool === 'pen' && ActiveTool === 'pen') {\n <span class=\"pen-flyout\" (click)=\"$event.stopPropagation()\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"PenColor === color\"\n [style.background]=\"color\"\n (click)=\"PenColorChange.emit(color)\"></span>\n }\n <span class=\"pen-w\">\n @for (width of PenWidths; track width; let i = $index) {\n <span [class]=\"'w' + (i + 1)\"\n [class.sel]=\"PenWidth === width\"\n (click)=\"PenWidthChange.emit(width)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'text' && ActiveTool === 'text') {\n <span class=\"pen-flyout text-flyout\" (click)=\"$event.stopPropagation()\">\n @for (size of TextSizes; track size) {\n <span class=\"txt-s\"\n [class.sel]=\"TextSize === size\"\n [title]=\"size + ' px'\"\n (click)=\"PickTextSize(size)\">{{ size }}</span>\n }\n <span class=\"txt-fams\">\n @for (fam of TextFamilies; track fam.Key) {\n <span class=\"txt-f\"\n [class.sel]=\"TextFamily === fam.Key\"\n [title]=\"fam.Title\"\n [style.fontFamily]=\"fam.Stack\"\n (click)=\"PickTextFamily(fam.Key)\">Ag</span>\n }\n <span class=\"txt-f txt-b\"\n [class.sel]=\"TextBold\"\n title=\"Bold\"\n (click)=\"ToggleTextBold()\"><i class=\"fa-solid fa-bold\"></i></span>\n </span>\n <span class=\"txt-colors\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"TextColor === color\"\n [style.background]=\"color\"\n (click)=\"PickTextColor(color)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'shape' && ActiveTool === 'shape') {\n <span class=\"pen-flyout shape-flyout\" (click)=\"$event.stopPropagation()\">\n @for (shape of ShapeKinds; track shape.Kind) {\n <span class=\"shape-c\"\n [class.sel]=\"ShapeKind === shape.Kind\"\n [title]=\"shape.Title\"\n (click)=\"ShapeKindChange.emit(shape.Kind)\"><i [class]=\"shape.Icon\"></i></span>\n }\n <span class=\"pen-note\">drag to draw</span>\n </span>\n }\n </button>\n }\n\n <div class=\"tool-sep\"></div>\n <button type=\"button\" class=\"tool\" title=\"Undo\" [disabled]=\"!CanUndo\" (click)=\"Undo.emit()\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n </button>\n <button type=\"button\" class=\"tool\" title=\"Redo\" [disabled]=\"!CanRedo\" (click)=\"Redo.emit()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n </button>\n</div>\n", styles: ["/* Floating left-edge board toolbar \u2014 ported pixel-faithfully from\n plans/realtime/mockups/whiteboard.html (.board-toolbar / .tool / .pen-flyout). */\n\n:host {\n display: block;\n position: absolute;\n left: 14px;\n top: 14px;\n z-index: 10;\n}\n\n.board-toolbar {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 6px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg, 12px);\n box-shadow: var(--mj-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.3));\n}\n\n.tool {\n position: relative;\n width: 36px;\n height: 36px;\n border-radius: var(--mj-radius-md, 8px);\n border: 0;\n cursor: pointer;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 13.5px;\n display: grid;\n place-items: center;\n transition: all 130ms ease;\n font-family: inherit;\n}\n.tool:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.tool.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #fff);\n box-shadow: var(--mj-shadow-brand, 0 4px 14px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent));\n}\n.tool:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.tool:disabled:hover {\n background: transparent;\n color: var(--mj-text-secondary);\n}\n.tool .kbd {\n position: absolute;\n bottom: 1px;\n right: 3px;\n font-size: 7px;\n font-weight: 700;\n color: currentColor;\n opacity: 0.55;\n}\n\n.tool-sep {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 4px;\n}\n\n/* ---------- pen / shape flyout ---------- */\n.pen-flyout {\n position: absolute;\n left: calc(100% + 10px);\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 8px 11px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n box-shadow: var(--mj-shadow-xl, 0 20px 25px -5px rgba(0, 0, 0, 0.3));\n white-space: nowrap;\n cursor: default;\n}\n.pen-flyout::before {\n content: \"\";\n position: absolute;\n left: -5px;\n top: calc(50% - 5px);\n width: 9px;\n height: 9px;\n transform: rotate(45deg);\n background: var(--mj-bg-surface-card);\n border-left: 1px solid var(--mj-border-default);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.pen-c {\n width: 17px;\n height: 17px;\n border-radius: 50%;\n cursor: pointer;\n border: 2px solid transparent;\n}\n.pen-c.sel {\n border-color: var(--mj-text-inverse, #fff);\n box-shadow: 0 0 0 2px var(--mj-brand-primary);\n}\n\n.pen-w {\n display: flex;\n align-items: center;\n gap: 7px;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n.pen-w span {\n border-radius: 99px;\n background: var(--mj-text-secondary);\n cursor: pointer;\n}\n.pen-w .w1 { width: 14px; height: 2px; }\n.pen-w .w2 { width: 14px; height: 4px; }\n.pen-w .w3 { width: 14px; height: 7px; }\n.pen-w span.sel {\n background: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 2px;\n}\n\n.pen-note {\n font-size: 9.5px;\n color: var(--mj-text-muted);\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n\n/* shape flyout reuses pen-flyout chrome */\n.shape-c {\n width: 22px;\n height: 22px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n.shape-c:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n.shape-c.sel {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 1px;\n}\n.shape-c i.wb-diamond {\n transform: rotate(45deg);\n font-size: 10px;\n}\n\n/* ---------- text-style flyout (reuses pen-flyout chrome) ---------- */\n.text-flyout {\n gap: 6px;\n}\n.txt-s {\n min-width: 20px;\n height: 20px;\n padding: 0 3px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 10px;\n font-weight: 700;\n}\n.txt-s:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n.txt-s.sel {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 1px;\n}\n\n.txt-fams {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n.txt-f {\n width: 22px;\n height: 22px;\n border-radius: var(--mj-radius-md, 8px);\n display: grid;\n place-items: center;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 11px;\n font-weight: 600;\n}\n.txt-f:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n.txt-f.sel {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n outline: 2px solid color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n outline-offset: 1px;\n}\n.txt-b {\n font-size: 10px;\n}\n\n.txt-colors {\n display: flex;\n align-items: center;\n gap: 9px;\n padding-left: 9px;\n border-left: 1px solid var(--mj-border-default);\n}\n"] }]
298
311
  }], null, { ActiveTool: [{
299
312
  type: Input
313
+ }], ToolRoster: [{
314
+ type: Input
300
315
  }], PenColor: [{
301
316
  type: Input
302
317
  }], PenWidth: [{
@@ -1 +1 @@
1
- {"version":3,"file":"whiteboard-toolbar.component.js","sourceRoot":"","sources":["../../src/lib/whiteboard-toolbar.component.ts","../../src/lib/whiteboard-toolbar.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { WHITEBOARD_FONT_SIZES, WhiteboardFontFamily, WhiteboardShapeKind } from './whiteboard-state';\n\n/** A user-selectable board tool. */\nexport type WhiteboardTool = 'select' | 'pan' | 'pen' | 'shape' | 'sticky' | 'text' | 'markdown' | 'html' | 'image' | 'connector' | 'eraser';\n\n/** One entry in the floating toolbar. */\ninterface ToolbarEntry {\n Tool: WhiteboardTool;\n Icon: string;\n Title: string;\n Kbd: string;\n}\n\n/**\n * USER pen palette — categorical ink colors. Violet is deliberately EXCLUDED:\n * violet is the reserved ownership hue of the agent's marks.\n */\nexport const WHITEBOARD_PEN_COLORS: readonly string[] = ['#cbd5e1', '#fbbf24', '#5cc0ed', '#4ade80', '#f87171'];\n\n/** Available pen stroke widths (px). */\nexport const WHITEBOARD_PEN_WIDTHS: readonly number[] = [2, 4, 7];\n\n/**\n * A partial text-style choice emitted when the user picks a style with an existing\n * text / sticky selection — the board applies it to the selected item via the state engine.\n */\nexport interface WhiteboardTextStyleEvent {\n FontSize?: number;\n FontFamily?: WhiteboardFontFamily;\n Bold?: boolean;\n Color?: string;\n}\n\n/** One font-family choice in the text-style flyout (key + preview stack). */\ninterface FontFamilyEntry {\n Key: WhiteboardFontFamily;\n Title: string;\n Stack: string;\n}\n\n/**\n * The floating left-edge toolbar of the live whiteboard: tool buttons with kbd hints,\n * the pen color/width flyout (with the \"violet = agent's\" reservation note), the shape\n * flyout, and undo/redo. Pure presentational — all state in/out via bindings.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-whiteboard-toolbar',\n imports: [CommonModule],\n templateUrl: './whiteboard-toolbar.component.html',\n styleUrl: './whiteboard-toolbar.component.css'\n})\nexport class RealtimeWhiteboardToolbarComponent {\n /** The currently active tool. */\n @Input() ActiveTool: WhiteboardTool = 'select';\n /** Selected pen ink color (from {@link WHITEBOARD_PEN_COLORS}). */\n @Input() PenColor: string = WHITEBOARD_PEN_COLORS[0];\n /** Selected pen stroke width. */\n @Input() PenWidth = 4;\n /** Selected shape kind for drag-create. */\n @Input() ShapeKind: WhiteboardShapeKind = 'rect';\n /** Selected text font size (curated steps; 12 matches the CSS default). */\n @Input() TextSize = 12;\n /** Selected text font family. */\n @Input() TextFamily: WhiteboardFontFamily = 'sans';\n /** Selected text bold state (labels render bold by default). */\n @Input() TextBold = true;\n /** Selected text color (null = the theme default; palette excludes the agent's violet). */\n @Input() TextColor: string | null = null;\n /** Whether undo / redo are available (drives nothing visually but kept for a11y). */\n @Input() CanUndo = false;\n @Input() CanRedo = false;\n /** Display name of the session's agent (the pen flyout note: \"violet = Sage's\"). */\n @Input() AgentName = 'Agent';\n\n @Output() ToolChange = new EventEmitter<WhiteboardTool>();\n @Output() PenColorChange = new EventEmitter<string>();\n @Output() PenWidthChange = new EventEmitter<number>();\n @Output() ShapeKindChange = new EventEmitter<WhiteboardShapeKind>();\n @Output() TextSizeChange = new EventEmitter<number>();\n @Output() TextFamilyChange = new EventEmitter<WhiteboardFontFamily>();\n @Output() TextBoldChange = new EventEmitter<boolean>();\n @Output() TextColorChange = new EventEmitter<string>();\n /** A style choice was made — the board applies it to the selected text/sticky item (if any). */\n @Output() StyleSelection = new EventEmitter<WhiteboardTextStyleEvent>();\n @Output() Undo = new EventEmitter<void>();\n @Output() Redo = new EventEmitter<void>();\n\n public readonly Tools: ToolbarEntry[] = [\n { Tool: 'select', Icon: 'fa-solid fa-arrow-pointer', Title: 'Select / move', Kbd: 'V' },\n { Tool: 'pan', Icon: 'fa-regular fa-hand', Title: 'Pan', Kbd: 'H' },\n { Tool: 'pen', Icon: 'fa-solid fa-pen', Title: 'Pen', Kbd: 'P' },\n { Tool: 'shape', Icon: 'fa-regular fa-square', Title: 'Shapes', Kbd: 'R' },\n { Tool: 'sticky', Icon: 'fa-regular fa-note-sticky', Title: 'Sticky note', Kbd: 'S' },\n { Tool: 'text', Icon: 'fa-solid fa-font', Title: 'Text', Kbd: 'T' },\n { Tool: 'markdown', Icon: 'fa-brands fa-markdown', Title: 'Markdown panel', Kbd: 'M' },\n { Tool: 'html', Icon: 'fa-solid fa-code', Title: 'HTML widget (sandboxed)', Kbd: 'W' },\n { Tool: 'image', Icon: 'fa-regular fa-image', Title: 'Paste / insert image', Kbd: 'I' },\n { Tool: 'connector', Icon: 'fa-solid fa-arrow-trend-up', Title: 'Connector', Kbd: 'C' },\n { Tool: 'eraser', Icon: 'fa-solid fa-eraser', Title: 'Eraser', Kbd: 'E' }\n ];\n\n public readonly PenColors = WHITEBOARD_PEN_COLORS;\n public readonly PenWidths = WHITEBOARD_PEN_WIDTHS;\n public readonly ShapeKinds: { Kind: WhiteboardShapeKind; Icon: string; Title: string }[] = [\n { Kind: 'rect', Icon: 'fa-regular fa-square', Title: 'Rectangle' },\n { Kind: 'ellipse', Icon: 'fa-regular fa-circle', Title: 'Ellipse' },\n { Kind: 'diamond', Icon: 'fa-regular fa-square wb-diamond', Title: 'Diamond' }\n ];\n public readonly TextSizes = WHITEBOARD_FONT_SIZES;\n public readonly TextFamilies: FontFamilyEntry[] = [\n { Key: 'sans', Title: 'Sans-serif', Stack: 'inherit' },\n { Key: 'serif', Title: 'Serif', Stack: 'Georgia, \"Times New Roman\", serif' },\n { Key: 'mono', Title: 'Monospace', Stack: 'var(--mj-font-mono, ui-monospace, \"SF Mono\", Menlo, monospace)' }\n ];\n\n public SelectTool(tool: WhiteboardTool): void {\n this.ToolChange.emit(tool);\n }\n\n // Each pick updates the chosen style for NEW text AND restyles the current\n // text/sticky selection (the board ignores StyleSelection when nothing applies).\n public PickTextSize(size: number): void {\n this.TextSizeChange.emit(size);\n this.StyleSelection.emit({ FontSize: size });\n }\n\n public PickTextFamily(family: WhiteboardFontFamily): void {\n this.TextFamilyChange.emit(family);\n this.StyleSelection.emit({ FontFamily: family });\n }\n\n public ToggleTextBold(): void {\n const next = !this.TextBold;\n this.TextBoldChange.emit(next);\n this.StyleSelection.emit({ Bold: next });\n }\n\n public PickTextColor(color: string): void {\n this.TextColorChange.emit(color);\n this.StyleSelection.emit({ Color: color });\n }\n\n public TrackTool(index: number, entry: ToolbarEntry): WhiteboardTool {\n return entry.Tool;\n }\n}\n","<div class=\"board-toolbar\">\n @for (entry of Tools; track entry.Tool) {\n <button type=\"button\"\n class=\"tool\"\n [class.active]=\"ActiveTool === entry.Tool\"\n [title]=\"entry.Title\"\n (click)=\"SelectTool(entry.Tool)\">\n <i [class]=\"entry.Icon\"></i><span class=\"kbd\">{{ entry.Kbd }}</span>\n\n @if (entry.Tool === 'pen' && ActiveTool === 'pen') {\n <span class=\"pen-flyout\" (click)=\"$event.stopPropagation()\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"PenColor === color\"\n [style.background]=\"color\"\n (click)=\"PenColorChange.emit(color)\"></span>\n }\n <span class=\"pen-w\">\n @for (width of PenWidths; track width; let i = $index) {\n <span [class]=\"'w' + (i + 1)\"\n [class.sel]=\"PenWidth === width\"\n (click)=\"PenWidthChange.emit(width)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'text' && ActiveTool === 'text') {\n <span class=\"pen-flyout text-flyout\" (click)=\"$event.stopPropagation()\">\n @for (size of TextSizes; track size) {\n <span class=\"txt-s\"\n [class.sel]=\"TextSize === size\"\n [title]=\"size + ' px'\"\n (click)=\"PickTextSize(size)\">{{ size }}</span>\n }\n <span class=\"txt-fams\">\n @for (fam of TextFamilies; track fam.Key) {\n <span class=\"txt-f\"\n [class.sel]=\"TextFamily === fam.Key\"\n [title]=\"fam.Title\"\n [style.fontFamily]=\"fam.Stack\"\n (click)=\"PickTextFamily(fam.Key)\">Ag</span>\n }\n <span class=\"txt-f txt-b\"\n [class.sel]=\"TextBold\"\n title=\"Bold\"\n (click)=\"ToggleTextBold()\"><i class=\"fa-solid fa-bold\"></i></span>\n </span>\n <span class=\"txt-colors\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"TextColor === color\"\n [style.background]=\"color\"\n (click)=\"PickTextColor(color)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'shape' && ActiveTool === 'shape') {\n <span class=\"pen-flyout shape-flyout\" (click)=\"$event.stopPropagation()\">\n @for (shape of ShapeKinds; track shape.Kind) {\n <span class=\"shape-c\"\n [class.sel]=\"ShapeKind === shape.Kind\"\n [title]=\"shape.Title\"\n (click)=\"ShapeKindChange.emit(shape.Kind)\"><i [class]=\"shape.Icon\"></i></span>\n }\n <span class=\"pen-note\">drag to draw</span>\n </span>\n }\n </button>\n }\n\n <div class=\"tool-sep\"></div>\n <button type=\"button\" class=\"tool\" title=\"Undo\" [disabled]=\"!CanUndo\" (click)=\"Undo.emit()\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n </button>\n <button type=\"button\" class=\"tool\" title=\"Redo\" [disabled]=\"!CanRedo\" (click)=\"Redo.emit()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n </button>\n</div>\n"]}
1
+ {"version":3,"file":"whiteboard-toolbar.component.js","sourceRoot":"","sources":["../../src/lib/whiteboard-toolbar.component.ts","../../src/lib/whiteboard-toolbar.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { WHITEBOARD_FONT_SIZES, WhiteboardFontFamily, WhiteboardShapeKind } from './whiteboard-state';\n// WhiteboardTool is imported, never re-exported: public-api.ts `export *`s this file and the\n// roster module, and two modules exporting the same name that way is a TS2308 ambiguity.\nimport { WhiteboardTool, WhiteboardToolRoster, VisibleToolbarEntries } from './whiteboard-tool-roster';\n\n/** One entry in the floating toolbar. */\ninterface ToolbarEntry {\n Tool: WhiteboardTool;\n Icon: string;\n Title: string;\n Kbd: string;\n}\n\n/**\n * USER pen palette — categorical ink colors. Violet is deliberately EXCLUDED:\n * violet is the reserved ownership hue of the agent's marks.\n */\nexport const WHITEBOARD_PEN_COLORS: readonly string[] = ['#cbd5e1', '#fbbf24', '#5cc0ed', '#4ade80', '#f87171'];\n\n/** Available pen stroke widths (px). */\nexport const WHITEBOARD_PEN_WIDTHS: readonly number[] = [2, 4, 7];\n\n/**\n * A partial text-style choice emitted when the user picks a style with an existing\n * text / sticky selection — the board applies it to the selected item via the state engine.\n */\nexport interface WhiteboardTextStyleEvent {\n FontSize?: number;\n FontFamily?: WhiteboardFontFamily;\n Bold?: boolean;\n Color?: string;\n}\n\n/** One font-family choice in the text-style flyout (key + preview stack). */\ninterface FontFamilyEntry {\n Key: WhiteboardFontFamily;\n Title: string;\n Stack: string;\n}\n\n/**\n * The floating left-edge toolbar of the live whiteboard: tool buttons with kbd hints,\n * the pen color/width flyout (with the \"violet = agent's\" reservation note), the shape\n * flyout, and undo/redo. Pure presentational — all state in/out via bindings.\n */\n@Component({\n standalone: true,\n selector: 'mj-realtime-whiteboard-toolbar',\n imports: [CommonModule],\n templateUrl: './whiteboard-toolbar.component.html',\n styleUrl: './whiteboard-toolbar.component.css'\n})\nexport class RealtimeWhiteboardToolbarComponent {\n /** The currently active tool. */\n @Input() ActiveTool: WhiteboardTool = 'select';\n /**\n * Which tools the palette offers. `null` (default) is all eleven, today's rendering. A host\n * that narrows this also narrows the keyboard shortcuts and the canvas context menu, because\n * the same roster is threaded to all three (see `whiteboard-tool-roster.ts`).\n */\n @Input() ToolRoster: WhiteboardToolRoster = null;\n /** Selected pen ink color (from {@link WHITEBOARD_PEN_COLORS}). */\n @Input() PenColor: string = WHITEBOARD_PEN_COLORS[0];\n /** Selected pen stroke width. */\n @Input() PenWidth = 4;\n /** Selected shape kind for drag-create. */\n @Input() ShapeKind: WhiteboardShapeKind = 'rect';\n /** Selected text font size (curated steps; 12 matches the CSS default). */\n @Input() TextSize = 12;\n /** Selected text font family. */\n @Input() TextFamily: WhiteboardFontFamily = 'sans';\n /** Selected text bold state (labels render bold by default). */\n @Input() TextBold = true;\n /** Selected text color (null = the theme default; palette excludes the agent's violet). */\n @Input() TextColor: string | null = null;\n /** Whether undo / redo are available (drives nothing visually but kept for a11y). */\n @Input() CanUndo = false;\n @Input() CanRedo = false;\n /** Display name of the session's agent (the pen flyout note: \"violet = Sage's\"). */\n @Input() AgentName = 'Agent';\n\n @Output() ToolChange = new EventEmitter<WhiteboardTool>();\n @Output() PenColorChange = new EventEmitter<string>();\n @Output() PenWidthChange = new EventEmitter<number>();\n @Output() ShapeKindChange = new EventEmitter<WhiteboardShapeKind>();\n @Output() TextSizeChange = new EventEmitter<number>();\n @Output() TextFamilyChange = new EventEmitter<WhiteboardFontFamily>();\n @Output() TextBoldChange = new EventEmitter<boolean>();\n @Output() TextColorChange = new EventEmitter<string>();\n /** A style choice was made — the board applies it to the selected text/sticky item (if any). */\n @Output() StyleSelection = new EventEmitter<WhiteboardTextStyleEvent>();\n @Output() Undo = new EventEmitter<void>();\n @Output() Redo = new EventEmitter<void>();\n\n public readonly Tools: ToolbarEntry[] = [\n { Tool: 'select', Icon: 'fa-solid fa-arrow-pointer', Title: 'Select / move', Kbd: 'V' },\n { Tool: 'pan', Icon: 'fa-regular fa-hand', Title: 'Pan', Kbd: 'H' },\n { Tool: 'pen', Icon: 'fa-solid fa-pen', Title: 'Pen', Kbd: 'P' },\n { Tool: 'shape', Icon: 'fa-regular fa-square', Title: 'Shapes', Kbd: 'R' },\n { Tool: 'sticky', Icon: 'fa-regular fa-note-sticky', Title: 'Sticky note', Kbd: 'S' },\n { Tool: 'text', Icon: 'fa-solid fa-font', Title: 'Text', Kbd: 'T' },\n { Tool: 'markdown', Icon: 'fa-brands fa-markdown', Title: 'Markdown panel', Kbd: 'M' },\n { Tool: 'html', Icon: 'fa-solid fa-code', Title: 'HTML widget (sandboxed)', Kbd: 'W' },\n { Tool: 'image', Icon: 'fa-regular fa-image', Title: 'Paste / insert image', Kbd: 'I' },\n { Tool: 'connector', Icon: 'fa-solid fa-arrow-trend-up', Title: 'Connector', Kbd: 'C' },\n { Tool: 'eraser', Icon: 'fa-solid fa-eraser', Title: 'Eraser', Kbd: 'E' }\n ];\n\n /** `Tools` narrowed by `ToolRoster`, in `Tools` order. The template loops over this. */\n public get VisibleTools(): ToolbarEntry[] {\n return VisibleToolbarEntries(this.Tools, this.ToolRoster);\n }\n\n public readonly PenColors = WHITEBOARD_PEN_COLORS;\n public readonly PenWidths = WHITEBOARD_PEN_WIDTHS;\n public readonly ShapeKinds: { Kind: WhiteboardShapeKind; Icon: string; Title: string }[] = [\n { Kind: 'rect', Icon: 'fa-regular fa-square', Title: 'Rectangle' },\n { Kind: 'ellipse', Icon: 'fa-regular fa-circle', Title: 'Ellipse' },\n { Kind: 'diamond', Icon: 'fa-regular fa-square wb-diamond', Title: 'Diamond' }\n ];\n public readonly TextSizes = WHITEBOARD_FONT_SIZES;\n public readonly TextFamilies: FontFamilyEntry[] = [\n { Key: 'sans', Title: 'Sans-serif', Stack: 'inherit' },\n { Key: 'serif', Title: 'Serif', Stack: 'Georgia, \"Times New Roman\", serif' },\n { Key: 'mono', Title: 'Monospace', Stack: 'var(--mj-font-mono, ui-monospace, \"SF Mono\", Menlo, monospace)' }\n ];\n\n public SelectTool(tool: WhiteboardTool): void {\n this.ToolChange.emit(tool);\n }\n\n // Each pick updates the chosen style for NEW text AND restyles the current\n // text/sticky selection (the board ignores StyleSelection when nothing applies).\n public PickTextSize(size: number): void {\n this.TextSizeChange.emit(size);\n this.StyleSelection.emit({ FontSize: size });\n }\n\n public PickTextFamily(family: WhiteboardFontFamily): void {\n this.TextFamilyChange.emit(family);\n this.StyleSelection.emit({ FontFamily: family });\n }\n\n public ToggleTextBold(): void {\n const next = !this.TextBold;\n this.TextBoldChange.emit(next);\n this.StyleSelection.emit({ Bold: next });\n }\n\n public PickTextColor(color: string): void {\n this.TextColorChange.emit(color);\n this.StyleSelection.emit({ Color: color });\n }\n\n public TrackTool(index: number, entry: ToolbarEntry): WhiteboardTool {\n return entry.Tool;\n }\n}\n","<div class=\"board-toolbar\">\n @for (entry of VisibleTools; track entry.Tool) {\n <button type=\"button\"\n class=\"tool\"\n [class.active]=\"ActiveTool === entry.Tool\"\n [title]=\"entry.Title\"\n (click)=\"SelectTool(entry.Tool)\">\n <i [class]=\"entry.Icon\"></i><span class=\"kbd\">{{ entry.Kbd }}</span>\n\n @if (entry.Tool === 'pen' && ActiveTool === 'pen') {\n <span class=\"pen-flyout\" (click)=\"$event.stopPropagation()\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"PenColor === color\"\n [style.background]=\"color\"\n (click)=\"PenColorChange.emit(color)\"></span>\n }\n <span class=\"pen-w\">\n @for (width of PenWidths; track width; let i = $index) {\n <span [class]=\"'w' + (i + 1)\"\n [class.sel]=\"PenWidth === width\"\n (click)=\"PenWidthChange.emit(width)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'text' && ActiveTool === 'text') {\n <span class=\"pen-flyout text-flyout\" (click)=\"$event.stopPropagation()\">\n @for (size of TextSizes; track size) {\n <span class=\"txt-s\"\n [class.sel]=\"TextSize === size\"\n [title]=\"size + ' px'\"\n (click)=\"PickTextSize(size)\">{{ size }}</span>\n }\n <span class=\"txt-fams\">\n @for (fam of TextFamilies; track fam.Key) {\n <span class=\"txt-f\"\n [class.sel]=\"TextFamily === fam.Key\"\n [title]=\"fam.Title\"\n [style.fontFamily]=\"fam.Stack\"\n (click)=\"PickTextFamily(fam.Key)\">Ag</span>\n }\n <span class=\"txt-f txt-b\"\n [class.sel]=\"TextBold\"\n title=\"Bold\"\n (click)=\"ToggleTextBold()\"><i class=\"fa-solid fa-bold\"></i></span>\n </span>\n <span class=\"txt-colors\">\n @for (color of PenColors; track color) {\n <span class=\"pen-c\"\n [class.sel]=\"TextColor === color\"\n [style.background]=\"color\"\n (click)=\"PickTextColor(color)\"></span>\n }\n </span>\n <span class=\"pen-note\">violet = {{ AgentName }}'s</span>\n </span>\n }\n\n @if (entry.Tool === 'shape' && ActiveTool === 'shape') {\n <span class=\"pen-flyout shape-flyout\" (click)=\"$event.stopPropagation()\">\n @for (shape of ShapeKinds; track shape.Kind) {\n <span class=\"shape-c\"\n [class.sel]=\"ShapeKind === shape.Kind\"\n [title]=\"shape.Title\"\n (click)=\"ShapeKindChange.emit(shape.Kind)\"><i [class]=\"shape.Icon\"></i></span>\n }\n <span class=\"pen-note\">drag to draw</span>\n </span>\n }\n </button>\n }\n\n <div class=\"tool-sep\"></div>\n <button type=\"button\" class=\"tool\" title=\"Undo\" [disabled]=\"!CanUndo\" (click)=\"Undo.emit()\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n </button>\n <button type=\"button\" class=\"tool\" title=\"Redo\" [disabled]=\"!CanRedo\" (click)=\"Redo.emit()\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n </button>\n</div>\n"]}
@@ -38,6 +38,7 @@ export * from './lib/whiteboard-export';
38
38
  export * from './lib/whiteboard-widget-bridge';
39
39
  export * from './lib/whiteboard-srcdoc.pipe';
40
40
  export * from './lib/whiteboard-context-menu';
41
+ export * from './lib/whiteboard-tool-roster';
41
42
  export * from './lib/whiteboard-board.component';
42
43
  export * from './lib/whiteboard-toolbar.component';
43
44
  export * from './lib/whiteboard-zoom.component';
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,cAAc,wBAAwB,CAAC;AAGvC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,gCAAgC,CAAC;AAI/C,cAAc,8BAA8B,CAAC;AAG7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AAGpD,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,cAAc,wBAAwB,CAAC;AAGvC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,gCAAgC,CAAC;AAI/C,cAAc,8BAA8B,CAAC;AAG7C,cAAc,+BAA+B,CAAC;AAE9C,cAAc,8BAA8B,CAAC;AAG7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AAGpD,cAAc,yBAAyB,CAAC"}
@@ -46,6 +46,8 @@ export * from './lib/whiteboard-widget-bridge';
46
46
  export * from './lib/whiteboard-srcdoc.pipe';
47
47
  // Right-click context-menu model (pure — decides WHAT is offered, not how it renders).
48
48
  export * from './lib/whiteboard-context-menu';
49
+ // The host-controllable tool roster (pure): one predicate for toolbar, key map and context menu.
50
+ export * from './lib/whiteboard-tool-roster';
49
51
  // Components (all standalone).
50
52
  export * from './lib/whiteboard-board.component';
51
53
  export * from './lib/whiteboard-toolbar.component';
@@ -1 +1 @@
1
- {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,oFAAoF;AACpF,+CAA+C;AAC/C,cAAc,wBAAwB,CAAC;AAEvC,gFAAgF;AAChF,cAAc,wBAAwB,CAAC;AAEvC,wEAAwE;AACxE,cAAc,yBAAyB,CAAC;AAExC,uFAAuF;AACvF,cAAc,gCAAgC,CAAC;AAE/C,iFAAiF;AACjF,oFAAoF;AACpF,cAAc,8BAA8B,CAAC;AAE7C,uFAAuF;AACvF,cAAc,+BAA+B,CAAC;AAE9C,+BAA+B;AAC/B,cAAc,kCAAkC,CAAC;AACjD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AAEpD,uDAAuD;AACvD,cAAc,yBAAyB,CAAC","sourcesContent":["/**\n * @packageDocumentation\n *\n * # @memberjunction/ng-whiteboard\n *\n * A generic, reusable collaborative whiteboard for ANY Angular application, designed for\n * dual authorship: a human user drawing with direct-manipulation tools, and a co-author\n * (typically an AI agent) mutating the same board through a programmatic, JSON-described\n * tool API. The package follows the MemberJunction Generic-component conventions: no\n * Router dependency, PascalCase public surface, standalone components, design-token\n * theming, and a cancelable before / after event pattern on every major mutation.\n *\n * ## Layers\n *\n * - **State engine** ({@link WhiteboardState}, `whiteboard-state.ts`) — Angular-free\n * typed board model: items, selection, snapshot undo/redo, a change journal with\n * coalesced scene deltas (the \"agent perception\" feed), JSON persistence, and the\n * before/after mutation events (`ItemAdding$` / `ItemAdded$`, …).\n * - **Programmatic tool API** (`whiteboard-tools.ts`) — the `Whiteboard_*` JSON tool\n * definitions plus {@link ApplyWhiteboardAgentTool}, the pure execute-one-tool-call\n * round-trip any agent/automation layer can drive.\n * - **Components** — {@link RealtimeWhiteboardHostComponent} (the full board surface:\n * header, toolbar, zoom cluster, perception popover, export menu, agent toast),\n * {@link RealtimeWhiteboardBoardComponent} (the canvas itself), and the supporting\n * toolbar / zoom / popover / read-only snapshot components.\n * - **Export builders** (`whiteboard-export.ts`) — pure functions producing one\n * self-contained HTML document or a standalone SVG of a board snapshot.\n * - **Widget input bridge** (`whiteboard-widget-bridge.ts`) — the `MJWhiteboard.submit`\n * postMessage contract that lets STRICTLY SANDBOXED HTML widgets send user input back\n * to the host.\n *\n * See the package README for a quickstart, the agent-integration recipe, the event\n * surface, security notes, and theming/extension points.\n */\n\n// State engine — board model, mutations, undo/redo, perception deltas, persistence,\n// and the before/after mutation event surface.\nexport * from './lib/whiteboard-state';\n\n// Programmatic mutation tool API (agent-facing JSON tools + the pure executor).\nexport * from './lib/whiteboard-tools';\n\n// Pure export builders (self-contained HTML document / standalone SVG).\nexport * from './lib/whiteboard-export';\n\n// Sandboxed HTML-widget input bridge (MJWhiteboard.submit contract + host validation).\nexport * from './lib/whiteboard-widget-bridge';\n\n// View-scoped srcdoc builder pipe for sandboxed HTML widgets (rebuilt per mount,\n// identity-stable while mounted — see the pipe's TSDoc for the lifecycle contract).\nexport * from './lib/whiteboard-srcdoc.pipe';\n\n// Right-click context-menu model (pure — decides WHAT is offered, not how it renders).\nexport * from './lib/whiteboard-context-menu';\n\n// Components (all standalone).\nexport * from './lib/whiteboard-board.component';\nexport * from './lib/whiteboard-toolbar.component';\nexport * from './lib/whiteboard-zoom.component';\nexport * from './lib/whiteboard-pages.component';\nexport * from './lib/whiteboard-agent-sees-popover.component';\nexport * from './lib/whiteboard-host.component';\nexport * from './lib/whiteboard-snapshot.component';\n\n// Convenience NgModule + tree-shaking prevention hook.\nexport * from './lib/whiteboard.module';\n"]}
1
+ {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,oFAAoF;AACpF,+CAA+C;AAC/C,cAAc,wBAAwB,CAAC;AAEvC,gFAAgF;AAChF,cAAc,wBAAwB,CAAC;AAEvC,wEAAwE;AACxE,cAAc,yBAAyB,CAAC;AAExC,uFAAuF;AACvF,cAAc,gCAAgC,CAAC;AAE/C,iFAAiF;AACjF,oFAAoF;AACpF,cAAc,8BAA8B,CAAC;AAE7C,uFAAuF;AACvF,cAAc,+BAA+B,CAAC;AAC9C,iGAAiG;AACjG,cAAc,8BAA8B,CAAC;AAE7C,+BAA+B;AAC/B,cAAc,kCAAkC,CAAC;AACjD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+CAA+C,CAAC;AAC9D,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AAEpD,uDAAuD;AACvD,cAAc,yBAAyB,CAAC","sourcesContent":["/**\n * @packageDocumentation\n *\n * # @memberjunction/ng-whiteboard\n *\n * A generic, reusable collaborative whiteboard for ANY Angular application, designed for\n * dual authorship: a human user drawing with direct-manipulation tools, and a co-author\n * (typically an AI agent) mutating the same board through a programmatic, JSON-described\n * tool API. The package follows the MemberJunction Generic-component conventions: no\n * Router dependency, PascalCase public surface, standalone components, design-token\n * theming, and a cancelable before / after event pattern on every major mutation.\n *\n * ## Layers\n *\n * - **State engine** ({@link WhiteboardState}, `whiteboard-state.ts`) — Angular-free\n * typed board model: items, selection, snapshot undo/redo, a change journal with\n * coalesced scene deltas (the \"agent perception\" feed), JSON persistence, and the\n * before/after mutation events (`ItemAdding$` / `ItemAdded$`, …).\n * - **Programmatic tool API** (`whiteboard-tools.ts`) — the `Whiteboard_*` JSON tool\n * definitions plus {@link ApplyWhiteboardAgentTool}, the pure execute-one-tool-call\n * round-trip any agent/automation layer can drive.\n * - **Components** — {@link RealtimeWhiteboardHostComponent} (the full board surface:\n * header, toolbar, zoom cluster, perception popover, export menu, agent toast),\n * {@link RealtimeWhiteboardBoardComponent} (the canvas itself), and the supporting\n * toolbar / zoom / popover / read-only snapshot components.\n * - **Export builders** (`whiteboard-export.ts`) — pure functions producing one\n * self-contained HTML document or a standalone SVG of a board snapshot.\n * - **Widget input bridge** (`whiteboard-widget-bridge.ts`) — the `MJWhiteboard.submit`\n * postMessage contract that lets STRICTLY SANDBOXED HTML widgets send user input back\n * to the host.\n *\n * See the package README for a quickstart, the agent-integration recipe, the event\n * surface, security notes, and theming/extension points.\n */\n\n// State engine — board model, mutations, undo/redo, perception deltas, persistence,\n// and the before/after mutation event surface.\nexport * from './lib/whiteboard-state';\n\n// Programmatic mutation tool API (agent-facing JSON tools + the pure executor).\nexport * from './lib/whiteboard-tools';\n\n// Pure export builders (self-contained HTML document / standalone SVG).\nexport * from './lib/whiteboard-export';\n\n// Sandboxed HTML-widget input bridge (MJWhiteboard.submit contract + host validation).\nexport * from './lib/whiteboard-widget-bridge';\n\n// View-scoped srcdoc builder pipe for sandboxed HTML widgets (rebuilt per mount,\n// identity-stable while mounted — see the pipe's TSDoc for the lifecycle contract).\nexport * from './lib/whiteboard-srcdoc.pipe';\n\n// Right-click context-menu model (pure — decides WHAT is offered, not how it renders).\nexport * from './lib/whiteboard-context-menu';\n// The host-controllable tool roster (pure): one predicate for toolbar, key map and context menu.\nexport * from './lib/whiteboard-tool-roster';\n\n// Components (all standalone).\nexport * from './lib/whiteboard-board.component';\nexport * from './lib/whiteboard-toolbar.component';\nexport * from './lib/whiteboard-zoom.component';\nexport * from './lib/whiteboard-pages.component';\nexport * from './lib/whiteboard-agent-sees-popover.component';\nexport * from './lib/whiteboard-host.component';\nexport * from './lib/whiteboard-snapshot.component';\n\n// Convenience NgModule + tree-shaking prevention hook.\nexport * from './lib/whiteboard.module';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-whiteboard",
3
- "version": "5.51.1",
3
+ "version": "5.51.3",
4
4
  "description": "MemberJunction: Generic collaborative whiteboard for any Angular application — Angular-free state engine with undo/redo + change journal, agent perception deltas, a programmatic (AI-agent-ready) mutation tool API, sandboxed HTML widgets with an input bridge, markdown panels, and self-contained HTML/SVG export",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -25,7 +25,7 @@
25
25
  "devDependencies": {
26
26
  "@angular/compiler": "21.1.3",
27
27
  "@angular/compiler-cli": "21.1.3",
28
- "@memberjunction/ng-test-utils": "5.51.1",
28
+ "@memberjunction/ng-test-utils": "5.51.3",
29
29
  "vitest": "^4.0.18"
30
30
  },
31
31
  "peerDependencies": {
@@ -34,10 +34,10 @@
34
34
  "@angular/platform-browser": "21.1.3"
35
35
  },
36
36
  "dependencies": {
37
- "@memberjunction/ng-ui-components": "5.51.1",
38
- "@memberjunction/global": "5.51.1",
39
- "@memberjunction/ng-code-editor": "5.51.1",
40
- "@memberjunction/ng-markdown": "5.51.1",
37
+ "@memberjunction/ng-ui-components": "5.51.3",
38
+ "@memberjunction/global": "5.51.3",
39
+ "@memberjunction/ng-code-editor": "5.51.3",
40
+ "@memberjunction/ng-markdown": "5.51.3",
41
41
  "rxjs": "^7.8.2",
42
42
  "tslib": "^2.8.1"
43
43
  },