@anu3ev/fabric-image-editor 0.6.7 → 0.6.12

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
@@ -175,6 +175,71 @@ editor.textManager.updateText({
175
175
  })
176
176
  ```
177
177
 
178
+ ### Working with Shapes
179
+
180
+ `ShapeManager` works with composite objects: an outer shape plus an inner text node that stay in sync during layout, scaling, history restore, copy/paste, and template rehydration.
181
+
182
+ Built-in preset keys: `circle`, `triangle`, `square`, `diamond`, `pentagon`, `hexagon`, `star`, `sparkle`, `heart`, `arrow-right-fat`, `arrow-up-fat`, `arrow-right`, `arrow-down-fat`, `arrow-up-down`, `arrow-left-right`, `drop`, `cross`, `gear`, `badge`, `bookmark`, `tag`, `moon`.
183
+
184
+ ```javascript
185
+ // Create a shape group with text
186
+ const badge = await editor.shapeManager.add({
187
+ presetKey: 'badge',
188
+ options: {
189
+ id: 'promo-badge',
190
+ width: 220,
191
+ height: 160,
192
+ text: 'SALE',
193
+ fill: '#111827',
194
+ stroke: '#f59e0b',
195
+ strokeWidth: 6,
196
+ textStyle: {
197
+ fontSize: 34,
198
+ color: '#ffffff',
199
+ bold: true
200
+ },
201
+ alignH: 'center',
202
+ alignV: 'middle'
203
+ }
204
+ })
205
+
206
+ // Update shape-only styling
207
+ editor.shapeManager.setOpacity({
208
+ target: badge,
209
+ opacity: 0.9
210
+ })
211
+
212
+ editor.shapeManager.setStroke({
213
+ target: badge,
214
+ stroke: '#22c55e',
215
+ strokeWidth: 4,
216
+ dash: [12, 6]
217
+ })
218
+
219
+ // Update inner text with layout-aware recalculation
220
+ editor.shapeManager.updateTextStyle({
221
+ target: 'promo-badge',
222
+ style: {
223
+ text: 'LIMITED',
224
+ uppercase: true,
225
+ fontSize: 30,
226
+ color: '#f9fafb'
227
+ }
228
+ })
229
+
230
+ // Swap preset while preserving text, transforms, and metadata
231
+ await editor.shapeManager.update({
232
+ target: badge,
233
+ presetKey: 'tag',
234
+ options: {
235
+ fill: '#dc2626',
236
+ width: 240
237
+ }
238
+ })
239
+ ```
240
+
241
+ All mutating `ShapeManager` methods save to history by default. Pass `withoutSave: true` for internal or batched updates.
242
+
178
243
  ### Configuring Fonts
179
244
 
180
245
  By default the editor ships with a curated Google Fonts collection (Latin + Cyrillic coverage).
@@ -242,7 +307,7 @@ The editor follows a modular architecture with specialized managers:
242
307
  - **`ClipboardManager`** - Copy/paste with system clipboard integration
243
308
  - **`GroupingManager`** - Object grouping and ungrouping operations
244
309
  - **`DeletionManager`** - Object deletion with group handling
245
- - **`ShapeManager`** - Shape creation (rectangles, circles, triangles)
310
+ - **`ShapeManager`** - Preset-based shape groups with inner text, layout, scaling, and style controls
246
311
  - **`ObjectLockManager`** - Object locking and unlocking functionality
247
312
  - **`SnappingManager`** - Alignment guides and equal-spacing snaps while moving objects
248
313
  - **`MeasurementManager`** - ALT-triggered distance guides to hovered objects or the montage area
@@ -351,6 +416,71 @@ editor.layerManager.sendBackwards(object)
351
416
  editor.layerManager.bringForward(object)
352
417
  ```
353
418
 
