dune-react 0.0.16 → 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.
@@ -801,4 +801,27 @@ export declare const form: {
801
801
  };
802
802
  };
803
803
  export declare const formDefaults: CompoundFormProps;
804
+ /** 地图定位的核心数据:地址 + 坐标 */
805
+ export interface MapLocation {
806
+ /** 用户可读的完整地址(显示 & 搜索用) */
807
+ address: string;
808
+ /** 纬度 */
809
+ lat: number;
810
+ /** 经度 */
811
+ lng: number;
812
+ /** 地图缩放级别,默认 14 */
813
+ zoom?: number;
814
+ /** Google Place ID(可选,便于精确定位) */
815
+ placeId?: string;
816
+ }
817
+ /** 从 MapLocation 生成 Google Maps embed URL */
818
+ export declare function getMapEmbedUrl(loc: MapLocation): string;
819
+ /** 从 MapLocation 生成 Google Maps 导航 URL */
820
+ export declare function getDirectionsUrl(loc: MapLocation): string;
821
+ export declare const locationDefaults: MapLocation;
822
+ export declare const location: {
823
+ type: "custom";
824
+ label: string;
825
+ render: any;
826
+ };
804
827
  export * from "./styles";
@@ -1,7 +1,7 @@
1
1
  import { fieldTypes } from "../field.js";
2
2
  import { ActionField } from "../fields/action-field.js";
3
3
  import { IconPickerField } from "../icon-picker-field.js";
4
- import { backgroundColor, backgroundImage, bannerStylesDefaults, bannerStylesField, createStylesDefaults, createStylesField, heroStylesDefaults, padding, paddingDefaults, paddingLevel, sectionBaseStyleDefaults, sectionBaseStyleFields, sectionOverlay, sectionStyle } from "./styles.js";
4
+ import { LocationField } from "../fields/location-field.js";
5
5
  const formMethods = ["get", "post", "put", "patch", "delete"];
6
6
  const icon = {
7
7
  type: "custom",
@@ -241,42 +241,51 @@ const formDefaults = {
241
241
  icon: "move-right"
242
242
  }
243
243
  };
244
+ function getMapEmbedUrl(loc) {
245
+ const { lat, lng, zoom = 14 } = loc;
246
+ return `https://maps.google.com/maps?q=${lat},${lng}&z=${zoom}&output=embed`;
247
+ }
248
+ function getDirectionsUrl(loc) {
249
+ return `https://www.google.com/maps/dir/?api=1&destination=${loc.lat},${loc.lng}`;
250
+ }
251
+ const locationDefaults = {
252
+ address: "San Francisco, CA, USA",
253
+ lat: 37.7749,
254
+ lng: -122.4194,
255
+ zoom: 13
256
+ };
257
+ const location = {
258
+ type: "custom",
259
+ label: "Location",
260
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
261
+ render: LocationField
262
+ };
244
263
  export {
245
264
  action,
246
265
  actionDefaults,
247
- backgroundColor,
248
- backgroundImage,
249
266
  badge,
250
- bannerStylesDefaults,
251
- bannerStylesField,
252
267
  button,
253
268
  buttons,
254
269
  card,
255
270
  cards,
256
271
  contentFields,
257
272
  contentFieldsWithFeatures,
258
- createStylesDefaults,
259
- createStylesField,
260
273
  description,
261
274
  features,
262
275
  field,
263
276
  fieldDefaults,
264
277
  form,
265
278
  formDefaults,
279
+ getDirectionsUrl,
280
+ getMapEmbedUrl,
266
281
  getPlaceholderImageUrl,
267
282
  heading,
268
- heroStylesDefaults,
269
283
  icon,
270
284
  image,
271
285
  image16x9Placeholder,
272
286
  image1x1Placeholder,
273
287
  image9x16Placeholder,
274
288
  images,
275
- padding,
276
- paddingDefaults,
277
- paddingLevel,
278
- sectionBaseStyleDefaults,
279
- sectionBaseStyleFields,
280
- sectionOverlay,
281
- sectionStyle
289
+ location,
290
+ locationDefaults
282
291
  };
@@ -1394,11 +1394,7 @@ export declare const contactStylesDefaults: {
1394
1394
  readonly bottom: "medium";
1395
1395
  };
1396
1396
  };
1397
- export interface LocationSectionStyles extends SectionBaseStyles {
1398
- mapHeight?: number;
1399
- mapFilter?: string;
1400
- mapTintColor?: string;
1401
- }
1397
+ export type LocationSectionStyles = SectionBaseStyles;
1402
1398
  export declare const locationStylesField: {
1403
1399
  type: "object";
1404
1400
  label: string;
@@ -216,11 +216,7 @@ createStylesField({
216
216
  }
217
217
  });
218
218
  createStylesDefaults();
