@xom11/whiteboard 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/ai.d.mts +1 -1
  2. package/dist/ai.d.ts +1 -1
  3. package/dist/ai.js +54 -23
  4. package/dist/ai.js.map +1 -1
  5. package/dist/ai.mjs +54 -23
  6. package/dist/ai.mjs.map +1 -1
  7. package/dist/catalog.json +4 -4
  8. package/dist/{chunk-D5JLJ3PT.mjs → chunk-5JM35CXV.mjs} +4 -4
  9. package/dist/{chunk-D5JLJ3PT.mjs.map → chunk-5JM35CXV.mjs.map} +1 -1
  10. package/dist/{chunk-KYMBUTPO.mjs → chunk-BU5KLO3P.mjs} +3 -3
  11. package/dist/{chunk-KYMBUTPO.mjs.map → chunk-BU5KLO3P.mjs.map} +1 -1
  12. package/dist/{chunk-AYJPOHCI.mjs → chunk-H22OZYTW.mjs} +3 -3
  13. package/dist/{chunk-AYJPOHCI.mjs.map → chunk-H22OZYTW.mjs.map} +1 -1
  14. package/dist/{chunk-I3L56GVH.mjs → chunk-OQIQNKPQ.mjs} +3 -3
  15. package/dist/{chunk-I3L56GVH.mjs.map → chunk-OQIQNKPQ.mjs.map} +1 -1
  16. package/dist/{chunk-KZGPSTZI.mjs → chunk-QCZVFEN4.mjs} +4 -4
  17. package/dist/{chunk-KZGPSTZI.mjs.map → chunk-QCZVFEN4.mjs.map} +1 -1
  18. package/dist/{chunk-4ETJ4CDY.mjs → chunk-QRUAEXLR.mjs} +4 -4
  19. package/dist/{chunk-4ETJ4CDY.mjs.map → chunk-QRUAEXLR.mjs.map} +1 -1
  20. package/dist/{chunk-HLAOGXEK.mjs → chunk-V3YJ6JFL.mjs} +3 -3
  21. package/dist/{chunk-HLAOGXEK.mjs.map → chunk-V3YJ6JFL.mjs.map} +1 -1
  22. package/dist/{chunk-D5LWSN2Y.mjs → chunk-ZTQBUKLJ.mjs} +30 -13
  23. package/dist/chunk-ZTQBUKLJ.mjs.map +1 -0
  24. package/dist/geometry-2d.d.mts +1 -1
  25. package/dist/geometry-2d.d.ts +1 -1
  26. package/dist/geometry-2d.js +143 -33
  27. package/dist/geometry-2d.js.map +1 -1
  28. package/dist/geometry-2d.mjs +3 -3
  29. package/dist/geometry-3d.d.mts +1 -1
  30. package/dist/geometry-3d.d.ts +1 -1
  31. package/dist/geometry-3d.js +28 -11
  32. package/dist/geometry-3d.js.map +1 -1
  33. package/dist/geometry-3d.mjs +3 -3
  34. package/dist/graph-2d.d.mts +1 -1
  35. package/dist/graph-2d.d.ts +1 -1
  36. package/dist/graph-2d.js +28 -11
  37. package/dist/graph-2d.js.map +1 -1
  38. package/dist/graph-2d.mjs +3 -3
  39. package/dist/{host-M26FS244.mjs → host-2ISGVO7O.mjs} +5 -5
  40. package/dist/{host-M26FS244.mjs.map → host-2ISGVO7O.mjs.map} +1 -1
  41. package/dist/{host-HAYCJJ2T.mjs → host-4P766V4J.mjs} +110 -27
  42. package/dist/host-4P766V4J.mjs.map +1 -0
  43. package/dist/{host-LTJHAY5A.mjs → host-HOSJHQ5H.mjs} +6 -6
  44. package/dist/{host-LTJHAY5A.mjs.map → host-HOSJHQ5H.mjs.map} +1 -1
  45. package/dist/index.d.mts +9 -4
  46. package/dist/index.d.ts +9 -4
  47. package/dist/index.js +147 -35
  48. package/dist/index.js.map +1 -1
  49. package/dist/index.mjs +17 -15
  50. package/dist/index.mjs.map +1 -1
  51. package/dist/latex.d.mts +1 -1
  52. package/dist/latex.d.ts +1 -1
  53. package/dist/serialize-N4G6RFBB.mjs +9 -0
  54. package/dist/{serialize-C3LSUMSA.mjs.map → serialize-N4G6RFBB.mjs.map} +1 -1
  55. package/dist/{types-zc_Pa0mp.d.mts → types-BHYC2Fiw.d.mts} +25 -1
  56. package/dist/{types-zc_Pa0mp.d.ts → types-BHYC2Fiw.d.ts} +25 -1
  57. package/package.json +1 -1
  58. package/dist/chunk-D5LWSN2Y.mjs.map +0 -1
  59. package/dist/host-HAYCJJ2T.mjs.map +0 -1
  60. package/dist/serialize-C3LSUMSA.mjs +0 -9
