@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.
- package/dist/ai.d.mts +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/ai.js +54 -23
- package/dist/ai.js.map +1 -1
- package/dist/ai.mjs +54 -23
- package/dist/ai.mjs.map +1 -1
- package/dist/catalog.json +4 -4
- package/dist/{chunk-D5JLJ3PT.mjs → chunk-5JM35CXV.mjs} +4 -4
- package/dist/{chunk-D5JLJ3PT.mjs.map → chunk-5JM35CXV.mjs.map} +1 -1
- package/dist/{chunk-KYMBUTPO.mjs → chunk-BU5KLO3P.mjs} +3 -3
- package/dist/{chunk-KYMBUTPO.mjs.map → chunk-BU5KLO3P.mjs.map} +1 -1
- package/dist/{chunk-AYJPOHCI.mjs → chunk-H22OZYTW.mjs} +3 -3
- package/dist/{chunk-AYJPOHCI.mjs.map → chunk-H22OZYTW.mjs.map} +1 -1
- package/dist/{chunk-I3L56GVH.mjs → chunk-OQIQNKPQ.mjs} +3 -3
- package/dist/{chunk-I3L56GVH.mjs.map → chunk-OQIQNKPQ.mjs.map} +1 -1
- package/dist/{chunk-KZGPSTZI.mjs → chunk-QCZVFEN4.mjs} +4 -4
- package/dist/{chunk-KZGPSTZI.mjs.map → chunk-QCZVFEN4.mjs.map} +1 -1
- package/dist/{chunk-4ETJ4CDY.mjs → chunk-QRUAEXLR.mjs} +4 -4
- package/dist/{chunk-4ETJ4CDY.mjs.map → chunk-QRUAEXLR.mjs.map} +1 -1
- package/dist/{chunk-HLAOGXEK.mjs → chunk-V3YJ6JFL.mjs} +3 -3
- package/dist/{chunk-HLAOGXEK.mjs.map → chunk-V3YJ6JFL.mjs.map} +1 -1
- package/dist/{chunk-D5LWSN2Y.mjs → chunk-ZTQBUKLJ.mjs} +30 -13
- package/dist/chunk-ZTQBUKLJ.mjs.map +1 -0
- package/dist/geometry-2d.d.mts +1 -1
- package/dist/geometry-2d.d.ts +1 -1
- package/dist/geometry-2d.js +143 -33
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +3 -3
- package/dist/geometry-3d.d.mts +1 -1
- package/dist/geometry-3d.d.ts +1 -1
- package/dist/geometry-3d.js +28 -11
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +3 -3
- package/dist/graph-2d.d.mts +1 -1
- package/dist/graph-2d.d.ts +1 -1
- package/dist/graph-2d.js +28 -11
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +3 -3
- package/dist/{host-M26FS244.mjs → host-2ISGVO7O.mjs} +5 -5
- package/dist/{host-M26FS244.mjs.map → host-2ISGVO7O.mjs.map} +1 -1
- package/dist/{host-HAYCJJ2T.mjs → host-4P766V4J.mjs} +110 -27
- package/dist/host-4P766V4J.mjs.map +1 -0
- package/dist/{host-LTJHAY5A.mjs → host-HOSJHQ5H.mjs} +6 -6
- package/dist/{host-LTJHAY5A.mjs.map → host-HOSJHQ5H.mjs.map} +1 -1
- package/dist/index.d.mts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +147 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +17 -15
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +1 -1
- package/dist/latex.d.ts +1 -1
- package/dist/serialize-N4G6RFBB.mjs +9 -0
- package/dist/{serialize-C3LSUMSA.mjs.map → serialize-N4G6RFBB.mjs.map} +1 -1
- package/dist/{types-zc_Pa0mp.d.mts → types-BHYC2Fiw.d.mts} +25 -1
- package/dist/{types-zc_Pa0mp.d.ts → types-BHYC2Fiw.d.ts} +25 -1
- package/package.json +1 -1
- package/dist/chunk-D5LWSN2Y.mjs.map +0 -1
- package/dist/host-HAYCJJ2T.mjs.map +0 -1
- package/dist/serialize-C3LSUMSA.mjs +0 -9
package/dist/index.js
CHANGED
|
@@ -2296,9 +2296,11 @@ var init_circle = __esm({
|
|
|
2296
2296
|
},
|
|
2297
2297
|
render: (obj, ctx) => {
|
|
2298
2298
|
const board = ctx.jxg;
|
|
2299
|
+
const isCenterLabel = (l) => /^[A-Z]['′]?\d*$/u.test(l);
|
|
2300
|
+
const isCenter = isCenterLabel(obj.label);
|
|
2299
2301
|
const baseOpts = {
|
|
2300
2302
|
name: obj.label,
|
|
2301
|
-
withLabel: obj.attrs.showLabel ?? false,
|
|
2303
|
+
withLabel: isCenter ? obj.attrs.showLabel ?? false : true,
|
|
2302
2304
|
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
2303
2305
|
strokeWidth: obj.attrs.width ?? 2,
|
|
2304
2306
|
dash: obj.attrs.dash ?? 0,
|
|
@@ -2311,22 +2313,37 @@ var init_circle = __esm({
|
|
|
2311
2313
|
const p1 = ctx.resolveRef(c.p1);
|
|
2312
2314
|
const p2 = ctx.resolveRef(c.p2);
|
|
2313
2315
|
const p3 = ctx.resolveRef(c.p3);
|
|
2316
|
+
if (isCenter) {
|
|
2317
|
+
const center2 = board.create("circumcenter", [p1, p2, p3], {
|
|
2318
|
+
visible: obj.visible,
|
|
2319
|
+
withLabel: true,
|
|
2320
|
+
fixed: true,
|
|
2321
|
+
name: obj.label
|
|
2322
|
+
});
|
|
2323
|
+
const circ = board.create("circumcircle", [p1, p2, p3], { ...baseOpts, withLabel: false });
|
|
2324
|
+
circ.center = circ.center ?? center2;
|
|
2325
|
+
circ._helpers = [center2];
|
|
2326
|
+
return circ;
|
|
2327
|
+
}
|
|
2314
2328
|
return board.create("circumcircle", [p1, p2, p3], baseOpts);
|
|
2315
2329
|
}
|
|
2316
2330
|
if (c?.kind === "incircle") {
|
|
2317
2331
|
const p1 = ctx.resolveRef(c.p1);
|
|
2318
2332
|
const p2 = ctx.resolveRef(c.p2);
|
|
2319
2333
|
const p3 = ctx.resolveRef(c.p3);
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2334
|
+
if (isCenter) {
|
|
2335
|
+
const center2 = board.create("incenter", [p1, p2, p3], {
|
|
2336
|
+
visible: obj.visible,
|
|
2337
|
+
withLabel: true,
|
|
2338
|
+
fixed: true,
|
|
2339
|
+
name: obj.label
|
|
2340
|
+
});
|
|
2341
|
+
const circ = board.create("incircle", [p1, p2, p3], { ...baseOpts, withLabel: false });
|
|
2342
|
+
circ.center = circ.center ?? center2;
|
|
2343
|
+
circ._helpers = [center2];
|
|
2344
|
+
return circ;
|
|
2345
|
+
}
|
|
2346
|
+
return board.create("incircle", [p1, p2, p3], baseOpts);
|
|
2330
2347
|
}
|
|
2331
2348
|
if (c?.kind === "excircle") {
|
|
2332
2349
|
const P = [ctx.resolveRef(c.p1), ctx.resolveRef(c.p2), ctx.resolveRef(c.p3)];
|
|
@@ -12552,6 +12569,94 @@ var init_AiFigurePrompt = __esm({
|
|
|
12552
12569
|
StopIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) });
|
|
12553
12570
|
}
|
|
12554
12571
|
});
|
|
12572
|
+
|
|
12573
|
+
// src/stamps/geometry-2d/draft.ts
|
|
12574
|
+
function svgIntrinsicSize(svg) {
|
|
12575
|
+
const w = svg.match(/<svg[^>]*\swidth="([\d.]+)"/);
|
|
12576
|
+
const h = svg.match(/<svg[^>]*\sheight="([\d.]+)"/);
|
|
12577
|
+
if (w && h) return { width: parseFloat(w[1]), height: parseFloat(h[1]) };
|
|
12578
|
+
const vb = svg.match(/viewBox="0 0 ([\d.]+) ([\d.]+)"/);
|
|
12579
|
+
if (vb) return { width: parseFloat(vb[1]), height: parseFloat(vb[2]) };
|
|
12580
|
+
return { width: 300, height: 200 };
|
|
12581
|
+
}
|
|
12582
|
+
function draftFromViewport(svg, appState, seq) {
|
|
12583
|
+
const { width, height } = svgIntrinsicSize(svg);
|
|
12584
|
+
const zoom = appState.zoom?.value ?? 1;
|
|
12585
|
+
const vw = appState.width ?? 800;
|
|
12586
|
+
const vh = appState.height ?? 600;
|
|
12587
|
+
const cx = appState.scrollX + vw / 2 / zoom;
|
|
12588
|
+
const cy = appState.scrollY + vh / 2 / zoom;
|
|
12589
|
+
return { svg, width, height, x: cx - width / 2, y: cy - height / 2, seq };
|
|
12590
|
+
}
|
|
12591
|
+
function didStateChange(seen, jsonState) {
|
|
12592
|
+
if (seen.last === jsonState) return false;
|
|
12593
|
+
seen.last = jsonState;
|
|
12594
|
+
return true;
|
|
12595
|
+
}
|
|
12596
|
+
var init_draft = __esm({
|
|
12597
|
+
"src/stamps/geometry-2d/draft.ts"() {
|
|
12598
|
+
}
|
|
12599
|
+
});
|
|
12600
|
+
function useGeometryDraftEmit({
|
|
12601
|
+
store,
|
|
12602
|
+
handleRef,
|
|
12603
|
+
api,
|
|
12604
|
+
showAxis,
|
|
12605
|
+
showGrid,
|
|
12606
|
+
onGeometryDraft,
|
|
12607
|
+
debounceMs = 350
|
|
12608
|
+
}) {
|
|
12609
|
+
const seqRef = React19.useRef(0);
|
|
12610
|
+
const seenRef = React19.useRef({ last: null });
|
|
12611
|
+
const timerRef = React19.useRef(null);
|
|
12612
|
+
const cbRef = React19.useRef(onGeometryDraft);
|
|
12613
|
+
cbRef.current = onGeometryDraft;
|
|
12614
|
+
React19.useEffect(() => {
|
|
12615
|
+
if (!cbRef.current) return;
|
|
12616
|
+
const emit = () => {
|
|
12617
|
+
const h = handleRef.current;
|
|
12618
|
+
if (!h) return;
|
|
12619
|
+
const state = h.getState();
|
|
12620
|
+
if (Object.keys(state.objects).length === 0) {
|
|
12621
|
+
if (seenRef.current.last !== null) {
|
|
12622
|
+
seenRef.current.last = null;
|
|
12623
|
+
cbRef.current?.(null);
|
|
12624
|
+
}
|
|
12625
|
+
return;
|
|
12626
|
+
}
|
|
12627
|
+
const bbox = h.getBbox();
|
|
12628
|
+
const jsonState = serializeBoard(state, { bbox, showAxis, showGrid });
|
|
12629
|
+
if (!didStateChange(seenRef.current, jsonState)) return;
|
|
12630
|
+
void (async () => {
|
|
12631
|
+
try {
|
|
12632
|
+
const svg = await renderGeometrySvgFromState(jsonState);
|
|
12633
|
+
const appState = api?.getAppState?.() ?? { scrollX: 0, scrollY: 0, width: 800, height: 600, zoom: { value: 1 } };
|
|
12634
|
+
seqRef.current += 1;
|
|
12635
|
+
cbRef.current?.(draftFromViewport(svg, appState, seqRef.current));
|
|
12636
|
+
} catch (err) {
|
|
12637
|
+
console.warn("[geometry] draft render failed:", err);
|
|
12638
|
+
}
|
|
12639
|
+
})();
|
|
12640
|
+
};
|
|
12641
|
+
const schedule = () => {
|
|
12642
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
12643
|
+
timerRef.current = setTimeout(emit, debounceMs);
|
|
12644
|
+
};
|
|
12645
|
+
const unsub = store.subscribe(schedule);
|
|
12646
|
+
return () => {
|
|
12647
|
+
unsub();
|
|
12648
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
12649
|
+
cbRef.current?.(null);
|
|
12650
|
+
};
|
|
12651
|
+
}, [store, handleRef, api, showAxis, showGrid, debounceMs]);
|
|
12652
|
+
}
|
|
12653
|
+
var init_useGeometryDraftEmit = __esm({
|
|
12654
|
+
"src/stamps/geometry-2d/editor/useGeometryDraftEmit.ts"() {
|
|
12655
|
+
init_serialize();
|
|
12656
|
+
init_render();
|
|
12657
|
+
init_draft();
|
|
12658
|
+
}
|
|
12659
|
+
});
|
|
12555
12660
|
var GeometryEditorPanelInner, GeometryEditorPanel;
|
|
12556
12661
|
var init_EditorPanel = __esm({
|
|
12557
12662
|
"src/stamps/geometry-2d/editor/EditorPanel.tsx"() {
|
|
@@ -12568,6 +12673,7 @@ var init_EditorPanel = __esm({
|
|
|
12568
12673
|
init_constants();
|
|
12569
12674
|
init_Toast2();
|
|
12570
12675
|
init_AiFigurePrompt();
|
|
12676
|
+
init_useGeometryDraftEmit();
|
|
12571
12677
|
GeometryEditorPanelInner = React19.forwardRef(
|
|
12572
12678
|
function GeometryEditorPanelInner2({
|
|
12573
12679
|
store,
|
|
@@ -12586,7 +12692,9 @@ var init_EditorPanel = __esm({
|
|
|
12586
12692
|
canUndo,
|
|
12587
12693
|
canRedo,
|
|
12588
12694
|
onSelectionChange,
|
|
12589
|
-
generateGeometryFigure
|
|
12695
|
+
generateGeometryFigure,
|
|
12696
|
+
api,
|
|
12697
|
+
onGeometryDraft
|
|
12590
12698
|
}, ref) {
|
|
12591
12699
|
const { showToast } = useToast();
|
|
12592
12700
|
const handleRef = React19.useRef(null);
|
|
@@ -12599,12 +12707,14 @@ var init_EditorPanel = __esm({
|
|
|
12599
12707
|
React19.useEffect(() => {
|
|
12600
12708
|
onSelectionChangeRef.current = onSelectionChange;
|
|
12601
12709
|
}, [onSelectionChange]);
|
|
12710
|
+
const onGeometryDraftRef = React19.useRef(onGeometryDraft);
|
|
12711
|
+
React19.useEffect(() => {
|
|
12712
|
+
onGeometryDraftRef.current = onGeometryDraft;
|
|
12713
|
+
}, [onGeometryDraft]);
|
|
12602
12714
|
useEditorState({ store, onHistoryChange });
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
() => store.getState()
|
|
12607
|
-
);
|
|
12715
|
+
useGeometryDraftEmit({ store, handleRef, api, showAxis, showGrid, onGeometryDraft });
|
|
12716
|
+
const snap = () => store.getState();
|
|
12717
|
+
const currentSceneState = React19.useSyncExternalStore((cb) => store.subscribe(cb), snap, snap);
|
|
12608
12718
|
React19.useEffect(() => {
|
|
12609
12719
|
const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
|
|
12610
12720
|
sync();
|
|
@@ -12614,22 +12724,22 @@ var init_EditorPanel = __esm({
|
|
|
12614
12724
|
const h = handleRef.current;
|
|
12615
12725
|
if (!h) return;
|
|
12616
12726
|
setReady(true);
|
|
12617
|
-
h.onSelect((
|
|
12618
|
-
setPropsPopover(
|
|
12727
|
+
h.onSelect((snap2) => {
|
|
12728
|
+
setPropsPopover(snap2);
|
|
12619
12729
|
setMultiSelection(null);
|
|
12620
|
-
onSelectionChangeRef.current?.(
|
|
12730
|
+
onSelectionChangeRef.current?.(snap2.id);
|
|
12621
12731
|
});
|
|
12622
12732
|
h.onTransformParam((info) => setTransformPopover(info));
|
|
12623
|
-
h.onSelectionState((
|
|
12624
|
-
if (!
|
|
12733
|
+
h.onSelectionState((snap2) => {
|
|
12734
|
+
if (!snap2 || snap2.ids.length === 0) {
|
|
12625
12735
|
setPropsPopover(null);
|
|
12626
12736
|
setMultiSelection(null);
|
|
12627
12737
|
onSelectionChangeRef.current?.(void 0);
|
|
12628
12738
|
return;
|
|
12629
12739
|
}
|
|
12630
|
-
if (
|
|
12631
|
-
const id =
|
|
12632
|
-
const single = buildObjectSnapshot(store.getState(), id,
|
|
12740
|
+
if (snap2.ids.length === 1) {
|
|
12741
|
+
const id = snap2.ids[0];
|
|
12742
|
+
const single = buildObjectSnapshot(store.getState(), id, snap2.anchor);
|
|
12633
12743
|
if (single) {
|
|
12634
12744
|
setPropsPopover(single);
|
|
12635
12745
|
setMultiSelection(null);
|
|
@@ -12637,7 +12747,7 @@ var init_EditorPanel = __esm({
|
|
|
12637
12747
|
}
|
|
12638
12748
|
return;
|
|
12639
12749
|
}
|
|
12640
|
-
setMultiSelection(
|
|
12750
|
+
setMultiSelection(snap2);
|
|
12641
12751
|
setPropsPopover(null);
|
|
12642
12752
|
onSelectionChangeRef.current?.(void 0);
|
|
12643
12753
|
});
|
|
@@ -12681,15 +12791,13 @@ var init_EditorPanel = __esm({
|
|
|
12681
12791
|
try {
|
|
12682
12792
|
const svgString = await renderGeometrySvgFromState(jsonState);
|
|
12683
12793
|
onInsert(jsonState, svgString);
|
|
12794
|
+
onGeometryDraftRef.current?.(null);
|
|
12684
12795
|
} catch (err) {
|
|
12685
12796
|
console.error("Geometry insert failed:", err);
|
|
12686
12797
|
}
|
|
12687
12798
|
})();
|
|
12688
12799
|
return true;
|
|
12689
12800
|
}, [onInsert, showAxis, showGrid]);
|
|
12690
|
-
const handleInsert = React19.useCallback(() => {
|
|
12691
|
-
performInsert();
|
|
12692
|
-
}, [performInsert]);
|
|
12693
12801
|
const loadAiFigure = React19.useCallback((generated) => {
|
|
12694
12802
|
handleRef.current?.clearSelection();
|
|
12695
12803
|
setPropsPopover(null);
|
|
@@ -12784,7 +12892,7 @@ var init_EditorPanel = __esm({
|
|
|
12784
12892
|
"button",
|
|
12785
12893
|
{
|
|
12786
12894
|
type: "button",
|
|
12787
|
-
onClick:
|
|
12895
|
+
onClick: performInsert,
|
|
12788
12896
|
disabled: !ready || !hasContent,
|
|
12789
12897
|
title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
|
|
12790
12898
|
"data-testid": "geometry-insert-btn-mobile",
|
|
@@ -12902,7 +13010,7 @@ var init_EditorPanel = __esm({
|
|
|
12902
13010
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12903
13011
|
"button",
|
|
12904
13012
|
{
|
|
12905
|
-
onClick:
|
|
13013
|
+
onClick: performInsert,
|
|
12906
13014
|
disabled: !ready || !hasContent,
|
|
12907
13015
|
title: !hasContent ? "V\u1EBD \xEDt nh\u1EA5t m\u1ED9t \u0111\u1ED1i t\u01B0\u1EE3ng tr\u01B0\u1EDBc khi ch\xE8n" : void 0,
|
|
12908
13016
|
"data-testid": "geometry-insert-btn",
|
|
@@ -13263,7 +13371,7 @@ var init_host = __esm({
|
|
|
13263
13371
|
init_useStampStore();
|
|
13264
13372
|
init_dslRenderRow();
|
|
13265
13373
|
GeometryStampHost = React19.forwardRef(
|
|
13266
|
-
function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure }, ref) {
|
|
13374
|
+
function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure, onGeometryDraft }, ref) {
|
|
13267
13375
|
const panelRef = React19.useRef(null);
|
|
13268
13376
|
const { isMobile } = useIsMobile();
|
|
13269
13377
|
const [drawerOpen, setDrawerOpen] = React19.useState(false);
|
|
@@ -13378,7 +13486,9 @@ var init_host = __esm({
|
|
|
13378
13486
|
canUndo,
|
|
13379
13487
|
canRedo,
|
|
13380
13488
|
onSelectionChange: setSelectedObjectId,
|
|
13381
|
-
generateGeometryFigure
|
|
13489
|
+
generateGeometryFigure,
|
|
13490
|
+
api,
|
|
13491
|
+
onGeometryDraft
|
|
13382
13492
|
}
|
|
13383
13493
|
)
|
|
13384
13494
|
] });
|
|
@@ -20388,7 +20498,8 @@ function Whiteboard({
|
|
|
20388
20498
|
stamps = DEFAULT_STAMPS,
|
|
20389
20499
|
initialScene,
|
|
20390
20500
|
initialFiles,
|
|
20391
|
-
generateGeometryFigure
|
|
20501
|
+
generateGeometryFigure,
|
|
20502
|
+
onGeometryDraft
|
|
20392
20503
|
}) {
|
|
20393
20504
|
const { api, apiRef, isDark, setApiFromExcalidraw, syncThemeFromAppState } = useExcalidrawApi({ onApi });
|
|
20394
20505
|
const {
|
|
@@ -20561,7 +20672,8 @@ function Whiteboard({
|
|
|
20561
20672
|
editingElement,
|
|
20562
20673
|
onClose: closeStamp,
|
|
20563
20674
|
isDark,
|
|
20564
|
-
generateGeometryFigure
|
|
20675
|
+
generateGeometryFigure,
|
|
20676
|
+
onGeometryDraft
|
|
20565
20677
|
}
|
|
20566
20678
|
)
|
|
20567
20679
|
] });
|