dune-react 0.0.43 → 0.0.44

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.
Files changed (55) hide show
  1. package/dist/_virtual/_commonjsHelpers.js +6 -0
  2. package/dist/_virtual/index.js +4 -0
  3. package/dist/components/puck-base/media.d.ts +1 -0
  4. package/dist/components/puck-base/media.js +272 -129
  5. package/dist/components/puck-block/gallery-sections/static-grid/static-grid.js +14 -10
  6. package/dist/components/puck-block/testimonial-sections/bento-testimonial/component.js +7 -6
  7. package/dist/components/puck-core/core/props/index.js +7 -0
  8. package/dist/components/shadcn/slider.js +1 -1
  9. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/algorithms/flipImageAlgorithm.js +44 -0
  10. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/algorithms/moveCoordinatesAlgorithm.js +8 -0
  11. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/algorithms/resizeCoordinatesAlgorithm.js +291 -0
  12. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/algorithms/rotateImageAlgorithm.js +38 -0
  13. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/algorithms/transformImageAlgorithm.js +84 -0
  14. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/animation/index.js +78 -0
  15. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/boundary/index.js +31 -0
  16. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/canvas/index.js +94 -0
  17. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/constants/index.js +8 -0
  18. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultAreaPositionRestrictions.js +51 -0
  19. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultAreaSizeRestrictions.js +30 -0
  20. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultBoundary.js +10 -0
  21. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultPosition.js +12 -0
  22. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultPositionRestrictions.js +17 -0
  23. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultSize.js +31 -0
  24. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultSizeRestrictions.js +16 -0
  25. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultStencilConstraints.js +13 -0
  26. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/defaultVisibleArea.js +49 -0
  27. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/defaults/index.js +84 -0
  28. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/extensions/stencil-size/index.js +107 -0
  29. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/image/index.js +350 -0
  30. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/instance/AbstractCropperInstance.js +494 -0
  31. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/approximateSize.js +30 -0
  32. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/fitCoordinates.js +30 -0
  33. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/fitVisibleArea.js +26 -0
  34. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/helpers.js +125 -0
  35. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/imageTransforms.js +83 -0
  36. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/interactions.js +19 -0
  37. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/normalize.js +83 -0
  38. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/sizeRestrictions.js +58 -0
  39. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/service/utils.js +313 -0
  40. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/copyState.js +7 -0
  41. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/createState.js +41 -0
  42. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/moveCoordinates.js +15 -0
  43. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/reconcileState.js +44 -0
  44. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/resizeCoordinates.js +22 -0
  45. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/setBoundary.js +31 -0
  46. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/setCoordinates.js +83 -0
  47. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/setVisibleArea.js +18 -0
  48. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/state/transformImage.js +18 -0
  49. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/types/index.js +16 -0
  50. package/dist/node_modules/.pnpm/advanced-cropper@0.17.1/node_modules/advanced-cropper/utils/index.js +268 -0
  51. package/dist/node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.js +63 -0
  52. package/dist/node_modules/.pnpm/react-advanced-cropper@0.20.1_react@19.2.4/node_modules/react-advanced-cropper/dist/index.esm-bundler.js +1715 -0
  53. package/dist/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib/tslib.es6.js +181 -0
  54. package/dist/style.css +406 -0
  55. package/package.json +21 -20
@@ -0,0 +1,6 @@
1
+ function getDefaultExportFromCjs(x) {
2
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
3
+ }
4
+ export {
5
+ getDefaultExportFromCjs
6
+ };
@@ -0,0 +1,4 @@
1
+ var classnames = { exports: {} };
2
+ export {
3
+ classnames as __module
4
+ };
@@ -1,3 +1,4 @@
1
+ import "react-advanced-cropper/dist/style.css";
1
2
  export declare function detectMediaType(src: string): "image" | "video" | "embed";
