dune-react 0.0.15 → 0.0.18

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 (34) hide show
  1. package/dist/components/puck-base/button.js +1 -1
  2. package/dist/components/puck-base/core/fields.d.ts +33 -10
  3. package/dist/components/puck-base/core/fields.js +27 -3
  4. package/dist/components/puck-base/core/styles.d.ts +1 -5
  5. package/dist/components/puck-base/core/styles.js +1 -5
  6. package/dist/components/puck-base/core/with-editable.js +33 -21
  7. package/dist/components/puck-base/editor-context.d.ts +2 -0
  8. package/dist/components/puck-base/fields/action-field.js +19 -43
  9. package/dist/components/puck-base/fields/auto-field.js +27 -214
  10. package/dist/components/puck-base/fields/color-field.d.ts +6 -0
  11. package/dist/components/puck-base/fields/color-field.js +37 -0
  12. package/dist/components/puck-base/fields/index.d.ts +8 -0
  13. package/dist/components/puck-base/fields/location-field.d.ts +44 -0
  14. package/dist/components/puck-base/fields/location-field.js +207 -0
  15. package/dist/components/puck-base/fields/object-field.d.ts +8 -0
  16. package/dist/components/puck-base/fields/object-field.js +30 -0
  17. package/dist/components/puck-base/fields/radio-toggle-field.d.ts +10 -0
  18. package/dist/components/puck-base/fields/radio-toggle-field.js +53 -0
  19. package/dist/components/puck-base/fields/virtualized-select-field.d.ts +13 -0
  20. package/dist/components/puck-base/fields/virtualized-select-field.js +146 -0
  21. package/dist/components/puck-base/image.js +175 -104
  22. package/dist/components/puck-base/index.d.ts +2 -3
  23. package/dist/components/puck-block/location-sections/location-1/index.js +17 -22
  24. package/dist/components/puck-block/location-sections/location-1/location.d.ts +5 -7
  25. package/dist/components/puck-block/location-sections/location-1/location.js +15 -12
  26. package/dist/components/puck-block/location-sections/location-2/index.js +28 -24
  27. package/dist/components/puck-block/location-sections/location-2/location.d.ts +6 -8
  28. package/dist/components/puck-block/location-sections/location-2/location.js +18 -15
  29. package/dist/components/puck-block/location-sections/location-3/index.js +43 -20
  30. package/dist/components/puck-block/location-sections/location-3/location.d.ts +5 -6
  31. package/dist/components/puck-block/location-sections/location-3/location.js +96 -86
  32. package/dist/components/puck-block/location-sections/props.d.ts +9 -10
  33. package/dist/components/shadcn/slider.js +4 -1
  34. package/package.json +4 -2
