@anu3ev/fabric-image-editor 0.10.2 → 0.10.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.
package/README.md CHANGED
@@ -26,6 +26,8 @@ A modern, powerful browser-based image editor built with [FabricJS](https://fabr
26
26
  - **Font Loader** - FontManager handles Google Fonts + custom sources with automatic `@font-face` registration
27
27
  - **Configurable Toolbar** - Dynamic toolbar with context-sensitive actions
28
28
  - **Clipboard Integration** - Native copy/paste support with system clipboard
29
+ - **Deletion Guards** - Application-defined rules can prevent user deletion for protected objects
30
+ - **Clone Preparation** - Applications can sanitize object clones before copy, paste, duplicate, or cut
29
31
 
30
32
  ### Developer Features
31
33
  - **TypeScript Support** - Full type definitions included
@@ -72,6 +74,44 @@ document.addEventListener('DOMContentLoaded', async () => {
72
74
  })
73
75
  ```
74
76
 
77
+ ### Deletion Guards and Clone Preparation
78
+
79
+ The editor does not know application-specific object roles. If an application needs to protect a domain object from user deletion, pass a rule through `canDeleteObject`.
80
+
81
+ ```javascript
82
+ const MAIN_IMAGE_HANDLE = 'main-image'
83
+
84
+ const editor = await initEditor('editor', {
85
+ canDeleteObject: (object) => {
86
+ return object.customData?.handle !== MAIN_IMAGE_HANDLE
87
+ }
88
+ })
89
+ ```
90
+
91
+ The rule is checked by shared delete operations, so keyboard deletion, toolbar deletion, direct `DeletionManager` calls, and `cut()` use the same result. Locked objects are still skipped by the editor itself. If a technical operation must delete a protected object, call deletion with `ignoreDeleteGuard: true`.
92
+
93
+ When deletion is skipped by the guard, the editor fires `editor:objects-delete-skipped`. The event is only a notification for UI code; it does not cancel deletion, because the decision was already made by `canDeleteObject`.
94
+
95
+ ```javascript
96
+ editor.canvas.on('editor:objects-delete-skipped', ({ skippedObjects }) => {
97
+ console.log('Some objects were not deleted:', skippedObjects)
98
+ })
99
+ ```
100
+
101
+ Use `prepareObjectClone` when copied objects must not keep a domain marker from the source object. The callback receives only clones. The editor calls it for the root clone and for nested objects inside groups or active selections.
102
+
103
+ ```javascript
104
+ const editor = await initEditor('editor', {
105
+ prepareObjectClone: (object) => {
106
+ if (object.customData?.handle !== MAIN_IMAGE_HANDLE) return
107
+
108
+ delete object.customData.handle
109
+ }
110
+ })
111
+ ```
112
+
113
+ This hook is used by `copy()`, `cut()`, `copyPaste()`, and `paste()`. Before the hook is called, the editor detaches `customData` on the clone so the callback does not accidentally mutate the original object.
114
+
75
115
  ### Working with Images
76
116
 
77
117
  ```javascript
@@ -398,9 +438,9 @@ The editor follows a modular architecture with specialized managers:
398
438
 
399
439
  ### Utility Managers
400
440
  - **`SelectionManager`** - Object selection and multi-selection handling
401
- - **`ClipboardManager`** - Copy/paste with system clipboard integration
441
+ - **`ClipboardManager`** - Copy/paste, cut, duplicate, clone preparation, and system clipboard integration
402
442
  - **`GroupingManager`** - Object grouping and ungrouping operations
403
- - **`DeletionManager`** - Object deletion with group handling
443
+ - **`DeletionManager`** - Object deletion, delete guards, skipped-delete events, and group handling
404
444
  - **`ShapeManager`** - Preset-based shape groups with inner text, layout, scaling, and style controls
405
445
  - **`ObjectLockManager`** - Object locking and unlocking functionality
406
446
  - **`SnappingManager`** - Alignment guides and equal-spacing snaps while moving objects
@@ -451,7 +491,13 @@ initEditor(containerId, options): Promise<ImageEditor>
451
491
  acceptContentTypes: ['image/png', 'image/jpeg', 'image/svg+xml'],
452
492
 
453
493
  // Callback when ready
454
- _onReadyCallback: (editor) => console.log('Ready!')
494
+ _onReadyCallback: (editor) => console.log('Ready!'),
495
+
496
+ // Optional user-delete rule. Return false to skip this object.
497
+ canDeleteObject: (object) => true,
498
+
499
+ // Optional clone preparation for copy, cut, duplicate, and paste.
500
+ prepareObjectClone: (object) => {}
455
501
  }
456
502
  ```
457
503
 
@@ -1,2 +1,2 @@
1
1
  (function(){self.onmessage=async e=>{let{action:t,payload:n,requestId:r}=e.data;try{switch(t){case`resizeImage`:{let{dataURL:e,maxWidth:i,maxHeight:a,minWidth:o,minHeight:s,contentType:c,quality:l,sizeType:u}=n,d=await createImageBitmap(await(await fetch(e)).blob()),{width:f,height:p}=d,m=Math.min(i/f,a/p);u===`min`&&(m=Math.max(o/f,s/p)),f=Math.floor(f*m),p=Math.floor(p*m);let h=new OffscreenCanvas(f,p),g=h.getContext(`2d`);if(!g)throw Error(`Failed to get 2D context from OffscreenCanvas`);g.drawImage(d,0,0,f,p);let _=await h.convertToBlob({type:c,quality:l});self.postMessage({requestId:r,action:t,success:!0,data:_});break}case`toDataURL`:{let{bitmap:e,contentType:i,quality:a,returnBlob:o}=n,{width:s,height:c}=e,l=new OffscreenCanvas(e.width,e.height),u=l.getContext(`2d`);if(!u)throw Error(`Failed to get 2D context from OffscreenCanvas`);u.drawImage(e,0,0,s,c);let d=await l.convertToBlob({type:i,quality:a});if(o){self.postMessage({requestId:r,action:t,success:!0,data:d});break}let f=await new Promise(e=>{let t=new FileReader;t.onload=()=>e(t.result),t.readAsDataURL(d)});self.postMessage({requestId:r,action:t,success:!0,data:f});break}default:throw Error(`Unknown action ${t}`)}}catch(e){self.postMessage({requestId:r,action:t,success:!1,error:e.message})}}})();
2
- //# sourceMappingURL=worker-CA0Zz9Rg.js.map
2
+ //# sourceMappingURL=worker-Ds8wxpzF.js.map