2
3
  export interface CompoundMediaProps {
3
4
  src: string;
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef, useCallback, useMemo } from "react";
4
- import Cropper from "react-easy-crop";
5
- import { Pencil, Film, Youtube, Search, Upload, Loader2, Check } from "lucide-react";
4
+ import { Cropper, CircleStencil, RectangleStencil, DraggableArea as DraggableElement } from "../../node_modules/.pnpm/react-advanced-cropper@0.20.1_react@19.2.4/node_modules/react-advanced-cropper/dist/index.esm-bundler.js";
5
+ /* empty css */
6
+ import { Pencil, Film, Search, Upload, Square, Circle, FlipHorizontal, RotateCcw, RotateCw, FlipVertical, Loader2, Check } from "lucide-react";
6
7
  import { cn } from "../../utils/css-utils.js";
7
8
  import { withEditable } from "../puck-core/core/with-editable.js";
8
9
  import { mediaField } from "../puck-core/core/props/media.js";
@@ -11,7 +12,6 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "
11
12
  import { Input } from "../shadcn/input.js";
12
13
  import { Label } from "../shadcn/label.js";
13
14
  import { ScrollArea } from "../shadcn/scroll-area.js";
14
- import { Slider } from "../shadcn/slider.js";
15
15
  import { Tabs, TabsList, TabsTrigger, TabsIndicator, TabsContent } from "../shadcn/tabs.js";
16
16
  import useUpload from "../puck-core/use-upload.js";
17
17
  import { useEditorContext } from "../puck-core/core/context/editor-context.js";
@@ -31,41 +31,116 @@ function getEmbedUrl(url) {
31
31
  return `https://player.vimeo.com/video/${vimeoMatch[1]}?autoplay=1`;
32
32
  return url;
33
33
  }