@@ -33,7 +33,11 @@ const getCroppedImg = async (imageSrc, pixelCrop, rotation) => {
33
33
  ctx.translate(safeArea / 2, safeArea / 2);
34
34
  ctx.rotate(rotation * Math.PI / 180);
35
35
  ctx.translate(-safeArea / 2, -safeArea / 2);
36
- ctx.drawImage(image2, safeArea / 2 - image2.width * 0.5, safeArea / 2 - image2.height * 0.5);
36
+ ctx.drawImage(
37
+ image2,
38
+ safeArea / 2 - image2.width * 0.5,
39
+ safeArea / 2 - image2.height * 0.5
40
+ );
37
41
  const data = ctx.getImageData(0, 0, safeArea, safeArea);
38
42
  canvas.width = pixelCrop.width;
39
43
  canvas.height = pixelCrop.height;
@@ -48,7 +52,14 @@ const getCroppedImg = async (imageSrc, pixelCrop, rotation) => {
48
52
  };
49
53
  const DEFAULT_LIBRARY_IMAGES = [];
50
54
  function CompoundImageBase(props) {
51
- return /* @__PURE__ */ jsx("img", { src: props.src, alt: props.alt, className: cn("block h-full w-full object-cover", props.className) });
55
+ return /* @__PURE__ */ jsx(
56
+ "img",
57
+ {
58
+ src: props.src,
59
+ alt: props.alt,
60
+ className: cn("block h-full w-full object-cover", props.className)
61
+ }
62
+ );
52
63
  }
53
64
  function ImageEditDialog({
54
65
  open,
@@ -58,7 +69,9 @@ function ImageEditDialog({
58
69
  }) {
59
70
  const [tab, setTab] = useState("library");
60
71
  const [alt, setAlt] = useState(initialData.alt ?? "");
61
- const [libraryImages, setLibraryImages] = useState(DEFAULT_LIBRARY_IMAGES);
72
+ const [libraryImages, setLibraryImages] = useState(
73
+ DEFAULT_LIBRARY_IMAGES
74
+ );
62
75
  const [isLoadingImages, setIsLoadingImages] = useState(false);
63
76
  const { fetchLibraryImages } = useEditorContext();
64
77
  useEffect(() => {
@@ -97,7 +110,11 @@ function ImageEditDialog({
97
110
  const handleCropSave = useCallback(async () => {
98
111
  if (!croppedAreaPixels || !initialData.src) return;
99
112
  try {
100
- const croppedBlob = await getCroppedImg(initialData.src, croppedAreaPixels, rotation);
113
+ const croppedBlob = await getCroppedImg(
114
+ initialData.src,
115
+ croppedAreaPixels,
116
+ rotation
117
+ );
101
118
  const file = new File([croppedBlob], "cropped-image.jpg", {
102
119
  type: "image/jpeg"
103
120
  });
@@ -122,112 +139,166 @@ function ImageEditDialog({
122
139
  }, [selectedImg, alt, onSave, handleClose]);
123
140
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (o) => !o && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "flex max-h-[80vh] max-w-lg flex-col gap-0 overflow-hidden p-0", children: [
124
141
  /* @__PURE__ */ jsx(DialogHeader, { className: "px-6 pt-5 pb-0", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-base font-semibold", children: "Edit Image" }) }),
125
- /* @__PURE__ */ jsxs(Tabs, { value: tab, onValueChange: (v) => setTab(v), className: "flex flex-1 flex-col overflow-hidden", children: [
126
- /* @__PURE__ */ jsxs(TabsList, { className: "mx-6 mt-3 bg-transparent", children: [
127
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "adjust", children: [
128
- /* @__PURE__ */ jsx(Pencil, {}),
129
- "Crop"
130
- ] }),
131
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "library", children: [
132
- /* @__PURE__ */ jsx(Search, {}),
133
- "Library"
134
- ] }),
135
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "upload", children: [
136
- /* @__PURE__ */ jsx(Upload, {}),
137
- "Upload"
138
- ] })
139
- ] }),
140
- /* @__PURE__ */ jsxs("div", { className: "mt-3 flex-1 overflow-hidden", children: [
141
- /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", tab !== "adjust" && "hidden"), children: [
142
- /* @__PURE__ */ jsx("div", { className: "bg-muted relative h-64", children: /* @__PURE__ */ jsx(
143
- Cropper,
144
- {
145
- image: initialData.src,
146
- crop,
147
- zoom,
148
- rotation,
149
- aspect: 16 / 9,
150
- onCropChange: setCrop,
151
- onZoomChange: setZoom,
152
- onRotationChange: setRotation,
153
- onCropComplete: (_, pixels) => setCroppedAreaPixels(pixels)
154
- }
155
- ) }),
156
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4 px-6 py-3", children: [
157
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
158
- /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500", children: "Zoom" }),
159
- /* @__PURE__ */ jsx(Slider, { value: [zoom], onValueChange: (vals) => setZoom(Array.isArray(vals) ? vals[0] ?? 1 : vals), min: 1, max: 3, step: 0.1 })
142
+ /* @__PURE__ */ jsxs(
143
+ Tabs,
144
+ {
145
+ value: tab,
146
+ onValueChange: (v) => setTab(v),
147
+ className: "flex flex-1 flex-col overflow-hidden",
148
+ children: [
149
+ /* @__PURE__ */ jsxs(TabsList, { className: "mx-6 mt-3 bg-transparent", children: [
150
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "adjust", children: [
151
+ /* @__PURE__ */ jsx(Pencil, {}),
152
+ "Crop"
153
+ ] }),
154
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "library", children: [
155
+ /* @__PURE__ */ jsx(Search, {}),
156
+ "Library"
160
157
  ] }),
161
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
162
- /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500", children: "Rotation" }),
163
- /* @__PURE__ */ jsx(Slider, { value: [rotation], onValueChange: (vals) => setRotation(Array.isArray(vals) ? vals[0] ?? 0 : vals), min: 0, max: 360, step: 1 })
158
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "upload", children: [
159
+ /* @__PURE__ */ jsx(Upload, {}),
160
+ "Upload"
164
161
  ] })
165
- ] })
166
- ] }),
167
- /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-3 px-6 py-4", tab !== "library" && "hidden"), children: /* @__PURE__ */ jsx(ScrollArea, { className: "h-[280px]", children: isLoadingImages ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center py-20", children: /* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin text-gray-400" }) }) : libraryImages.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center py-20 text-center", children: [
168
- /* @__PURE__ */ jsx(Search, { className: "h-8 w-8 text-gray-300" }),
169
- /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm font-medium text-gray-500", children: "No images available" }),
170
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-400", children: "Try uploading an image instead" })
171
- ] }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2", children: libraryImages.map((src) => {
172
- const isSelected = selectedImg === src;
173
- return /* @__PURE__ */ jsxs(
174
- "button",
175
- {
176
- type: "button",
177
- onClick: () => setSelectedImg(src),
178
- className: `relative aspect-4/3 overflow-hidden rounded-lg border-2 transition-all ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-transparent hover:border-gray-300"}`,
179
- children: [
180
- /* @__PURE__ */ jsx("img", { src, alt: "", className: "h-full w-full object-cover" }),
181
- isSelected && /* @__PURE__ */ jsx("div", { className: "absolute top-1.5 right-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-blue-500 shadow-sm", children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 text-white" }) })
182
- ]
183
- },
184
- src
185
- );
186
- }) }) }) }),
187
- /* @__PURE__ */ jsxs(
188
- "div",
189
- {
190
- className: cn("flex flex-col items-center justify-center gap-4 px-6 py-14", tab !== "upload" && "hidden"),
191
- children: [
192
- /* @__PURE__ */ jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-gray-100", children: /* @__PURE__ */ jsx(Upload, { className: "h-6 w-6 text-gray-400" }) }),
193
- /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
194
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: "Upload a new image to replace the current one" }),
195
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-400", children: "Supports JPG, PNG, WebP formats" })
196
- ] }),
197
- /* @__PURE__ */ jsxs(
198
- Button,
162
+ ] }),
163
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex-1 overflow-hidden", children: [
164
+ /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", tab !== "adjust" && "hidden"), children: [
165
+ /* @__PURE__ */ jsx("div", { className: "bg-muted relative h-64", children: /* @__PURE__ */ jsx(
166
+ Cropper,
199
167
  {
200
- variant: "outline",
201
- size: "sm",
202
- onClick: () => {
203
- var _a;
204
- return (_a = replaceInputRef.current) == null ? void 0 : _a.click();
205
- },
206
- disabled: isReplaceUploading,
207
- children: [
208
- isReplaceUploading ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Upload, { className: "mr-1.5 h-3.5 w-3.5" }),
209
- "Choose File"
210
- ]
168
+ image: initialData.src,
169
+ crop,
170
+ zoom,
171
+ rotation,
172
+ aspect: 16 / 9,
173
+ onCropChange: setCrop,
174
+ onZoomChange: setZoom,
175
+ onRotationChange: setRotation,
176
+ onCropComplete: (_, pixels) => setCroppedAreaPixels(pixels)
211
177
  }
212
- ),
213
- /* @__PURE__ */ jsx(
214
- "input",
215
- {
216
- ref: replaceInputRef,
217
- type: "file",
218
- accept: "image/*",
219
- onChange: handleFileReplace,
220
- className: "hidden"
221
- }
222
- )
223
- ]
224
- }
225
- )
226
- ] })
227
- ] }),
178
+ ) }),
179
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4 px-6 py-3", children: [
180
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
181
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500", children: "Zoom" }),
182
+ /* @__PURE__ */ jsx(
183
+ Slider,
184
+ {
185
+ className: "flex",
186
+ value: [zoom],
187
+ onValueChange: (vals) => setZoom(Array.isArray(vals) ? vals[0] ?? 1 : vals),
188
+ min: 1,
189
+ max: 3,
190
+ step: 0.1
191
+ }
192
+ )
193
+ ] }),
194
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
195
+ /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-gray-500", children: "Rotation" }),
196
+ /* @__PURE__ */ jsx(
197
+ Slider,
198
+ {
199
+ className: "flex",
200
+ value: [rotation],
201
+ onValueChange: (vals) => setRotation(Array.isArray(vals) ? vals[0] ?? 0 : vals),
202
+ min: 0,
203
+ max: 360,
204
+ step: 1
205
+ }
206
+ )
207
+ ] })
208
+ ] })
209
+ ] }),
210
+ /* @__PURE__ */ jsx(
211
+ "div",
212
+ {
213
+ className: cn(
214
+ "flex flex-col gap-3 px-6 py-4",
215
+ tab !== "library" && "hidden"
216
+ ),
217
+ children: /* @__PURE__ */ jsx(ScrollArea, { className: "h-[280px]", children: isLoadingImages ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center py-20", children: /* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin text-gray-400" }) }) : libraryImages.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center py-20 text-center", children: [
218
+ /* @__PURE__ */ jsx(Search, { className: "h-8 w-8 text-gray-300" }),
219
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm font-medium text-gray-500", children: "No images available" }),
220
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-400", children: "Try uploading an image instead" })
221
+ ] }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2", children: libraryImages.map((src) => {
222
+ const isSelected = selectedImg === src;
223
+ return /* @__PURE__ */ jsxs(
224
+ "button",
225
+ {
226
+ type: "button",
227
+ onClick: () => setSelectedImg(src),
228
+ className: `relative aspect-4/3 overflow-hidden rounded-lg border-2 transition-all ${isSelected ? "border-blue-500 ring-2 ring-blue-100" : "border-transparent hover:border-gray-300"}`,
229
+ children: [
230
+ /* @__PURE__ */ jsx(
231
+ "img",
232
+ {
233
+ src,
234
+ alt: "",
235
+ className: "h-full w-full object-cover"
236
+ }
237
+ ),
238
+ isSelected && /* @__PURE__ */ jsx("div", { className: "absolute top-1.5 right-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-blue-500 shadow-sm", children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 text-white" }) })
239
+ ]
240
+ },
241
+ src
242
+ );
243
+ }) }) })
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsxs(
247
+ "div",
248
+ {
249
+ className: cn(
250
+ "flex flex-col items-center justify-center gap-4 px-6 py-14",
251
+ tab !== "upload" && "hidden"
252
+ ),
253
+ children: [
254
+ /* @__PURE__ */ jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-gray-100", children: /* @__PURE__ */ jsx(Upload, { className: "h-6 w-6 text-gray-400" }) }),
255
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
256
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: "Upload a new image to replace the current one" }),
257
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-gray-400", children: "Supports JPG, PNG, WebP formats" })
258
+ ] }),
259
+ /* @__PURE__ */ jsxs(
260
+ Button,
261
+ {
262
+ variant: "outline",
263
+ size: "sm",
264
+ onClick: () => {
265
+ var _a;
266
+ return (_a = replaceInputRef.current) == null ? void 0 : _a.click();
267
+ },
268
+ disabled: isReplaceUploading,
269
+ children: [
270
+ isReplaceUploading ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Upload, { className: "mr-1.5 h-3.5 w-3.5" }),
271
+ "Choose File"
272
+ ]
273
+ }
274
+ ),
275
+ /* @__PURE__ */ jsx(
276
+ "input",
277
+ {
278
+ ref: replaceInputRef,
279
+ type: "file",
280
+ accept: "image/*",
281
+ onChange: handleFileReplace,
282
+ className: "hidden"
283
+ }
284
+ )
285
+ ]
286
+ }
287
+ )
288
+ ] })
289
+ ]
290
+ }
291
+ ),
228
292
  /* @__PURE__ */ jsx("div", { className: "border-t px-6 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
229
293
  /* @__PURE__ */ jsx(Label, { className: "flex-none", children: "Alt Text" }),
230
- /* @__PURE__ */ jsx(Input, { value: alt, onChange: (e) => setAlt(e.target.value), placeholder: "Image description..." })
294
+ /* @__PURE__ */ jsx(
295
+ Input,
296
+ {
297
+ value: alt,
298
+ onChange: (e) => setAlt(e.target.value),
299
+ placeholder: "Image description..."
300
+ }
301
+ )
231
302
  ] }) }),
