@overtone-art/canvas-editor-core 0.3.1 → 0.3.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.mjs CHANGED
@@ -1616,6 +1616,43 @@ function applyLayerShadow(object, config) {
1616
1616
  });
1617
1617
  }
1618
1618
 
1619
+ // src/selection-style.ts
1620
+ var DEFAULT_SELECTION_STYLE = {
1621
+ borderColor: "#c9a96e",
1622
+ cornerColor: "#c9a96e",
1623
+ cornerStrokeColor: "#101010",
1624
+ cornerSize: 11,
1625
+ cornerStyle: "circle",
1626
+ borderWidth: 1,
1627
+ borderDashArray: null,
1628
+ padding: 0,
1629
+ marqueeFill: "rgba(201, 169, 110, 0.12)"
1630
+ };
1631
+ function applyObjectSelectionStyle(object, style, zoom) {
1632
+ const scale = zoom > 0 ? 1 / zoom : 1;
1633
+ object.set({
1634
+ cornerSize: style.cornerSize * scale,
1635
+ cornerStyle: style.cornerStyle,
1636
+ cornerColor: style.cornerColor,
1637
+ cornerStrokeColor: style.cornerStrokeColor,
1638
+ // A filled handle is what makes the stroke colour visible at all.
1639
+ transparentCorners: false,
1640
+ borderColor: style.borderColor,
1641
+ borderScaleFactor: style.borderWidth * scale,
1642
+ borderDashArray: style.borderDashArray?.map((segment) => segment * scale) ?? null,
1643
+ padding: style.padding * scale
1644
+ });
1645
+ }
1646
+ function applySelectionStyle(canvas, style, zoom) {
1647
+ for (const object of canvas.getObjects()) applyObjectSelectionStyle(object, style, zoom);
1648
+ const active = canvas.getActiveObject();
1649
+ if (active) applyObjectSelectionStyle(active, style, zoom);
1650
+ canvas.selectionColor = style.marqueeFill;
1651
+ canvas.selectionBorderColor = style.borderColor;
1652
+ canvas.selectionLineWidth = style.borderWidth * (zoom > 0 ? 1 / zoom : 1);
1653
+ canvas.requestRenderAll();
1654
+ }
1655
+
1619
1656
  // src/transform.ts
1620
1657
  var SIDE_CONTROLS = ["ml", "mr", "mt", "mb"];
1621
1658
  function applyAspectLock(object, locked) {
@@ -2372,6 +2409,7 @@ var CanvasEditor = class {
2372
2409
  fileAdapter;
2373
2410
  imageProvider;
2374
2411
  zoomLevel = 1;
2412
+ selectionStyle = { ...DEFAULT_SELECTION_STYLE };
2375
2413
  mockup = null;
2376
2414
  // The design's configured background. The live canvas background is forced
2377
2415
  // transparent while a mockup preview is shown, so this is the source of truth
@@ -2419,6 +2457,7 @@ var CanvasEditor = class {
2419
2457
  this.curves = new TextCurveManager(this.canvas, this.layers, this.history, this.events);
2420
2458
  this.maskPresets = new MaskPresetManager(this.canvas, this.layers, this.history, this.events);
2421
2459
  this.setupCanvasEvents();
2460
+ this.refreshSelectionStyle();
2422
2461
  this.history.saveImmediate();
2423
2462
  this.pages = new ProjectManager(this);
2424
2463
  this.masks = new MaskController(this);
@@ -3089,6 +3128,7 @@ var CanvasEditor = class {
3089
3128
  const next = clamp(round2(level), MIN_ZOOM, MAX_ZOOM);
3090
3129
  if (next === this.zoomLevel) return;
3091
3130
  this.zoomLevel = next;
3131
+ this.refreshSelectionStyle();
3092
3132
  this.events.emit("zoom:changed", { zoom: next });
3093
3133
  }
3094
3134
  /** @deprecated use setZoom — kept for backward compatibility. */
@@ -3237,8 +3277,31 @@ var CanvasEditor = class {
3237
3277
  this.events.removeAllListeners();
3238
3278
  this.canvas.dispose();
3239
3279
  }
3280
+ // ─── Selection style ────────────────────────────────
3281
+ /** Current look of the selection frame and its handles. */
3282
+ getSelectionStyle() {
3283
+ return { ...this.selectionStyle };
3284
+ }
3285
+ /**
3286
+ * Restyles the selection frame and resize handles. Sizes are in screen
3287
+ * pixels and stay constant across zoom levels (see `SelectionStyle`).
3288
+ */
3289
+ setSelectionStyle(style) {
3290
+ this.selectionStyle = { ...this.selectionStyle, ...style };
3291
+ this.refreshSelectionStyle();
3292
+ }
3293
+ refreshSelectionStyle() {
3294
+ applySelectionStyle(this.canvas, this.selectionStyle, this.zoomLevel);
3295
+ }
3240
3296
  // ─── Private ────────────────────────────────────────
3241
3297
  setupCanvasEvents() {
3298
+ this.canvas.on("object:added", (e) => {
3299
+ if (e.target) applyObjectSelectionStyle(e.target, this.selectionStyle, this.zoomLevel);
3300
+ });
3301
+ const styleActive = () => {
3302
+ const active = this.canvas.getActiveObject();
3303
+ if (active) applyObjectSelectionStyle(active, this.selectionStyle, this.zoomLevel);
3304
+ };
3242
3305
  this.canvas.on("object:modified", (e) => {
3243
3306
  if (!e.target) return;
3244
3307
  const layer = this.layers.findByObject(e.target);
@@ -3248,10 +3311,12 @@ var CanvasEditor = class {
3248
3311
  }
3249
3312
  });
3250
3313
  this.canvas.on("selection:created", (e) => {
3314
+ styleActive();
3251
3315
  const selected = (e.selected ?? []).map((obj) => this.layers.findByObject(obj)?.id).filter((id) => id !== void 0);
3252
3316
  this.events.emit("selection:changed", { selected });
3253
3317
  });
3254
3318
  this.canvas.on("selection:updated", (e) => {
3319
+ styleActive();
3255
3320
  const selected = (e.selected ?? []).map((obj) => this.layers.findByObject(obj)?.id).filter((id) => id !== void 0);
3256
3321
  this.events.emit("selection:changed", { selected });
3257
3322
  });
@@ -3332,6 +3397,7 @@ export {
3332
3397
  CropController,
3333
3398
  DEFAULT_LAYER_SHADOW,
3334
3399
  DEFAULT_PATTERN_CONFIG,
3400
+ DEFAULT_SELECTION_STYLE,
3335
3401
  DEFAULT_TEXT_CURVE,
3336
3402
  EventEmitter,
3337
3403
  FontRegistry,
@@ -3353,7 +3419,9 @@ export {
3353
3419
  UnitConverter,
3354
3420
  applyAspectLock,
3355
3421
  applyLayerShadow,
3422
+ applyObjectSelectionStyle,
3356
3423
  applyPatternLocks,
3424
+ applySelectionStyle,
3357
3425
  buildCurvePathData,
3358
3426
  buildPatternDataURL,
3359
3427
  captureLocks,