34
- const createImage = (url) => new Promise((resolve, reject) => {
35
- const image = new Image();
36
- image.addEventListener("load", () => resolve(image));
37
- image.addEventListener("error", (error) => reject(error));
38
- image.setAttribute("crossOrigin", "anonymous");
39
- image.src = url;
40
- });
41
- const getCroppedImg = async (imageSrc, pixelCrop, rotation) => {
42
- const image = await createImage(imageSrc);
43
- const canvas = document.createElement("canvas");
44
- const ctx = canvas.getContext("2d");
45
- const maxSize = Math.max(image.width, image.height);
46
- const safeArea = 2 * (maxSize / 2 * Math.sqrt(2));
47
- canvas.width = safeArea;
48
- canvas.height = safeArea;
49
- ctx.translate(safeArea / 2, safeArea / 2);
50
- ctx.rotate(rotation * Math.PI / 180);
51
- ctx.translate(-safeArea / 2, -safeArea / 2);
52
- ctx.drawImage(
53
- image,
54
- safeArea / 2 - image.width * 0.5,
55
- safeArea / 2 - image.height * 0.5
56
- );
57
- const data = ctx.getImageData(0, 0, safeArea, safeArea);
58
- canvas.width = pixelCrop.width;
59
- canvas.height = pixelCrop.height;
60
- ctx.putImageData(
61
- data,
62
- Math.round(0 - safeArea / 2 + image.width * 0.5 - pixelCrop.x),
63
- Math.round(0 - safeArea / 2 + image.height * 0.5 - pixelCrop.y)
34
+ const ASPECT_PRESETS = [
35
+ { label: "Free", value: void 0 },
36
+ { label: "1:1", value: 1 },
37
+ { label: "4:3", value: 4 / 3 },
38
+ { label: "16:9", value: 16 / 9 }
39
+ ];
40
+ function rangeArray(from, to, step = 1) {
41
+ const result = [];
42
+ for (let v = from; v < to; v += step) result.push(v);
43
+ return result;
44
+ }
45
+ function RotateBar({
46
+ value,
47
+ onChange,
48
+ onEnd,
49
+ from = -45,
50
+ to = 45,
51
+ step = 2.5
52
+ }) {
53
+ const barsRef = useRef(null);
54
+ const density = 10;
55
+ const thickness = 2;
56
+ const items = useMemo(() => {
57
+ var _a;
58
+ const width = ((_a = barsRef.current) == null ? void 0 : _a.clientWidth) || 260;
59
+ const count = width / density;
60
+ const neededLeft = Math.max(
61
+ 0,
62
+ Math.floor(count / 2) - Math.round((value - from) / step)
63
+ );
64
+ const neededRight = Math.max(
65
+ 0,
66
+ Math.floor(count / 2) - Math.round((to - value) / step)
67
+ );
68
+ const values = [
69
+ ...rangeArray(from - neededLeft * step, from, step),
70
+ ...rangeArray(from, to + step, step),
71
+ ...rangeArray(to + step, to + step + neededRight * step, step)
72
+ ];
73
+ const radius = Math.abs(Math.ceil(count / 2) * step);
74
+ return values.map((barValue) => {
75
+ const sign = Math.sign(barValue - value);
76
+ let translate;
77
+ if (Math.abs(barValue - value) / step <= Math.ceil(count / 2)) {
78
+ const multiplier = Math.sqrt(
79
+ Math.pow(radius, 2) - Math.pow(value + sign * radius - barValue, 2)
80
+ ) / radius;
81
+ translate = width / 2 + sign * (width / 2) * Math.pow(multiplier, 2.5);
82
+ } else {
83
+ translate = width / 2 + sign * width / 2;
84
+ }
85
+ let opacity = 0;
86
+ if (count > 0 && Math.abs(barValue - value) / step <= Math.ceil(count / 2)) {
87
+ opacity = Math.pow(
88
+ Math.sqrt(Math.pow(radius, 2) - Math.pow(value - barValue, 2)) / radius,
89
+ 4
90
+ );
91
+ }
92
+ return {
93
+ value: barValue,
94
+ highlighted: value < 0 && barValue >= value && barValue <= 0 || value > 0 && barValue <= value && barValue >= 0,
95
+ zero: barValue === 0,
96
+ opacity,
97
+ translate: translate - thickness / 2
98
+ };
99
+ });
100
+ }, [value, from, to, step]);
101
+ const onMove = useCallback(
102
+ (directions) => {
103
+ if (!barsRef.current) return;
104
+ const width = barsRef.current.clientWidth;
105
+ const count = width / density;
106
+ const shift = -(directions.left / width) * count * step;
107
+ if (value + shift > to) onChange(to - value);
108
+ else if (value + shift < from) onChange(from - value);
109
+ else onChange(shift);
110
+ },
111
+ [value, from, to, step, onChange]
64
112
  );
65
- return new Promise((resolve) => {
66
- canvas.toBlob((blob) => resolve(blob), "image/jpeg", 0.95);
67
- });
68
- };
113
+ return /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(DraggableElement, { onMove, onMoveEnd: onEnd, useAnchor: false, children: /* @__PURE__ */ jsxs(
114
+ "div",
115
+ {
116
+ ref: barsRef,
117
+ className: "relative flex h-[15px] w-full cursor-grab select-none active:cursor-grabbing",
118
+ children: [
119
+ items.map((bar) => /* @__PURE__ */ jsx(
120
+ "div",
121
+ {
122
+ className: cn(
123
+ "absolute left-0 top-1/2 flex-shrink-0",
124
+ bar.zero ? "h-[20px]" : "h-[15px]",
125
+ bar.highlighted ? "bg-primary" : "bg-muted-foreground/40"
126
+ ),
127
+ style: {
128
+ width: bar.opacity ? thickness : 0,
129
+ opacity: bar.opacity,
130
+ transform: `translate(${bar.translate}px, -50%)`
131
+ }
132
+ },
133
+ bar.value
134
+ )),
135
+ /* @__PURE__ */ jsx("div", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 h-[25px] w-[3px] rounded-sm bg-primary" }),
136
+ /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -top-4 -translate-x-1/2 text-[11px] font-medium text-primary tabular-nums", children: [
137
+ value.toFixed(1),
138
+ "°"
139
+ ] })
140
+ ]
141
+ }
142
+ ) }) });
143
+ }
69
144
  const DEFAULT_LIBRARY_IMAGES = [];
