@bwp-web/canvas 0.9.2 → 0.9.4

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.
@@ -120,7 +120,7 @@ export declare function useEditCanvas(options?: UseEditCanvasOptions): {
120
120
  canvasRef: import("react").RefObject<FabricCanvas | null>;
121
121
  /** Current zoom level (reactive). */
122
122
  zoom: number;
123
- /** Loaded objects (reactive). Populated when `canvasData` is provided. */
123
+ /** Canvas objects (reactive). Populated from `canvasData` on load, and kept in sync as objects are added or removed at runtime. */
124
124
  objects: FabricObject<Partial<import("fabric").FabricObjectProps>, import("fabric").SerializedObjectProps, import("fabric").ObjectEvents>[];
125
125
  /** Whether canvas data is currently being loaded. */
126
126
  isLoading: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"useEditCanvas.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditCanvas.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,KAAK,YAAY,EAAW,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAEL,KAAK,iBAAiB,EAEtB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEL,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EAIL,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,kGAAkG;IAClG,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC,mIAAmI;IACnI,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;IAC7C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAChD;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC;IACxC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB;IAqXtD,8CAA8C;sBAnSvC,YAAY;IAqSnB,oDAAoD;;IAEpD,qCAAqC;;IAErC,0EAA0E;;IAE1E,qDAAqD;;IAErD,6CAA6C;;IAE7C,yBAAyB;;QAtFzB,wCAAwC;;QAExC,wDAAwD;wBAbjB,YAAY;QAenD,wFAAwF;;QAExF,2DAA2D;;QAE3D,0DAA0D;;QAE1D,uDAAuD;;QAEvD,6DAA6D;;;IA4E7D,+DAA+D;;IAE/D;;;;;;;;;;;;;;OAcG;qBA1W6B,SAAS,GAAG,IAAI;IA4WhD;;;;;;;OAOG;yBAnEO,MAAM,WAAW;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE;IAqEzD,uIAAuI;;IAEvI,4DAA4D;;IAE5D,oGAAoG;;IAEpG,sDAAsD;;IAEtD,iEAAiE;;IAEjE,mFAAmF;;IAEnF,kFAAkF;;IAElF,gFAAgF;;IAEhF,wEAAwE;8BAtJ/B,OAAO;EAwKrD"}