219
- createStylesField({
220
- mapHeight: { type: "number", label: "Map Height", min: 200, max: 800 },
221
- mapFilter: { type: "text", label: "Map Filter (CSS)" },
222
- mapTintColor: { type: "text", label: "Map Tint Color" }
223
- });
219
+ createStylesField();
224
220
  createStylesDefaults();
225
221
  createStylesField();
226
222
  createStylesDefaults();
@@ -17,6 +17,8 @@ type EditorContextValue = {
17
17
  domain?: string;
18
18
  /** 站内可选页面列表,用于 url 字段快捷选择 */
19
19
  sitePages?: SitePage[];
20
+ /** Google Maps API Key,用于 LocationField 地址搜索 */
21
+ googleMapsApiKey?: string;
20
22
  };
21
23
  export declare const EditorContextProvider: import("react").Provider<EditorContextValue>;
22
24
  export declare const useEditorContext: () => EditorContextValue;
@@ -4,4 +4,5 @@ export { ColorField } from "./color-field";
4
4
  export { RadioToggleField } from "./radio-toggle-field";
5
5
  export { ObjectField } from "./object-field";
6
6
  export { VirtualizedSelectField, LARGE_SELECT_THRESHOLD, } from "./virtualized-select-field";
7
+ export { LocationField } from "./location-field";
7
8
  export { ActionField, ACTION_TYPE_FIELD_MAP, ACTION_TYPE_OPTIONS, PageActionFields, ExternalActionFields, EmailActionFields, PhoneActionFields, SectionActionFields, DownloadActionFields, type ActionTypeFieldProps, } from "./action-field";