@@ -1,12 +1,12 @@
1
1
  "use client";
2
2
  import { useChordShortcut } from './chunk-HNQLZIEP.mjs';
3
3
  import { useToolStateMachine } from './chunk-NVJ7K3DK.mjs';
4
- import { safeJsx, initJxgBoard, attachJxgWheelZoom, useToast, ToastHost, STAMP_PANEL_DESKTOP, ToastProvider, useStampStore, StampLeftPanel, ObjectRow } from './chunk-I3L56GVH.mjs';
5
- import { serializeBoard, renderGeometrySvgFromState, isGeometryCustomData, deserializeBoard } from './chunk-AYJPOHCI.mjs';
4
+ import { safeJsx, initJxgBoard, attachJxgWheelZoom, useToast, ToastHost, STAMP_PANEL_DESKTOP, ToastProvider, useStampStore, StampLeftPanel, ObjectRow } from './chunk-OQIQNKPQ.mjs';
5
+ import { serializeBoard, renderGeometrySvgFromState, isGeometryCustomData, deserializeBoard } from './chunk-H22OZYTW.mjs';
6
6
  import { themeLabel, paletteFor, themeAxis, themeGrid } from './chunk-R5FL6S7L.mjs';
7
7
  import { JxgRenderer } from './chunk-SZDAS7LK.mjs';
8
8
  import './chunk-ICR4CVOE.mjs';
9
- import { nextLabel, useEditorState, listObjects } from './chunk-D5LWSN2Y.mjs';
9
+ import { nextLabel, useEditorState, listObjects } from './chunk-ZTQBUKLJ.mjs';
10
10
  import './chunk-IHUFOV7L.mjs';
11
11
  import { validateFile, fileToImagePart, describeDsl, serializeState } from './chunk-AJAHD35N.mjs';
12
12
  import { handleExtractProblem } from './chunk-T3SOHYB2.mjs';
@@ -3697,6 +3697,85 @@ function AiFigurePrompt({
3697
3697
  ocrWarning && /* @__PURE__ */ jsx("p", { className: "mt-1 rounded bg-amber-50 px-2 py-1 text-[11px] text-amber-700", children: ocrWarning })
3698
3698
  ] });
3699
3699
  }
