@leavepulse/ui 0.37.7 → 0.37.8

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.
@@ -2,22 +2,22 @@
2
2
  /* The picture settles into the frame instead of appearing in it. Scale rather
3
3
  than a slide: the frame is the fixed thing here and the image lives inside
4
4
  it, so anything that moved would read as a crop that had shifted. */
5
- .lp-editor__image[data-v-3587f639] {
6
- animation: lp-editor-in-3587f639 var(--duration-slow) var(--ease-settle) both;
5
+ .lp-editor__image[data-v-667d4388] {
6
+ animation: lp-editor-in-667d4388 var(--duration-slow) var(--ease-settle) both;
7
7
  }
8
- .lp-editor__image--waiting[data-v-3587f639] {
8
+ .lp-editor__image--waiting[data-v-667d4388] {
9
9
  opacity: 0;
10
10
  animation: none;
11
11
  }
12
- @keyframes lp-editor-in-3587f639 {
12
+ @keyframes lp-editor-in-667d4388 {
13
13
  from {
14
14
  opacity: 0;
15
15
  scale: 1.04;
16
16
  }
17
17
  }
18
18
  @media (prefers-reduced-motion: reduce) {
19
- .lp-editor__image[data-v-3587f639],
20
- .lp-editor__image--waiting[data-v-3587f639] {
19
+ .lp-editor__image[data-v-667d4388],
20
+ .lp-editor__image--waiting[data-v-667d4388] {
21
21
  opacity: 1;
22
22
  scale: 1;
23
23
  animation: none;
@@ -15,7 +15,19 @@ declare const __VLS_export: import('vue').DefineComponent<{
15
15
  aspect?: "free" | "square" | "4:3" | "3:4" | "16:9" | number;
16
16
  /** Longest edge of the exported image. Larger sources are scaled down. */
17
17
  maxEdge?: number;
18
- /** JPEG quality of the export. */
18
+ /**
19
+ * Encoding of the export; read the result's `blob.type` for the one used.
20
+ *
21
+ * JPEG, the default, is the smallest for photographs, the case this was
22
+ * built for. It has no alpha channel, though: a transparent PNG comes back
23
+ * with its background filled black, and a logo or an icon is ruined by the
24
+ * crop. "source" keeps the picture's own format where a canvas can write it
25
+ * (PNG, JPEG, WebP) and falls back to PNG for the ones it cannot (GIF, BMP,
26
+ * SVG), so transparency survives either way. An animated GIF still comes
27
+ * back as its first frame: a canvas holds one picture.
28
+ */
29
+ type?: "image/jpeg" | "image/png" | "image/webp" | "source";
30
+ /** Quality of a lossy export (JPEG, WebP); PNG ignores it. */
19
31
  quality?: number;
20
32
  /**
21
33
  * Labels for the toolbar. Defaulted in English rather than left blank: an
@@ -61,7 +73,19 @@ declare const __VLS_export: import('vue').DefineComponent<{
61
73
  aspect?: "free" | "square" | "4:3" | "3:4" | "16:9" | number;
62
74
  /** Longest edge of the exported image. Larger sources are scaled down. */
63
75
  maxEdge?: number;
64
- /** JPEG quality of the export. */
76
+ /**
77
+ * Encoding of the export; read the result's `blob.type` for the one used.
78
+ *
79
+ * JPEG, the default, is the smallest for photographs, the case this was
80
+ * built for. It has no alpha channel, though: a transparent PNG comes back
81
+ * with its background filled black, and a logo or an icon is ruined by the
82
+ * crop. "source" keeps the picture's own format where a canvas can write it
83
+ * (PNG, JPEG, WebP) and falls back to PNG for the ones it cannot (GIF, BMP,
84
+ * SVG), so transparency survives either way. An animated GIF still comes
85
+ * back as its first frame: a canvas holds one picture.
86
+ */
87
+ type?: "image/jpeg" | "image/png" | "image/webp" | "source";
88
+ /** Quality of a lossy export (JPEG, WebP); PNG ignores it. */
65
89
  quality?: number;
66
90
  /**
67
91
  * Labels for the toolbar. Defaulted in English rather than left blank: an
@@ -73,6 +97,7 @@ declare const __VLS_export: import('vue').DefineComponent<{
73
97
  /** Fade the picture in when the editor first comes into view. */
74
98
  animate?: boolean;
75
99
  }> & Readonly<{}>, {
100
+ type: "image/jpeg" | "image/png" | "image/webp" | "source";
76
101
  animate: boolean;
77
102
  labels: Partial<Record<"rotateLeft" | "rotateRight" | "zoomIn" | "zoomOut" | "reset" | "canvas", string>>;
78
103
  aspect: "free" | "square" | "4:3" | "3:4" | "16:9" | number;
@@ -7,7 +7,7 @@ import "reka-ui";
7
7
  import { _ as _sfc_main$2 } from "../chunks/LpIcon-CCnX5_2j.js";
8
8
  import { useMergedAttrs } from "../composables/useMergedClass.js";
9
9
  import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
10
- import '../assets/LpImageEditor-BsSwej47.css';const _hoisted_1 = ["aria-label"];
10
+ import '../assets/LpImageEditor-D-s8tNGO.css';const _hoisted_1 = ["aria-label"];
11
11
  const _hoisted_2 = ["src"];
12
12
  const _hoisted_3 = {
13
13
  key: 0,
@@ -25,6 +25,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
25
25
  file: {},
26
26
  aspect: { default: "free" },
27
27
  maxEdge: { default: 2400 },
28
+ type: { default: "image/jpeg" },
28
29
  quality: { default: 0.9 },
29
30
  labels: { default: () => ({}) },
30
31
  animate: { type: Boolean, default: true }
@@ -164,9 +165,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
164
165
  const readY = (turned ? centreX : centreY) - readH / 2;
165
166
  ctx.drawImage(picture, readX, readY, readW, readH, -readW / 2, -readH / 2, readW, readH);
166
167
  return await new Promise(
167
- (resolve) => canvas.toBlob(resolve, "image/jpeg", props.quality)
168
+ (resolve) => canvas.toBlob(resolve, outputType.value, props.quality)
168
169
  );
169
170
  }
171
+ const ENCODABLE = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
172
+ const outputType = computed(() => {
173
+ if (props.type !== "source") return props.type;
174
+ return ENCODABLE.has(props.file.type) ? props.file.type : "image/png";
175
+ });
170
176
  function clamp(value, low, high) {
171
177
  return Math.min(Math.max(value, low), Math.max(low, high));
172
178
  }
@@ -357,7 +363,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
357
363
  };
358
364
  }
359
365
  });
360
- const LpImageEditor = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-3587f639"]]);
366
+ const LpImageEditor = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-667d4388"]]);
361
367
  export {
362
368
  LpImageEditor as default
363
369
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leavepulse/ui",
3
- "version": "0.37.7",
3
+ "version": "0.37.8",
4
4
  "type": "module",
5
5
  "description": "LeavePulse token-driven Vue component kit.",
6
6
  "repository": {
@@ -48,7 +48,19 @@ const props = withDefaults(
48
48
  aspect?: "free" | "square" | "4:3" | "3:4" | "16:9" | number
49
49
  /** Longest edge of the exported image. Larger sources are scaled down. */
50
50
  maxEdge?: number
51
- /** JPEG quality of the export. */
51
+ /**
52
+ * Encoding of the export; read the result's `blob.type` for the one used.
53
+ *
54
+ * JPEG, the default, is the smallest for photographs, the case this was
55
+ * built for. It has no alpha channel, though: a transparent PNG comes back
56
+ * with its background filled black, and a logo or an icon is ruined by the
57
+ * crop. "source" keeps the picture's own format where a canvas can write it
58
+ * (PNG, JPEG, WebP) and falls back to PNG for the ones it cannot (GIF, BMP,
59
+ * SVG), so transparency survives either way. An animated GIF still comes
60
+ * back as its first frame: a canvas holds one picture.
61
+ */
62
+ type?: "image/jpeg" | "image/png" | "image/webp" | "source"
63
+ /** Quality of a lossy export (JPEG, WebP); PNG ignores it. */
52
64
  quality?: number
53
65
  /**
54
66
  * Labels for the toolbar. Defaulted in English rather than left blank: an
@@ -62,7 +74,7 @@ const props = withDefaults(
62
74
  /** Fade the picture in when the editor first comes into view. */
63
75
  animate?: boolean
64
76
  }>(),
65
- { aspect: "free", maxEdge: 2400, quality: 0.9, labels: () => ({}), animate: true },
77
+ { aspect: "free", maxEdge: 2400, type: "image/jpeg", quality: 0.9, labels: () => ({}), animate: true },
66
78
  )
67
79
 
68
80
  // Same rule as the rest of the kit: the entrance belongs to arrival, not to
@@ -289,10 +301,17 @@ async function exportImage(): Promise<Blob | null> {
289
301
  ctx.drawImage(picture, readX, readY, readW, readH, -readW / 2, -readH / 2, readW, readH)
290
302
 
291
303
  return await new Promise<Blob | null>((resolve) =>
292
- canvas.toBlob(resolve, "image/jpeg", props.quality),
304
+ canvas.toBlob(resolve, outputType.value, props.quality),
293
305
  )
294
306
  }
295
307
 
308
+ const ENCODABLE = new Set(["image/png", "image/jpeg", "image/webp"])
309
+
310
+ const outputType = computed(() => {
311
+ if (props.type !== "source") return props.type
312
+ return ENCODABLE.has(props.file.type) ? props.file.type : "image/png"
313
+ })
314
+
296
315
  function clamp(value: number, low: number, high: number) {
297
316
  return Math.min(Math.max(value, low), Math.max(low, high))
298
317
  }