@@ -0,0 +1,44 @@
1
+ import type { MapLocation } from "../core/fields";
2
+ interface GLatLng {
3
+ lat(): number;
4
+ lng(): number;
5
+ }
6
+ interface GGeometry {
7
+ location?: GLatLng;
8
+ }
9
+ interface GPlaceResult {
10
+ formatted_address?: string;
11
+ geometry?: GGeometry;
12
+ place_id?: string;
13
+ address_components?: unknown[];
14
+ }
15
+ interface GAutocomplete {
16
+ getPlace(): GPlaceResult;
17
+ addListener(event: string, handler: () => void): void;
18
+ }
19
+ interface GAutocompleteConstructor {
20
+ new (input: HTMLInputElement, opts?: Record<string, unknown>): GAutocomplete;
21
+ }
22
+ interface GGoogleMaps {
23
+ places: {
24
+ Autocomplete: GAutocompleteConstructor;
25
+ };
26
+ event: {
27
+ clearInstanceListeners(instance: unknown): void;
28
+ };
29
+ }
30
+ interface GGoogle {
31
+ maps: GGoogleMaps;
32
+ }
33
+ declare global {
34
+ interface Window {
35
+ google?: GGoogle;
36
+ }
37
+ }
38
+ export interface LocationFieldProps {
39
+ name: string;
40
+ value: MapLocation | undefined;
41
+ onChange: (value: MapLocation) => void;
42
+ }
43
+ export declare const LocationField: import("react").NamedExoticComponent<LocationFieldProps>;
44
+ export {};
@@ -0,0 +1,207 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import { memo, useState, useRef, useEffect, useCallback } from "react";
4
+ import { Input } from "../../shadcn/input.js";
5
+ import { Label } from "../../shadcn/label.js";
6
+ import { Loader2, Search, X, MapPin } from "lucide-react";
7
+ import { useEditorContext } from "../editor-context.js";
8
+ let googleLoadPromise = null;
9
+ function loadGooglePlaces(apiKey) {
10
+ var _a, _b;
11
+ if (googleLoadPromise) return googleLoadPromise;
12
+ if (typeof window !== "undefined" && ((_b = (_a = window.google) == null ? void 0 : _a.maps) == null ? void 0 : _b.places)) {
13
+ return Promise.resolve();
14
+ }
15
+ googleLoadPromise = new Promise((resolve, reject) => {
16
+ const script = document.createElement("script");
17
+ script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places`;
18
+ script.async = true;
19
+ script.onload = () => resolve();
20
+ script.onerror = () => {
21
+ googleLoadPromise = null;
22
+ reject(new Error("Failed to load Google Maps API"));
23
+ };
24
+ document.head.appendChild(script);
25
+ });
26
+ return googleLoadPromise;
27
+ }
28
+ const LocationField = memo(function LocationField2({
29
+ value,
30
+ onChange
31
+ }) {
32
+ const { googleMapsApiKey } = useEditorContext();
33
+ const apiKey = googleMapsApiKey || "";
34
+ const [inputValue, setInputValue] = useState((value == null ? void 0 : value.address) || "");
35
+ const [isLoaded, setIsLoaded] = useState(false);
36
+ const [loadError, setLoadError] = useState(false);
37
+ const inputRef = useRef(null);
38
+ const autocompleteRef = useRef(null);
39
+ useEffect(() => {
40
+ if ((value == null ? void 0 : value.address) && value.address !== inputValue) {
41
+ setInputValue(value.address);
42
+ }
43
+ }, [value == null ? void 0 : value.address]);
44
+ useEffect(() => {
45
+ if (!apiKey) {
46
+ setLoadError(true);
47
+ return;
48
+ }
49
+ loadGooglePlaces(apiKey).then(() => setIsLoaded(true)).catch(() => setLoadError(true));
50
+ }, [apiKey]);
51
+ useEffect(() => {
52
+ if (!isLoaded || !inputRef.current || autocompleteRef.current) return;
53
+ const G = window.google;
54
+ const autocomplete = new G.maps.places.Autocomplete(inputRef.current, {
55
+ fields: [
56
+ "formatted_address",
57
+ "geometry",
58
+ "place_id",
59
+ "address_components"
60
+ ]
61
+ });
62
+ autocomplete.addListener("place_changed", () => {
63
+ var _a;
64
+ const place = autocomplete.getPlace();
65
+ if (!((_a = place.geometry) == null ? void 0 : _a.location)) return;
66
+ const lat = place.geometry.location.lat();
67
+ const lng = place.geometry.location.lng();
68
+ const address = place.formatted_address || "";
69
+ const newLocation = {
70
+ address,
71
+ lat,
72
+ lng,
73
+ zoom: (value == null ? void 0 : value.zoom) ?? 14,
74
+ placeId: place.place_id || ""
75
+ };
76
+ setInputValue(address);
77
+ onChange(newLocation);
78
+ });
79
+ autocompleteRef.current = autocomplete;
80
+ return () => {
81
+ var _a;
82
+ (_a = window.google) == null ? void 0 : _a.maps.event.clearInstanceListeners(autocomplete);
83
+ autocompleteRef.current = null;
84
+ };
85
+ }, [isLoaded]);
86
+ const handleClear = useCallback(() => {
87
+ var _a;
88
+ setInputValue("");
89
+ onChange({
90
+ address: "",
91
+ lat: 0,
92
+ lng: 0,
93
+ zoom: 14,
94
+ placeId: ""
95
+ });
96
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
97
+ }, [onChange]);
98
+ const handleZoomChange = useCallback(
99
+ (e) => {
100
+ if (!value) return;
101
+ onChange({ ...value, zoom: Number(e.target.value) });
102
+ },
103
+ [value, onChange]
104
+ );
105
+ const embedUrl = value && value.lat !== 0 ? `https://maps.google.com/maps?q=${value.lat},${value.lng}&z=${value.zoom ?? 14}&output=embed` : null;
106
+ return /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-3", children: [
107
+ /* @__PURE__ */ jsx(Label, { children: "Location" }),
108
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
109
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3", children: !isLoaded && !loadError ? /* @__PURE__ */ jsx(Loader2, { className: "text-muted-foreground size-4 animate-spin" }) : /* @__PURE__ */ jsx(Search, { className: "text-muted-foreground size-4" }) }),
110
+ /* @__PURE__ */ jsx(
111
+ Input,
112
+ {
113
+ ref: inputRef,
114
+ value: inputValue,
115
+ onChange: (e) => setInputValue(e.target.value),
116
+ placeholder: loadError ? "Enter address manually..." : "Search address or place...",
117
+ className: "pl-9 pr-8"
118
+ }
119
+ ),
120
+ inputValue && /* @__PURE__ */ jsx(
121
+ "button",
122
+ {
123
+ type: "button",
124
+ onClick: handleClear,
125
+ className: "text-muted-foreground hover:text-foreground absolute inset-y-0 right-0 flex items-center pr-3",
126
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
127
+ }
128
+ )
129
+ ] }),
130
+ loadError && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
131
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
132
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Latitude" }),
133
+ /* @__PURE__ */ jsx(
134
+ Input,
135
+ {
136
+ type: "number",
137
+ step: "any",
138
+ value: (value == null ? void 0 : value.lat) ?? "",
139
+ onChange: (e) => onChange({
140
+ ...value || { address: "", lng: 0, zoom: 14 },
141
+ lat: Number(e.target.value)
142
+ }),
143
+ placeholder: "37.7749",
144
+ className: "h-8 text-xs"
145
+ }
146
+ )
147
+ ] }),
148
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
149
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Longitude" }),
150
+ /* @__PURE__ */ jsx(
151
+ Input,
152
+ {
153
+ type: "number",
154
+ step: "any",
155
+ value: (value == null ? void 0 : value.lng) ?? "",
156
+ onChange: (e) => onChange({
157
+ ...value || { address: "", lat: 0, zoom: 14 },
158
+ lng: Number(e.target.value)
159
+ }),
160
+ placeholder: "-122.4194",
161
+ className: "h-8 text-xs"
162
+ }
163
+ )
164
+ ] })
165
+ ] }),
166
+ value && value.lat !== 0 && /* @__PURE__ */ jsxs("div", { className: "border-border bg-muted/50 space-y-2 rounded-lg border p-3", children: [
167
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
168
+ /* @__PURE__ */ jsx(MapPin, { className: "text-primary mt-0.5 size-3.5 shrink-0" }),
169
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium leading-tight", children: value.address })
170
+ ] }),
171
+ /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground pl-5.5 text-xs", children: [
172
+ value.lat.toFixed(4),
173
+ ", ",
174
+ value.lng.toFixed(4)
175
+ ] })
176
+ ] }),
177
+ embedUrl && /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg border", children: /* @__PURE__ */ jsx(
178
+ "iframe",
179
+ {
180
+ src: embedUrl,
181
+ title: "Location preview",
182
+ className: "h-[160px] w-full border-0",
183
+ loading: "lazy",
184
+ referrerPolicy: "no-referrer-when-downgrade"
185
+ }
186
+ ) }),
187
+ value && value.lat !== 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
188
+ /* @__PURE__ */ jsx(Label, { className: "shrink-0 text-xs", children: "Zoom" }),
189
+ /* @__PURE__ */ jsx(
190
+ "input",
191
+ {
192
+ type: "range",
193
+ min: 1,
194
+ max: 20,
195
+ step: 1,
196
+ value: value.zoom ?? 14,
197
+ onChange: handleZoomChange,
198
+ className: "h-1.5 flex-1 cursor-pointer appearance-none rounded-full bg-gray-200 accent-current"
199
+ }
200
+ ),
201
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-6 text-right text-xs tabular-nums", children: value.zoom ?? 14 })
202
+ ] })
203
+ ] });
204
+ });
205
+ export {
206
+ LocationField
207
+ };
@@ -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 {};
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { CompoundButton } from "../../../puck-base/button.js";
3
3
  import { cn } from "../../../../utils/css-utils.js";
