@mhamz.01/easyflow-whiteboard 2.37.0 → 2.39.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.
@@ -1 +1 @@
1
- {"version":3,"file":"custom-node-overlay-layer.d.ts","sourceRoot":"","sources":["../../../src/components/node/custom-node-overlay-layer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAS9C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,uBAAuB;IAC/B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACxC,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,YAAY,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzE,qBAAqB,CAAC,EAAE,YAAY,EAAE,CAAC;IACvC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/C;AAaD,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EACzC,KAAK,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,UAAc,EACd,cAA+B,EAC/B,YAAmB,EACnB,qBAA0B,EAC1B,YAAY,GACb,EAAE,uBAAuB,2CA0hBzB"}
1
+ {"version":3,"file":"custom-node-overlay-layer.d.ts","sourceRoot":"","sources":["../../../src/components/node/custom-node-overlay-layer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAS9C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,uBAAuB;IAC/B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACxC,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,YAAY,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzE,qBAAqB,CAAC,EAAE,YAAY,EAAE,CAAC;IACvC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/C;AAaD,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EACzC,KAAK,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,UAAc,EACd,cAA+B,EAC/B,YAAmB,EACnB,qBAA0B,EAC1B,YAAY,GACb,EAAE,uBAAuB,2CA6hBzB"}
@@ -116,8 +116,10 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
116
116
  return;
117
117
  }
118
118
  // ── Read from ref — not stale closure ──
119
- const activeObjects = canvas.getActiveObjects();
120
- const isTargetAlreadySelected = activeObjects.includes(target);
119
+ const activeObject = canvas.getActiveObject(); // the group/selection box
120
+ const activeObjects = canvas.getActiveObjects(); // individual objects inside it
121
+ const isTargetAlreadySelected = activeObjects.includes(target) || // clicked an individual selected object
122
+ activeObject === target; // clicked the selection box itself
121
123
  if (!isTargetAlreadySelected) {
122
124
  setSelectedIds(new Set());
123
125
  }
@@ -62,38 +62,22 @@ interface WhiteboardState {
62
62
  addCanvasObject: (obj: FabricObject) => void;
63
63
  removeCanvasObject: (obj: FabricObject) => void;
64
64
  clearCanvasObjects: () => void;
65
+ selectedObjects: FabricObject[];
66
+ setSelectedObjects: (objects: FabricObject[]) => void;
65
67
  toolOptions: ToolOptions;
66
68
  setToolOption: <T extends keyof ToolOptions>(tool: T, option: keyof ToolOptions[T], value: any) => void;
67
69
  history: string[];
68
70
  historyIndex: number;
69
71
  canUndo: boolean;
70
72
  canRedo: boolean;
71
- pushHistory: (state: string) => void;
73
+ pushHistory: (snapshot: string) => void;
72
74
  undo: () => string | null;
73
75
  redo: () => string | null;
74
- setCanUndo: (canUndo: boolean) => void;
75
- setCanRedo: (canRedo: boolean) => void;
76
+ setCanUndo: (v: boolean) => void;
77
+ setCanRedo: (v: boolean) => void;
76
78
  zoom: number;
77
79
  setZoom: (zoom: number) => void;
78
- selectedObjects: FabricObject[];
79
- setSelectedObjects: (objects: FabricObject[]) => void;
80
80
  }
81
- export declare const useWhiteboardStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<WhiteboardState>, "setState" | "devtools"> & {
82
- setState(partial: WhiteboardState | Partial<WhiteboardState> | ((state: WhiteboardState) => WhiteboardState | Partial<WhiteboardState>), replace?: false | undefined, action?: (string | {
83
- [x: string]: unknown;
84
- [x: number]: unknown;
85
- [x: symbol]: unknown;
86
- type: string;
87
- }) | undefined): void;
88
- setState(state: WhiteboardState | ((state: WhiteboardState) => WhiteboardState), replace: true, action?: (string | {
89
- [x: string]: unknown;
90
- [x: number]: unknown;
91
- [x: symbol]: unknown;
92
- type: string;
93
- }) | undefined): void;
94
- devtools: {
95
- cleanup: () => void;
96
- };
97
- }>;
81
+ export declare const useWhiteboardStore: import("zustand").UseBoundStore<import("zustand").StoreApi<WhiteboardState>>;
98
82
  export {};
99
83
  //# sourceMappingURL=whiteboard-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"whiteboard-store.d.ts","sourceRoot":"","sources":["../../src/store/whiteboard-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"whiteboard-store.d.ts","sourceRoot":"","sources":["../../src/store/whiteboard-store.ts"],"names":[],"mappings":"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"}
@@ -1,137 +1,84 @@
1
1
  import { create } from "zustand";
2
- import { devtools } from "zustand/middleware";
2
+ // ─── Constants ────────────────────────────────────────────────────────────────
3
+ // Each history entry is a full JSON canvas snapshot (can be 100KB+).
4
+ // Without a cap: 200 actions × 100KB = 20MB of undo history in memory.
5
+ const MAX_HISTORY = 50;
3
6
  const defaultToolOptions = {
4
- pen: {
5
- color: "#ffffff",
6
- strokeWidth: 2,
7
- opacity: 1,
8
- strokeDashArray: null,
9
- },
10
- rectangle: {
11
- fillColor: "transparent",
12
- strokeColor: "#ffffff",
13
- strokeWidth: 2,
14
- strokeDashArray: null,
15
- },
16
- circle: {
17
- fillColor: "transparent",
18
- strokeColor: "#ffffff",
19
- strokeWidth: 2,
20
- strokeDashArray: null,
21
- },
22
- frame: {
23
- fillColor: "#FFFFFF",
24
- strokeColor: "#E5E7EB",
25
- strokeWidth: 1,
26
- strokeDashArray: null,
27
- },
28
- text: {
29
- fontSize: 24,
30
- fontFamily: "cursive",
31
- color: "#ffffff",
32
- fontWeight: "400",
33
- textAlign: "left",
34
- },
35
- image: {
36
- opacity: 1,
37
- filters: [],
38
- },
39
- eraser: {
40
- size: 20,
41
- },
42
- line: {
43
- strokeColor: "#ffffff",
44
- strokeWidth: 2,
45
- strokeDashArray: null,
46
- }, // ← ADD THIS
47
- arrow: {
48
- strokeColor: "#ffffff",
49
- strokeWidth: 2,
50
- strokeDashArray: null,
51
- }, // ← ADD THIS
7
+ pen: { color: "#ffffff", strokeWidth: 2, opacity: 1, strokeDashArray: null },
8
+ rectangle: { fillColor: "transparent", strokeColor: "#ffffff", strokeWidth: 2, strokeDashArray: null },
9
+ circle: { fillColor: "transparent", strokeColor: "#ffffff", strokeWidth: 2, strokeDashArray: null },
10
+ frame: { fillColor: "#FFFFFF", strokeColor: "#E5E7EB", strokeWidth: 1, strokeDashArray: null },
11
+ text: { fontSize: 24, fontFamily: "cursive", color: "#ffffff", fontWeight: "400", textAlign: "left" },
12
+ image: { opacity: 1, filters: [] },
13
+ eraser: { size: 20 },
14
+ line: { strokeColor: "#ffffff", strokeWidth: 2, strokeDashArray: null },
15
+ arrow: { strokeColor: "#ffffff", strokeWidth: 2, strokeDashArray: null },
52
16
  };
53
- export const useWhiteboardStore = create()(devtools((set, get) => ({
54
- // Tool state
17
+ // ─── Store ────────────────────────────────────────────────────────────────────
18
+ export const useWhiteboardStore = create()((set, get) => ({
19
+ // ── Tool ──────────────────────────────────────────────────────────────────
55
20
  activeTool: "select",
56
21
  setActiveTool: (tool) => set({ activeTool: tool }),
57
- // Selected object type (for editing)
22
+ // ── Dropdown ──────────────────────────────────────────────────────────────
23
+ activeDropdown: null,
24
+ setActiveDropdown: (id) => set({ activeDropdown: id }),
25
+ // ── Selected object type ──────────────────────────────────────────────────
58
26
  selectedObjectType: null,
59
27
  setSelectedObjectType: (type) => set({ selectedObjectType: type }),
60
- // Canvas objects
28
+ // ── Canvas objects ────────────────────────────────────────────────────────
29
+ // NOTE: Fabric instances have circular refs and DOM refs — they cannot be
30
+ // serialized. If you add devtools back, exclude this slice or it will throw.
31
+ // Using concat() instead of spread avoids the intermediate spread allocation.
61
32
  canvasObjects: [],
62
- addCanvasObject: (obj) => set((state) => ({
63
- canvasObjects: [...state.canvasObjects, obj],
64
- })),
65
- removeCanvasObject: (obj) => set((state) => ({
66
- canvasObjects: state.canvasObjects.filter((o) => o !== obj),
67
- })),
33
+ addCanvasObject: (obj) => set((s) => ({ canvasObjects: s.canvasObjects.concat(obj) })),
34
+ removeCanvasObject: (obj) => set((s) => ({ canvasObjects: s.canvasObjects.filter((o) => o !== obj) })),
68
35
  clearCanvasObjects: () => set({ canvasObjects: [] }),
69
- // Tool options
36
+ // ── Selected objects ──────────────────────────────────────────────────────
37
+ selectedObjects: [],
38
+ setSelectedObjects: (objects) => set({ selectedObjects: objects }),
39
+ // ── Tool options ──────────────────────────────────────────────────────────
70
40
  toolOptions: defaultToolOptions,
71
- setToolOption: (tool, option, value) => set((state) => ({
41
+ setToolOption: (tool, option, value) => set((s) => ({
72
42
  toolOptions: {
73
- ...state.toolOptions,
74
- [tool]: {
75
- ...state.toolOptions[tool],
76
- [option]: value,
77
- },
43
+ ...s.toolOptions,
44
+ [tool]: { ...s.toolOptions[tool], [option]: value },
78
45
  },
79
46
  })),
80
- // History
47
+ // ── History ───────────────────────────────────────────────────────────────
81
48
  history: [],
82
49
  historyIndex: -1,
83
50
  canUndo: false,
84
51
  canRedo: false,
85
- pushHistory: (state) => {
86
- const { history, historyIndex } = get();
87
- // Slice off any redo states ahead of current index
88
- const newHistory = history.slice(0, historyIndex + 1);
89
- newHistory.push(state);
90
- set({
91
- history: newHistory,
92
- historyIndex: newHistory.length - 1,
93
- // Can undo if there is at least 1 previous state (index > 0)
94
- canUndo: newHistory.length > 1,
95
- canRedo: false,
96
- });
97
- },
98
- // Sets the selected dropdown (task/document) - used to auto-switch back to select tool when closing
99
- activeDropdown: null,
100
- setActiveDropdown: (id) => set({
101
- activeDropdown: id,
52
+ // Uses set() updater (single atomic write) instead of get() + set() which
53
+ // could interleave in React concurrent mode.
54
+ pushHistory: (snapshot) => set((s) => {
55
+ const trimmed = s.history.slice(0, s.historyIndex + 1);
56
+ trimmed.push(snapshot);
57
+ const capped = trimmed.length > MAX_HISTORY ? trimmed.slice(-MAX_HISTORY) : trimmed;
58
+ const newIndex = capped.length - 1;
59
+ return { history: capped, historyIndex: newIndex, canUndo: newIndex > 0, canRedo: false };
102
60
  }),
103
61
  undo: () => {
104
62
  const { history, historyIndex } = get();
105
- // Must have a previous state to go back to
106
63
  if (historyIndex > 0) {
107
- const newIndex = historyIndex - 1;
108
- set({
109
- historyIndex: newIndex,
110
- canUndo: newIndex > 0,
111
- canRedo: true,
112
- });
113
- return history[newIndex];
64
+ const i = historyIndex - 1;
65
+ set({ historyIndex: i, canUndo: i > 0, canRedo: true });
66
+ return history[i];
114
67
  }
115
68
  return null;
116
69
  },
117
70
  redo: () => {
118
71
  const { history, historyIndex } = get();
119
72
  if (historyIndex < history.length - 1) {
120
- const newIndex = historyIndex + 1;
121
- set({
122
- historyIndex: newIndex,
123
- canUndo: true,
124
- canRedo: newIndex < history.length - 1,
125
- });
126
- return history[newIndex];
73
+ const i = historyIndex + 1;
74
+ set({ historyIndex: i, canUndo: true, canRedo: i < history.length - 1 });
75
+ return history[i];
127
76
  }
128
77
  return null;
129
78
  },
130
79
  setCanUndo: (v) => set({ canUndo: v }),
131
80
  setCanRedo: (v) => set({ canRedo: v }),
132
- // Zoom
81
+ // ── Zoom ──────────────────────────────────────────────────────────────────
133
82
  zoom: 1,
134
83
  setZoom: (zoom) => set({ zoom }),
135
- selectedObjects: [],
136
- setSelectedObjects: (objects) => set({ selectedObjects: objects }),
137
- }), { name: "fabric-whiteboard-store" }));
84
+ }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "2.37.0",
3
+ "version": "2.39.0",
4
4
  "description": "A feature-rich whiteboard component built with Fabric.js and React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",