70
145
  function CompoundMediaBase(props) {
71
146
  const type = detectMediaType(props.src);
@@ -112,8 +187,8 @@ function MediaEditDialog({
112
187
  onSave
113
188
  }) {
114
189
  const currentType = detectMediaType(initialData.src);
115
- const [mediaTab, setMediaTab] = useState(currentType);
116
- const [imageSubTab, setImageSubTab] = useState("library");
190
+ const [mediaTab, setMediaTab] = useState(currentType === "embed" ? "video" : currentType);
191
+ const [imageSubTab, setImageSubTab] = useState("adjust");
117
192
  const [alt, setAlt] = useState(initialData.alt ?? "");
118
193
  const [libraryImages, setLibraryImages] = useState(
119
194
  DEFAULT_LIBRARY_IMAGES
@@ -128,18 +203,15 @@ function MediaEditDialog({
128
203
  }).catch(() => {
129
204
  }).finally(() => setIsLoadingImages(false));
130
205
  }, [open, fetchLibraryImages]);
131
- const [crop, setCrop] = useState({ x: 0, y: 0 });
132
- const [zoom, setZoom] = useState(1);
133
- const [rotation, setRotation] = useState(0);
134
- const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
206
+ const cropperRef = useRef(null);
207
+ const [aspectRatio, setAspectRatio] = useState(void 0);
208
+ const [cropShape, setCropShape] = useState("rect");
209
+ const [adjustAngle, setAdjustAngle] = useState(0);
135
210
  const [selectedImg, setSelectedImg] = useState(null);
136
211
  const replaceInputRef = useRef(null);
137
212
  const lastUploadedFile = useRef(null);
138
213
  const [videoUrl, setVideoUrl] = useState(
139
- currentType === "video" ? initialData.src : ""
140
- );
141
- const [embedUrl, setEmbedUrl] = useState(
142
- currentType === "embed" ? initialData.src : ""
214
+ currentType === "video" || currentType === "embed" ? initialData.src : ""
143
215
  );
144
216
  const { brandId, domain } = useEditorContext();
145
217
  const saveToAssetLibrary = useCallback(
@@ -172,12 +244,11 @@ function MediaEditDialog({
172
244
  );
173
245
  const handleClose = useCallback(() => {
174
246
  onOpenChange(false);
175
- setCrop({ x: 0, y: 0 });
176
- setZoom(1);
177
- setRotation(0);
178
247
  setSelectedImg(null);
179
248
  setVideoUrl("");
180
- setEmbedUrl("");
249
+ setAspectRatio(void 0);
250
+ setCropShape("rect");
251
+ setAdjustAngle(0);
181
252
  }, [onOpenChange]);
182
253
  const { upload: uploadCrop, isUploading: isCropUploading } = useUpload({
183
254
  onSuccess: (url) => {
@@ -194,21 +265,22 @@ function MediaEditDialog({
194
265
  }
195
266
  });
196
267
  const handleCropSave = useCallback(async () => {
197
- if (!croppedAreaPixels || !initialData.src) return;
268
+ const cropper = cropperRef.current;
269
+ if (!cropper) return;
198
270
  try {
199
- const croppedBlob = await getCroppedImg(
200
- initialData.src,
201
- croppedAreaPixels,
202
- rotation
271
+ const canvas = cropper.getCanvas();
272
+ if (!canvas) return;
273
+ const blob = await new Promise(
274
+ (resolve) => canvas.toBlob((b) => resolve(b), "image/jpeg", 0.95)
203
275
  );
204
- const file = new File([croppedBlob], "cropped-image.jpg", {
276
+ const file = new File([blob], "cropped-image.jpg", {
205
277
  type: "image/jpeg"
206
278
  });
207
279
  await uploadCrop(file);
208
280
  } catch (error) {
209
281
  console.error("Crop failed:", error);
210
282
  }
211
- }, [croppedAreaPixels, initialData.src, rotation, uploadCrop]);
283
+ }, [uploadCrop]);
212
284
  const handleFileReplace = useCallback(
213
285
  (e) => {
214
286
  var _a;
@@ -232,12 +304,6 @@ function MediaEditDialog({
232
304
  onSave({ src: url, alt });
233
305
  handleClose();
234
306
  }, [videoUrl, alt, onSave, handleClose]);
235
- const handleEmbedDone = useCallback(() => {
236
- const url = embedUrl.trim();
237
- if (!url) return;
238
- onSave({ src: url, alt });
239
- handleClose();
240
- }, [embedUrl, alt, onSave, handleClose]);
241
307
  const canDone = useMemo(() => {
242
308
  if (mediaTab === "image") {
243
309
  if (imageSubTab === "library") return !!selectedImg;
@@ -245,9 +311,8 @@ function MediaEditDialog({
245
311
  return true;
246
312
  }
247
313
  if (mediaTab === "video") return !!videoUrl.trim();
248
- if (mediaTab === "embed") return !!embedUrl.trim();
249
314
  return false;
250
- }, [mediaTab, imageSubTab, selectedImg, isCropUploading, videoUrl, embedUrl]);
315
+ }, [mediaTab, imageSubTab, selectedImg, isCropUploading, videoUrl]);
251
316
  const handleDone = useCallback(() => {
252
317
  if (mediaTab === "image") {
253
318
  if (imageSubTab === "library") handleLibraryDone();
@@ -258,8 +323,6 @@ function MediaEditDialog({
258
323
  }
259
324
  } else if (mediaTab === "video") {
260
325
  handleVideoDone();
261
- } else if (mediaTab === "embed") {
262
- handleEmbedDone();
263
326
  }
264
327
  }, [
265
328
  mediaTab,
@@ -267,7 +330,6 @@ function MediaEditDialog({
267
330
  handleLibraryDone,
268
331
  handleCropSave,
269
332
  handleVideoDone,
270
- handleEmbedDone,
271
333
  onSave,
272
334
  alt,
273
335
  handleClose
@@ -290,10 +352,6 @@ function MediaEditDialog({
290
352
  /* @__PURE__ */ jsx(Film, { className: "size-3.5" }),
291
353
  "Video"
292
354
  ] }),
293
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "embed", children: [
294
- /* @__PURE__ */ jsx(Youtube, { className: "size-3.5" }),
295
- "YouTube"
296
- ] }),
297
355
  /* @__PURE__ */ jsx(TabsIndicator, {})
298
356
  ] }),
299
357
  /* @__PURE__ */ jsx(
@@ -327,48 +385,154 @@ function MediaEditDialog({
327
385
  TabsContent,
328
386
  {
329
387
  value: "adjust",
330
- className: "m-3 bg-muted rounded-lg animate-tabs flex flex-col",
388
+ className: "m-3 animate-tabs flex flex-col overflow-hidden rounded-lg",
331
389
  children: [
332
- /* @__PURE__ */ jsx("div", { className: "bg-muted relative h-64", children: /* @__PURE__ */ jsx(
390
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-t-lg bg-muted", children: /* @__PURE__ */ jsx(
333
391
  Cropper,
334
392
  {
335
- image: currentType === "image" ? initialData.src : "",
336
- crop,
337
- zoom,
338
- rotation,
339
- aspect: 16 / 9,
340
- onCropChange: setCrop,
341
- onZoomChange: setZoom,
342
- onRotationChange: setRotation,
343
- onCropComplete: (_, pixels) => setCroppedAreaPixels(pixels)
393
+ ref: cropperRef,
394
+ src: currentType === "image" ? `${initialData.src}${initialData.src.includes("?") ? "&" : "?"}_cors=1` : "",
395
+ crossOrigin: "anonymous",
396
+ stencilComponent: cropShape === "circle" ? CircleStencil : RectangleStencil,
397
+ stencilProps: {
398
+ aspectRatio,
399
+ grid: true
400
+ },
401
+ transitions: true
344
402
  }
345
403
  ) }),
346
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4 px-6 py-3", children: [
347
- /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
348
- /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500", children: "Zoom" }),
404
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-b-lg bg-muted/60 px-3 py-2", children: [
405
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
406
+ ASPECT_PRESETS.map((preset) => /* @__PURE__ */ jsx(
407
+ "button",
408
+ {
409
+ type: "button",
410
+ onClick: () => setAspectRatio(preset.value),
411
+ className: cn(
412
+ "rounded px-2 py-0.5 text-xs font-medium transition-colors",
413
+ aspectRatio === preset.value ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-accent"
414
+ ),
415
+ children: preset.label
416
+ },
417
+ preset.label
418
+ )),
419
+ /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }),
349
420
  /* @__PURE__ */ jsx(
350
- Slider,
421
+ "button",
351
422
  {
352
- className: "flex",
353
- value: [zoom],
354
- onValueChange: (vals) => setZoom(Array.isArray(vals) ? vals[0] ?? 1 : vals),
355
- min: 1,
356
- max: 3,
357
- step: 0.1
423
+ type: "button",
424
+ onClick: () => setCropShape("rect"),
425
+ className: cn(
426
+ "flex h-6 w-6 items-center justify-center rounded transition-colors",
427
+ cropShape === "rect" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-accent"
428
+ ),
429
+ title: "Rectangle",
430
+ children: /* @__PURE__ */ jsx(Square, { className: "size-3" })
431
+ }
432
+ ),
433
+ /* @__PURE__ */ jsx(
434
+ "button",
435
+ {
436
+ type: "button",
437
+ onClick: () => {
438
+ setCropShape("circle");
439
+ setAspectRatio(1);
440
+ },
441
+ className: cn(
442
+ "flex h-6 w-6 items-center justify-center rounded transition-colors",
443
+ cropShape === "circle" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-accent"
444
+ ),
445
+ title: "Circle",
446
+ children: /* @__PURE__ */ jsx(Circle, { className: "size-3" })
358
447
  }
359
448
  )
360
449
  ] }),
361
- /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
362
- /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500", children: "Rotation" }),
450
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 pt-1", children: [
451
+ /* @__PURE__ */ jsx(
452
+ "button",
453
+ {
454
+ type: "button",
455
+ onClick: () => {
456
+ var _a;
457
+ return (_a = cropperRef.current) == null ? void 0 : _a.flipImage(true, false);
458
+ },
459
+ className: "flex h-7 w-7 flex-none items-center justify-center rounded text-muted-foreground hover:bg-accent",
460
+ title: "Flip Horizontal",
461
+ children: /* @__PURE__ */ jsx(FlipHorizontal, { className: "size-3.5" })
462
+ }
463
+ ),
363
464
  /* @__PURE__ */ jsx(
364
- Slider,
465
+ "button",
365
466
  {
366
- className: "flex",
367
- value: [rotation],
368
- onValueChange: (vals) => setRotation(Array.isArray(vals) ? vals[0] ?? 0 : vals),
369
- min: 0,
370
- max: 360,
371
- step: 1
467
+ type: "button",
468
+ onClick: () => {
469
+ var _a, _b, _c;
470
+ if (adjustAngle > 0) {
471
+ (_a = cropperRef.current) == null ? void 0 : _a.rotateImage(-adjustAngle);
472
+ } else if (adjustAngle < 0) {
473
+ (_b = cropperRef.current) == null ? void 0 : _b.rotateImage(-90 - adjustAngle);
474
+ } else {
475
+ (_c = cropperRef.current) == null ? void 0 : _c.rotateImage(-90);
476
+ }
477
+ setAdjustAngle(0);
478
+ },
479
+ className: "flex h-7 w-7 flex-none items-center justify-center rounded text-muted-foreground hover:bg-accent",
480
+ title: "Rotate Left 90°",
481
+ children: /* @__PURE__ */ jsx(RotateCcw, { className: "size-3.5" })
482
+ }
483
+ ),
484
+ /* @__PURE__ */ jsx(
485
+ RotateBar,
486
+ {
487
+ value: adjustAngle,
488
+ onChange: (delta) => {
489
+ var _a;
490
+ (_a = cropperRef.current) == null ? void 0 : _a.rotateImage(delta, {
491
+ transitions: false,
492
+ interaction: true,
493
+ immediately: true
494
+ });
495
+ setAdjustAngle(
496
+ (prev) => Math.max(-45, Math.min(45, prev + delta))
497
+ );
498
+ },
499
+ onEnd: () => {
500
+ var _a, _b;
501
+ return (_b = (_a = cropperRef.current) == null ? void 0 : _a.transformImageEnd) == null ? void 0 : _b.call(_a);
502
+ }
503
+ }
504
+ ),
505
+ /* @__PURE__ */ jsx(
506
+ "button",
507
+ {
508
+ type: "button",
509
+ onClick: () => {
510
+ var _a, _b, _c;
511
+ if (adjustAngle > 0) {
512
+ (_a = cropperRef.current) == null ? void 0 : _a.rotateImage(90 - adjustAngle);
513
+ } else if (adjustAngle < 0) {
514
+ (_b = cropperRef.current) == null ? void 0 : _b.rotateImage(-adjustAngle);
515
+ } else {
516
+ (_c = cropperRef.current) == null ? void 0 : _c.rotateImage(90);
517
+ }
518
+ setAdjustAngle(0);
519
+ },
520
+ className: "flex h-7 w-7 flex-none items-center justify-center rounded text-muted-foreground hover:bg-accent",
521
+ title: "Rotate Right 90°",
522
+ children: /* @__PURE__ */ jsx(RotateCw, { className: "size-3.5" })
523
+ }
524
+ ),
525
+ /* @__PURE__ */ jsx(
526
+ "button",
527
+ {
528
+ type: "button",
529
+ onClick: () => {
530
+ var _a;
531
+ return (_a = cropperRef.current) == null ? void 0 : _a.flipImage(false, true);
532
+ },
533
+ className: "flex h-7 w-7 flex-none items-center justify-center rounded text-muted-foreground hover:bg-accent",
534
+ title: "Flip Vertical",
535
+ children: /* @__PURE__ */ jsx(FlipVertical, { className: "size-3.5" })
372
536
  }
373
537
  )
374
538
  ] })
@@ -466,12 +630,12 @@ function MediaEditDialog({
466
630
  /* @__PURE__ */ jsx(
467
631
  Input,
468
632
  {
469
- placeholder: "https://example.com/video.mp4",
633
+ placeholder: "https://example.com/video.mp4 or YouTube / Vimeo link",
470
634
  value: videoUrl,
471
635
  onChange: (e) => setVideoUrl(e.target.value)
472
636
  }
473
637
  ),
474
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Supports .mp4, .webm, .mov, .ogg direct links" })
638
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Supports .mp4, .webm, .mov, .ogg direct links and YouTube / Vimeo" })
475
639
  ] }),
476
640
  videoUrl.trim() && detectMediaType(videoUrl.trim()) === "video" && /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-md border bg-muted", children: /* @__PURE__ */ jsx(
477
641
  "video",
@@ -482,32 +646,11 @@ function MediaEditDialog({
482
646
  playsInline: true,
483
647
  className: "h-48 w-full object-contain"
484
648
  }
485
- ) })
486
- ]
487
- }
488
- ),
489
- /* @__PURE__ */ jsxs(
490
- TabsContent,
491
- {
492
- value: "embed",
493
- className: "animate-tabs flex-none h-[360px] flex flex-col gap-4 px-6 py-6",
494
- children: [
495
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
496
- /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: "YouTube / Vimeo URL" }),
497
- /* @__PURE__ */ jsx(
498
- Input,
499
- {
500
- placeholder: "https://www.youtube.com/watch?v=...",
501
- value: embedUrl,
502
- onChange: (e) => setEmbedUrl(e.target.value)
503
- }
504
- ),
505
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Paste a YouTube or Vimeo link" })
506
- ] }),
507
- embedUrl.trim() && detectMediaType(embedUrl.trim()) === "embed" && /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-md border bg-muted", children: /* @__PURE__ */ jsx(
649
+ ) }),
650
+ videoUrl.trim() && detectMediaType(videoUrl.trim()) === "embed" && /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-md border bg-muted", children: /* @__PURE__ */ jsx(
508
651
  "iframe",