4
+ import { getMapEmbedUrl } from "../../../puck-base/core/fields.js";
4
5
  const ActionButton = ({
5
6
  label,
6
7
  url,
@@ -34,24 +35,27 @@ const ActionButton = ({
34
35
  }
35
36
  ) });
36
37
  };
38
+ const MAP_STYLE_FILTERS = {
39
+ default: "",
40
+ grayscale: "grayscale(40%) contrast(1.05) brightness(1.0) saturate(0.85)",
41
+ dark: "grayscale(100%) invert(1) contrast(1.1) brightness(0.8)"
42
+ };
37
43
  const Location2 = ({
38
44
  heading,
39
45
  description,
40
- address,
46
+ displayAddress,
41
47
  contentPosition = "left",
42
- mapEmbedUrl,
43
- mapTitle = "Google Maps",
44
- mapFilter,
45
- mapTintMode = "none",
46
- mapTintColor,
47
- mapTintOpacity = 0.15,
48
+ location: loc,
49
+ mapStyle = "default",
50
+ mapTint = "none",
48
51
  buttons = [],
49
52
  styles
50
53
  }) => {
51
54
  const isRight = contentPosition === "right";
52
55
  const isGlass = (styles == null ? void 0 : styles.cardStyle) === "glass";
53
- const showMapTint = mapTintMode !== "none" && mapTintOpacity > 0;
54
- const tintColor = mapTintMode === "custom" ? mapTintColor || void 0 : void 0;
56
+ const showMapTint = mapTint === "theme";
57
+ const mapEmbedUrl = loc && loc.lat !== 0 ? getMapEmbedUrl(loc) : void 0;
58
+ const mapFilter = MAP_STYLE_FILTERS[mapStyle] || "";
55
59
  const heightClass = (styles == null ? void 0 : styles.sectionHeight) === "sm" ? "h-[480px]" : (styles == null ? void 0 : styles.sectionHeight) === "lg" ? "h-[75vh] min-h-[520px]" : "h-[600px]";
56
60
  return /* @__PURE__ */ jsxs("div", { className: cn("relative w-full overflow-hidden", heightClass), children: [
57
61
  /* @__PURE__ */ jsxs("div", { className: "absolute inset-0", children: [
@@ -59,12 +63,12 @@ const Location2 = ({
59
63
  "iframe",
60
64
  {
61
65
  src: mapEmbedUrl,
62
- title: mapTitle,
66
+ title: (loc == null ? void 0 : loc.address) || "Google Maps",
63
67
  className: "h-full w-full border-0",
64
68
  loading: "lazy",
65
69
  referrerPolicy: "no-referrer-when-downgrade",
66
70
  allowFullScreen: true,
67
- style: { filter: mapFilter }
71
+ style: mapFilter ? { filter: mapFilter } : void 0
68
72
  }
69
73
  ) : /* @__PURE__ */ jsx("div", { className: "bg-muted text-muted-foreground flex h-full w-full items-center justify-center text-sm", children: "Map address not configured" }),
70
74
  showMapTint && /* @__PURE__ */ jsx(
@@ -72,8 +76,7 @@ const Location2 = ({
72
76
  {
73
77
  className: "bg-primary pointer-events-none absolute inset-0",
74
78
  style: {
75
- backgroundColor: tintColor,
76
- opacity: mapTintOpacity,
79
+ opacity: 0.15,
77
80
  mixBlendMode: "color"
78
81
  }
79
82
  }
@@ -96,7 +99,7 @@ const Location2 = ({
96
99
  children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
97
100
  heading && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ jsx("h2", { className: "text-foreground whitespace-pre-line font-serif text-3xl leading-tight tracking-tighter md:text-4xl", children: heading }) }),
98
101
  description && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm leading-relaxed", children: description }),
99
- address && /* @__PURE__ */ jsxs("div", { className: "text-foreground flex items-start gap-2 text-sm", children: [
102
+ displayAddress && /* @__PURE__ */ jsxs("div", { className: "text-foreground flex items-start gap-2 text-sm", children: [
100
103
  /* @__PURE__ */ jsxs(
101
104
  "svg",
102
105
  {
@@ -115,7 +118,7 @@ const Location2 = ({
115
118
  ]
116
119
  }
117
120
  ),
118
- /* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: address })
121
+ /* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: displayAddress })
119
122
  ] }),
120
123
  buttons.some((button) => button == null ? void 0 : button.label) && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 pt-1", children: buttons.map((button, index) => /* @__PURE__ */ jsx(ActionButton, { ...button }, index)) })
121
124
  ] })
@@ -1,11 +1,16 @@
1
+ import { location } from "../../../puck-base/core/fields.js";
1
2
  import { Location3 } from "./location.js";
2
3
  import { createStylesDefaults, createStylesField } from "../../../puck-base/core/styles.js";
3
- const defaultLocation = {
4
+ const defaultLocationEntry = {
4
5
  name: "San Francisco, CA",
5
- address: "123 Market Street\nSan Francisco, CA 94105",
6
+ location: {
7
+ address: "123 Market Street, San Francisco, CA 94105",
8
+ lat: 37.7749,
9
+ lng: -122.4194,
10
+ zoom: 14
11
+ },
6
12
  phone: "+1 (415) 555-0100",
7
- hours: "Mon–Fri: 9am–6pm\nSat: 10am–4pm",
8
- directionsUrl: "https://maps.google.com"
13
+ hours: "Mon–Fri: 9am–6pm\nSat: 10am–4pm"
9
14
  };
10
15
  const location3ExtraStyleFields = {
11
16
  mapHeight: {
@@ -30,9 +35,16 @@ const conf = {
30
35
  fields: {
31
36
  heading: { type: "textarea", contentEditable: true },
32
37
  description: { type: "textarea", contentEditable: true },
33
- mapEmbedUrl: { type: "text", label: "Google Map Embed URL" },
34
- mapTitle: { type: "text", label: "Map Title" },
35
- mapFilter: { type: "text", label: "Map Filter (CSS)" },
38
+ mapLocation: { ...location, label: "Map Location" },
39
+ mapStyle: {
40
+ type: "radio",
41
+ label: "Map Style",
42
+ options: [
43
+ { label: "Default", value: "default" },
44
+ { label: "Grayscale", value: "grayscale" },
45
+ { label: "Dark", value: "dark" }
46
+ ]
47
+ },
36
48
  locations: {
37
49
  type: "array",
38
50
  min: 1,
@@ -40,37 +52,48 @@ const conf = {
40
52
  getItemSummary: (item, index = 0) => item.name || `Location ${index + 1}`,
41
53
  arrayFields: {
42
54
  name: { type: "text", contentEditable: true },
43
- address: { type: "textarea", contentEditable: true },
55
+ location,
44
56
  phone: { type: "text" },
45
57
  hours: { type: "textarea", label: "Business Hours" },
46
- directionsUrl: { type: "text", label: "Directions URL" },
47
58
  directionsLabel: { type: "text", label: "Directions Button Label" }
48
59
  },
49
- defaultItemProps: defaultLocation
60
+ defaultItemProps: defaultLocationEntry
50
61
  },
51
62
  styles: createStylesField(location3ExtraStyleFields)
52
63
  },
53
64
  defaultProps: {
54
65
  heading: "Our Offices",
55
66
  description: "We have teams around the world ready to help you succeed.",
56
- mapEmbedUrl: "https://maps.google.com/maps?q=New%20York%2C%20NY%2C%20United%20States&z=11&t=m&output=embed",
57
- mapTitle: "Google Maps",
58
- mapFilter: "grayscale(35%) contrast(1.05) brightness(1.0)",
67
+ mapLocation: {
68
+ address: "New York, NY, United States",
69
+ lat: 40.7128,
70
+ lng: -74.006,
71
+ zoom: 11
72
+ },
73
+ mapStyle: "grayscale",
59
74
  locations: [
60
- defaultLocation,
75
+ defaultLocationEntry,
61
76
  {
62
77
  name: "London, UK",
63
- address: "10 Finsbury Square\nLondon, EC2A 1AF",
78
+ location: {
79
+ address: "10 Finsbury Square, London, EC2A 1AF",
80
+ lat: 51.5207,
81
+ lng: -0.0876,
82
+ zoom: 14
83
+ },
64
84
  phone: "+44 20 7946 0200",
65
- hours: "Mon–Fri: 9am–6pm\nSat: 10am–3pm",
66
- directionsUrl: "https://maps.google.com"
85
+ hours: "Mon–Fri: 9am–6pm\nSat: 10am–3pm"
67
86
  },
68
87
  {
69
88
  name: "Tokyo, Japan",
70
- address: "1-1-2 Marunouchi\nChiyoda-ku, Tokyo 100-0005",
89
+ location: {
90
+ address: "1-1-2 Marunouchi, Chiyoda-ku, Tokyo 100-0005",
91
+ lat: 35.6812,
92
+ lng: 139.7671,
93
+ zoom: 14
94
+ },
71
95
  phone: "+81 3-1234-5678",
72
- hours: "Mon–Fri: 9am–6pm",
73
- directionsUrl: "https://maps.google.com"
96
+ hours: "Mon–Fri: 9am–6pm"
74
97
  }
75
98
  ],
76
99
  styles: createStylesDefaults({
@@ -1,20 +1,19 @@
1
1
  import { CompoundContainerProps } from "@/components/puck-base/container";
2
2
  import type { Action } from "@/components/puck-base/core/types";
3
+ import type { MapLocation } from "@/components/puck-base/core/fields";
3
4
  export interface LocationEntry {
4
5
  name: string;
5
- address?: string;
6
+ location?: MapLocation;
6
7
  phone?: string;
7
8
  hours?: string;
8
- directionsUrl?: string;
9
9
  directionsLabel?: string;
10
10
  directionsAction?: Action;
11
11
  }
12
12
  export interface Location3Props {
13
13
  heading?: string;
14
14
  description?: string;
15
- mapEmbedUrl?: string;
16
- mapTitle?: string;
17
- mapFilter?: string;
15
+ mapLocation?: MapLocation;
16
+ mapStyle?: "default" | "grayscale" | "dark";
18
17
  locations: LocationEntry[];
19
18
  styles?: {
20
19
  padding?: CompoundContainerProps["padding"];
@@ -24,4 +23,4 @@ export interface Location3Props {
24
23
  columns?: "2" | "3";
25
24
  };
26
25
  }
27
- export declare const Location3: ({ heading, description, mapEmbedUrl, mapTitle, mapFilter, locations, styles, }: Location3Props) => import("react/jsx-runtime").JSX.Element;
26
+ export declare const Location3: ({ heading, description, mapLocation, mapStyle, locations, styles, }: Location3Props) => import("react/jsx-runtime").JSX.Element;
@@ -2,15 +2,22 @@ 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, getDirectionsUrl } from "../../../puck-base/core/fields.js";
6
+ const MAP_STYLE_FILTERS = {
7
+ default: "",
8
+ grayscale: "grayscale(35%) contrast(1.05) brightness(1.0)",
9
+ dark: "grayscale(100%) invert(1) contrast(1.1) brightness(0.8)"
10
+ };
5
11
  const Location3 = ({
6
12
  heading,
7
13
  description,
8
- mapEmbedUrl,
9
- mapTitle = "Google Maps",
10
- mapFilter,
14
+ mapLocation,
15
+ mapStyle = "default",
11
16
  locations = [],
12
17
  styles
13
18
  }) => {
19
+ const mapEmbedUrl = mapLocation && mapLocation.lat !== 0 ? getMapEmbedUrl(mapLocation) : void 0;
20
+ const mapFilter = MAP_STYLE_FILTERS[mapStyle] || "";
14
21
  const mapHeight = (styles == null ? void 0 : styles.mapHeight) ?? "md";
15
22
  const columns = (styles == null ? void 0 : styles.columns) ?? "3";
16
23
  const mapHeightClass = mapHeight === "sm" ? "h-[220px] md:h-[260px]" : mapHeight === "lg" ? "h-[360px] md:h-[440px]" : "h-[280px] md:h-[340px]";
@@ -30,97 +37,100 @@ const Location3 = ({
30
37
  "iframe",
31
38
  {
32
39
  src: mapEmbedUrl,
33
- title: mapTitle,
40
+ title: (mapLocation == null ? void 0 : mapLocation.address) || "Google Maps",
34
41
  className: "h-full w-full border-0",
35
42
  loading: "lazy",
36
43
  referrerPolicy: "no-referrer-when-downgrade",
37
44
  allowFullScreen: true,
38
- style: { filter: mapFilter }
45
+ style: mapFilter ? { filter: mapFilter } : void 0
39
46
  }
40
47
  ) : /* @__PURE__ */ jsx("div", { className: "bg-muted text-muted-foreground flex h-full w-full items-center justify-center text-sm", children: "Map address not configured" }) }),
41
- locations.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-1 gap-5", colClass), children: locations.map((loc, i) => /* @__PURE__ */ jsxs(
42
- "div",
43
- {
44
- className: "bg-card border-border flex flex-col gap-3 rounded-xl border p-6",
45
- children: [
46
- /* @__PURE__ */ jsx("h3", { className: "text-foreground text-lg font-semibold", children: loc.name }),
47
- loc.address && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-start gap-2 text-sm", children: [
48
- /* @__PURE__ */ jsxs(
49
- "svg",
50
- {
51
- className: "text-primary mt-0.5 shrink-0",
52
- width: "14",
53
- height: "14",
54
- viewBox: "0 0 24 24",
55
- fill: "none",
56
- stroke: "currentColor",
57
- strokeWidth: "2",
58
- strokeLinecap: "round",
59
- strokeLinejoin: "round",
60
- children: [
61
- /* @__PURE__ */ jsx("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }),
62
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "10", r: "3" })
63
- ]
64
- }
65
- ),
66
- /* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: loc.address })
67
- ] }),
68
- loc.phone && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
69
- /* @__PURE__ */ jsx(
70
- "svg",
71
- {
72
- className: "text-primary shrink-0",
73
- width: "14",
74
- height: "14",
75
- viewBox: "0 0 24 24",
76
- fill: "none",
77
- stroke: "currentColor",
78
- strokeWidth: "2",
79
- strokeLinecap: "round",
80
- strokeLinejoin: "round",
81
- children: /* @__PURE__ */ jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 14a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3.62 3h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 10.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 17.92Z" })
82
- }
83
- ),
84
- /* @__PURE__ */ jsx("span", { children: loc.phone })
85
- ] }),
86
- loc.hours && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-start gap-2 text-sm", children: [
87
- /* @__PURE__ */ jsxs(
88
- "svg",
48
+ locations.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-1 gap-5", colClass), children: locations.map((loc, i) => {
49
+ var _a;
50
+ return /* @__PURE__ */ jsxs(
51
+ "div",
52
+ {
53
+ className: "bg-card border-border flex flex-col gap-3 rounded-xl border p-6",
54
+ children: [
55
+ /* @__PURE__ */ jsx("h3", { className: "text-foreground text-lg font-semibold", children: loc.name }),
56
+ ((_a = loc.location) == null ? void 0 : _a.address) && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-start gap-2 text-sm", children: [
57
+ /* @__PURE__ */ jsxs(
58
+ "svg",
59
+ {
60
+ className: "text-primary mt-0.5 shrink-0",
61
+ width: "14",
62
+ height: "14",
63
+ viewBox: "0 0 24 24",
64
+ fill: "none",
65
+ stroke: "currentColor",
66
+ strokeWidth: "2",
67
+ strokeLinecap: "round",
68
+ strokeLinejoin: "round",
69
+ children: [
70
+ /* @__PURE__ */ jsx("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }),
71
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "10", r: "3" })
72
+ ]
73
+ }
74
+ ),
75
+ /* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: loc.location.address })
76
+ ] }),
77
+ loc.phone && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
78
+ /* @__PURE__ */ jsx(
79
+ "svg",
80
+ {
81
+ className: "text-primary shrink-0",
82
+ width: "14",
83
+ height: "14",
84
+ viewBox: "0 0 24 24",
85
+ fill: "none",
86
+ stroke: "currentColor",
87
+ strokeWidth: "2",
88
+ strokeLinecap: "round",
89
+ strokeLinejoin: "round",
90
+ children: /* @__PURE__ */ jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 14a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3.62 3h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 10.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 17.92Z" })
91
+ }
92
+ ),
93
+ /* @__PURE__ */ jsx("span", { children: loc.phone })
94
+ ] }),
95
+ loc.hours && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground flex items-start gap-2 text-sm", children: [
96
+ /* @__PURE__ */ jsxs(
97
+ "svg",
98
+ {
99
+ className: "text-primary mt-0.5 shrink-0",
100
+ width: "14",
101
+ height: "14",
102
+ viewBox: "0 0 24 24",
103
+ fill: "none",
104
+ stroke: "currentColor",
105
+ strokeWidth: "2",
106
+ strokeLinecap: "round",
107
+ strokeLinejoin: "round",
108
+ children: [
109
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
110
+ /* @__PURE__ */ jsx("polyline", { points: "12 6 12 12 16 14" })
111
+ ]
112
+ }
113
+ ),
114
+ /* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: loc.hours })
115
+ ] }),
116
+ (loc.directionsAction || loc.location && loc.location.lat !== 0) && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-2", children: /* @__PURE__ */ jsx(
117
+ CompoundButton,
89
118
  {
90
- className: "text-primary mt-0.5 shrink-0",
91
- width: "14",
92
- height: "14",
93
- viewBox: "0 0 24 24",
94
- fill: "none",
95
- stroke: "currentColor",
96
- strokeWidth: "2",
97
- strokeLinecap: "round",
98
- strokeLinejoin: "round",
99
- children: [
100
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
101
- /* @__PURE__ */ jsx("polyline", { points: "12 6 12 12 16 14" })
102
- ]
119
+ label: loc.directionsLabel || "Get Directions",
120
+ action: loc.directionsAction ?? (loc.location ? {
121
+ type: "external",
122
+ externalUrl: getDirectionsUrl(loc.location)
123
+ } : void 0),
124
+ variant: "outline",
125
+ size: "sm",
126
+ icon: "map-pin"
103
127
  }
104
- ),
105
- /* @__PURE__ */ jsx("span", { className: "whitespace-pre-line", children: loc.hours })
106
- ] }),
107
- (loc.directionsAction || loc.directionsUrl) && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-2", children: /* @__PURE__ */ jsx(
108
- CompoundButton,
109
- {
110
- label: loc.directionsLabel || "Get Directions",
111
- action: loc.directionsAction ?? (loc.directionsUrl ? {
112
- type: "external",
113
- externalUrl: loc.directionsUrl
114
- } : void 0),
115
- variant: "outline",
116
- size: "sm",
117
- icon: "map-pin"
118
- }
119
- ) })
120
- ]
121
- },
122
- i
123
- )) })
128
+ ) })
129
+ ]
130
+ },
131
+ i
132
+ );
133
+ }) })
124
134
  ] })
