@bwp-web/canvas 0.4.0 → 0.4.2

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/index.d.ts CHANGED
@@ -5,6 +5,12 @@ export { useEditCanvas } from './hooks';
5
5
  export type { UseEditCanvasOptions } from './hooks';
6
6
  export { useViewCanvas } from './hooks';
7
7
  export type { UseViewCanvasOptions, ViewObjectStyle } from './hooks';
8
+ export { useCanvasEvents } from './hooks';
9
+ export type { CanvasEventHandlers } from './hooks';
10
+ export { useCanvasTooltip } from './hooks';
11
+ export type { UseCanvasTooltipOptions, CanvasTooltipState } from './hooks';
12
+ export { useCanvasClick } from './hooks';
13
+ export type { UseCanvasClickOptions } from './hooks';
8
14
  export type { Point2D, ShapeStyleOptions, SnappingOptions, InteractionModeOptions, SnappableInteractionOptions, DragBounds, ModeSetup, } from './types';
9
15
  export { createRectangle, createRectangleAtPoint, editRectangle, } from './shapes';
10
16
  export type { RectangleOptions, RectangleAtPointOptions } from './shapes';
@@ -31,8 +37,9 @@ export { snapCursorPoint } from './alignment';
31
37
  export type { CursorSnapResult, CursorSnapOptions, GuidelineStyle, } from './alignment';
32
38
  export { deleteObjects, enableKeyboardShortcuts } from './keyboard';
33
39
  export { enableScaledStrokes, serializeCanvas, loadCanvas, getBaseStrokeWidth, } from './serialization';
34
- export type { SerializeOptions } from './serialization';
40
+ export type { SerializeOptions, LoadCanvasOptions } from './serialization';
35
41
  export { fitViewportToBackground, setBackgroundOpacity, getBackgroundOpacity, setBackgroundInverted, getBackgroundInverted, resizeImageUrl, setBackgroundImage, } from './background';
36
- export type { FitViewportOptions, ResizeResult, ResizeImageOptions, } from './background';
42
+ export type { FitViewportOptions, ResizeResult, ResizeImageOptions, SetBackgroundImageOptions, } from './background';
37
43
  export { DEFAULT_CONTROL_STYLE, DEFAULT_SHAPE_STYLE, DEFAULT_CIRCLE_STYLE, DEFAULT_DRAG_SHAPE_STYLE, DEFAULT_GUIDELINE_SHAPE_STYLE, DEFAULT_ALIGNMENT_STYLE, } from './styles';
44
+ export { Canvas as FabricCanvas, FabricObject, FabricImage, Rect, Polygon, } from 'fabric';
38
45
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/fabricAugmentation.ts
2
+ import "fabric";
3
+
1
4
  // src/Canvas/Canvas.tsx
2
5
  import { Canvas as FabricCanvas } from "fabric";
3
6
  import { useEffect, useRef } from "react";
@@ -369,14 +372,18 @@ function resizeImageUrl(url, options) {
369
372
  img.src = url;
370
373
  });
371
374
  }
372
- async function setBackgroundImage(canvas, url, resize) {
375
+ async function setBackgroundImage(canvas, url, options) {
376
+ const prevOpacity = options?.preserveOpacity ? getBackgroundOpacity(canvas) : void 0;
373
377
  let imageUrl = url;
374
- if (resize !== void 0) {
375
- const result = await resizeImageUrl(url, resize);
378
+ if (options !== void 0) {
379
+ const result = await resizeImageUrl(url, options);
376
380
  imageUrl = result.url;
377
381
  }
378
382
  const img = await FabricImage.fromURL(imageUrl, { crossOrigin: "anonymous" });
379
383
  canvas.backgroundImage = img;
384
+ if (prevOpacity !== void 0 && prevOpacity !== 1) {
385
+ img.set("opacity", prevOpacity);
386
+ }
380
387
  canvas.requestRenderAll();
381
388
  return img;
382
389
  }
@@ -1973,8 +1980,15 @@ function serializeCanvas(canvas, options) {
1973
1980
  });
1974
1981
  return json;
1975
1982
  }
