@memberjunction/ng-whiteboard 6.1.0-edge.3 → 6.1.0-edge.5
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.
|
@@ -36,6 +36,23 @@ export declare class RealtimeWhiteboardHostComponent implements OnInit, OnDestro
|
|
|
36
36
|
BoardTitle: string;
|
|
37
37
|
/** Persistence chip text (e.g. "Saved to session · v14"). */
|
|
38
38
|
SavedLabel: string;
|
|
39
|
+
/**
|
|
40
|
+
* Opt back in to DOCUMENT-WIDE keyboard shortcuts.
|
|
41
|
+
*
|
|
42
|
+
* The host binds eleven bare single-character tool shortcuts (v h p r s t m w i c e). While
|
|
43
|
+
* those listened on `document` unconditionally they fired wherever the user was on the page,
|
|
44
|
+
* which fails WCAG 2.1.4 (Character Key Shortcuts): a speech-input user saying an ordinary
|
|
45
|
+
* word, or anyone typing in a non-input control elsewhere, silently switched the board tool.
|
|
46
|
+
* They are now scoped to focus being inside this host, which satisfies the criterion's
|
|
47
|
+
* "active only on focus" branch.
|
|
48
|
+
*
|
|
49
|
+
* Scoping covers the host's ENTIRE keydown handler, not only the letters: undo/redo
|
|
50
|
+
* (Cmd/Ctrl+Z, +Y), Escape and Delete/Backspace are focus-gated as well.
|
|
51
|
+
*
|
|
52
|
+
* Set `true` only for a surface where the whiteboard is the entire page AND the 2.1.4
|
|
53
|
+
* exposure has been accepted — it is an accessibility regression, not a convenience flag.
|
|
54
|
+
*/
|
|
55
|
+
EnableGlobalShortcuts: boolean;
|
|
39
56
|
/** Debounced (750 ms), coalesced scene-delta JSON — the live perception feed. */
|
|
40
57
|
SceneDelta: EventEmitter<string>;
|
|
41
58
|
/** The user clicked Undo on the agent-action toast (the undo itself already applied). */
|
|
@@ -153,6 +170,24 @@ export declare class RealtimeWhiteboardHostComponent implements OnInit, OnDestro
|
|
|
153
170
|
private downloadBlob;
|
|
154
171
|
private static exportDateStamp;
|
|
155
172
|
OnToastUndo(event: Event): void;
|
|
173
|
+
/**
|
|
174
|
+
* The board is made focusable so its shortcuts have a focus scope to be bound to. `-1`, not
|
|
175
|
+
* `0`: the canvas has no keyboard interaction model yet (see the whiteboard keyboard-
|
|
176
|
+
* operability work), so adding a real Tab stop would put a stop in the page that a keyboard
|
|
177
|
+
* user can reach and do nothing with. Click focuses it; that is the whole contract today.
|
|
178
|
+
*/
|
|
179
|
+
readonly HostTabIndex = "-1";
|
|
180
|
+
private readonly host;
|
|
181
|
+
/**
|
|
182
|
+
* Clicking the board takes focus, so the shortcuts below apply. The browser would usually do
|
|
183
|
+
* this on its own by focusing the nearest focusable ancestor, but the board's pointer
|
|
184
|
+
* pipeline is elaborate enough (drag, marquee, handles, transient shapes) that relying on
|
|
185
|
+
* that default is fragile — one `preventDefault()` added later would silently kill every
|
|
186
|
+
* shortcut. This makes it explicit.
|
|
187
|
+
*/
|
|
188
|
+
OnHostPointerDown(): void;
|
|
189
|
+
/** Whether focus currently sits on, or inside, this whiteboard host. */
|
|
190
|
+
private hasFocusWithin;
|
|
156
191
|
OnKeydown(event: KeyboardEvent): void;
|
|
157
192
|
get ElementCount(): number;
|
|
158
193
|
get UserCount(): number;
|
|
@@ -169,6 +204,6 @@ export declare class RealtimeWhiteboardHostComponent implements OnInit, OnDestro
|
|
|
169
204
|
private static toolPhrase;
|
|
170
205
|
private static toolForKey;
|
|
171
206
|
static ɵfac: i0.ɵɵFactoryDeclaration<RealtimeWhiteboardHostComponent, never>;
|
|
172
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeWhiteboardHostComponent, "mj-realtime-whiteboard-host", never, { "State": { "alias": "State"; "required": true; }; "AgentName": { "alias": "AgentName"; "required": false; }; "BoardTitle": { "alias": "BoardTitle"; "required": false; }; "SavedLabel": { "alias": "SavedLabel"; "required": false; }; }, { "SceneDelta": "SceneDelta"; "AgentUndo": "AgentUndo"; "FocusModeChange": "FocusModeChange"; "SaveToArtifactsRequested": "SaveToArtifactsRequested"; "WidgetSubmitting": "WidgetSubmitting"; "WidgetSubmitted": "WidgetSubmitted"; "WidgetInteraction": "WidgetInteraction"; "ContentApplying": "ContentApplying"; "ContentApplied": "ContentApplied"; "ItemAdding": "ItemAdding"; "ItemAdded": "ItemAdded"; "ItemUpdating": "ItemUpdating"; "ItemUpdated": "ItemUpdated"; "ItemRemoving": "ItemRemoving"; "ItemRemoved": "ItemRemoved"; }, never, never, true, never>;
|
|
207
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RealtimeWhiteboardHostComponent, "mj-realtime-whiteboard-host", never, { "State": { "alias": "State"; "required": true; }; "AgentName": { "alias": "AgentName"; "required": false; }; "BoardTitle": { "alias": "BoardTitle"; "required": false; }; "SavedLabel": { "alias": "SavedLabel"; "required": false; }; "EnableGlobalShortcuts": { "alias": "EnableGlobalShortcuts"; "required": false; }; }, { "SceneDelta": "SceneDelta"; "AgentUndo": "AgentUndo"; "FocusModeChange": "FocusModeChange"; "SaveToArtifactsRequested": "SaveToArtifactsRequested"; "WidgetSubmitting": "WidgetSubmitting"; "WidgetSubmitted": "WidgetSubmitted"; "WidgetInteraction": "WidgetInteraction"; "ContentApplying": "ContentApplying"; "ContentApplied": "ContentApplied"; "ItemAdding": "ItemAdding"; "ItemAdded": "ItemAdded"; "ItemUpdating": "ItemUpdating"; "ItemUpdated": "ItemUpdated"; "ItemRemoving": "ItemRemoving"; "ItemRemoved": "ItemRemoved"; }, never, never, true, never>;
|
|
173
208
|
}
|
|
174
209
|
//# sourceMappingURL=whiteboard-host.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whiteboard-host.component.d.ts","sourceRoot":"","sources":["../../src/lib/whiteboard-host.component.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"whiteboard-host.component.d.ts","sourceRoot":"","sources":["../../src/lib/whiteboard-host.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACqC,YAAY,EACtD,SAAS,EAAE,MAAM,EAClB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EAAE,4BAA4B,EAAE,6BAA6B,EACjF,8BAA8B,EAAE,+BAA+B,EAC/D,8BAA8B,EAAE,+BAA+B,EAAE,eAAe,EACjF,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EACL,gCAAgC,EAAE,uBAAuB,EACzD,iCAAiC,EAAE,kCAAkC,EACtE,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,gCAAgC,EAAE,2BAA2B,EAAE,mCAAmC,EACnG,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAsC,cAAc,EAAyB,MAAM,gCAAgC,CAAC;;AAW3H;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAaa,+BAAgC,YAAW,MAAM,EAAE,SAAS;IACvE,iEAAiE;IACtC,KAAK,EAAG,eAAe,CAAC;IACnD,2EAA2E;IAClE,SAAS,SAAW;IAC7B,uCAAuC;IAC9B,UAAU,SAAgB;IACnC,6DAA6D;IACpD,UAAU,SAAsB;IACzC;;;;;;;;;;;;;;;OAeG;IACM,qBAAqB,UAAS;IAEvC,iFAAiF;IACvE,UAAU,uBAA8B;IAClD,yFAAyF;IAC/E,SAAS,qBAA4B;IAC/C,+EAA+E;IACrE,eAAe,wBAA+B;IACxD,0GAA0G;IAChG,wBAAwB,qBAA4B;IAC9D;;;;OAIG;IACO,gBAAgB,oDAA2D;IACrF;;;;OAIG;IACO,eAAe,4CAAmD;IAC5E;;;;;;OAMG;IACO,iBAAiB,iDAAwD;IACnF;;;OAGG;IACO,eAAe,mDAA0D;IACnF,wEAAwE;IAC9D,cAAc,kDAAyD;IAQjF,uEAAuE;IAC7D,UAAU,8CAAqD;IACzE,0DAA0D;IAChD,SAAS,6CAAoD;IACvE,mGAAmG;IACzF,YAAY,gDAAuD;IAC7E,4DAA4D;IAClD,WAAW,+CAAsD;IAC3E,yEAAyE;IAC/D,YAAY,gDAAuD;IAC7E,4DAA4D;IAClD,WAAW,+CAAsD;IAEvB,KAAK,CAAC,EAAE,gCAAgC,CAAC;IAGtF,IAAI,EAAE,cAAc,CAAY;IAChC,QAAQ,EAAE,MAAM,CAA4B;IAC5C,QAAQ,SAAK;IACb,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAU;IACnD,QAAQ,SAAM;IACd,UAAU,EAAE,oBAAoB,CAAU;IAC1C,QAAQ,UAAQ;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGhC,QAAQ,UAAS;IACjB,SAAS,UAAS;IAClB,UAAU,UAAS;IAGnB,aAAa,EAAE,uBAAuB,GAAG,IAAI,CAAQ;IACrD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IACvC,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,aAAa,CAA8C;IAG5D,aAAa,SAAM;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,UAAU,CAA8C;IAGzD,OAAO,SAAc;IAC5B,OAAO,CAAC,MAAM,CAA+C;IAE7D,OAAO,CAAC,UAAU,CAAC,CAAe;IAClC,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,GAAG,CAA6B;IAExC,QAAQ,IAAI,IAAI;IAyBhB,WAAW,IAAI,IAAI;IAsBnB;;;;;OAKG;IACI,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAmB1D,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAM9B,SAAS,IAAI,IAAI;IAMjB,WAAW,IAAI,IAAI;IAOnB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAMhC,WAAW,IAAI,IAAI;IAM1B,8DAA8D;IAC9D,4FAA4F;IACrF,qBAAqB,IAAI,IAAI;IAK7B,kBAAkB,IAAI,IAAI;IAKjC,yFAAyF;IAClF,0BAA0B,IAAI,IAAI;IAMzC,6DAA6D;IACtD,iBAAiB,IAAI,IAAI;IAKhC;;;;OAIG;IACI,yBAAyB,IAAI,IAAI;IASxC,uFAAuF;IACvF,IAAW,gBAAgB,IAAI,OAAO,CAErC;IAED;;;;OAIG;IACI,WAAW,IAAI,IAAI;IAc1B,OAAO,CAAC,eAAe;IAIvB,6EAA6E;IAC7E,OAAO,CAAC,aAAa;IAQrB,+FAA+F;IAC/F,OAAO,CAAC,MAAM,CAAC,YAAY;IAI3B,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,MAAM,CAAC,eAAe;IAMvB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAUtC;;;;;OAKG;IAC2B,QAAQ,CAAC,YAAY,QAAQ;IAE3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+C;IAEpE;;;;;;OAMG;IAEI,iBAAiB,IAAI,IAAI;IAMhC,wEAAwE;IACxE,OAAO,CAAC,cAAc;IAOf,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IA0D5C,IAAW,YAAY,IAAI,MAAM,CAEhC;IAED,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED,iFAAiF;IACjF,IAAW,cAAc,IAAI,MAAM,CASlC;IAED,IAAW,oBAAoB,IAAI,MAAM,CAExC;IAID,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,MAAM,CAAC,UAAU;IAoBzB,OAAO,CAAC,MAAM,CAAC,UAAU;yCA1hBd,+BAA+B;2CAA/B,+BAA+B;CA0iB3C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChangeDetectorRef, Component, EventEmitter, HostListener, Input, Output, ViewChild, inject } from '@angular/core';
|
|
1
|
+
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostBinding, HostListener, Input, Output, ViewChild, inject } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import { WhiteboardState } from './whiteboard-state';
|
|
4
4
|
import { BuildWhiteboardExportHtml, BuildWhiteboardExportHtmlAllPages, BuildWhiteboardExportSvg, BuildWhiteboardExportSvgPages } from './whiteboard-export';
|
|
@@ -115,6 +115,23 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
115
115
|
this.BoardTitle = 'Whiteboard';
|
|
116
116
|
/** Persistence chip text (e.g. "Saved to session · v14"). */
|
|
117
117
|
this.SavedLabel = 'Saved to session';
|
|
118
|
+
/**
|
|
119
|
+
* Opt back in to DOCUMENT-WIDE keyboard shortcuts.
|
|
120
|
+
*
|
|
121
|
+
* The host binds eleven bare single-character tool shortcuts (v h p r s t m w i c e). While
|
|
122
|
+
* those listened on `document` unconditionally they fired wherever the user was on the page,
|
|
123
|
+
* which fails WCAG 2.1.4 (Character Key Shortcuts): a speech-input user saying an ordinary
|
|
124
|
+
* word, or anyone typing in a non-input control elsewhere, silently switched the board tool.
|
|
125
|
+
* They are now scoped to focus being inside this host, which satisfies the criterion's
|
|
126
|
+
* "active only on focus" branch.
|
|
127
|
+
*
|
|
128
|
+
* Scoping covers the host's ENTIRE keydown handler, not only the letters: undo/redo
|
|
129
|
+
* (Cmd/Ctrl+Z, +Y), Escape and Delete/Backspace are focus-gated as well.
|
|
130
|
+
*
|
|
131
|
+
* Set `true` only for a surface where the whiteboard is the entire page AND the 2.1.4
|
|
132
|
+
* exposure has been accepted — it is an accessibility regression, not a convenience flag.
|
|
133
|
+
*/
|
|
134
|
+
this.EnableGlobalShortcuts = false;
|
|
118
135
|
/** Debounced (750 ms), coalesced scene-delta JSON — the live perception feed. */
|
|
119
136
|
this.SceneDelta = new EventEmitter();
|
|
120
137
|
/** The user clicked Undo on the agent-action toast (the undo itself already applied). */
|
|
@@ -196,6 +213,15 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
196
213
|
this.ticker = null;
|
|
197
214
|
this.mirrorSubs = [];
|
|
198
215
|
this.cdr = inject(ChangeDetectorRef);
|
|
216
|
+
// ────────────────────────────────────────────── keyboard shortcuts
|
|
217
|
+
/**
|
|
218
|
+
* The board is made focusable so its shortcuts have a focus scope to be bound to. `-1`, not
|
|
219
|
+
* `0`: the canvas has no keyboard interaction model yet (see the whiteboard keyboard-
|
|
220
|
+
* operability work), so adding a real Tab stop would put a stop in the page that a keyboard
|
|
221
|
+
* user can reach and do nothing with. Click focuses it; that is the whole contract today.
|
|
222
|
+
*/
|
|
223
|
+
this.HostTabIndex = '-1';
|
|
224
|
+
this.host = inject(ElementRef);
|
|
199
225
|
}
|
|
200
226
|
ngOnInit() {
|
|
201
227
|
this.changedSub = this.State.Changed$.subscribe((change) => {
|
|
@@ -370,8 +396,34 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
370
396
|
this.hideToast();
|
|
371
397
|
this.AgentUndo.emit();
|
|
372
398
|
}
|
|
373
|
-
|
|
399
|
+
/**
|
|
400
|
+
* Clicking the board takes focus, so the shortcuts below apply. The browser would usually do
|
|
401
|
+
* this on its own by focusing the nearest focusable ancestor, but the board's pointer
|
|
402
|
+
* pipeline is elaborate enough (drag, marquee, handles, transient shapes) that relying on
|
|
403
|
+
* that default is fragile — one `preventDefault()` added later would silently kill every
|
|
404
|
+
* shortcut. This makes it explicit.
|
|
405
|
+
*/
|
|
406
|
+
OnHostPointerDown() {
|
|
407
|
+
if (!this.hasFocusWithin()) {
|
|
408
|
+
this.host.nativeElement.focus({ preventScroll: true });
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/** Whether focus currently sits on, or inside, this whiteboard host. */
|
|
412
|
+
hasFocusWithin() {
|
|
413
|
+
const el = this.host.nativeElement;
|
|
414
|
+
const active = document.activeElement;
|
|
415
|
+
return !!active && (active === el || el.contains(active));
|
|
416
|
+
}
|
|
374
417
|
OnKeydown(event) {
|
|
418
|
+
// WCAG 2.1.4: only live while focus is on the board. NOTE this gates the WHOLE handler,
|
|
419
|
+
// not just the single-character tool keys that 2.1.4 is about — undo/redo (Cmd/Ctrl+Z,
|
|
420
|
+
// +Y), Escape and Delete/Backspace are scoped too. That is deliberate: a board that
|
|
421
|
+
// swallows the document's Cmd+Z from anywhere on the page is its own bug, and "the board
|
|
422
|
+
// responds to keys when you are on the board" is the only model that stays predictable.
|
|
423
|
+
// See {@link EnableGlobalShortcuts} for the (discouraged) opt-out.
|
|
424
|
+
if (!this.EnableGlobalShortcuts && !this.hasFocusWithin()) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
375
427
|
const target = event.target;
|
|
376
428
|
if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)) {
|
|
377
429
|
return;
|
|
@@ -546,9 +598,11 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
546
598
|
} if (rf & 2) {
|
|
547
599
|
let _t;
|
|
548
600
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.Board = _t.first);
|
|
549
|
-
} }, hostBindings: function RealtimeWhiteboardHostComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
550
|
-
i0.ɵɵlistener("click", function RealtimeWhiteboardHostComponent_click_HostBindingHandler() { return ctx.CloseExport(); }, i0.ɵɵresolveDocument)("keydown", function RealtimeWhiteboardHostComponent_keydown_HostBindingHandler($event) { return ctx.OnKeydown($event); }, i0.ɵɵresolveDocument);
|
|
551
|
-
}
|
|
601
|
+
} }, hostVars: 1, hostBindings: function RealtimeWhiteboardHostComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
602
|
+
i0.ɵɵlistener("click", function RealtimeWhiteboardHostComponent_click_HostBindingHandler() { return ctx.CloseExport(); }, i0.ɵɵresolveDocument)("pointerdown", function RealtimeWhiteboardHostComponent_pointerdown_HostBindingHandler() { return ctx.OnHostPointerDown(); })("keydown", function RealtimeWhiteboardHostComponent_keydown_HostBindingHandler($event) { return ctx.OnKeydown($event); }, i0.ɵɵresolveDocument);
|
|
603
|
+
} if (rf & 2) {
|
|
604
|
+
i0.ɵɵattribute("tabindex", ctx.HostTabIndex);
|
|
605
|
+
} }, inputs: { State: "State", AgentName: "AgentName", BoardTitle: "BoardTitle", SavedLabel: "SavedLabel", EnableGlobalShortcuts: "EnableGlobalShortcuts" }, outputs: { SceneDelta: "SceneDelta", AgentUndo: "AgentUndo", FocusModeChange: "FocusModeChange", SaveToArtifactsRequested: "SaveToArtifactsRequested", WidgetSubmitting: "WidgetSubmitting", WidgetSubmitted: "WidgetSubmitted", WidgetInteraction: "WidgetInteraction", ContentApplying: "ContentApplying", ContentApplied: "ContentApplied", ItemAdding: "ItemAdding", ItemAdded: "ItemAdded", ItemUpdating: "ItemUpdating", ItemUpdated: "ItemUpdated", ItemRemoving: "ItemRemoving", ItemRemoved: "ItemRemoved" }, decls: 70, vars: 48, consts: [["board", ""], [1, "board-head"], [1, "bt"], [1, "fa-solid", "fa-chalkboard"], [1, "board-save"], [1, "fa-solid", "fa-circle-check"], [1, "board-legend"], [1, "sw", "sw--you"], [1, "sw", "sw--sage"], [1, "fa-solid", "fa-feather", "legend-feather"], [1, "head-end"], ["type", "button", 1, "head-btn", "head-btn--sees", 3, "click"], [1, "eye-pulse"], [1, "fa-regular", "fa-eye"], [3, "AgentName", "DeltaJson", "DebounceMs", "ElementCount", "LastDeltaLabel"], [1, "export-wrap"], ["type", "button", 1, "head-btn", 3, "click"], [1, "fa-solid", "fa-file-export"], [1, "export-menu"], ["type", "button", "title", "More", 1, "head-btn", "head-btn--more"], [1, "fa-solid", "fa-ellipsis"], [1, "board-wrap"], [3, "ToolChangeRequest", "WidgetSubmitting", "WidgetSubmitted", "WidgetInteraction", "ContentApplying", "ContentApplied", "State", "AgentName", "Tool", "PenColor", "PenWidth", "ShapeKind", "TextSize", "TextFamily", "TextBold", "TextColor", "AgentPresence"], [3, "ToolChange", "PenColorChange", "PenWidthChange", "ShapeKindChange", "TextSizeChange", "TextFamilyChange", "TextBoldChange", "TextColorChange", "StyleSelection", "Undo", "Redo", "ActiveTool", "PenColor", "PenWidth", "ShapeKind", "TextSize", "TextFamily", "TextBold", "TextColor", "CanUndo", "CanRedo", "AgentName"], [3, "ZoomOut", "ZoomIn", "ZoomBy", "Fit", "ToggleMinimap", "ZoomPercent", "MinimapOpen"], [1, "board-toast"], [1, "board-status"], [1, "stat"], [1, "seg-r"], [1, "stat", "ctx-live", 3, "title"], [1, "d"], [1, "ctx-live__text"], ["title", "Persists as a session artifact when the call ends", 1, "stat", "persist"], ["aria-hidden", "true", 1, "fa-solid", "fa-box-archive"], [1, "persist__long"], [1, "persist__short"], ["type", "button", 1, "export-item", 3, "click"], [1, "fa-solid", "fa-file-code"], ["type", "button", 1, "export-item"], [1, "fa-solid", "fa-bezier-curve"], ["type", "button", "title", "One SVG file per page", 1, "export-item"], [1, "fa-solid", "fa-print"], [1, "fa-solid", "fa-box-archive"], ["type", "button", "title", "One SVG file per page", 1, "export-item", 3, "click"], [1, "fa-solid", "fa-feather"], [1, "board-toast__text"], [1, "undo", 3, "click"], [1, "fa-solid", "fa-rotate-left"]], template: function RealtimeWhiteboardHostComponent_Template(rf, ctx) { if (rf & 1) {
|
|
552
606
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
553
607
|
i0.ɵɵelementStart(0, "div", 1)(1, "span", 2);
|
|
554
608
|
i0.ɵɵelement(2, "i", 3);
|
|
@@ -691,7 +745,7 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
691
745
|
RealtimeWhiteboardBoardComponent,
|
|
692
746
|
RealtimeWhiteboardToolbarComponent,
|
|
693
747
|
RealtimeWhiteboardZoomComponent,
|
|
694
|
-
RealtimeWhiteboardAgentSeesPopoverComponent], styles: ["\n\n\n\n\n[_nghost-%COMP%] {\n \n\n --sage: var(--mj-color-violet-400, #a78bfa);\n --sage-bg: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 14%, transparent);\n --sage-border: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 45%, transparent);\n --sage-chip-bg: color-mix(in srgb, var(--mj-color-violet-500, #8b5cf6) 32%, var(--mj-bg-surface-sunken));\n\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n height: 100%;\n \n\n container-type: inline-size;\n container-name: wb-host;\n}\n\n\n\n.board-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 9px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n.board-head[_ngcontent-%COMP%] .bt[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: 13.5px;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--mj-text-primary);\n}\n.board-head[_ngcontent-%COMP%] .bt[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n font-size: 13px;\n}\n.board-save[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n.board-save[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-size: 10px;\n}\n\n.board-legend[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-left: 6px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n}\n.board-legend[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] {\n width: 10px;\n height: 10px;\n border-radius: 3px;\n display: inline-block;\n vertical-align: -1px;\n margin-right: 5px;\n}\n.board-legend[_ngcontent-%COMP%] .sw--you[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n}\n.board-legend[_ngcontent-%COMP%] .sw--sage[_ngcontent-%COMP%] {\n background: var(--sage-bg);\n border: 1px solid var(--sage);\n}\n.legend-feather[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--sage);\n}\n\n.head-end[_ngcontent-%COMP%] {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 8px;\n position: relative;\n}\n\n.head-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 5px 11px;\n font-size: 11.5px;\n font-weight: 600;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n cursor: pointer;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n transition: all 140ms ease;\n font-family: inherit;\n}\n.head-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n.head-btn.on[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.head-btn--sees[_ngcontent-%COMP%] {\n position: relative;\n}\n.head-btn--sees[_ngcontent-%COMP%] .eye-pulse[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent);\n animation: _ngcontent-%COMP%_wb-pulse-ring 2s infinite;\n}\n.head-btn--more[_ngcontent-%COMP%] {\n padding: 5px 9px;\n}\n\n\n\n.export-wrap[_ngcontent-%COMP%] {\n position: relative;\n display: inline-flex;\n}\n.export-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 6px);\n right: 0;\n z-index: 30;\n min-width: 168px;\n display: flex;\n flex-direction: column;\n padding: 5px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-elevated);\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n}\n.export-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 11.5px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n border: none;\n border-radius: var(--mj-radius-sm, 5px);\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n white-space: nowrap;\n}\n.export-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.export-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 14px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n.export-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n@keyframes _ngcontent-%COMP%_wb-pulse-ring {\n 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent); }\n 70% { box-shadow: 0 0 0 6px transparent; }\n 100% { box-shadow: 0 0 0 0 transparent; }\n}\n\n\n\n.board-wrap[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n\n\n\n\n\n.board-toast[_ngcontent-%COMP%] {\n position: absolute;\n left: 50%;\n bottom: 64px;\n transform: translateX(-50%);\n z-index: 9;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 8px 16px;\n max-width: calc(100% - 32px);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--sage-chip-bg);\n border: 1px solid var(--sage-border);\n color: var(--mj-color-violet-300, #c4b5fd);\n font-size: 12px;\n font-weight: 600;\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n animation: _ngcontent-%COMP%_wb-toast-fade 300ms ease both;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n.board-toast__text[_ngcontent-%COMP%] {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast[_ngcontent-%COMP%] .undo[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n@keyframes _ngcontent-%COMP%_wb-toast-fade {\n from { opacity: 0; transform: translate(-50%, 4px); }\n to { opacity: 1; transform: translate(-50%, 0); }\n}\n.board-toast[_ngcontent-%COMP%] .undo[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-weight: 600;\n cursor: pointer;\n margin-left: 4px;\n}\n.board-toast[_ngcontent-%COMP%] .undo[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n\n\n.board-status[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 18px;\n padding: 6px 16px;\n flex-shrink: 0;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 10.5px;\n color: var(--mj-text-muted);\n font-weight: 500;\n}\n.board-status[_ngcontent-%COMP%] b[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n.board-status[_ngcontent-%COMP%] .seg-r[_ngcontent-%COMP%] {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 18px;\n}\n.board-status[_ngcontent-%COMP%] .ctx-live[_ngcontent-%COMP%] {\n color: var(--mj-color-violet-300, var(--mj-text-secondary));\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n}\n.board-status[_ngcontent-%COMP%] .ctx-live[_ngcontent-%COMP%] .d[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n animation: _ngcontent-%COMP%_wb-pulse-ring 2s infinite;\n}"] }); }
|
|
748
|
+
RealtimeWhiteboardAgentSeesPopoverComponent], styles: ["\n\n\n\n[_nghost-%COMP%]:focus:not(:focus-visible) {\n outline: none;\n}\n\n\n\n\n\n\n[_nghost-%COMP%] {\n \n\n --sage: var(--mj-color-violet-400, #a78bfa);\n --sage-bg: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 14%, transparent);\n --sage-border: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 45%, transparent);\n --sage-chip-bg: color-mix(in srgb, var(--mj-color-violet-500, #8b5cf6) 32%, var(--mj-bg-surface-sunken));\n\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n height: 100%;\n \n\n container-type: inline-size;\n container-name: wb-host;\n}\n\n\n\n.board-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 9px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n.board-head[_ngcontent-%COMP%] .bt[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: 13.5px;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--mj-text-primary);\n}\n.board-head[_ngcontent-%COMP%] .bt[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n font-size: 13px;\n}\n.board-save[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n.board-save[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-size: 10px;\n}\n\n.board-legend[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-left: 6px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n}\n.board-legend[_ngcontent-%COMP%] .sw[_ngcontent-%COMP%] {\n width: 10px;\n height: 10px;\n border-radius: 3px;\n display: inline-block;\n vertical-align: -1px;\n margin-right: 5px;\n}\n.board-legend[_ngcontent-%COMP%] .sw--you[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n}\n.board-legend[_ngcontent-%COMP%] .sw--sage[_ngcontent-%COMP%] {\n background: var(--sage-bg);\n border: 1px solid var(--sage);\n}\n.legend-feather[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--sage);\n}\n\n.head-end[_ngcontent-%COMP%] {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 8px;\n position: relative;\n}\n\n.head-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 5px 11px;\n font-size: 11.5px;\n font-weight: 600;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n cursor: pointer;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n transition: all 140ms ease;\n font-family: inherit;\n}\n.head-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n.head-btn.on[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.head-btn--sees[_ngcontent-%COMP%] {\n position: relative;\n}\n.head-btn--sees[_ngcontent-%COMP%] .eye-pulse[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent);\n animation: _ngcontent-%COMP%_wb-pulse-ring 2s infinite;\n}\n.head-btn--more[_ngcontent-%COMP%] {\n padding: 5px 9px;\n}\n\n\n\n.export-wrap[_ngcontent-%COMP%] {\n position: relative;\n display: inline-flex;\n}\n.export-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 6px);\n right: 0;\n z-index: 30;\n min-width: 168px;\n display: flex;\n flex-direction: column;\n padding: 5px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-elevated);\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n}\n.export-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 11.5px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n border: none;\n border-radius: var(--mj-radius-sm, 5px);\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n white-space: nowrap;\n}\n.export-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.export-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 14px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n.export-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n@keyframes _ngcontent-%COMP%_wb-pulse-ring {\n 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent); }\n 70% { box-shadow: 0 0 0 6px transparent; }\n 100% { box-shadow: 0 0 0 0 transparent; }\n}\n\n\n\n.board-wrap[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n\n\n\n\n\n.board-toast[_ngcontent-%COMP%] {\n position: absolute;\n left: 50%;\n bottom: 64px;\n transform: translateX(-50%);\n z-index: 9;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 8px 16px;\n max-width: calc(100% - 32px);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--sage-chip-bg);\n border: 1px solid var(--sage-border);\n color: var(--mj-color-violet-300, #c4b5fd);\n font-size: 12px;\n font-weight: 600;\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n animation: _ngcontent-%COMP%_wb-toast-fade 300ms ease both;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n.board-toast__text[_ngcontent-%COMP%] {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast[_ngcontent-%COMP%] .undo[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n@keyframes _ngcontent-%COMP%_wb-toast-fade {\n from { opacity: 0; transform: translate(-50%, 4px); }\n to { opacity: 1; transform: translate(-50%, 0); }\n}\n.board-toast[_ngcontent-%COMP%] .undo[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-weight: 600;\n cursor: pointer;\n margin-left: 4px;\n}\n.board-toast[_ngcontent-%COMP%] .undo[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n\n\n.board-status[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 18px;\n padding: 6px 16px;\n flex-shrink: 0;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 10.5px;\n color: var(--mj-text-muted);\n font-weight: 500;\n}\n.board-status[_ngcontent-%COMP%] b[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n.board-status[_ngcontent-%COMP%] .seg-r[_ngcontent-%COMP%] {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 18px;\n}\n.board-status[_ngcontent-%COMP%] .ctx-live[_ngcontent-%COMP%] {\n color: var(--mj-color-violet-300, var(--mj-text-secondary));\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n}\n.board-status[_ngcontent-%COMP%] .ctx-live[_ngcontent-%COMP%] .d[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n animation: _ngcontent-%COMP%_wb-pulse-ring 2s infinite;\n}"] }); }
|
|
695
749
|
}
|
|
696
750
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeWhiteboardHostComponent, [{
|
|
697
751
|
type: Component,
|
|
@@ -701,7 +755,7 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
701
755
|
RealtimeWhiteboardToolbarComponent,
|
|
702
756
|
RealtimeWhiteboardZoomComponent,
|
|
703
757
|
RealtimeWhiteboardAgentSeesPopoverComponent
|
|
704
|
-
], template: "<!-- 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 \u2014 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 \u2014 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 \u2014 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> \u00B7 {{ AgentName }} <b>{{ AgentCount }}</b></span>\n <span class=\"stat\">synced <b>{{ LastDeltaLabel }}</b> \u00B7 seq <b>{{ CurrentSeq }}</b></span>\n <span class=\"seg-r\">\n <span class=\"stat ctx-live\" [title]=\"AgentName + '\u2019s 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", styles: ["/* LIVE WHITEBOARD host chrome \u2014 board header, board wrap, agent toast, status footer.\n Ported pixel-faithfully from plans/realtime/mockups/whiteboard.html\n (.board-head, .head-btn, .board-legend, .board-toast, .board-status). */\n\n:host {\n /* agent (violet) accent \u2014 same derivation as the sibling realtime components */\n --sage: var(--mj-color-violet-400, #a78bfa);\n --sage-bg: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 14%, transparent);\n --sage-border: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 45%, transparent);\n --sage-chip-bg: color-mix(in srgb, var(--mj-color-violet-500, #8b5cf6) 32%, var(--mj-bg-surface-sunken));\n\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n height: 100%;\n /* width container \u2014 drives the status footer's narrow-width collapse rules */\n container-type: inline-size;\n container-name: wb-host;\n}\n\n/* ---------- board header row ---------- */\n.board-head {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 9px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n.board-head .bt {\n font-weight: 700;\n font-size: 13.5px;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--mj-text-primary);\n}\n.board-head .bt i {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n font-size: 13px;\n}\n.board-save {\n font-size: 11px;\n color: var(--mj-text-muted);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n.board-save i {\n color: var(--mj-status-success);\n font-size: 10px;\n}\n\n.board-legend {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-left: 6px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n}\n.board-legend .sw {\n width: 10px;\n height: 10px;\n border-radius: 3px;\n display: inline-block;\n vertical-align: -1px;\n margin-right: 5px;\n}\n.board-legend .sw--you {\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n}\n.board-legend .sw--sage {\n background: var(--sage-bg);\n border: 1px solid var(--sage);\n}\n.legend-feather {\n font-size: 9px;\n color: var(--sage);\n}\n\n.head-end {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 8px;\n position: relative;\n}\n\n.head-btn {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 5px 11px;\n font-size: 11.5px;\n font-weight: 600;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n cursor: pointer;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n transition: all 140ms ease;\n font-family: inherit;\n}\n.head-btn:hover {\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n.head-btn.on {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.head-btn--sees {\n position: relative;\n}\n.head-btn--sees .eye-pulse {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent);\n animation: wb-pulse-ring 2s infinite;\n}\n.head-btn--more {\n padding: 5px 9px;\n}\n\n/* ---------- export menu (Download HTML / Download SVG / Print) ---------- */\n.export-wrap {\n position: relative;\n display: inline-flex;\n}\n.export-menu {\n position: absolute;\n top: calc(100% + 6px);\n right: 0;\n z-index: 30;\n min-width: 168px;\n display: flex;\n flex-direction: column;\n padding: 5px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-elevated);\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n}\n.export-item {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 11.5px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n border: none;\n border-radius: var(--mj-radius-sm, 5px);\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n white-space: nowrap;\n}\n.export-item:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.export-item i {\n width: 14px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n.export-item:hover i {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n@keyframes wb-pulse-ring {\n 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent); }\n 70% { box-shadow: 0 0 0 6px transparent; }\n 100% { box-shadow: 0 0 0 0 transparent; }\n}\n\n/* ---------- the board ---------- */\n.board-wrap {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n/* ---------- agent action toast ----------\n Bottom-center, raised ABOVE the zoom cluster's row (cluster: bottom 14px + ~38px\n tall) so the two can never collide, and width-capped clear of the cluster at the\n board's right edge. Sits just above the status footer per the mockup. */\n.board-toast {\n position: absolute;\n left: 50%;\n bottom: 64px;\n transform: translateX(-50%);\n z-index: 9;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 8px 16px;\n max-width: calc(100% - 32px);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--sage-chip-bg);\n border: 1px solid var(--sage-border);\n color: var(--mj-color-violet-300, #c4b5fd);\n font-size: 12px;\n font-weight: 600;\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n animation: wb-toast-fade 300ms ease both;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast > i {\n flex-shrink: 0;\n}\n.board-toast__text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast .undo {\n flex-shrink: 0;\n}\n@keyframes wb-toast-fade {\n from { opacity: 0; transform: translate(-50%, 4px); }\n to { opacity: 1; transform: translate(-50%, 0); }\n}\n.board-toast .undo {\n color: var(--mj-text-muted);\n font-weight: 600;\n cursor: pointer;\n margin-left: 4px;\n}\n.board-toast .undo:hover {\n color: var(--mj-text-primary);\n}\n\n/* ---------- board status footer ---------- */\n.board-status {\n display: flex;\n align-items: center;\n gap: 18px;\n padding: 6px 16px;\n flex-shrink: 0;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 10.5px;\n color: var(--mj-text-muted);\n font-weight: 500;\n}\n.board-status b {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n.board-status .seg-r {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 18px;\n}\n.board-status .ctx-live {\n color: var(--mj-color-violet-300, var(--mj-text-secondary));\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n}\n.board-status .ctx-live .d {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n animation: wb-pulse-ring 2s infinite;\n}\n"] }]
|
|
758
|
+
], template: "<!-- 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 \u2014 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 \u2014 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 \u2014 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> \u00B7 {{ AgentName }} <b>{{ AgentCount }}</b></span>\n <span class=\"stat\">synced <b>{{ LastDeltaLabel }}</b> \u00B7 seq <b>{{ CurrentSeq }}</b></span>\n <span class=\"seg-r\">\n <span class=\"stat ctx-live\" [title]=\"AgentName + '\u2019s 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", styles: ["/* The host carries tabindex=\"-1\" so the board has a focus scope for its keyboard\n shortcuts (WCAG 2.1.4). Suppress the ring for the pointer path only \u2014 a keyboard\n focus, if the board ever becomes tab-reachable, must still show one (2.4.7). */\n:host:focus:not(:focus-visible) {\n outline: none;\n}\n\n/* LIVE WHITEBOARD host chrome \u2014 board header, board wrap, agent toast, status footer.\n Ported pixel-faithfully from plans/realtime/mockups/whiteboard.html\n (.board-head, .head-btn, .board-legend, .board-toast, .board-status). */\n\n:host {\n /* agent (violet) accent \u2014 same derivation as the sibling realtime components */\n --sage: var(--mj-color-violet-400, #a78bfa);\n --sage-bg: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 14%, transparent);\n --sage-border: color-mix(in srgb, var(--mj-color-violet-400, #a78bfa) 45%, transparent);\n --sage-chip-bg: color-mix(in srgb, var(--mj-color-violet-500, #8b5cf6) 32%, var(--mj-bg-surface-sunken));\n\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n height: 100%;\n /* width container \u2014 drives the status footer's narrow-width collapse rules */\n container-type: inline-size;\n container-name: wb-host;\n}\n\n/* ---------- board header row ---------- */\n.board-head {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 9px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n.board-head .bt {\n font-weight: 700;\n font-size: 13.5px;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--mj-text-primary);\n}\n.board-head .bt i {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n font-size: 13px;\n}\n.board-save {\n font-size: 11px;\n color: var(--mj-text-muted);\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n.board-save i {\n color: var(--mj-status-success);\n font-size: 10px;\n}\n\n.board-legend {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-left: 6px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-bg-surface-card);\n}\n.board-legend .sw {\n width: 10px;\n height: 10px;\n border-radius: 3px;\n display: inline-block;\n vertical-align: -1px;\n margin-right: 5px;\n}\n.board-legend .sw--you {\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-strong);\n}\n.board-legend .sw--sage {\n background: var(--sage-bg);\n border: 1px solid var(--sage);\n}\n.legend-feather {\n font-size: 9px;\n color: var(--sage);\n}\n\n.head-end {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 8px;\n position: relative;\n}\n\n.head-btn {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n padding: 5px 11px;\n font-size: 11.5px;\n font-weight: 600;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full, 9999px);\n cursor: pointer;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n transition: all 140ms ease;\n font-family: inherit;\n}\n.head-btn:hover {\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n.head-btn.on {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, transparent);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n.head-btn--sees {\n position: relative;\n}\n.head-btn--sees .eye-pulse {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent);\n animation: wb-pulse-ring 2s infinite;\n}\n.head-btn--more {\n padding: 5px 9px;\n}\n\n/* ---------- export menu (Download HTML / Download SVG / Print) ---------- */\n.export-wrap {\n position: relative;\n display: inline-flex;\n}\n.export-menu {\n position: absolute;\n top: calc(100% + 6px);\n right: 0;\n z-index: 30;\n min-width: 168px;\n display: flex;\n flex-direction: column;\n padding: 5px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-elevated);\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n}\n.export-item {\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 7px 10px;\n font-size: 11.5px;\n font-weight: 600;\n font-family: inherit;\n text-align: left;\n border: none;\n border-radius: var(--mj-radius-sm, 5px);\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n white-space: nowrap;\n}\n.export-item:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.export-item i {\n width: 14px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n.export-item:hover i {\n color: var(--mj-brand-accent, var(--mj-brand-primary));\n}\n@keyframes wb-pulse-ring {\n 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sage) 50%, transparent); }\n 70% { box-shadow: 0 0 0 6px transparent; }\n 100% { box-shadow: 0 0 0 0 transparent; }\n}\n\n/* ---------- the board ---------- */\n.board-wrap {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n/* ---------- agent action toast ----------\n Bottom-center, raised ABOVE the zoom cluster's row (cluster: bottom 14px + ~38px\n tall) so the two can never collide, and width-capped clear of the cluster at the\n board's right edge. Sits just above the status footer per the mockup. */\n.board-toast {\n position: absolute;\n left: 50%;\n bottom: 64px;\n transform: translateX(-50%);\n z-index: 9;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 8px 16px;\n max-width: calc(100% - 32px);\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--sage-chip-bg);\n border: 1px solid var(--sage-border);\n color: var(--mj-color-violet-300, #c4b5fd);\n font-size: 12px;\n font-weight: 600;\n box-shadow: var(--mj-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.3));\n animation: wb-toast-fade 300ms ease both;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast > i {\n flex-shrink: 0;\n}\n.board-toast__text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.board-toast .undo {\n flex-shrink: 0;\n}\n@keyframes wb-toast-fade {\n from { opacity: 0; transform: translate(-50%, 4px); }\n to { opacity: 1; transform: translate(-50%, 0); }\n}\n.board-toast .undo {\n color: var(--mj-text-muted);\n font-weight: 600;\n cursor: pointer;\n margin-left: 4px;\n}\n.board-toast .undo:hover {\n color: var(--mj-text-primary);\n}\n\n/* ---------- board status footer ---------- */\n.board-status {\n display: flex;\n align-items: center;\n gap: 18px;\n padding: 6px 16px;\n flex-shrink: 0;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 10.5px;\n color: var(--mj-text-muted);\n font-weight: 500;\n}\n.board-status b {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n.board-status .seg-r {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 18px;\n}\n.board-status .ctx-live {\n color: var(--mj-color-violet-300, var(--mj-text-secondary));\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n}\n.board-status .ctx-live .d {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sage);\n animation: wb-pulse-ring 2s infinite;\n}\n"] }]
|
|
705
759
|
}], null, { State: [{
|
|
706
760
|
type: Input,
|
|
707
761
|
args: [{ required: true }]
|
|
@@ -711,6 +765,8 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
711
765
|
type: Input
|
|
712
766
|
}], SavedLabel: [{
|
|
713
767
|
type: Input
|
|
768
|
+
}], EnableGlobalShortcuts: [{
|
|
769
|
+
type: Input
|
|
714
770
|
}], SceneDelta: [{
|
|
715
771
|
type: Output
|
|
716
772
|
}], AgentUndo: [{
|
|
@@ -750,6 +806,12 @@ export class RealtimeWhiteboardHostComponent {
|
|
|
750
806
|
}], CloseExport: [{
|
|
751
807
|
type: HostListener,
|
|
752
808
|
args: ['document:click']
|
|
809
|
+
}], HostTabIndex: [{
|
|
810
|
+
type: HostBinding,
|
|
811
|
+
args: ['attr.tabindex']
|
|
812
|
+
}], OnHostPointerDown: [{
|
|
813
|
+
type: HostListener,
|
|
814
|
+
args: ['pointerdown']
|
|
753
815
|
}], OnKeydown: [{
|
|
754
816
|
type: HostListener,
|
|
755
817
|
args: ['document:keydown', ['$event']]
|
|
@@ -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 {\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 * 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 /** 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 /**\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 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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-whiteboard",
|
|
3
|
-
"version": "6.1.0-edge.
|
|
3
|
+
"version": "6.1.0-edge.5",
|
|
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",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@angular/compiler": "21.1.3",
|
|
22
22
|
"@angular/compiler-cli": "21.1.3",
|
|
23
|
-
"@memberjunction/ng-test-utils": "6.1.0-edge.
|
|
23
|
+
"@memberjunction/ng-test-utils": "6.1.0-edge.5",
|
|
24
24
|
"vitest": "^4.0.18"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"@angular/platform-browser": "^21.1.3"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@memberjunction/ng-ui-components": "6.1.0-edge.
|
|
33
|
-
"@memberjunction/global": "6.1.0-edge.
|
|
34
|
-
"@memberjunction/ng-code-editor": "6.1.0-edge.
|
|
35
|
-
"@memberjunction/ng-markdown": "6.1.0-edge.
|
|
32
|
+
"@memberjunction/ng-ui-components": "6.1.0-edge.5",
|
|
33
|
+
"@memberjunction/global": "6.1.0-edge.5",
|
|
34
|
+
"@memberjunction/ng-code-editor": "6.1.0-edge.5",
|
|
35
|
+
"@memberjunction/ng-markdown": "6.1.0-edge.5",
|
|
36
36
|
"rxjs": "^7.8.2",
|
|
37
37
|
"tslib": "^2.8.1"
|
|
38
38
|
},
|