125
135
  }
126
136
  );
@@ -1,3 +1,4 @@
1
+ import type { MapLocation } from "@/components/puck-base/core/fields";
1
2
  type LocationVariant = "location-1" | "location-2" | "location-3";
2
3
  type LocationPadding = {
3
4
  top?: "none" | "small" | "medium" | "large";
@@ -13,22 +14,19 @@ type LocationButton = {
13
14
  };
14
15
  type LocationItem = {
15
16
  name: string;
16
- address?: string;
17
+ location?: MapLocation;
17
18
  phone?: string;
18
19
  hours?: string;
19
- directionsUrl?: string;
20
20
  };
21
- type LocationSectionProps = {
21
+ export type LocationSectionProps = {
22
22
  variant?: LocationVariant;
23
23
  heading?: string;
24
24
  description?: string;
25
- address?: string;
26
- mapEmbedUrl?: string;
27
- mapTitle?: string;
28
- mapFilter?: string;
29
- mapTintMode?: "none" | "theme" | "custom";
30
- mapTintColor?: string;
31
- mapTintOpacity?: number;
25
+ displayAddress?: string;
26
+ location?: MapLocation;
27
+ mapLocation?: MapLocation;
28
+ mapStyle?: "default" | "grayscale" | "dark";
29
+ mapTint?: "none" | "theme";
32
30
  buttons?: LocationButton[];
33
31
  locations?: LocationItem[];
34
32
  contentPosition?: "left" | "right";
@@ -43,3 +41,4 @@ type LocationSectionProps = {
43
41
  sectionHeight?: "sm" | "md" | "lg";
44
42
  };
45
43
  };
44
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dune-react",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -16,7 +16,8 @@
16
16
  "build-storybook": "storybook build && cp -r skills storybook-static/skills",
17
17
  "deploy-storybook": "storybook-to-ghpages -- --existing-output-dir=storybook-static",
18
18
  "ondeploy": "pnpm build-storybook && pnpm deploy-storybook",
19
- "postpublish": "bash scripts/postpublish.sh"
19
+ "postpublish": "bash scripts/postpublish.sh",
20
+ "upload:previews": "tsx scripts/upload-previews-r2.ts"
20
21
  },
21
22
  "sideEffects": [
22
23
  "*.css"