@bluepic/embed 0.6.21 → 0.6.22

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.
@@ -159,6 +159,7 @@ export type SocialCheckoutEvent = ExportSessionContext & RenderOutcome & Deliver
159
159
  nativeShare: boolean;
160
160
  status: SocialShareStatus;
161
161
  captionLength: number;
162
+ /** @deprecated Never sent (AVV: the caption is user content). Use `captionLength`. */
162
163
  caption?: string;
163
164
  /** Only present for verifiable networks that return a post URL (LinkedIn). */
164
165
  postUrl?: string;
@@ -210,6 +211,7 @@ type SocialCheckoutArgs = {
210
211
  nativeShare: boolean;
211
212
  status: SocialShareStatus;
212
213
  captionLength: number;
214
+ /** @deprecated Never sent (AVV: the caption is user content). Use `captionLength`. */
213
215
  caption?: string;
214
216
  postUrl?: string;
215
217
  errorMessage?: string;
@@ -73,10 +73,10 @@ export declare function useFieldHitboxes(options: {
73
73
  } | undefined;
74
74
  frameIndex?: number | undefined;
75
75
  props: {
76
- layout: "normal" | "compact" | (() => "normal" | "compact");
76
+ layout: "normal" | (() => "normal" | "compact") | "compact";
77
77
  width: number | (() => number);
78
78
  height: number | (() => number);
79
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
79
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
80
80
  allowUploadFromDevice: boolean | (() => boolean);
81
81
  uploadLabel: string | (() => string);
82
82
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -188,7 +188,7 @@ export declare function useFieldHitboxes(options: {
188
188
  maxY: number | (() => number);
189
189
  minScale: number | (() => number);
190
190
  maxScale: number | (() => number);
191
- type: "popup" | "inline" | (() => "popup" | "inline");
191
+ type: "popup" | (() => "popup" | "inline") | "inline";
192
192
  aspectRatio: number | (() => number);
193
193
  };
194
194
  } | {
@@ -210,7 +210,7 @@ export declare function useFieldHitboxes(options: {
210
210
  frameIndex?: number | undefined;
211
211
  props: {
212
212
  card: boolean | (() => boolean);
213
- layout: "list" | "flex" | (() => "list" | "flex");
213
+ layout: (() => "flex" | "list") | "flex" | "list";
214
214
  fields: (() => BluepicField[]) | ({
215
215
  type: "Image";
216
216
  model: {
@@ -231,10 +231,10 @@ export declare function useFieldHitboxes(options: {
231
231
  } | undefined;
232
232
  frameIndex?: number | undefined;
233
233
  props: {
234
- layout: "normal" | "compact" | (() => "normal" | "compact");
234
+ layout: "normal" | (() => "normal" | "compact") | "compact";
235
235
  width: number | (() => number);
236
236
  height: number | (() => number);
237
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
237
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
238
238
  allowUploadFromDevice: boolean | (() => boolean);
239
239
  uploadLabel: string | (() => string);
240
240
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -346,7 +346,7 @@ export declare function useFieldHitboxes(options: {
346
346
  maxY: number | (() => number);
347
347
  minScale: number | (() => number);
348
348
  maxScale: number | (() => number);
349
- type: "popup" | "inline" | (() => "popup" | "inline");
349
+ type: "popup" | (() => "popup" | "inline") | "inline";
350
350
  aspectRatio: number | (() => number);
351
351
  };
352
352
  } | /*elided*/ any | {
@@ -389,10 +389,10 @@ export declare function useFieldHitboxes(options: {
389
389
  } | undefined;
390
390
  frameIndex?: number | undefined;
391
391
  props: {
392
- layout: "normal" | "compact" | (() => "normal" | "compact");
392
+ layout: "normal" | (() => "normal" | "compact") | "compact";
393
393
  width: number | (() => number);
394
394
  height: number | (() => number);
395
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
395
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
396
396
  allowUploadFromDevice: boolean | (() => boolean);
397
397
  uploadLabel: string | (() => string);
398
398
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -504,7 +504,7 @@ export declare function useFieldHitboxes(options: {
504
504
  maxY: number | (() => number);
505
505
  minScale: number | (() => number);
506
506
  maxScale: number | (() => number);
507
- type: "popup" | "inline" | (() => "popup" | "inline");
507
+ type: "popup" | (() => "popup" | "inline") | "inline";
508
508
  aspectRatio: number | (() => number);
509
509
  };
510
510
  } | /*elided*/ any | /*elided*/ any | {
@@ -894,7 +894,7 @@ export declare function useFieldHitboxes(options: {
894
894
  autoCrop?: boolean | (() => boolean | undefined) | undefined;
895
895
  };
896
896
  })[];
897
- layout: "list" | "flex" | (() => "list" | "flex");
897
+ layout: "flex" | "list" | (() => "flex" | "list");
898
898
  min: number | (() => number);
899
899
  max: number | (() => number);
900
900
  defaultObject?: (() => {
@@ -1331,10 +1331,10 @@ export declare function useFieldHitboxes(options: {
1331
1331
  } | undefined;
1332
1332
  frameIndex?: number | undefined;
1333
1333
  props: {
1334
- layout: "normal" | "compact" | (() => "normal" | "compact");
1334
+ layout: "normal" | (() => "normal" | "compact") | "compact";
1335
1335
  width: number | (() => number);
1336
1336
  height: number | (() => number);
1337
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
1337
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
1338
1338
  allowUploadFromDevice: boolean | (() => boolean);
1339
1339
  uploadLabel: string | (() => string);
1340
1340
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -1446,7 +1446,7 @@ export declare function useFieldHitboxes(options: {
1446
1446
  maxY: number | (() => number);
1447
1447
  minScale: number | (() => number);
1448
1448
  maxScale: number | (() => number);
1449
- type: "popup" | "inline" | (() => "popup" | "inline");
1449
+ type: "popup" | (() => "popup" | "inline") | "inline";
1450
1450
  aspectRatio: number | (() => number);
1451
1451
  };
1452
1452
  } | {
@@ -1468,7 +1468,7 @@ export declare function useFieldHitboxes(options: {
1468
1468
  frameIndex?: number | undefined;
1469
1469
  props: {
1470
1470
  card: boolean | (() => boolean);
1471
- layout: "list" | "flex" | (() => "list" | "flex");
1471
+ layout: (() => "flex" | "list") | "flex" | "list";
1472
1472
  fields: (() => BluepicField[]) | ({
1473
1473
  type: "Image";
1474
1474
  model: {
@@ -1489,10 +1489,10 @@ export declare function useFieldHitboxes(options: {
1489
1489
  } | undefined;
1490
1490
  frameIndex?: number | undefined;
1491
1491
  props: {
1492
- layout: "normal" | "compact" | (() => "normal" | "compact");
1492
+ layout: "normal" | (() => "normal" | "compact") | "compact";
1493
1493
  width: number | (() => number);
1494
1494
  height: number | (() => number);
1495
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
1495
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
1496
1496
  allowUploadFromDevice: boolean | (() => boolean);
1497
1497
  uploadLabel: string | (() => string);
1498
1498
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -1604,7 +1604,7 @@ export declare function useFieldHitboxes(options: {
1604
1604
  maxY: number | (() => number);
1605
1605
  minScale: number | (() => number);
1606
1606
  maxScale: number | (() => number);
1607
- type: "popup" | "inline" | (() => "popup" | "inline");
1607
+ type: "popup" | (() => "popup" | "inline") | "inline";
1608
1608
  aspectRatio: number | (() => number);
1609
1609
  };
1610
1610
  } | /*elided*/ any | /*elided*/ any | {
@@ -2382,7 +2382,7 @@ export declare function useFieldHitboxes(options: {
2382
2382
  autoCrop?: boolean | (() => boolean | undefined) | undefined;
2383
2383
  };
2384
2384
  })[];
2385
- layout: "list" | "flex" | (() => "list" | "flex");
2385
+ layout: "flex" | "list" | (() => "flex" | "list");
2386
2386
  min: number | (() => number);
2387
2387
  max: number | (() => number);
2388
2388
  defaultObject?: (() => {
@@ -2849,10 +2849,10 @@ export declare function useFieldHitboxes(options: {
2849
2849
  } | undefined;
2850
2850
  frameIndex?: number | undefined;
2851
2851
  props: {
2852
- layout: "normal" | "compact" | (() => "normal" | "compact");
2852
+ layout: "normal" | (() => "normal" | "compact") | "compact";
2853
2853
  width: number | (() => number);
2854
2854
  height: number | (() => number);
2855
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
2855
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
2856
2856
  allowUploadFromDevice: boolean | (() => boolean);
2857
2857
  uploadLabel: string | (() => string);
2858
2858
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -2964,7 +2964,7 @@ export declare function useFieldHitboxes(options: {
2964
2964
  maxY: number | (() => number);
2965
2965
  minScale: number | (() => number);
2966
2966
  maxScale: number | (() => number);
2967
- type: "popup" | "inline" | (() => "popup" | "inline");
2967
+ type: "popup" | (() => "popup" | "inline") | "inline";
2968
2968
  aspectRatio: number | (() => number);
2969
2969
  };
2970
2970
  } | {
@@ -2986,7 +2986,7 @@ export declare function useFieldHitboxes(options: {
2986
2986
  frameIndex?: number | undefined;
2987
2987
  props: {
2988
2988
  card: boolean | (() => boolean);
2989
- layout: "list" | "flex" | (() => "list" | "flex");
2989
+ layout: (() => "flex" | "list") | "flex" | "list";
2990
2990
  fields: (() => BluepicField[]) | ({
2991
2991
  type: "Image";
2992
2992
  model: {
@@ -3007,10 +3007,10 @@ export declare function useFieldHitboxes(options: {
3007
3007
  } | undefined;
3008
3008
  frameIndex?: number | undefined;
3009
3009
  props: {
3010
- layout: "normal" | "compact" | (() => "normal" | "compact");
3010
+ layout: "normal" | (() => "normal" | "compact") | "compact";
3011
3011
  width: number | (() => number);
3012
3012
  height: number | (() => number);
3013
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
3013
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
3014
3014
  allowUploadFromDevice: boolean | (() => boolean);
3015
3015
  uploadLabel: string | (() => string);
3016
3016
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -3122,7 +3122,7 @@ export declare function useFieldHitboxes(options: {
3122
3122
  maxY: number | (() => number);
3123
3123
  minScale: number | (() => number);
3124
3124
  maxScale: number | (() => number);
3125
- type: "popup" | "inline" | (() => "popup" | "inline");
3125
+ type: "popup" | (() => "popup" | "inline") | "inline";
3126
3126
  aspectRatio: number | (() => number);
3127
3127
  };
3128
3128
  } | /*elided*/ any | {
@@ -3165,10 +3165,10 @@ export declare function useFieldHitboxes(options: {
3165
3165
  } | undefined;
3166
3166
  frameIndex?: number | undefined;
3167
3167
  props: {
3168
- layout: "normal" | "compact" | (() => "normal" | "compact");
3168
+ layout: "normal" | (() => "normal" | "compact") | "compact";
3169
3169
  width: number | (() => number);
3170
3170
  height: number | (() => number);
3171
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
3171
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
3172
3172
  allowUploadFromDevice: boolean | (() => boolean);
3173
3173
  uploadLabel: string | (() => string);
3174
3174
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -3280,7 +3280,7 @@ export declare function useFieldHitboxes(options: {
3280
3280
  maxY: number | (() => number);
3281
3281
  minScale: number | (() => number);
3282
3282
  maxScale: number | (() => number);
3283
- type: "popup" | "inline" | (() => "popup" | "inline");
3283
+ type: "popup" | (() => "popup" | "inline") | "inline";
3284
3284
  aspectRatio: number | (() => number);
3285
3285
  };
3286
3286
  } | /*elided*/ any | /*elided*/ any | {
@@ -3670,7 +3670,7 @@ export declare function useFieldHitboxes(options: {
3670
3670
  autoCrop?: boolean | (() => boolean | undefined) | undefined;
3671
3671
  };
3672
3672
  })[];
3673
- layout: "list" | "flex" | (() => "list" | "flex");
3673
+ layout: "flex" | "list" | (() => "flex" | "list");
3674
3674
  min: number | (() => number);
3675
3675
  max: number | (() => number);
3676
3676
  defaultObject?: (() => {
@@ -4107,10 +4107,10 @@ export declare function useFieldHitboxes(options: {
4107
4107
  } | undefined;
4108
4108
  frameIndex?: number | undefined;
4109
4109
  props: {
4110
- layout: "normal" | "compact" | (() => "normal" | "compact");
4110
+ layout: "normal" | (() => "normal" | "compact") | "compact";
4111
4111
  width: number | (() => number);
4112
4112
  height: number | (() => number);
4113
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
4113
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
4114
4114
  allowUploadFromDevice: boolean | (() => boolean);
4115
4115
  uploadLabel: string | (() => string);
4116
4116
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -4222,7 +4222,7 @@ export declare function useFieldHitboxes(options: {
4222
4222
  maxY: number | (() => number);
4223
4223
  minScale: number | (() => number);
4224
4224
  maxScale: number | (() => number);
4225
- type: "popup" | "inline" | (() => "popup" | "inline");
4225
+ type: "popup" | (() => "popup" | "inline") | "inline";
4226
4226
  aspectRatio: number | (() => number);
4227
4227
  };
4228
4228
  } | {
@@ -4244,7 +4244,7 @@ export declare function useFieldHitboxes(options: {
4244
4244
  frameIndex?: number | undefined;
4245
4245
  props: {
4246
4246
  card: boolean | (() => boolean);
4247
- layout: "list" | "flex" | (() => "list" | "flex");
4247
+ layout: (() => "flex" | "list") | "flex" | "list";
4248
4248
  fields: (() => BluepicField[]) | ({
4249
4249
  type: "Image";
4250
4250
  model: {
@@ -4265,10 +4265,10 @@ export declare function useFieldHitboxes(options: {
4265
4265
  } | undefined;
4266
4266
  frameIndex?: number | undefined;
4267
4267
  props: {
4268
- layout: "normal" | "compact" | (() => "normal" | "compact");
4268
+ layout: "normal" | (() => "normal" | "compact") | "compact";
4269
4269
  width: number | (() => number);
4270
4270
  height: number | (() => number);
4271
- allowedTypes: Template.Fields.ImageMime[] | (() => Template.Fields.ImageMime[]);
4271
+ allowedTypes: (() => Template.Fields.ImageMime[]) | Template.Fields.ImageMime[];
4272
4272
  allowUploadFromDevice: boolean | (() => boolean);
4273
4273
  uploadLabel: string | (() => string);
4274
4274
  convertTo?: Template.Fields.ImageMime | (() => Template.Fields.ImageMime | undefined) | undefined;
@@ -4380,7 +4380,7 @@ export declare function useFieldHitboxes(options: {
4380
4380
  maxY: number | (() => number);
4381
4381
  minScale: number | (() => number);
4382
4382
  maxScale: number | (() => number);
4383
- type: "popup" | "inline" | (() => "popup" | "inline");
4383
+ type: "popup" | (() => "popup" | "inline") | "inline";
4384
4384
  aspectRatio: number | (() => number);
4385
4385
  };
4386
4386
  } | /*elided*/ any | /*elided*/ any | {
@@ -5158,7 +5158,7 @@ export declare function useFieldHitboxes(options: {
5158
5158
  autoCrop?: boolean | (() => boolean | undefined) | undefined;
5159
5159
  };
5160
5160
  })[];
5161
- layout: "list" | "flex" | (() => "list" | "flex");
5161
+ layout: "flex" | "list" | (() => "flex" | "list");
5162
5162
  min: number | (() => number);
5163
5163
  max: number | (() => number);
5164
5164
  defaultObject?: (() => {
@@ -0,0 +1,6 @@
1
+ export { ASPECT_FIELD_TYPES, aspectFieldKey, conformCropToAspect, aspectReferenceElements, fixedAspectRatio, isUsableAspectRatio, pickAspectRatio, planImageAspects, resolveFieldAspectRatio, staticElementAspectRatio, } from './resolve';
2
+ export type { AspectPlanEntry } from './resolve';
3
+ export { elementSizeProbe } from './probe';
4
+ export type { ElementSize, ElementSizeProbeResult } from './probe';
5
+ export { IMAGE_ASPECT_KEY, provideImageAspect, useImageAspect, useImageAspects } from './useImageAspects';
6
+ export type { ImageAspectController } from './useImageAspects';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Sandbox-side size probe for the image-field aspect ratio.
3
+ *
4
+ * The element's real size only exists after core resolved every expression,
5
+ * layout group, surface/edge connection and the active canvas — inside the
6
+ * sandbox iframe. Like the field-hint probe, this asks the frame that drew the
7
+ * pixels instead of linking @bluepic/core into this package.
8
+ *
9
+ * Measured in the element's OWN coordinate space (`getBBox`, no transform):
10
+ * that is the box core cover-fits a crop into, so its ratio is the crop ratio.
11
+ * For image elements core renders that box as a transparent
12
+ * `.bx-alt-bbox-source` rect (bluepic-core Image.vue: x/y/width/height of the
13
+ * element); other elements, and engines that predate the rect, fall back to the
14
+ * element group's own bbox.
15
+ */
16
+ export type ElementSize = {
17
+ width: number;
18
+ height: number;
19
+ };
20
+ export type ElementSizeProbeResult = {
21
+ supported: false;
22
+ reason: 'no-root' | 'no-element-identity';
23
+ } | {
24
+ supported: true;
25
+ sizes: {
26
+ [originalId: string]: ElementSize;
27
+ };
28
+ };
29
+ /**
30
+ * ⚠️ SHIPPED AS SOURCE TEXT, NOT AS A CLOSURE — `EmbeddedController.evaluate()`
31
+ * stringifies it and rebuilds it with `new Function` inside the iframe. One
32
+ * self-contained function, `document` as the only free variable, plain ES
33
+ * (`var`, no optional chaining), JSON in and JSON out. Enforced by
34
+ * `imageAspect.test.ts`.
35
+ */
36
+ export declare function elementSizeProbe(originalIdsJson: string): ElementSizeProbeResult;
@@ -0,0 +1,91 @@
1
+ import type { BluepicField, Template } from '@bluepic/types';
2
+ /**
3
+ * Crop aspect ratio of an image field (ImageEdit / Logo), resolved at runtime.
4
+ *
5
+ * A fixed `aspectRatio` prop stopped being true once elements could be sized
6
+ * dynamically (edge / surface connections, expressions) and once one template
7
+ * could carry several canvases: the same field then drives frames of different
8
+ * shapes. So the ratio is only fixed when the author opts in with
9
+ * `enforceAspectRatio`; otherwise it is read off the element the field's
10
+ * binding drives:
11
+ *
12
+ * field.model.modelValue → every element whose expressions reference that
13
+ * binding (also through computedBindings) → image elements first → the
14
+ * first one's width / height → fallback 1.
15
+ */
16
+ /** Field types whose crop ratio this module resolves. */
17
+ export declare const ASPECT_FIELD_TYPES: Set<"Image" | "Text" | "ImageAdjust" | "Group" | "Collection" | "Select" | "Checkbox" | "Number" | "Color" | "Map" | "ImageEdit" | "SelectColor" | "SelectImage" | "SelectText" | "Instruction" | "Logo">;
18
+ export declare function isUsableAspectRatio(value: unknown): value is number;
19
+ /**
20
+ * The author-pinned ratio, or `null` when the ratio is dynamic.
21
+ *
22
+ * Typed loosely on purpose: it reads stored field props, and every field
23
+ * authored before `enforceAspectRatio` existed has a number in `aspectRatio`
24
+ * but no flag — those are dynamic by design.
25
+ */
26
+ export declare function fixedAspectRatio(props: {
27
+ aspectRatio?: unknown;
28
+ enforceAspectRatio?: unknown;
29
+ } | undefined | null): number | null;
30
+ /**
31
+ * Identity of an image field across serial swaps (canvas switch, re-mount):
32
+ * the binding it writes. Object identity would not survive — the fields tree
33
+ * the panel renders is not always the very array the serial holds.
34
+ */
35
+ export declare function aspectFieldKey(field: Pick<BluepicField, 'type' | 'model'> | undefined | null): string | null;
36
+ /**
37
+ * The elements that reference the field's binding, ordered as candidates for
38
+ * the reference frame: image elements first, then by how directly they use the
39
+ * binding (an `image` property beats an opacity), then document order.
40
+ */
41
+ export declare function aspectReferenceElements(serial: Template.Serial, field: BluepicField): Template.Element[];
42
+ /**
43
+ * Ratio straight from the serial, for when nothing is rendered to measure
44
+ * (no sandbox yet, a hidden element). Only literal sizes count — evaluating an
45
+ * expression would need @bluepic/core, which this package keeps out on purpose.
46
+ */
47
+ export declare function staticElementAspectRatio(element: Template.Element): number | undefined;
48
+ export type AspectPlanEntry = {
49
+ key: string;
50
+ /** Candidate element ids, best first. */
51
+ elementIds: string[];
52
+ /** Literal-size ratio per candidate id, where the serial has one. */
53
+ staticRatios: Record<string, number>;
54
+ };
55
+ /** Every dynamic image field in the serial with its reference candidates. */
56
+ export declare function planImageAspects(serial: Template.Serial, fields: BluepicField[]): AspectPlanEntry[];
57
+ /**
58
+ * Walk the candidates in order and take the first one with a known size —
59
+ * measured in the sandbox, else its literal size in the serial. Usually that is
60
+ * the 0th (the image element the field feeds); falling through only happens
61
+ * when it is not rendered right now (hidden, other canvas) and has no literal.
62
+ */
63
+ export declare function pickAspectRatio(entry: AspectPlanEntry, measured: Record<string, {
64
+ width: number;
65
+ height: number;
66
+ }> | undefined): number | undefined;
67
+ /**
68
+ * The part of `crop` that is actually visible in a frame of `aspectRatio`.
69
+ *
70
+ * The ImageValue (and its crop) is shared by every canvas, but the frames are
71
+ * not: after a canvas switch the stored crop can have the previous frame's
72
+ * shape. Core then cover-fits it, centred (fitImageV2 'cover', align 0.5/0.5),
73
+ * so the visible region is the centred sub-rectangle with the new ratio. The
74
+ * cropper starts from exactly that, instead of a box it would have to snap.
75
+ * Returns the crop unchanged when it already matches (within 0.5%).
76
+ */
77
+ export declare function conformCropToAspect<T extends {
78
+ left: number;
79
+ top: number;
80
+ width: number;
81
+ height: number;
82
+ }>(crop: T, aspectRatio: number): T;
83
+ /**
84
+ * One-shot resolution for hosts that already hold live element sizes (the
85
+ * studio has core's composed elements in-process): same candidates and order
86
+ * as the sandbox path. `undefined` = nothing resolvable.
87
+ */
88
+ export declare function resolveFieldAspectRatio(serial: Template.Serial, field: BluepicField, sizes: Record<string, {
89
+ width: number;
90
+ height: number;
91
+ }> | undefined): number | undefined;
@@ -0,0 +1,37 @@
1
+ import { type InjectionKey, type Ref } from 'vue';
2
+ import type { BluepicField, Template } from '@bluepic/types';
3
+ type EvaluateFn = (func: Function, ...args: string[]) => Promise<unknown>;
4
+ export type ImageAspectController = {
5
+ /**
6
+ * Dynamic crop ratio for an image field, or `undefined` when nothing could be
7
+ * resolved (the field then falls back to 1). Reactive: re-evaluates when the
8
+ * data, the serial or the active canvas change the reference element's size.
9
+ */
10
+ aspectRatioFor(field: BluepicField | undefined): number | undefined;
11
+ /** Re-measure now and resolve once the fresh sizes are in. */
12
+ refresh(): Promise<void>;
13
+ };
14
+ export declare const IMAGE_ASPECT_KEY: InjectionKey<ImageAspectController>;
15
+ export declare function provideImageAspect(controller: ImageAspectController): void;
16
+ /** Absent whenever the fields tree is rendered outside `BxTemplateEditor` (or a host provider). */
17
+ export declare function useImageAspect(): ImageAspectController | undefined;
18
+ /**
19
+ * Live crop ratios for every dynamic ImageEdit / Logo field of the serial.
20
+ *
21
+ * Independent of the field-hints gate: hints are a campaign option, cropping
22
+ * correctly is not.
23
+ */
24
+ export declare function useImageAspects(options: {
25
+ serial: Ref<Template.Serial | undefined>;
26
+ /** Resolved lazily — the sandbox controller only exists once the iframe mounts. */
27
+ evaluate: () => EvaluateFn | undefined;
28
+ ready: Ref<boolean>;
29
+ data: Ref<{
30
+ [k: string]: unknown;
31
+ }>;
32
+ }): {
33
+ controller: ImageAspectController;
34
+ ratios: import("vue").ComputedRef<Record<string, number>>;
35
+ dispose: () => void;
36
+ };
37
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluepic/embed",
3
- "version": "0.6.21",
3
+ "version": "0.6.22",
4
4
  "description": "Bluepic embed sdk",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -43,7 +43,8 @@
43
43
  "test:gallery": "tsx src/util/gallery.test.ts",
44
44
  "test:fieldhints": "tsx src/util/fieldHints/fieldHints.test.ts",
45
45
  "test:clone": "tsx src/util/cloneDeep.test.ts",
46
- "test:imagestates": "tsx src/util/imageStates/imageStates.test.ts"
46
+ "test:imagestates": "tsx src/util/imageStates/imageStates.test.ts",
47
+ "test:imageaspect": "tsx src/util/imageAspect/imageAspect.test.ts"
47
48
  },
48
49
  "peerDependencies": {
49
50
  "vue": "^3.5.23"