1976
- async function loadCanvas(canvas, json) {
1983
+ async function loadCanvas(canvas, json, options) {
1977
1984
  await canvas.loadFromJSON(json);
1985
+ if (options?.filter) {
1986
+ const toRemove = [];
1987
+ canvas.forEachObject((obj) => {
1988
+ if (!options.filter(obj)) toRemove.push(obj);
1989
+ });
1990
+ for (const obj of toRemove) canvas.remove(obj);
1991
+ }
1978
1992
  canvas.forEachObject((obj) => {
1979
1993
  obj.set(DEFAULT_CONTROL_STYLE);
1980
1994
  if (obj.shapeType === "circle" && obj instanceof Rect5) {
@@ -1997,6 +2011,7 @@ function useEditCanvas(options) {
1997
2011
  const [selected, setSelected] = useState([]);
1998
2012
  const [viewportMode, setViewportModeState] = useState("select");
1999
2013
  const [isEditingVertices, setIsEditingVertices] = useState(false);
2014
+ const [isDirty, setIsDirty] = useState(false);
2000
2015
  const setMode = useCallback((setup) => {
2001
2016
  vertexEditCleanupRef.current?.();
2002
2017
  vertexEditCleanupRef.current = null;
@@ -2067,6 +2082,11 @@ function useEditCanvas(options) {
2067
2082
  canvas.on("selection:cleared", () => {
2068
2083
  setSelected([]);
2069
2084
  });
2085
+ if (options?.trackChanges) {
2086
+ canvas.on("object:added", () => setIsDirty(true));
2087
+ canvas.on("object:removed", () => setIsDirty(true));
2088
+ canvas.on("object:modified", () => setIsDirty(true));
2089
+ }
2070
2090
  if (options?.vertexEdit !== false) {
2071
2091
  const vertexOpts = typeof options?.vertexEdit === "object" ? options.vertexEdit : void 0;
2072
2092
  canvas.on("mouse:dblclick", (e) => {
@@ -2126,17 +2146,21 @@ function useEditCanvas(options) {
2126
2146
  viewportRef,
2127
2147
  setZoom
2128
2148
  );
2129
- const setBackground = useCallback(async (url) => {
2130
- const canvas = canvasRef.current;
2131
- if (!canvas) throw new Error("Canvas not ready");
2132
- const resizeOpts = options?.backgroundResize !== false ? typeof options?.backgroundResize === "object" ? options.backgroundResize : {} : void 0;
2133
- const img = await setBackgroundImage(canvas, url, resizeOpts);
2134
- if (options?.autoFitToBackground !== false) {
2135
- fitViewportToBackground(canvas);
2136
- syncZoom(canvasRef, setZoom);
2137
- }
2138
- return img;
2139
- }, []);
2149
+ const setBackground = useCallback(
2150
+ async (url, bgOpts) => {
2151
+ const canvas = canvasRef.current;
2152
+ if (!canvas) throw new Error("Canvas not ready");
2153
+ const resizeOpts = options?.backgroundResize !== false ? typeof options?.backgroundResize === "object" ? { ...options.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveOpacity ? { preserveOpacity: true } : void 0;
2154
+ const img = await setBackgroundImage(canvas, url, resizeOpts);
2155
+ if (options?.autoFitToBackground !== false) {
2156
+ fitViewportToBackground(canvas);
2157
+ syncZoom(canvasRef, setZoom);
2158
+ }
2159
+ return img;
2160
+ },
2161
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2162
+ []
2163
+ );
2140
2164
  return {
2141
2165
  /** Pass this to `<Canvas onReady={...} />` */
2142
2166
  onReady,
@@ -2181,8 +2205,15 @@ function useEditCanvas(options) {
2181
2205
  * Set a background image from a URL. Automatically resizes if the image
2182
2206
  * exceeds the configured limits (opt out via `backgroundResize: false`),
2183
2207
  * and fits the viewport after setting if `autoFitToBackground` is enabled.
2208
+ *
2209
+ * Pass `{ preserveOpacity: true }` to keep the current background opacity
2210
+ * when replacing the image.
2184
2211
  */
2185
- setBackground
2212
+ setBackground,
2213
+ /** Whether the canvas has been modified since the last `resetDirty()` call. Requires `trackChanges: true`. */
2214
+ isDirty,
2215
+ /** Reset the dirty flag (e.g., after a successful save). */
2216
+ resetDirty: useCallback(() => setIsDirty(false), [])
2186
2217
  };
2187
2218
  }
2188
2219
 
@@ -2316,6 +2347,155 @@ function useViewCanvas(options) {
2316
2347
  setObjectStyleByType
2317
2348
  };
2318
2349
  }
2350
+
2351
+ // src/hooks/useCanvasEvents.ts
2352
+ import { useEffect as useEffect3, useRef as useRef4 } from "react";
2353
+ function useCanvasEvents(canvasRef, events) {
2354
+ const eventsRef = useRef4(events);
2355
+ eventsRef.current = events;
2356
+ useEffect3(() => {
2357
+ const canvas = canvasRef.current;
2358
+ if (!canvas) return;
2359
+ const wrappers = /* @__PURE__ */ new Map();
2360
+ for (const key of Object.keys(eventsRef.current)) {
2361
+ if (!eventsRef.current[key]) continue;
2362
+ const wrapped = (options) => {
2363
+ eventsRef.current[key]?.(options);
2364
+ };
2365
+ canvas.on(key, wrapped);
2366
+ wrappers.set(key, wrapped);
2367
+ }
2368
+ return () => {
2369
+ wrappers.forEach((handler, name) => {
2370
+ canvas.off(name, handler);
2371
+ });
2372
+ };
2373
+ }, [canvasRef]);
2374
+ }
2375
+
2376
+ // src/hooks/useCanvasTooltip.ts
2377
+ import { useEffect as useEffect4, useRef as useRef5, useState as useState3 } from "react";
2378
+ function useCanvasTooltip(canvasRef, options) {
2379
+ const [state, setState] = useState3({
2380
+ visible: false,
2381
+ content: null,
2382
+ position: { x: 0, y: 0 }
2383
+ });
2384
+ const hoveredObjectRef = useRef5(null);
2385
+ const optionsRef = useRef5(options);
2386
+ optionsRef.current = options;
2387
+ useEffect4(() => {
2388
+ const canvas = canvasRef.current;
2389
+ if (!canvas) return;
2390
+ function calculatePosition(target) {
2391
+ const bounds = target.getBoundingRect();
2392
+ const zoom = canvas.getZoom();
2393
+ const vt = canvas.viewportTransform;
2394
+ if (!vt) return null;
2395
+ return {
2396
+ x: (bounds.left + bounds.width / 2) * zoom + vt[4],
2397
+ y: bounds.top * zoom + vt[5] - 10
2398
+ };
2399
+ }
2400
+ const handleMouseOver = (e) => {
2401
+ const target = e.target;
2402
+ if (!target) return;
2403
+ const content = optionsRef.current.getContent(target);
2404
+ if (content === null) return;
2405
+ if (hoveredObjectRef.current !== target) {
2406
+ hoveredObjectRef.current = target;
2407
+ const position = calculatePosition(target);
2408
+ if (position) {
2409
+ setState({ visible: true, content, position });
2410
+ }
2411
+ }
2412
+ };
2413
+ const handleMouseOut = (e) => {
2414
+ if (e.target && hoveredObjectRef.current === e.target) {
2415
+ setState((prev) => ({ ...prev, visible: false }));
2416
+ hoveredObjectRef.current = null;
2417
+ }
2418
+ };
2419
+ const updatePosition = () => {
2420
+ if (!hoveredObjectRef.current) return;
2421
+ const position = calculatePosition(hoveredObjectRef.current);
2422
+ if (position) {
2423
+ setState((prev) => prev.visible ? { ...prev, position } : prev);
2424
+ }
2425
+ };
2426
+ canvas.on("mouse:over", handleMouseOver);
2427
+ canvas.on("mouse:out", handleMouseOut);
2428
+ canvas.on("after:render", updatePosition);
2429
+ canvas.on("mouse:wheel", updatePosition);
2430
+ return () => {
2431
+ canvas.off("mouse:over", handleMouseOver);
2432
+ canvas.off("mouse:out", handleMouseOut);
2433
+ canvas.off("after:render", updatePosition);
2434
+ canvas.off("mouse:wheel", updatePosition);
2435
+ };
2436
+ }, [canvasRef]);
2437
+ return state;
2438
+ }
2439
+
2440
+ // src/hooks/useCanvasClick.ts
2441
+ import { useEffect as useEffect5, useRef as useRef6 } from "react";
2442
+ function useCanvasClick(canvasRef, onClick, options) {
2443
+ const onClickRef = useRef6(onClick);
2444
+ onClickRef.current = onClick;
2445
+ const optionsRef = useRef6(options);
2446
+ optionsRef.current = options;
2447
+ useEffect5(() => {
2448
+ const canvas = canvasRef.current;
2449
+ if (!canvas) return;
2450
+ let mouseDown = null;
2451
+ let isPanning = false;
2452
+ const handleMouseDown = (e) => {
2453
+ const native = e.e instanceof TouchEvent ? e.e.touches[0] : e.e;
2454
+ if (native) {
2455
+ mouseDown = { x: native.clientX, y: native.clientY, time: Date.now() };
2456
+ isPanning = false;
2457
+ }
2458
+ };
2459
+ const handleMouseMove = (e) => {
2460
+ if (!mouseDown) return;
2461
+ const native = e.e instanceof TouchEvent ? e.e.touches[0] : e.e;
2462
+ if (!native) return;
2463
+ const threshold = optionsRef.current?.threshold ?? 5;
2464
+ const deltaX = Math.abs(native.clientX - mouseDown.x);
2465
+ const deltaY = Math.abs(native.clientY - mouseDown.y);
2466
+ if (deltaX > threshold || deltaY > threshold) {
2467
+ isPanning = true;
2468
+ }
2469
+ };
2470
+ const handleMouseUp = (e) => {
2471
+ if (!mouseDown) return;
2472
+ const maxDuration = optionsRef.current?.maxDuration ?? 300;
2473
+ const elapsed = Date.now() - mouseDown.time;
2474
+ if (!isPanning && elapsed < maxDuration) {
2475
+ onClickRef.current(e.target);
2476
+ }
2477
+ mouseDown = null;
2478
+ isPanning = false;
2479
+ };
2480
+ canvas.on("mouse:down", handleMouseDown);
2481
+ canvas.on("mouse:move", handleMouseMove);
2482
+ canvas.on("mouse:up", handleMouseUp);
2483
+ return () => {
2484
+ canvas.off("mouse:down", handleMouseDown);
2485
+ canvas.off("mouse:move", handleMouseMove);
2486
+ canvas.off("mouse:up", handleMouseUp);
2487
+ };
2488
+ }, [canvasRef]);
2489
+ }
2490
+
2491
+ // src/index.ts
2492
+ import {
2493
+ Canvas as Canvas2,
2494
+ FabricObject as FabricObject5,
2495
+ FabricImage as FabricImage2,
2496
+ Rect as Rect7,
2497
+ Polygon as Polygon5
2498
+ } from "fabric";
2319
2499
  export {
2320
2500
  Canvas,
2321
2501
  DEFAULT_ALIGNMENT_STYLE,
@@ -2324,6 +2504,11 @@ export {
2324
2504
  DEFAULT_DRAG_SHAPE_STYLE,
2325
2505
  DEFAULT_GUIDELINE_SHAPE_STYLE,
2326
2506
  DEFAULT_SHAPE_STYLE,
2507
+ Canvas2 as FabricCanvas,
2508
+ FabricImage2 as FabricImage,
2509
+ FabricObject5 as FabricObject,
2510
+ Polygon5 as Polygon,
2511
+ Rect7 as Rect,
2327
2512
  createCircle,
2328
2513
  createCircleAtPoint,
2329
2514
  createPolygon,
@@ -2359,6 +2544,9 @@ export {
2359
2544
  setBackgroundInverted,
2360
2545
  setBackgroundOpacity,
2361
2546
  snapCursorPoint,
2547
+ useCanvasClick,
2548
+ useCanvasEvents,
2549
+ useCanvasTooltip,
2362
2550
  useEditCanvas,
2363
2551
  useViewCanvas
2364
2552
  };