509
652
  {
510
- src: getEmbedUrl(embedUrl.trim()),
653
+ src: getEmbedUrl(videoUrl.trim()),
511
654
  className: "h-48 w-full",
512
655
  allow: "autoplay; fullscreen",
513
656
  allowFullScreen: true
@@ -3,11 +3,11 @@ import { cn } from "../../../../utils/css-utils.js";
3
3
  import { SectionWrapper } from "../../../puck-core/section-wrapper.js";
4
4
  import { CompoundMedia } from "../../../puck-base/media.js";
5
5
  const columnsMap = {
6
- "1": "grid-cols-1",
7
- "2": "grid-cols-1 md:grid-cols-2",
8
- "3": "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
9
- "2-lg3": "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
10
- "2-lg4": "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
6
+ "1": "md:grid-cols-1",
7
+ "2": "md:grid-cols-2",
8
+ "3": "md:grid-cols-2 lg:grid-cols-3",
9
+ "2-lg3": "sm:grid-cols-2 lg:grid-cols-3",
10
+ "2-lg4": "sm:grid-cols-2 lg:grid-cols-4"
11
11
  };
12
12
  const StaticGrid = (props) => {
13
13
  const { heading, description, medias, styles } = {
@@ -25,11 +25,15 @@ const StaticGrid = (props) => {
25
25
  /* @__PURE__ */ jsx(
26
26
  "div",
27
27
  {
28
- className: cn("grid auto-cols-fr", gridCols, {
29
- "gap-8": hasGap,
30
- "gap-0": !hasGap
31
- }),
32
- children: medias.map((media, index) => /* @__PURE__ */ jsx("a", { href: "#", className: "size-full", children: /* @__PURE__ */ jsx("div", { className: "w-full overflow-hidden", children: /* @__PURE__ */ jsx(
28
+ className: cn(
29
+ "flex overflow-x-auto snap-x snap-mandatory scrollbar-hide md:grid md:auto-cols-fr md:overflow-visible",
30
+ gridCols,
31
+ {
32
+ "gap-4 md:gap-8": hasGap,
33
+ "gap-0": !hasGap
34
+ }
35
+ ),
36
+ children: medias.map((media, index) => /* @__PURE__ */ jsx("a", { href: "#", className: "w-[75vw] flex-none snap-start md:w-auto md:flex-1", children: /* @__PURE__ */ jsx("div", { className: "w-full overflow-hidden", children: /* @__PURE__ */ jsx(
33
37
  CompoundMedia,
34
38
  {
35
39
  src: media.src,
@@ -35,6 +35,7 @@ const BentoTestimonial = (props) => {
35
35
  {
36
36
  className: `grid grid-cols-1 gap-6 sm:grid-rows-6 md:grid-cols-2 md:gap-8 lg:grid-cols-4 ${gridRowsClass}`,
37
37
  children: testimonialCards.map((card, index) => {
38
+ var _a, _b, _c, _d, _e, _f;
38
39
  if (card.component === "background" && hasBackgroundCards) {
39
40
  backgroundImageCardCount++;
40
41
  return /* @__PURE__ */ jsxs(
@@ -59,9 +60,9 @@ const BentoTestimonial = (props) => {
59
60
  /* @__PURE__ */ jsx(
60
61
  CompoundMedia,
61
62
  {
62
- src: card.props.media.src,
63
+ src: (_a = card.props.media) == null ? void 0 : _a.src,
63
64
  className: "size-full object-cover",
64
- alt: card.props.media.alt
65
+ alt: (_b = card.props.media) == null ? void 0 : _b.alt
65
66
  }
66
67
  ),
67
68
  /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/50" })
@@ -84,8 +85,8 @@ const BentoTestimonial = (props) => {
84
85
  children: /* @__PURE__ */ jsx(
85
86
  CompoundMedia,
86
87
  {
87
- src: card.props.media.src,
88
- alt: card.props.media.alt,
88
+ src: (_c = card.props.media) == null ? void 0 : _c.src,
89
+ alt: (_d = card.props.media) == null ? void 0 : _d.alt,
89
90
  className: "max-h-16"
90
91
  }
91
92
  )
@@ -104,8 +105,8 @@ const BentoTestimonial = (props) => {
104
105
  /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
105
106
  CompoundMedia,
106
107
  {
107
- src: card.props.media.src,
108
- alt: card.props.media.alt,
108
+ src: (_e = card.props.media) == null ? void 0 : _e.src,
109
+ alt: (_f = card.props.media) == null ? void 0 : _f.alt,
109
110
  className: "mb-4 size-12 min-h-12 min-w-12 rounded-full object-cover md:mb-0 md:mr-4"
110
111
  }
111
112
  ) }),