3700
+
3701
+ // src/stamps/geometry-2d/draft.ts
3702
+ function svgIntrinsicSize(svg) {
3703
+ const w = svg.match(/<svg[^>]*\swidth="([\d.]+)"/);
3704
+ const h = svg.match(/<svg[^>]*\sheight="([\d.]+)"/);
3705
+ if (w && h) return { width: parseFloat(w[1]), height: parseFloat(h[1]) };
3706
+ const vb = svg.match(/viewBox="0 0 ([\d.]+) ([\d.]+)"/);
3707
+ if (vb) return { width: parseFloat(vb[1]), height: parseFloat(vb[2]) };
3708
+ return { width: 300, height: 200 };
3709
+ }
3710
+ function draftFromViewport(svg, appState, seq) {
3711
+ const { width, height } = svgIntrinsicSize(svg);
3712
+ const zoom = appState.zoom?.value ?? 1;
3713
+ const vw = appState.width ?? 800;
3714
+ const vh = appState.height ?? 600;
3715
+ const cx = appState.scrollX + vw / 2 / zoom;
3716
+ const cy = appState.scrollY + vh / 2 / zoom;
3717
+ return { svg, width, height, x: cx - width / 2, y: cy - height / 2, seq };
3718
+ }
3719
+ function didStateChange(seen, jsonState) {
3720
+ if (seen.last === jsonState) return false;
3721
+ seen.last = jsonState;
3722
+ return true;
3723
+ }
3724
+
3725
+ // src/stamps/geometry-2d/editor/useGeometryDraftEmit.ts
3726
+ function useGeometryDraftEmit({
3727
+ store,
3728
+ handleRef,
3729
+ api,
3730
+ showAxis,
3731
+ showGrid,
3732
+ onGeometryDraft,
3733
+ debounceMs = 350
3734
+ }) {
3735
+ const seqRef = useRef(0);
3736
+ const seenRef = useRef({ last: null });
3737
+ const timerRef = useRef(null);
3738
+ const cbRef = useRef(onGeometryDraft);
3739
+ cbRef.current = onGeometryDraft;
3740
+ useEffect(() => {
3741
+ if (!cbRef.current) return;
3742
+ const emit = () => {
3743
+ const h = handleRef.current;
3744
+ if (!h) return;
3745
+ const state = h.getState();
3746
+ if (Object.keys(state.objects).length === 0) {
3747
+ if (seenRef.current.last !== null) {
3748
+ seenRef.current.last = null;
3749
+ cbRef.current?.(null);
3750
+ }
3751
+ return;
3752
+ }
3753
+ const bbox = h.getBbox();
3754
+ const jsonState = serializeBoard(state, { bbox, showAxis, showGrid });
3755
+ if (!didStateChange(seenRef.current, jsonState)) return;
3756
+ void (async () => {
3757
+ try {
3758
+ const svg = await renderGeometrySvgFromState(jsonState);
3759
+ const appState = api?.getAppState?.() ?? { scrollX: 0, scrollY: 0, width: 800, height: 600, zoom: { value: 1 } };
3760
+ seqRef.current += 1;
3761
+ cbRef.current?.(draftFromViewport(svg, appState, seqRef.current));
3762
+ } catch (err) {
3763
+ console.warn("[geometry] draft render failed:", err);
3764
+ }
3765
+ })();
3766
+ };
3767
+ const schedule = () => {
3768
+ if (timerRef.current) clearTimeout(timerRef.current);
3769
+ timerRef.current = setTimeout(emit, debounceMs);
3770
+ };
3771
+ const unsub = store.subscribe(schedule);
3772
+ return () => {
3773
+ unsub();
3774
+ if (timerRef.current) clearTimeout(timerRef.current);
3775
+ cbRef.current?.(null);
3776
+ };
3777
+ }, [store, handleRef, api, showAxis, showGrid, debounceMs]);
3778
+ }
3700
3779
  var GeometryEditorPanelInner = forwardRef(
3701
3780
  function GeometryEditorPanelInner2({
3702
3781
  store,
@@ -3715,7 +3794,9 @@ var GeometryEditorPanelInner = forwardRef(
3715
3794
  canUndo,
3716
3795
  canRedo,
3717
3796
  onSelectionChange,
3718
- generateGeometryFigure
3797
+ generateGeometryFigure,
3798
+ api,
3799
+ onGeometryDraft
3719
3800
  }, ref) {
3720
3801
  const { showToast } = useToast();
3721
3802
  const handleRef = useRef(null);
@@ -3728,12 +3809,14 @@ var GeometryEditorPanelInner = forwardRef(
3728
3809
  useEffect(() => {
3729
3810
  onSelectionChangeRef.current = onSelectionChange;
3730
3811
  }, [onSelectionChange]);
3812
+ const onGeometryDraftRef = useRef(onGeometryDraft);
3813
+ useEffect(() => {
3814
+ onGeometryDraftRef.current = onGeometryDraft;
3815
+ }, [onGeometryDraft]);
3731
3816
  useEditorState({ store, onHistoryChange });
3732
- const currentSceneState = useSyncExternalStore(
3733
- (cb) => store.subscribe(cb),
3734
- () => store.getState(),
3735
- () => store.getState()
3736
- );
3817
+ useGeometryDraftEmit({ store, handleRef, api, showAxis, showGrid, onGeometryDraft });
3818
+ const snap = () => store.getState();
3819
+ const currentSceneState = useSyncExternalStore((cb) => store.subscribe(cb), snap, snap);
3737
3820
  useEffect(() => {
3738
3821
  const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
3739
3822
  sync();
@@ -3743,22 +3826,22 @@ var GeometryEditorPanelInner = forwardRef(
3743
3826
  const h = handleRef.current;
3744
3827
  if (!h) return;
3745
3828
  setReady(true);
3746
- h.onSelect((snap) => {
3747
- setPropsPopover(snap);
3829
+ h.onSelect((snap2) => {
3830
+ setPropsPopover(snap2);
3748
3831
  setMultiSelection(null);
3749
- onSelectionChangeRef.current?.(snap.id);
3832
+ onSelectionChangeRef.current?.(snap2.id);
3750
3833
  });
3751
3834
  h.onTransformParam((info) => setTransformPopover(info));
3752
- h.onSelectionState((snap) => {
3753
- if (!snap || snap.ids.length === 0) {
3835
+ h.onSelectionState((snap2) => {
3836
+ if (!snap2 || snap2.ids.length === 0) {
3754
3837
  setPropsPopover(null);
3755
3838
  setMultiSelection(null);
3756
3839
  onSelectionChangeRef.current?.(void 0);
3757
3840
  return;
3758
3841
  }
3759
- if (snap.ids.length === 1) {
3760
- const id = snap.ids[0];
3761
- const single = buildObjectSnapshot(store.getState(), id, snap.anchor);
3842
+ if (snap2.ids.length === 1) {
3843
+ const id = snap2.ids[0];
3844
+ const single = buildObjectSnapshot(store.getState(), id, snap2.anchor);
3762
3845
  if (single) {
3763
3846
  setPropsPopover(single);
3764
3847
  setMultiSelection(null);
@@ -3766,7 +3849,7 @@ var GeometryEditorPanelInner = forwardRef(
3766
3849
  }
3767
3850
  return;
3768
3851
  }
3769
- setMultiSelection(snap);
3852
+ setMultiSelection(snap2);
3770
3853
  setPropsPopover(null);
3771
3854
  onSelectionChangeRef.current?.(void 0);
3772
3855
  });
@@ -3810,15 +3893,13 @@ var GeometryEditorPanelInner = forwardRef(
3810
3893
  try {
3811
3894
  const svgString = await renderGeometrySvgFromState(jsonState);
3812
3895
  onInsert(jsonState, svgString);
3896
+ onGeometryDraftRef.current?.(null);
3813
3897
  } catch (err) {
3814
3898
  console.error("Geometry insert failed:", err);
3815
3899
  }
3816
3900
  })();
3817
3901
  return true;
3818
3902
  }, [onInsert, showAxis, showGrid]);
3819
- const handleInsert = useCallback(() => {
3820
- performInsert();
3821
- }, [performInsert]);
3822
3903
  const loadAiFigure = useCallback((generated) => {
3823
3904
  handleRef.current?.clearSelection();
3824
3905
  setPropsPopover(null);
@@ -3913,7 +3994,7 @@ var GeometryEditorPanelInner = forwardRef(
3913
3994
  "button",
3914
3995
  {
3915
3996
  type: "button",
3916
- onClick: handleInsert,
3997
+ onClick: performInsert,
3917
3998
  disabled: !ready || !hasContent,
3918
3999
  title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
3919
4000
  "data-testid": "geometry-insert-btn-mobile",
@@ -4031,7 +4112,7 @@ var GeometryEditorPanelInner = forwardRef(
4031
4112
  /* @__PURE__ */ jsx(
4032
4113
  "button",
4033
4114
  {
4034
- onClick: handleInsert,
4115
+ onClick: performInsert,
4035
4116
  disabled: !ready || !hasContent,
4036
4117
  title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
4037
4118
  "data-testid": "geometry-insert-btn",
@@ -4087,7 +4168,7 @@ function parseInitialState(data) {
4087
4168
  return deserializeBoard(data.jsonState);
4088
4169
  }
4089
4170
  var GeometryStampHost = forwardRef(
4090
- function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure }, ref) {
4171
+ function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure, onGeometryDraft }, ref) {
4091
4172
  const panelRef = useRef(null);
4092
4173
  const { isMobile } = useIsMobile();
4093
4174
  const [drawerOpen, setDrawerOpen] = useState(false);
@@ -4202,7 +4283,9 @@ var GeometryStampHost = forwardRef(
4202
4283
  canUndo,
4203
4284
  canRedo,
4204
4285
  onSelectionChange: setSelectedObjectId,
4205
- generateGeometryFigure
4286
+ generateGeometryFigure,
4287
+ api,
4288
+ onGeometryDraft
4206
4289
  }
4207
4290
  )
4208
4291
  ] });
@@ -4210,5 +4293,5 @@ var GeometryStampHost = forwardRef(
4210
4293
  );
4211
4294
 
4212
4295
  export { GeometryStampHost };
4213
- //# sourceMappingURL=host-HAYCJJ2T.mjs.map
4214
- //# sourceMappingURL=host-HAYCJJ2T.mjs.map
4296
+ //# sourceMappingURL=host-4P766V4J.mjs.map
4297
+ //# sourceMappingURL=host-4P766V4J.mjs.map