232
303
  /* @__PURE__ */ jsxs(DialogFooter, { className: "border-t px-6 py-3", children: [
233
304
  /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleClose, children: "Cancel" }),
@@ -8,7 +8,7 @@ export { CompoundForm, type CompoundFormProps, formMethods, type FormMethods } f
8
8
  export { CompoundImage, type CompoundImageProps } from "./image";
9
9
  export { CompoundArticleCard, type CompoundArticleCardProps } from "./article-card";
10
10
  export { ImageUploadField } from "./image-upload-field";
11
- export { ActionField, ACTION_TYPE_FIELD_MAP, ACTION_TYPE_OPTIONS, PageActionFields, ExternalActionFields, EmailActionFields, PhoneActionFields, SectionActionFields, DownloadActionFields, type ActionTypeFieldProps, } from "./fields/action-field";
11
+ export { ActionField, ACTION_TYPE_FIELD_MAP, ACTION_TYPE_OPTIONS, PageActionFields, ExternalActionFields, EmailActionFields, PhoneActionFields, SectionActionFields, DownloadActionFields, type ActionTypeFieldProps, } from "./fields";
12
12
  export { ErrorBoundary } from "./error-boundary";
13
13
  export { GradientText, type GradientTextProps } from "./gradient-text";
14
14
  export { InlineEditable } from "./inline-editable";
@@ -18,6 +18,5 @@ export { usePuckDispatch, usePuckAppState, usePuckHistory, usePuckConfig, usePuc
18
18
  export { findComponentById, getRandomAdjective } from "./core/utils";
19
19
  export { icon, action, actionDefaults, button, buttons, badge, image, images, padding, paddingDefaults, paddingLevel, heading, description, features, contentFields, contentFieldsWithFeatures, card, cards, field, fieldDefaults, form, formDefaults, getPlaceholderImageUrl, image16x9Placeholder, image1x1Placeholder, image9x16Placeholder, sectionStyle, sectionOverlay, backgroundColor, backgroundImage, } from "./core/fields";
20
20
  export { EditorContextProvider, useEditorContext } from "./editor-context";
21
- export { AutoField } from "./fields/auto-field";
22
- export { type FieldDef, type AutoFieldProps, type FieldsPanelProps } from "./fields/types";
21
+ export { AutoField, type FieldDef, type AutoFieldProps, type FieldsPanelProps } from "./fields";
23
22
  export { default as useUpload, type UploadFileItem, type UploadStatus, type UseUploadOptions } from "./use-upload";
@@ -1,4 +1,4 @@
1
- import { button } from "../../../puck-base/core/fields.js";
1
+ import { locationDefaults, button, location } from "../../../puck-base/core/fields.js";
2
2
  import { LocationSection } from "./location.js";
3
3
  import { createStylesDefaults, createStylesField } from "../../../puck-base/core/styles.js";
4
4
  const locationButtonFields = {
@@ -40,26 +40,24 @@ const conf = {
40
40
  { label: "Map Left / Text Right", value: "right" }
41
41
  ]
42
42
  },
43
- mapEmbedUrl: { type: "text", label: "Google Map Embed URL" },
44
- mapTitle: { type: "text", label: "Map Title" },
45
- mapFilter: { type: "text", label: "Map Filter (CSS)" },
46
- mapTintMode: {
47
- type: "select",
48
- label: "Map Tint Mode",
43
+ location,
44
+ mapStyle: {
45
+ type: "radio",
46
+ label: "Map Style",
47
+ options: [
48
+ { label: "Default", value: "default" },
49
+ { label: "Grayscale", value: "grayscale" },
50
+ { label: "Dark", value: "dark" }
51
+ ]
52
+ },
53
+ mapTint: {
54
+ type: "radio",
55
+ label: "Map Tint",
49
56
  options: [
50
57
  { label: "Theme", value: "theme" },
51
- { label: "Custom", value: "custom" },
52
58
  { label: "None", value: "none" }
53
59
  ]
54
60
  },
55
- mapTintColor: { type: "text", label: "Map Tint Color" },
56
- mapTintOpacity: {
57
- type: "number",
58
- label: "Map Tint Opacity",
59
- min: 0,
60
- max: 1,
61
- step: 0.01
62
- },
63
61
  buttons: {
64
62
  type: "array",
65
63
  max: 3,
@@ -74,12 +72,9 @@ const conf = {
74
72
  description: "We have offices around the globe. Visit us or get in touch with a local team near you.",
75
73
  contentAlign: "left",
76
74
  contentPosition: "left",
77
- mapEmbedUrl: "https://maps.google.com/maps?q=San%20Francisco%2C%20California%2C%20United%20States&z=13&t=m&output=embed",
78
- mapTitle: "Google Maps",
79
- mapFilter: "grayscale(45%) contrast(1.06) brightness(0.98) saturate(0.9)",
80
- mapTintMode: "theme",
81
- mapTintColor: "var(--primary)",
82
- mapTintOpacity: 0.21,
75
+ location: locationDefaults,
76
+ mapStyle: "grayscale",
77
+ mapTint: "theme",
83
78
  buttons: [
84
79
  {
85
80
  label: "Contact us",
@@ -1,5 +1,6 @@
1
1
  import { CompoundContainerProps } from "@/components/puck-base/container";
2
2
  import { CompoundButtonProps } from "@/components/puck-base/button";
3
+ import type { MapLocation } from "@/components/puck-base/core/fields";
3
4
  interface LocationButton extends Omit<CompoundButtonProps, "label"> {
4
5
  label?: string;
5
6
  url?: string;
@@ -12,12 +13,9 @@ export interface LocationSectionProps {
12
13
  description?: string;
13
14
  contentAlign?: "left" | "right";
14
15
  contentPosition?: "left" | "right";
15
- mapEmbedUrl?: string;
16
- mapTitle?: string;
17
- mapFilter?: string;
18
- mapTintMode?: "theme" | "custom" | "none";
19
- mapTintColor?: string;
20
- mapTintOpacity?: number;
16
+ location?: MapLocation;
17
+ mapStyle?: "default" | "grayscale" | "dark";
18
+ mapTint?: "none" | "theme";
21
19
  buttons?: LocationButton[];
22
20
  styles?: {
23
21
  padding?: CompoundContainerProps["padding"];
@@ -25,5 +23,5 @@ export interface LocationSectionProps {
25
23
  backgroundColor?: string;
26
24
  };
27
25
  }
28
- export declare const LocationSection: ({ heading, description, contentAlign, contentPosition, mapEmbedUrl, mapTitle, mapFilter, mapTintMode, mapTintColor, mapTintOpacity, buttons, styles, }: LocationSectionProps) => import("react/jsx-runtime").JSX.Element;
26
+ export declare const LocationSection: ({ heading, description, contentAlign, contentPosition, location: loc, mapStyle, mapTint, buttons, styles, }: LocationSectionProps) => import("react/jsx-runtime").JSX.Element;
29
27
  export {};
@@ -2,6 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { CompoundContainer } from "../../../puck-base/container.js";
3
3
  import { CompoundButton } from "../../../puck-base/button.js";
4
4
  import { cn } from "../../../../utils/css-utils.js";
5
+ import { getMapEmbedUrl } from "../../../puck-base/core/fields.js";
5
6
  const LocationActionButton = ({
6
7
  label,
7
8
  url,
@@ -35,24 +36,27 @@ const LocationActionButton = ({
35
36
  }
36
37
  ) });
37
38
  };
39
+ const MAP_STYLE_FILTERS = {
40
+ default: "",
41
+ grayscale: "grayscale(45%) contrast(1.06) brightness(0.98) saturate(0.9)",
42
+ dark: "grayscale(100%) invert(1) contrast(1.1) brightness(0.8)"
43
+ };
38
44
  const LocationSection = ({
39
45
  heading,
40
46
  description,
41
47
  contentAlign = "left",
42
48
  contentPosition = "left",
43
- mapEmbedUrl,
44
- mapTitle = "Google Maps",
45
- mapFilter,
46
- mapTintMode = "theme",
47
- mapTintColor,
48
- mapTintOpacity = 0.2,
49
+ location: loc,
50
+ mapStyle = "default",
51
+ mapTint = "theme",
49
52
  buttons = [],
50
53
  styles
51
54
  }) => {
52
55
  const isTextRight = contentAlign === "right";
53
56
  const isContentRight = contentPosition === "right";
54
- const showMapTint = mapTintMode !== "none" && mapTintOpacity > 0;
55
- const mapTintBackgroundColor = mapTintMode === "custom" ? mapTintColor || void 0 : void 0;
57
+ const showMapTint = mapTint === "theme";
58
+ const mapEmbedUrl = loc && loc.lat !== 0 ? getMapEmbedUrl(loc) : void 0;
59
+ const mapFilter = MAP_STYLE_FILTERS[mapStyle] || "";
56
60
  return /* @__PURE__ */ jsx(
57
61
  CompoundContainer,
58
62
  {
@@ -105,12 +109,12 @@ const LocationSection = ({
105
109
  "iframe",
106
110
  {
107
111
  src: mapEmbedUrl,
108
- title: mapTitle,
112
+ title: (loc == null ? void 0 : loc.address) || "Google Maps",
109
113
  className: "h-full w-full border-0",
110
114
  loading: "lazy",
111
115
  referrerPolicy: "no-referrer-when-downgrade",
112
116
  allowFullScreen: true,
113
- style: { filter: mapFilter }
117
+ style: mapFilter ? { filter: mapFilter } : void 0
114
118
  }
115
119
  ) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center bg-muted text-muted-foreground", children: "Map address not configured" }),
116
120
  showMapTint ? /* @__PURE__ */ jsx(
@@ -118,8 +122,7 @@ const LocationSection = ({
118
122
  {
119
123
  className: "bg-primary pointer-events-none absolute inset-0",
120
124
  style: {
121
- backgroundColor: mapTintBackgroundColor,
122
- opacity: mapTintOpacity,
125
+ opacity: 0.2,
123
126
  mixBlendMode: "color"
124
127
  }
125
128
  }
@@ -1,4 +1,4 @@
1
- import { button } from "../../../puck-base/core/fields.js";
1
+ import { button, location } from "../../../puck-base/core/fields.js";
2
2
  import { Location2 } from "./location.js";
3
3
  import { createStylesDefaults, createStylesField } from "../../../puck-base/core/styles.js";
4
4
  const locationButtonFields = {
@@ -43,7 +43,11 @@ const conf = {
43
43
  fields: {
44
44
  heading: { type: "textarea", contentEditable: true },
45
45
  description: { type: "textarea", contentEditable: true },
46
- address: { type: "textarea", label: "Address", contentEditable: true },
46
+ displayAddress: {
47
+ type: "textarea",
48
+ label: "Display Address",
49
+ contentEditable: true
50
+ },
47
51
  contentPosition: {
48
52
  type: "radio",
49
53
  label: "Card Position",
@@ -52,26 +56,24 @@ const conf = {
52
56
  { label: "Right", value: "right" }
53
57
  ]
54
58
  },
55
- mapEmbedUrl: { type: "text", label: "Google Map Embed URL" },
56
- mapTitle: { type: "text", label: "Map Title" },
57
- mapFilter: { type: "text", label: "Map Filter (CSS)" },
58
- mapTintMode: {
59
- type: "select",
59
+ location,
60
+ mapStyle: {
61
+ type: "radio",
62
+ label: "Map Style",
63
+ options: [
64
+ { label: "Default", value: "default" },
65
+ { label: "Grayscale", value: "grayscale" },
66
+ { label: "Dark", value: "dark" }
67
+ ]
68
+ },
69
+ mapTint: {
70
+ type: "radio",
60
71
  label: "Map Tint",
61
72
  options: [
62
73
  { label: "None", value: "none" },
63
- { label: "Theme", value: "theme" },
64
- { label: "Custom", value: "custom" }
74
+ { label: "Theme", value: "theme" }
65
75
  ]
66
76
  },
67
- mapTintColor: { type: "text", label: "Map Tint Color" },
68
- mapTintOpacity: {
69
- type: "number",
70
- label: "Map Tint Opacity",
71
- min: 0,
72
- max: 1,
73
- step: 0.01
74
- },
75
77
  buttons: {
76
78
  type: "array",
77
79
  max: 3,
@@ -84,14 +86,16 @@ const conf = {
84
86
  defaultProps: {
85
87
  heading: "Our Offices",
86
88
  description: "Visit our headquarters in London or reach out to one of our regional offices worldwide.",
87
- address: "10 Finsbury Square\nLondon, UK EC2A 1AF",
89
+ displayAddress: "10 Finsbury Square\nLondon, UK EC2A 1AF",
88
90
  contentPosition: "left",
89
- mapEmbedUrl: "https://maps.google.com/maps?q=London%2C%20United%20Kingdom&z=13&t=m&output=embed",
90
- mapTitle: "Google Maps",
91
- mapFilter: "grayscale(40%) contrast(1.05) brightness(1.0) saturate(0.85)",
92
- mapTintMode: "none",
93
- mapTintColor: "var(--primary)",
94
- mapTintOpacity: 0.15,
91
+ location: {
92
+ address: "London, United Kingdom",
93
+ lat: 51.5074,
94
+ lng: -0.1278,
95
+ zoom: 13
96
+ },
97
+ mapStyle: "grayscale",
98
+ mapTint: "none",
95
99
  buttons: [
96
100
  {
97
101
  label: "Get Directions",
@@ -1,5 +1,6 @@
1
1
  import { CompoundContainerProps } from "@/components/puck-base/container";
2
2
  import { CompoundButtonProps } from "@/components/puck-base/button";
3
+ import type { MapLocation } from "@/components/puck-base/core/fields";
3
4
  interface LocationButton extends Omit<CompoundButtonProps, "label"> {
4
5
  label?: string;
5
6
  url?: string;
@@ -10,14 +11,11 @@ interface LocationButton extends Omit<CompoundButtonProps, "label"> {
10
11
  export interface Location2Props {
11
12
  heading?: string;
12
13
  description?: string;
13
- address?: string;
14
+ displayAddress?: string;
14
15
  contentPosition?: "left" | "right";
15
- mapEmbedUrl?: string;
16
- mapTitle?: string;
17
- mapFilter?: string;
18
- mapTintMode?: "none" | "theme" | "custom";
19
- mapTintColor?: string;
20
- mapTintOpacity?: number;
16
+ location?: MapLocation;
17
+ mapStyle?: "default" | "grayscale" | "dark";
18
+ mapTint?: "none" | "theme";
21
19
  buttons?: LocationButton[];
22
20
  styles?: {
23
21
  padding?: CompoundContainerProps["padding"];
@@ -27,5 +25,5 @@ export interface Location2Props {
27
25
  sectionHeight?: "sm" | "md" | "lg";
28
26
  };
29
27
  }
30
- export declare const Location2: ({ heading, description, address, contentPosition, mapEmbedUrl, mapTitle, mapFilter, mapTintMode, mapTintColor, mapTintOpacity, buttons, styles, }: Location2Props) => import("react/jsx-runtime").JSX.Element;
28
+ export declare const Location2: ({ heading, description, displayAddress, contentPosition, location: loc, mapStyle, mapTint, buttons, styles, }: Location2Props) => import("react/jsx-runtime").JSX.Element;
31
29
  export {};