@q9labsai/chalk-whiteboard 5.0.1 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -33,7 +33,23 @@ export type ChalkEmbeddedWhiteboardTransportEvent = {
33
33
  readonly type: "reset_required";
34
34
  readonly sceneId: string;
35
35
  readonly reason: "scene_changed" | "cursor_expired" | "gap";
36
- };
36
+ } | ({
37
+ readonly type: "view";
38
+ readonly participantId: string;
39
+ readonly displayName: string;
40
+ readonly x: number;
41
+ readonly y: number;
42
+ readonly width: number;
43
+ readonly height: number;
44
+ readonly bring: boolean;
45
+ readonly occurredAt: string;
46
+ } & ({
47
+ readonly originParticipantId: string;
48
+ readonly originSequence: number;
49
+ } | {
50
+ readonly originParticipantId?: never;
51
+ readonly originSequence?: never;
52
+ }));
37
53
  export interface ChalkEmbeddedWhiteboardFileTransport {
38
54
  readonly getDownloadUrl: (fileId: string) => Promise<{
39
55
  readonly downloadUrl: string;
@@ -415,6 +415,8 @@ var ChalkWhiteboardController = class {
415
415
  case "cursor":
416
416
  this.#send({ type: "apply_cursor", payload: event });
417
417
  return;
418
+ case "view":
419
+ return;
418
420
  case "reset_required":
419
421
  this.#sceneGeneration = null;
420
422
  this.#send({ type: "reset_required", payload: event });
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ExcalidrawCollabEngine
3
- } from "./chunk-6ZV7GBAC.js";
3
+ } from "./chunk-X3WDTGPQ.js";
4
+ import "./chunk-IVFWOYSW.js";
4
5
  export {
5
6
  ExcalidrawCollabEngine
6
7
  };
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  mergeWhiteboardElements
3
- } from "./chunk-W4FLPXAX.js";
3
+ } from "./chunk-MPNIDZHM.js";
4
4
  import {
5
5
  fromWireElement,
6
6
  isWireElement,
7
7
  toWireElement
8
- } from "./chunk-6ZV7GBAC.js";
8
+ } from "./chunk-X3WDTGPQ.js";
9
+ import "./chunk-IVFWOYSW.js";
9
10
  export {
10
11
  fromWireElement,
11
12
  isWireElement,
@@ -1,6 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
2
  import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types";
3
3
  import type { ExcalidrawCollabEngineOptions } from "../collab/engine.js";
4
+ type ExcalidrawModule = typeof import("@excalidraw/excalidraw");
4
5
  export interface WhiteboardCollaborationOptions extends Omit<ExcalidrawCollabEngineOptions, "excalidrawAPI" | "canDraw"> {
5
6
  canDraw?: boolean;
6
7
  }
@@ -29,8 +30,24 @@ export interface WhiteboardCanvasIcons {
29
30
  submit?: ReactNode;
30
31
  submitting?: ReactNode;
31
32
  }
33
+ /** What a host that draws its own controls needs from the loaded engine. */
34
+ export interface WhiteboardEngineHandle {
35
+ api: ExcalidrawImperativeAPI;
36
+ excalidraw: ExcalidrawModule;
37
+ /** Clears the shared board; resolves once the new empty scene is committed. */
38
+ clear: () => Promise<void>;
39
+ /** Clears and returns a restore bound to that committed scene and this engine lifetime. */
40
+ clearWithUndo: () => Promise<() => boolean>;
41
+ /** Renders LaTeX and places it on the board, or replaces the selected formula. */
42
+ placeMath: (latex: string) => Promise<void>;
43
+ }
32
44
  export interface WhiteboardCanvasProps {
33
45
  className?: string;
46
+ /** Hides every engine control; the host draws its own and drives the engine through `onEngineReady`. */
47
+ headless?: boolean;
48
+ /** The colour this viewer sees for Ink. Ink travels as one canonical colour. */
49
+ inkColor?: string;
50
+ onEngineReady?: (engine: WhiteboardEngineHandle) => void;
34
51
  isVisible?: boolean;
35
52
  canDraw?: boolean;
36
53
  theme?: "light" | "dark";
@@ -0,0 +1,7 @@
1
+ import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types";
2
+ export type EngineHistoryState = {
3
+ readonly canUndo: boolean;
4
+ readonly canRedo: boolean;
5
+ };
6
+ /** 0.18.1 exposes clear, but not the history reader/emitter, on its imperative API. */
7
+ export declare function observeEngineHistory(api: ExcalidrawImperativeAPI, canvas: HTMLElement, onChange: (state: EngineHistoryState) => void): () => void;
@@ -1,7 +1,9 @@
1
1
  export { WhiteboardCanvas, preloadWhiteboardStylesheet } from "./WhiteboardCanvas.js";
2
- export type { WhiteboardCanvasClassNames, WhiteboardCanvasIcons, WhiteboardCanvasProps, WhiteboardCollaborationOptions } from "./WhiteboardCanvas.js";
2
+ export type { WhiteboardCanvasClassNames, WhiteboardCanvasIcons, WhiteboardCanvasProps, WhiteboardCollaborationOptions, WhiteboardEngineHandle } from "./WhiteboardCanvas.js";
3
3
  export { appendOrReplaceMathElement, CHALK_MATH_CUSTOM_DATA_KEY, CHALK_MATH_RENDERER, createMathFileId, createMathImageAsset, getChalkMathData, getInsertionPoint, getSelectedMathElement, isChalkMathElement, svgToDataUrl } from "./math-elements.js";
4
4
  export type { ChalkMathCustomData, MathImageAsset } from "./math-elements.js";
5
5
  export { getRenderedSvgSize, renderLatexToSvg } from "./mathjax-renderer.js";
6
6
  export type { RenderedMathSvg } from "./mathjax-renderer.js";
7
7
  export type { AppState, BinaryFileData, BinaryFiles, Collaborator, CollaboratorPointer, ExcalidrawElement, ExcalidrawImperativeAPI, OrderedExcalidrawElement } from "../collab/index.js";
8
+ export { CANONICAL_INK } from "../collab/ink.js";
9
+ export { observeEngineHistory, type EngineHistoryState } from "./engine-history.js";
@@ -1,3 +1,7 @@
1
+ import {
2
+ CANONICAL_INK
3
+ } from "../chunk-IVFWOYSW.js";
4
+
1
5
  // src/react/WhiteboardCanvas.tsx
2
6
  import { memo, useCallback, useEffect, useMemo, useRef, useState as useState2 } from "react";
3
7
 
@@ -282,6 +286,7 @@ function useWhiteboardCanvasConfiguration(props) {
282
286
  const rootClassName = [classNames.root, valueOr(props.className, "")].filter(Boolean).join(" ");
283
287
  return {
284
288
  canDraw,
289
+ headless: props.headless === true,
285
290
  classNames,
286
291
  excalidrawCssPath: valueOr(props.excalidrawCssPath, DEFAULT_EXCALIDRAW_CSS),
287
292
  icons: valueOr(props.icons, {}),
@@ -355,67 +360,71 @@ function useExcalidrawModule(onLoadError, setLoadError) {
355
360
  }, [onLoadError, setLoadError]);
356
361
  return excalidraw;
357
362
  }
358
- function useWhiteboardInitialData(theme, localParticipantColor) {
363
+ var TRANSPARENT = "transparent";
364
+ function useWhiteboardInitialData(theme, headless, localParticipantColor, inkColor) {
365
+ const initialInk = useRef(inkColor);
359
366
  return useMemo(
360
367
  () => ({
361
368
  appState: {
362
- viewBackgroundColor: theme === "dark" ? "#000000" : "#ffffff",
363
- currentItemStrokeColor: localParticipantColor ?? "#4CB9FF",
369
+ viewBackgroundColor: headless ? TRANSPARENT : theme === "dark" ? "#000000" : "#ffffff",
370
+ currentItemStrokeColor: (headless ? initialInk.current : localParticipantColor) ?? "#4CB9FF",
364
371
  theme
365
372
  }
366
373
  }),
367
- [localParticipantColor, theme]
368
- );
369
- }
370
- function useWhiteboardUiOptions() {
371
- return useMemo(
372
- () => ({
373
- canvasActions: {
374
- changeViewBackgroundColor: false,
375
- clearCanvas: false,
376
- export: false,
377
- loadScene: false,
378
- saveAsImage: false,
379
- saveToActiveFile: false,
380
- toggleTheme: false
381
- },
382
- tools: { image: false },
383
- welcomeScreen: false
384
- }),
385
- []
374
+ [headless, localParticipantColor, theme]
386
375
  );
387
376
  }
377
+ var UI_OPTIONS = {
378
+ canvasActions: {
379
+ changeViewBackgroundColor: false,
380
+ clearCanvas: false,
381
+ export: false,
382
+ loadScene: false,
383
+ saveAsImage: false,
384
+ saveToActiveFile: false,
385
+ toggleTheme: false
386
+ },
387
+ tools: { image: false },
388
+ welcomeScreen: false
389
+ };
388
390
  function useWhiteboardCollaboration(options) {
389
391
  const apiRef = useRef(null);
390
- const refs = useCollaborationRefs(options.collab, options.canDraw);
391
- const initializeEngine = useCollaborationEngineLoader(refs, apiRef, options.onLoadError, options.setLoadError);
392
+ const refs = useCollaborationRefs(options.collab, options.canDraw, options.inkColor);
393
+ const [engineReady, setEngineReady] = useState2(false);
394
+ const initializeEngine = useCollaborationEngineLoader(refs, apiRef, options.headless, options.onLoadError, options.setLoadError, setEngineReady);
392
395
  const handleApiReady = useExcalidrawApiReady(apiRef, initializeEngine, options.onExcalidrawApiReady);
393
396
  const handlers = useExcalidrawSceneHandlers(apiRef, refs.engineRef, options.onSelectedLatexChange);
394
- useCollaborationCanDraw(refs.engineRef, options.canDraw);
397
+ useCollaborationPermissions(refs.engineRef, options.canDraw, options.collab?.canManage);
398
+ useCollaborationInk(refs.engineRef, options.inkColor);
395
399
  useCollaborationDisposal(refs.engineRef, refs.isMountedRef);
396
400
  useCollaborationInitialization(options.collab, apiRef, refs.engineRef, initializeEngine);
397
- return { apiRef, handleApiReady, ...handlers };
401
+ return { ready: !options.collab || engineReady, apiRef, engineRef: refs.engineRef, handleApiReady, ...handlers };
398
402
  }
399
- function useCollaborationRefs(collab, canDraw) {
403
+ function useCollaborationRefs(collab, canDraw, inkColor) {
400
404
  const canDrawRef = useRef(canDraw);
405
+ const inkColorRef = useRef(inkColor);
401
406
  const collabOptionsRef = useRef(collab);
402
407
  const enginePromiseRef = useRef(null);
403
408
  const engineRef = useRef(null);
404
409
  const isMountedRef = useRef(true);
405
410
  canDrawRef.current = canDraw;
411
+ inkColorRef.current = inkColor;
406
412
  collabOptionsRef.current = collab;
407
- return useMemo(() => ({ canDrawRef, collabOptionsRef, enginePromiseRef, engineRef, isMountedRef }), [canDrawRef, collabOptionsRef, enginePromiseRef, engineRef, isMountedRef]);
413
+ return useMemo(() => ({ canDrawRef, inkColorRef, collabOptionsRef, enginePromiseRef, engineRef, isMountedRef }), [canDrawRef, inkColorRef, collabOptionsRef, enginePromiseRef, engineRef, isMountedRef]);
408
414
  }
409
- function useCollaborationEngineLoader(refs, apiRef, onLoadError, setLoadError) {
415
+ function useCollaborationEngineLoader(refs, apiRef, headless, onLoadError, setLoadError, setEngineReady) {
410
416
  return useCallback(() => {
411
417
  if (!refs.collabOptionsRef.current || refs.engineRef.current || refs.enginePromiseRef.current) return;
412
- refs.enginePromiseRef.current = import("../engine-BIJ57YN3.js").then(({ ExcalidrawCollabEngine }) => {
418
+ refs.enginePromiseRef.current = import("../engine-MERF7RL3.js").then(({ ExcalidrawCollabEngine }) => {
413
419
  const api = apiRef.current;
414
420
  const collab = refs.collabOptionsRef.current;
415
421
  if (!refs.isMountedRef.current || !api || !collab) return;
416
422
  refs.engineRef.current = new ExcalidrawCollabEngine({
417
423
  excalidrawAPI: api,
418
424
  canDraw: refs.canDrawRef.current,
425
+ canManage: collab.canManage,
426
+ renderCursors: !headless,
427
+ ...refs.inkColorRef.current ? { inkColor: refs.inkColorRef.current } : {},
419
428
  submitUpdate: collab.submitUpdate,
420
429
  sendCursor: collab.sendCursor,
421
430
  requestSnapshot: collab.requestSnapshot,
@@ -426,6 +435,7 @@ function useCollaborationEngineLoader(refs, apiRef, onLoadError, setLoadError) {
426
435
  onFileSyncStateChange: collab.onFileSyncStateChange,
427
436
  onSubmissionError: collab.onSubmissionError
428
437
  });
438
+ setEngineReady(true);
429
439
  }).catch((reason) => {
430
440
  if (!refs.isMountedRef.current) return;
431
441
  const error = reason instanceof Error ? reason : new Error("Failed to load whiteboard collaboration");
@@ -434,7 +444,7 @@ function useCollaborationEngineLoader(refs, apiRef, onLoadError, setLoadError) {
434
444
  }).finally(() => {
435
445
  refs.enginePromiseRef.current = null;
436
446
  });
437
- }, [apiRef, onLoadError, refs, setLoadError]);
447
+ }, [apiRef, headless, onLoadError, refs, setLoadError, setEngineReady]);
438
448
  }
439
449
  function useExcalidrawApiReady(apiRef, initializeEngine, onExcalidrawApiReady) {
440
450
  const didReportApiRef = useRef(false);
@@ -478,10 +488,16 @@ function selectedMathLatex(api) {
478
488
  const math = getChalkMathData(selected);
479
489
  return math ? math.latex : null;
480
490
  }
481
- function useCollaborationCanDraw(engineRef, canDraw) {
491
+ function useCollaborationPermissions(engineRef, canDraw, canManage) {
482
492
  useEffect(() => {
483
493
  engineRef.current?.setCanDraw(canDraw);
484
- }, [canDraw, engineRef]);
494
+ engineRef.current?.setCanManage(canManage);
495
+ }, [canDraw, canManage, engineRef]);
496
+ }
497
+ function useCollaborationInk(engineRef, inkColor) {
498
+ useEffect(() => {
499
+ if (inkColor) engineRef.current?.setInkColor(inkColor);
500
+ }, [engineRef, inkColor]);
485
501
  }
486
502
  function useCollaborationDisposal(engineRef, isMountedRef) {
487
503
  useEffect(() => {
@@ -537,6 +553,8 @@ function useWhiteboardCanvasState(props) {
537
553
  const stylesheet = useExternalStylesheet(configuration.excalidrawCssPath);
538
554
  const collaboration = useWhiteboardCollaboration({
539
555
  canDraw: configuration.canDraw,
556
+ headless: configuration.headless,
557
+ inkColor: props.inkColor,
540
558
  collab: props.collab,
541
559
  onExcalidrawApiReady: props.onExcalidrawApiReady,
542
560
  onLoadError: props.onLoadError,
@@ -552,39 +570,87 @@ function useWhiteboardCanvasState(props) {
552
570
  setSelectedLatex,
553
571
  syncScene: collaboration.syncScene
554
572
  });
555
- const initialData = useWhiteboardInitialData(configuration.theme, props.localParticipantColor);
556
- const uiOptions = useWhiteboardUiOptions();
573
+ const initialData = useWhiteboardInitialData(configuration.theme, configuration.headless, props.localParticipantColor, props.inkColor);
557
574
  const resolvedLoadError = loadError ?? stylesheet.error;
575
+ const isReady = Boolean(excalidraw && stylesheet.loaded && !resolvedLoadError);
576
+ const engine = useEngineHandle(props.onEngineReady, excalidraw, collaboration, math.handleSubmitMath, configuration.headless, isReady);
558
577
  return {
559
578
  collaboration,
560
579
  configuration,
561
580
  excalidraw,
562
581
  initialData,
563
- isReady: Boolean(excalidraw && stylesheet.loaded && !resolvedLoadError),
582
+ isReady,
564
583
  math,
565
584
  resolvedLoadError,
566
- uiOptions
585
+ uiOptions: UI_OPTIONS,
586
+ ...engine
567
587
  };
568
588
  }
589
+ function useEngineHandle(onEngineReady, excalidraw, collaboration, placeMath, headless, isReady) {
590
+ const [api, setApi] = useState2(null);
591
+ const [loaded, setLoaded] = useState2(false);
592
+ const { handleApiReady, handleChange } = collaboration;
593
+ const onApiReady = useCallback(
594
+ (next) => {
595
+ handleApiReady(next);
596
+ setApi(next);
597
+ },
598
+ [handleApiReady]
599
+ );
600
+ const onChange = useCallback(
601
+ (elements, appState, files) => {
602
+ handleChange(elements, appState, files);
603
+ if (!appState.isLoading) setLoaded(true);
604
+ if (headless && appState.viewBackgroundColor !== TRANSPARENT) api?.updateScene({ appState: { viewBackgroundColor: TRANSPARENT } });
605
+ },
606
+ [api, handleChange, headless]
607
+ );
608
+ const placeMathRef = useRef(placeMath);
609
+ placeMathRef.current = placeMath;
610
+ const liveApi = useRef(api);
611
+ useEffect(() => {
612
+ liveApi.current = api;
613
+ return () => {
614
+ liveApi.current = null;
615
+ };
616
+ }, [api]);
617
+ const { engineRef } = collaboration;
618
+ useEffect(() => {
619
+ if (!api || !excalidraw || !loaded || !isReady || !collaboration.ready || !onEngineReady) return;
620
+ onEngineReady({
621
+ api,
622
+ excalidraw,
623
+ clear: async () => {
624
+ const engine = engineRef.current;
625
+ if (engine) await engine.clear();
626
+ else {
627
+ api.updateScene({ elements: [], captureUpdate: excalidraw.CaptureUpdateAction.NEVER });
628
+ api.history.clear();
629
+ }
630
+ },
631
+ clearWithUndo: async () => {
632
+ const engine = engineRef.current;
633
+ if (engine) return engine.clearWithUndo();
634
+ const before = api.getSceneElements();
635
+ api.updateScene({ elements: [], captureUpdate: excalidraw.CaptureUpdateAction.NEVER });
636
+ api.history.clear();
637
+ return () => {
638
+ if (liveApi.current !== api || api.getSceneElementsIncludingDeleted().length > 0) return false;
639
+ api.updateScene({ elements: before.map((element) => excalidraw.newElementWith(element, {})), captureUpdate: excalidraw.CaptureUpdateAction.IMMEDIATELY });
640
+ return true;
641
+ };
642
+ },
643
+ placeMath: (latex) => placeMathRef.current(latex)
644
+ });
645
+ }, [api, engineRef, excalidraw, isReady, loaded, collaboration.ready, onEngineReady]);
646
+ return { onApiReady, onChange };
647
+ }
569
648
  function WhiteboardCanvasView({ state }) {
570
- const { collaboration, configuration, excalidraw, initialData, isReady, math, resolvedLoadError, uiOptions } = state;
649
+ const { configuration, excalidraw, initialData, isReady, math, onApiReady, onChange, collaboration, resolvedLoadError, uiOptions } = state;
571
650
  return /* @__PURE__ */ jsxs2("div", { className: configuration.rootClassName, hidden: !configuration.isVisible, children: [
572
- /* @__PURE__ */ jsx2(WhiteboardMathToolbar, { canDraw: configuration.canDraw && !configuration.isCollaborating, classNames: configuration.classNames, isReady, onOpenMath: math.openMath, selectedLatex: math.selectedLatex }),
573
- /* @__PURE__ */ jsx2(WhiteboardCanvasStatus, { classNames: configuration.classNames, error: resolvedLoadError, icons: configuration.icons, isReady }),
574
- excalidraw && /* @__PURE__ */ jsx2(
575
- WhiteboardScene,
576
- {
577
- canDraw: configuration.canDraw,
578
- collab: configuration.isCollaborating,
579
- excalidraw,
580
- initialData,
581
- onApiReady: collaboration.handleApiReady,
582
- onChange: collaboration.handleChange,
583
- onPointerUpdate: collaboration.handlePointerUpdate,
584
- theme: configuration.theme,
585
- uiOptions
586
- }
587
- ),
651
+ /* @__PURE__ */ jsx2(WhiteboardMathToolbar, { canDraw: configuration.canDraw && !configuration.isCollaborating && !configuration.headless, classNames: configuration.classNames, isReady, onOpenMath: math.openMath, selectedLatex: math.selectedLatex }),
652
+ /* @__PURE__ */ jsx2(WhiteboardCanvasStatus, { classNames: configuration.classNames, error: resolvedLoadError, icons: configuration.icons, isReady: isReady || configuration.headless }),
653
+ excalidraw && /* @__PURE__ */ jsx2(WhiteboardScene, { canDraw: configuration.canDraw, collab: configuration.isCollaborating, excalidraw, initialData, onApiReady, onChange, onPointerUpdate: collaboration.handlePointerUpdate, theme: configuration.theme, uiOptions }),
588
654
  math.isMathOpen && /* @__PURE__ */ jsx2(MathEditor, { initialLatex: math.initialLatex, isEditing: Boolean(math.selectedLatex), classNames: configuration.classNames, icons: configuration.icons, onClose: math.closeMath, onSubmit: math.handleSubmitMath })
589
655
  ] });
590
656
  }
@@ -605,7 +671,7 @@ function WhiteboardLoading({ classNames, loadingIcon }) {
605
671
  ] }) });
606
672
  }
607
673
  function WhiteboardLoadError({ className, error }) {
608
- return /* @__PURE__ */ jsx2("div", { className, style: { position: "absolute", inset: 0, zIndex: 30, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx2("div", { children: error }) });
674
+ return /* @__PURE__ */ jsx2("div", { role: "alert", className, style: { position: "absolute", inset: 0, zIndex: 30, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx2("div", { children: error }) });
609
675
  }
610
676
  function WhiteboardScene({
611
677
  canDraw,
@@ -625,7 +691,49 @@ function WhiteboardCanvasBase(props) {
625
691
  }
626
692
  var WhiteboardCanvas = memo(WhiteboardCanvasBase);
627
693
  WhiteboardCanvas.displayName = "WhiteboardCanvas";
694
+
695
+ // src/react/engine-history.ts
696
+ function observeEngineHistory(api, canvas, onChange) {
697
+ let connected = false;
698
+ let dispose = () => {
699
+ };
700
+ api.registerAction({
701
+ name: "stats",
702
+ label: "Stats",
703
+ trackEvent: false,
704
+ perform: () => false,
705
+ keyTest: (_event, _state, _elements, app) => {
706
+ if (connected) return false;
707
+ connected = true;
708
+ const history = app.history;
709
+ const read = () => ({ isUndoStackEmpty: history.isUndoStackEmpty, isRedoStackEmpty: history.isRedoStackEmpty });
710
+ const originalClear = history.clear;
711
+ const clear = () => {
712
+ originalClear.call(history);
713
+ history.onHistoryChangedEmitter.trigger(read());
714
+ };
715
+ history.clear = clear;
716
+ const update = () => {
717
+ const state = read();
718
+ onChange({ canUndo: !state.isUndoStackEmpty, canRedo: !state.isRedoStackEmpty });
719
+ };
720
+ const off = history.onHistoryChangedEmitter.on(update);
721
+ update();
722
+ dispose = () => {
723
+ off();
724
+ history.clear = originalClear;
725
+ };
726
+ return false;
727
+ }
728
+ });
729
+ canvas.dispatchEvent(new KeyboardEvent("keydown", { key: "Shift", bubbles: true }));
730
+ return () => {
731
+ connected = true;
732
+ dispose();
733
+ };
734
+ }
628
735
  export {
736
+ CANONICAL_INK,
629
737
  CHALK_MATH_CUSTOM_DATA_KEY,
630
738
  CHALK_MATH_RENDERER,
631
739
  WhiteboardCanvas,
@@ -637,6 +745,7 @@ export {
637
745
  getRenderedSvgSize,
638
746
  getSelectedMathElement,
639
747
  isChalkMathElement,
748
+ observeEngineHistory,
640
749
  preloadWhiteboardStylesheet,
641
750
  renderLatexToSvg,
642
751
  svgToDataUrl
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q9labsai/chalk-whiteboard",
3
- "version": "5.0.1",
3
+ "version": "5.2.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,7 +8,8 @@
8
8
  "directory": "packages/whiteboard"
9
9
  },
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "CHANGELOG.md"
12
13
  ],
13
14
  "type": "module",
14
15
  "sideEffects": false,
@@ -70,7 +71,7 @@
70
71
  "@types/react": "^19.0.0",
71
72
  "@types/react-dom": "^19.2.3",
72
73
  "esbuild": "0.28.2",
73
- "happy-dom": "^20.11.2",
74
+ "happy-dom": "^21.0.4",
74
75
  "react": "19.2.7",
75
76
  "react-dom": "19.2.7",
76
77
  "typescript": "^5.7.2"