419
+ #### Shape Management
420
+ ```javascript
421
+ // Add a new shape group
422
+ const shape = await editor.shapeManager.add({
423
+ presetKey: 'hexagon',
424
+ options: {
425
+ text: 'Hello',
426
+ fill: '#2563eb',
427
+ width: 220,
428
+ height: 180
429
+ }
430
+ })
431
+
432
+ // Rebuild the same shape group with another preset
433
+ await editor.shapeManager.update({
434
+ target: shape,
435
+ presetKey: 'diamond',
436
+ options: {
437
+ text: 'Updated',
438
+ alignH: 'center',
439
+ alignV: 'middle'
440
+ }
441
+ })
442
+
443
+ // Shape-only styling
444
+ editor.shapeManager.setFill({ target: shape, fill: '#7c3aed' })
445
+ editor.shapeManager.setStroke({ target: shape, stroke: '#111827', strokeWidth: 3 })
446
+ editor.shapeManager.setOpacity({ target: shape, opacity: 0.85 })
447
+
448
+ // Text styling inside the shape
449
+ editor.shapeManager.updateTextStyle({
450
+ target: shape,
451
+ style: {
452
+ fontSize: 28,
453
+ color: '#ffffff',
454
+ bold: true
455
+ }
456
+ })
457
+
458
+ editor.shapeManager.setTextAlign({
459
+ target: shape,
460
+ horizontal: 'center',
461
+ vertical: 'middle'
462
+ })
463
+
464
+ await editor.shapeManager.setRounding({
465
+ target: shape,
466
+ rounding: 20
467
+ })
468
+
469
+ editor.shapeManager.remove({ target: shape })
470
+ ```
471
+
472
+ `target` can be omitted to use the active shape group. You can also pass the shape group itself, an inner Fabric object from that group, or the group's `id` string.
473
+
474
+ `ShapeManager` public methods:
475
+ - `add()` creates a new shape group from a preset and optional text/style overrides.
476
+ - `update()` swaps the preset while preserving existing text, transforms, and object metadata.
477
+ - `remove()` deletes the shape group from canvas.
478
+ - `setFill()`, `setStroke()`, and `setOpacity()` update the visual style of the outer shape node.
479
+ - `getTextNode()` returns the inner `Textbox` so it can be inspected or passed into other APIs.
480
+ - `updateTextStyle()` applies `TextManager`-style updates to the inner text and recalculates the group layout.
481
+ - `setTextAlign()` changes horizontal and vertical alignment inside the shape bounds.
482
+ - `setRounding()` enables or updates corner rounding for roundable presets.
483
+
354
484
  #### Alignment & Guides
355
485
  - Objects snap to montage area edges/centers and nearby objects while dragging, with guides for matches and equal spacing.
356
486
  - Hold `Ctrl` during drag to temporarily disable snapping (movement still follows the configured move step).
@@ -1,2 +0,0 @@
1
- var b=(m,a,n)=>new Promise((f,e)=>{var l=t=>{try{r(n.next(t))}catch(c){e(c)}},d=t=>{try{r(n.throw(t))}catch(c){e(c)}},r=t=>t.done?f(t.value):Promise.resolve(t.value).then(l,d);r((n=n.apply(m,a)).next())});(function(){"use strict";self.onmessage=m=>b(null,null,function*(){const{action:a,payload:n,requestId:f}=m.data;try{switch(a){case"resizeImage":{const{dataURL:e,maxWidth:l,maxHeight:d,minWidth:r,minHeight:t,contentType:c,quality:w,sizeType:g}=n,h=yield createImageBitmap(yield(yield fetch(e)).blob());let{width:s,height:o}=h,i=Math.min(l/s,d/o);g==="min"&&(i=Math.max(r/s,t/o)),s=Math.floor(s*i),o=Math.floor(o*i);const u=new OffscreenCanvas(s,o),p=u.getContext("2d");if(!p)throw new Error("Failed to get 2D context from OffscreenCanvas");p.drawImage(h,0,0,s,o);const y=yield u.convertToBlob({type:c,quality:w});self.postMessage({requestId:f,action:a,success:!0,data:y});break}case"toDataURL":{const{bitmap:e,contentType:l,quality:d,returnBlob:r}=n,{width:t,height:c}=e,w=new OffscreenCanvas(e.width,e.height),g=w.getContext("2d");if(!g)throw new Error("Failed to get 2D context from OffscreenCanvas");g.drawImage(e,0,0,t,c);const h=yield w.convertToBlob({type:l,quality:d});if(r){self.postMessage({requestId:f,action:a,success:!0,data:h});break}const s=yield new Promise(o=>{const i=new FileReader;i.onload=()=>o(i.result),i.readAsDataURL(h)});self.postMessage({requestId:f,action:a,success:!0,data:s});break}default:throw new Error(`Unknown action ${a}`)}}catch(e){self.postMessage({requestId:f,action:a,success:!1,error:e.message})}})})();
2
- //# sourceMappingURL=worker-2TM2HcqM.js.map