1
+ {"version":3,"file":"useEditCanvas.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditCanvas.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,KAAK,YAAY,EAAW,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAEL,KAAK,iBAAiB,EAEtB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEL,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EAIL,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,kGAAkG;IAClG,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC,mIAAmI;IACnI,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;IAC7C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACzC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAChD;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC;IACxC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB;IAmYtD,8CAA8C;sBAjTvC,YAAY;IAmTnB,oDAAoD;;IAEpD,qCAAqC;;IAErC,mIAAmI;;IAEnI,qDAAqD;;IAErD,6CAA6C;;IAE7C,yBAAyB;;QAtFzB,wCAAwC;;QAExC,wDAAwD;wBAbjB,YAAY;QAenD,wFAAwF;;QAExF,2DAA2D;;QAE3D,0DAA0D;;QAE1D,uDAAuD;;QAEvD,6DAA6D;;;IA4E7D,+DAA+D;;IAE/D;;;;;;;;;;;;;;OAcG;qBAxX6B,SAAS,GAAG,IAAI;IA0XhD;;;;;;;OAOG;yBAnEO,MAAM,WAAW;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE;IAqEzD,uIAAuI;;IAEvI,4DAA4D;;IAE5D,oGAAoG;;IAEpG,sDAAsD;;IAEtD,iEAAiE;;IAEjE,mFAAmF;;IAEnF,kFAAkF;;IAElF,gFAAgF;;IAEhF,wEAAwE;8BAtJ/B,OAAO;EAwKrD"}
package/dist/index.cjs CHANGED
@@ -1826,7 +1826,43 @@ function enableDrawToCreate(canvas, options) {
1826
1826
  let exited = false;
1827
1827
  const angleSnapEnabled = options?.angleSnap !== false;
1828
1828
  const angleInterval = typeof options?.angleSnap === "object" ? options.angleSnap.interval ?? DEFAULT_ANGLE_SNAP_INTERVAL : DEFAULT_ANGLE_SNAP_INTERVAL;
1829
- const shiftTracker = createShiftKeyTracker();
1829
+ const dragEnabled = options?.dragOnHold !== false;
1830
+ let dragPending = false;
1831
+ let isDragMode = false;
1832
+ let dragStartX = 0;
1833
+ let dragStartY = 0;
1834
+ let dragLastEndX = 0;
1835
+ let dragLastEndY = 0;
1836
+ let dragPreviewRect = null;
1837
+ const computeDragDimensions = (endX, endY) => {
1838
+ let width = Math.max(0, endX - dragStartX);
1839
+ let height = Math.max(0, endY - dragStartY);
1840
+ if (shiftTracker.held) {
1841
+ const size = Math.max(width, height);
1842
+ width = size;
1843
+ height = size;
1844
+ }
1845
+ return { width, height };
1846
+ };
1847
+ const updateDragPreview = (endX, endY) => {
1848
+ dragLastEndX = endX;
1849
+ dragLastEndY = endY;
1850
+ if (!isDragMode || !dragPreviewRect) return;
1851
+ const { width, height } = computeDragDimensions(endX, endY);
1852
+ dragPreviewRect.set({
1853
+ left: dragStartX + width / 2,
1854
+ top: dragStartY + height / 2,
1855
+ width,
1856
+ height
1857
+ });
1858
+ dragPreviewRect.setCoords();
1859
+ canvas.requestRenderAll();
1860
+ };
1861
+ const shiftTracker = createShiftKeyTracker(() => {
1862
+ if (isDragMode) {
1863
+ updateDragPreview(dragLastEndX, dragLastEndY);
1864
+ }
1865
+ });
1830
1866
  const points = [];
1831
1867
  const markers = [];
1832
1868
  const edgeLines = [];
@@ -1894,20 +1930,7 @@ function enableDrawToCreate(canvas, options) {
1894
1930
  options?.onCreated?.(obj);
1895
1931
  points.length = 0;
1896
1932
  };
1897
- const handleMouseDown = (event) => {
1898
- let { x, y } = event.scenePoint;
1899
- if (angleSnapEnabled && shiftTracker.held && points.length > 0) {
1900
- const ref = points[points.length - 1];
1901
- const angleSnapped = snapAngleToInterval({ x, y }, ref, angleInterval);
1902
- ({ x, y } = snapAlongRay(
1903
- angleSnapped,
1904
- ref,
1905
- (sx, sy) => snapping.snap(sx, sy)
1906
- ));
1907
- } else {
1908
- ({ x, y } = snapping.snap(x, y));
1909
- }
1910
- snapping.clearSnapResult();
1933
+ const placeVertex = (x, y) => {
1911
1934
  if (points.length >= 3) {
1912
1935
  const dx = x - points[0].x;
1913
1936
  const dy = y - points[0].y;
@@ -1944,7 +1967,63 @@ function enableDrawToCreate(canvas, options) {
1944
1967
  }
1945
1968
  canvas.requestRenderAll();
1946
1969
  };
1970
+ const handleMouseDown = (event) => {
1971
+ if (dragEnabled && points.length === 0) {
1972
+ const snapped = snapping.snap(event.scenePoint.x, event.scenePoint.y);
1973
+ dragStartX = snapped.x;
1974
+ dragStartY = snapped.y;
1975
+ dragLastEndX = dragStartX;
1976
+ dragLastEndY = dragStartY;
1977
+ dragPending = true;
1978
+ snapping.clearSnapResult();
1979
+ return;
1980
+ }
1981
+ let { x, y } = event.scenePoint;
1982
+ if (angleSnapEnabled && shiftTracker.held && points.length > 0) {
1983
+ const ref = points[points.length - 1];
1984
+ const angleSnapped = snapAngleToInterval({ x, y }, ref, angleInterval);
1985
+ ({ x, y } = snapAlongRay(
1986
+ angleSnapped,
1987
+ ref,
1988
+ (sx, sy) => snapping.snap(sx, sy)
1989
+ ));
1990
+ } else {
1991
+ ({ x, y } = snapping.snap(x, y));
1992
+ }
1993
+ snapping.clearSnapResult();
1994
+ placeVertex(x, y);
1995
+ };
1947
1996
  const handleMouseMove = (event) => {
1997
+ if (dragPending) {
1998
+ const dx = Math.abs(event.scenePoint.x - dragStartX);
1999
+ const dy = Math.abs(event.scenePoint.y - dragStartY);
2000
+ if (dx >= MIN_DRAG_SIZE || dy >= MIN_DRAG_SIZE) {
2001
+ isDragMode = true;
2002
+ dragPending = false;
2003
+ previousSelection = canvas.selection;
2004
+ canvas.selection = false;
2005
+ dragPreviewRect = new import_fabric14.Rect({
2006
+ ...DEFAULT_GUIDELINE_SHAPE_STYLE,
2007
+ left: dragStartX,
2008
+ top: dragStartY,
2009
+ width: 0,
2010
+ height: 0,
2011
+ selectable: false,
2012
+ evented: false
2013
+ });
2014
+ snapping.excludeSet.add(dragPreviewRect);
2015
+ canvas.add(dragPreviewRect);
2016
+ }
2017
+ return;
2018
+ }
2019
+ if (isDragMode && dragPreviewRect) {
2020
+ const { x: endX, y: endY } = snapping.snapWithGuidelines(
2021
+ event.scenePoint.x,
2022
+ event.scenePoint.y
2023
+ );
2024
+ updateDragPreview(endX, endY);
2025
+ return;
2026
+ }
1948
2027
  if (points.length === 0) return;
1949
2028
  const lastPoint = points[points.length - 1];
1950
2029
  let { x, y } = event.scenePoint;
@@ -1987,6 +2066,47 @@ function enableDrawToCreate(canvas, options) {
1987
2066
  }
1988
2067
  canvas.requestRenderAll();
1989
2068
  };
2069
+ const handleMouseUp = () => {
2070
+ if (isDragMode && dragPreviewRect) {
2071
+ isDragMode = false;
2072
+ snapping.clearSnapResult();
2073
+ const { width, height } = computeDragDimensions(
2074
+ dragLastEndX,
2075
+ dragLastEndY
2076
+ );
2077
+ snapping.excludeSet.delete(dragPreviewRect);
2078
+ canvas.remove(dragPreviewRect);
2079
+ dragPreviewRect = null;
2080
+ if (width < MIN_DRAG_SIZE && height < MIN_DRAG_SIZE) {
2081
+ canvas.selection = previousSelection;
2082
+ canvas.requestRenderAll();
2083
+ placeVertex(dragStartX, dragStartY);
2084
+ return;
2085
+ }
2086
+ const obj = createPolygonFromVertices(
2087
+ canvas,
2088
+ [
2089
+ { x: dragStartX, y: dragStartY },
2090
+ { x: dragStartX + width, y: dragStartY },
2091
+ { x: dragStartX + width, y: dragStartY + height },
2092
+ { x: dragStartX, y: dragStartY + height }
2093
+ ],
2094
+ options?.style
2095
+ );
2096
+ if (options?.data) {
2097
+ obj.data = options.data;
2098
+ }
2099
+ canvas.selection = previousSelection;
2100
+ canvas.requestRenderAll();
2101
+ restoreViewport(options?.viewport);
2102
+ options?.onCreated?.(obj);
2103
+ return;
2104
+ }
2105
+ if (dragPending) {
2106
+ dragPending = false;
2107
+ placeVertex(dragStartX, dragStartY);
2108
+ }
2109
+ };
1990
2110
  const handleKeyDown = (e) => {
1991
2111
  if (e.key === "Escape" || e.key === "Backspace") {
1992
2112
  e.stopImmediatePropagation();
@@ -1996,20 +2116,29 @@ function enableDrawToCreate(canvas, options) {
1996
2116
  };
1997
2117
  canvas.on("mouse:down", handleMouseDown);
1998
2118
  canvas.on("mouse:move", handleMouseMove);
2119
+ canvas.on("mouse:up", handleMouseUp);
1999
2120
  document.addEventListener("keydown", handleKeyDown, true);
2000
2121
  function cleanup(reason) {
2001
2122
  if (exited) return;
2002
2123
  exited = true;
2003
2124
  canvas.off("mouse:down", handleMouseDown);
2004
2125
  canvas.off("mouse:move", handleMouseMove);
2126
+ canvas.off("mouse:up", handleMouseUp);
2005
2127
  document.removeEventListener("keydown", handleKeyDown, true);
2006
2128
  shiftTracker.cleanup();
2007
2129
  snapping.cleanup();
2008
2130
  removePreviewElements();
2009
- if (points.length > 0) {
2131
+ if (dragPreviewRect) {
2132
+ snapping.excludeSet.delete(dragPreviewRect);
2133
+ canvas.remove(dragPreviewRect);
2134
+ dragPreviewRect = null;
2135
+ }
2136
+ if (points.length > 0 || isDragMode || dragPending) {
2010
2137
  canvas.selection = previousSelection;
2011
2138
  }
2012
2139
  points.length = 0;
2140
+ dragPending = false;
2141
+ isDragMode = false;
2013
2142
  canvas.requestRenderAll();
2014
2143
  restoreViewport(options?.viewport);
2015
2144
  if (reason === "cancel") {
@@ -2644,6 +2773,16 @@ function useEditCanvas(options) {
2644
2773
  canvas.on("object:modified", markDirtyIfNotLoading);
2645
2774
  canvas.on("background:modified", markDirtyIfNotLoading);
2646
2775
  }
2776
+ canvas.on("object:added", (e) => {
2777
+ if (!isInitialLoadRef.current && e.target) {
2778
+ setObjects((prev) => [...prev, e.target]);
2779
+ }
2780
+ });
2781
+ canvas.on("object:removed", (e) => {
2782
+ if (!isInitialLoadRef.current && e.target) {
2783
+ setObjects((prev) => prev.filter((o) => o !== e.target));
2784
+ }
2785
+ });
2647
2786
  if (opts?.history) {
2648
2787
  const syncHistoryState = () => {
2649
2788
  const h = historyRef.current;
@@ -2817,7 +2956,7 @@ function useEditCanvas(options) {
2817
2956
  canvasRef,
2818
2957
  /** Current zoom level (reactive). */
2819
2958
  zoom,
2820
- /** Loaded objects (reactive). Populated when `canvasData` is provided. */
2959
+ /** Canvas objects (reactive). Populated from `canvasData` on load, and kept in sync as objects are added or removed at runtime. */
2821
2960
  objects,
2822
2961
  /** Whether canvas data is currently being loaded. */
2823
2962
  isLoading,