@opensite/ui 2.8.7 → 2.8.9

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 (163) hide show
  1. package/dist/about-culture-tabs.cjs +174 -174
  2. package/dist/about-culture-tabs.js +174 -174
  3. package/dist/about-developer-profile.cjs +200 -200
  4. package/dist/about-developer-profile.js +198 -198
  5. package/dist/about-developer-story.cjs +142 -142
  6. package/dist/about-developer-story.js +142 -142
  7. package/dist/about-mission-dual-image.cjs +142 -142
  8. package/dist/about-mission-dual-image.js +142 -142
  9. package/dist/about-mission-features.cjs +142 -142
  10. package/dist/about-mission-features.js +142 -142
  11. package/dist/about-network-spotlight.cjs +142 -142
  12. package/dist/about-network-spotlight.js +142 -142
  13. package/dist/about-story-expertise.cjs +142 -142
  14. package/dist/about-story-expertise.js +142 -142
  15. package/dist/about-streamline-team.cjs +142 -142
  16. package/dist/about-streamline-team.js +142 -142
  17. package/dist/carousel-icon-sidebar.cjs +5 -4
  18. package/dist/carousel-icon-sidebar.js +5 -4
  19. package/dist/community-initiatives.cjs +142 -142
  20. package/dist/community-initiatives.js +142 -142
  21. package/dist/components.cjs +723 -1364
  22. package/dist/components.d.cts +0 -2
  23. package/dist/components.d.ts +0 -2
  24. package/dist/components.js +633 -1273
  25. package/dist/contact-map.cjs +14 -1069
  26. package/dist/contact-map.d.cts +13 -3
  27. package/dist/contact-map.d.ts +13 -3
  28. package/dist/contact-map.js +14 -1069
  29. package/dist/cta-feature-checklist.cjs +142 -142
  30. package/dist/cta-feature-checklist.js +142 -142
  31. package/dist/faq-numbered-grid.cjs +142 -142
  32. package/dist/faq-numbered-grid.js +142 -142
  33. package/dist/feature-animated-carousel.cjs +142 -142
  34. package/dist/feature-animated-carousel.js +142 -142
  35. package/dist/feature-bento-utilities.cjs +142 -142
  36. package/dist/feature-bento-utilities.js +142 -142
  37. package/dist/feature-capabilities-grid.cjs +142 -142
  38. package/dist/feature-capabilities-grid.js +142 -142
  39. package/dist/feature-category-image-cards.cjs +142 -142
  40. package/dist/feature-category-image-cards.js +142 -142
  41. package/dist/feature-icon-grid-bordered.cjs +142 -142
  42. package/dist/feature-icon-grid-bordered.js +142 -142
  43. package/dist/feature-icon-grid-muted.cjs +142 -142
  44. package/dist/feature-icon-grid-muted.js +142 -142
  45. package/dist/feature-numbered-cards.cjs +142 -142
  46. package/dist/feature-numbered-cards.js +142 -142
  47. package/dist/feature-three-column-values.cjs +142 -142
  48. package/dist/feature-three-column-values.js +142 -142
  49. package/dist/hero-ad-campaign-expert.cjs +142 -142
  50. package/dist/hero-ad-campaign-expert.js +142 -142
  51. package/dist/hero-adaptable-product-grid.cjs +142 -142
  52. package/dist/hero-adaptable-product-grid.js +142 -142
  53. package/dist/hero-agency-animated-images.cjs +142 -142
  54. package/dist/hero-agency-animated-images.js +142 -142
  55. package/dist/hero-announcement-badge.cjs +142 -142
  56. package/dist/hero-announcement-badge.js +142 -142
  57. package/dist/hero-badge-image-split.cjs +142 -142
  58. package/dist/hero-badge-image-split.js +142 -142
  59. package/dist/hero-business-carousel-dots.cjs +142 -142
  60. package/dist/hero-business-carousel-dots.js +142 -142
  61. package/dist/hero-business-operations-mosaic.cjs +142 -142
  62. package/dist/hero-business-operations-mosaic.js +142 -142
  63. package/dist/hero-conversation-intelligence.cjs +142 -142
  64. package/dist/hero-conversation-intelligence.js +142 -142
  65. package/dist/hero-creative-studio-stacked.cjs +142 -142
  66. package/dist/hero-creative-studio-stacked.js +142 -142
  67. package/dist/hero-crm-streamlined.cjs +142 -142
  68. package/dist/hero-crm-streamlined.js +142 -142
  69. package/dist/hero-customer-support-layered.cjs +142 -142
  70. package/dist/hero-customer-support-layered.js +142 -142
  71. package/dist/hero-design-showcase-logos.cjs +142 -142
  72. package/dist/hero-design-showcase-logos.js +142 -142
  73. package/dist/hero-design-system-3d.cjs +142 -142
  74. package/dist/hero-design-system-3d.js +142 -142
  75. package/dist/hero-developer-tools-code.cjs +142 -142
  76. package/dist/hero-developer-tools-code.js +142 -142
  77. package/dist/hero-digital-agency-fullscreen.cjs +142 -142
  78. package/dist/hero-digital-agency-fullscreen.js +142 -142
  79. package/dist/hero-ecommerce-product-showcase.cjs +174 -174
  80. package/dist/hero-ecommerce-product-showcase.js +174 -174
  81. package/dist/hero-event-registration.cjs +142 -142
  82. package/dist/hero-event-registration.js +142 -142
  83. package/dist/hero-fullscreen-background-image.cjs +142 -142
  84. package/dist/hero-fullscreen-background-image.js +142 -142
  85. package/dist/hero-gradient-avatars-rating.cjs +142 -142
  86. package/dist/hero-gradient-avatars-rating.js +142 -142
  87. package/dist/hero-gradient-client-focused.cjs +142 -142
  88. package/dist/hero-gradient-client-focused.js +142 -142
  89. package/dist/hero-hiring-animated-text.cjs +142 -142
  90. package/dist/hero-hiring-animated-text.js +142 -142
  91. package/dist/hero-image-left-content.cjs +142 -142
  92. package/dist/hero-image-left-content.js +142 -142
  93. package/dist/hero-innovation-image-grid.cjs +142 -142
  94. package/dist/hero-innovation-image-grid.js +142 -142
  95. package/dist/hero-mental-health-team.cjs +142 -142
  96. package/dist/hero-mental-health-team.js +142 -142
  97. package/dist/hero-minimal-centered-dark.cjs +174 -174
  98. package/dist/hero-minimal-centered-dark.js +174 -174
  99. package/dist/hero-presentation-platform-video.cjs +142 -142
  100. package/dist/hero-presentation-platform-video.js +142 -142
  101. package/dist/hero-product-showcase-floating.cjs +174 -174
  102. package/dist/hero-product-showcase-floating.js +174 -174
  103. package/dist/hero-shared-inbox-layered.cjs +142 -142
  104. package/dist/hero-shared-inbox-layered.js +142 -142
  105. package/dist/hero-software-growth-video-dialog.cjs +142 -142
  106. package/dist/hero-software-growth-video-dialog.js +142 -142
  107. package/dist/hero-spiral-pattern-cards.cjs +174 -174
  108. package/dist/hero-spiral-pattern-cards.js +174 -174
  109. package/dist/hero-split-geometric-shapes.cjs +142 -142
  110. package/dist/hero-split-geometric-shapes.js +142 -142
  111. package/dist/hero-startup-launch-cta.cjs +174 -174
  112. package/dist/hero-startup-launch-cta.js +174 -174
  113. package/dist/hero-stats-social-proof.cjs +174 -174
  114. package/dist/hero-stats-social-proof.js +174 -174
  115. package/dist/hero-task-timer-animated.cjs +142 -142
  116. package/dist/hero-task-timer-animated.js +142 -142
  117. package/dist/hero-testimonial-image-grid.cjs +142 -142
  118. package/dist/hero-testimonial-image-grid.js +142 -142
  119. package/dist/hero-therapy-testimonial-grid.cjs +142 -142
  120. package/dist/hero-therapy-testimonial-grid.js +142 -142
  121. package/dist/hero-ui-library-showcase.cjs +142 -142
  122. package/dist/hero-ui-library-showcase.js +142 -142
  123. package/dist/hero-video-background-dark.cjs +174 -174
  124. package/dist/hero-video-background-dark.js +174 -174
  125. package/dist/hero-video-dialog-gradient.cjs +142 -142
  126. package/dist/hero-video-dialog-gradient.js +142 -142
  127. package/dist/hero-video-overlay-stars.cjs +142 -142
  128. package/dist/hero-video-overlay-stars.js +142 -142
  129. package/dist/hero-welcome-asymmetric-images.cjs +142 -142
  130. package/dist/hero-welcome-asymmetric-images.js +142 -142
  131. package/dist/index.cjs +725 -1366
  132. package/dist/index.d.cts +0 -2
  133. package/dist/index.d.ts +0 -2
  134. package/dist/index.js +634 -1274
  135. package/dist/registry.cjs +2371 -2915
  136. package/dist/registry.js +1120 -1664
  137. package/dist/testimonials-large-quote.cjs +74 -43
  138. package/dist/testimonials-large-quote.d.cts +5 -1
  139. package/dist/testimonials-large-quote.d.ts +5 -1
  140. package/dist/testimonials-large-quote.js +74 -43
  141. package/dist/testimonials-logo-cards.cjs +8 -2
  142. package/dist/testimonials-logo-cards.js +8 -2
  143. package/dist/testimonials-masonry-grid.cjs +486 -69
  144. package/dist/testimonials-masonry-grid.d.cts +5 -1
  145. package/dist/testimonials-masonry-grid.d.ts +5 -1
  146. package/dist/testimonials-masonry-grid.js +483 -63
  147. package/dist/testimonials-mini-dividers.cjs +2 -3
  148. package/dist/testimonials-mini-dividers.js +2 -3
  149. package/dist/testimonials-minimal-numbered.cjs +5 -4
  150. package/dist/testimonials-minimal-numbered.js +5 -4
  151. package/dist/testimonials-parallax-number.cjs +5 -4
  152. package/dist/testimonials-parallax-number.js +5 -4
  153. package/dist/testimonials-scrolling-columns.cjs +7 -12
  154. package/dist/testimonials-scrolling-columns.js +7 -12
  155. package/dist/testimonials-stats-header.cjs +528 -87
  156. package/dist/testimonials-stats-header.d.cts +39 -3
  157. package/dist/testimonials-stats-header.d.ts +39 -3
  158. package/dist/testimonials-stats-header.js +523 -82
  159. package/package.json +4 -7
  160. package/dist/geo-map.cjs +0 -1103
  161. package/dist/geo-map.d.cts +0 -92
  162. package/dist/geo-map.d.ts +0 -92
  163. package/dist/geo-map.js +0 -1081
@@ -3,11 +3,10 @@
3
3
 
4
4
  var React4 = require('react');
5
5
  var integration = require('@page-speed/forms/integration');
6
+ var maps = require('@page-speed/maps');
6
7
  var clsx = require('clsx');
7
8
  var tailwindMerge = require('tailwind-merge');
8
9
  var jsxRuntime = require('react/jsx-runtime');
9
- var maps = require('@page-speed/maps');
10
- var classVarianceAuthority = require('class-variance-authority');
11
10
  var icon = require('@page-speed/icon');
12
11
  var img = require('@page-speed/img');
13
12
 
@@ -58,1071 +57,6 @@ function CardContent({ className, ...props }) {
58
57
  }
59
58
  );
60
59
  }
61
- function normalizePhoneNumber(input) {
62
- const trimmed = input.trim();
63
- if (trimmed.toLowerCase().startsWith("tel:")) {
64
- return trimmed;
65
- }
66
- const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
67
- if (match) {
68
- const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
69
- const extension = match[3];
70
- const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
71
- const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
72
- return `tel:${withExtension}`;
73
- }
74
- const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
75
- return `tel:${cleaned}`;
76
- }
77
- function normalizeEmail(input) {
78
- const trimmed = input.trim();
79
- if (trimmed.toLowerCase().startsWith("mailto:")) {
80
- return trimmed;
81
- }
82
- return `mailto:${trimmed}`;
83
- }
84
- function isEmail(input) {
85
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
86
- return emailRegex.test(input.trim());
87
- }
88
- function isPhoneNumber(input) {
89
- const trimmed = input.trim();
90
- if (trimmed.toLowerCase().startsWith("tel:")) {
91
- return true;
92
- }
93
- const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
94
- return phoneRegex.test(trimmed);
95
- }
96
- function isInternalUrl(href) {
97
- if (typeof window === "undefined") {
98
- return href.startsWith("/") && !href.startsWith("//");
99
- }
100
- const trimmed = href.trim();
101
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
102
- return true;
103
- }
104
- try {
105
- const url = new URL(trimmed, window.location.href);
106
- const currentOrigin = window.location.origin;
107
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
108
- return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
109
- } catch {
110
- return false;
111
- }
112
- }
113
- function toRelativePath(href) {
114
- if (typeof window === "undefined") {
115
- return href;
116
- }
117
- const trimmed = href.trim();
118
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
119
- return trimmed;
120
- }
121
- try {
122
- const url = new URL(trimmed, window.location.href);
123
- const currentOrigin = window.location.origin;
124
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
125
- if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
126
- return url.pathname + url.search + url.hash;
127
- }
128
- } catch {
129
- }
130
- return trimmed;
131
- }
132
- function useNavigation({
133
- href,
134
- onClick
135
- } = {}) {
136
- const linkType = React4__namespace.useMemo(() => {
137
- if (!href || href.trim() === "") {
138
- return onClick ? "none" : "none";
139
- }
140
- const trimmed = href.trim();
141
- if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
142
- return "mailto";
143
- }
144
- if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
145
- return "tel";
146
- }
147
- if (isInternalUrl(trimmed)) {
148
- return "internal";
149
- }
150
- try {
151
- new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
152
- return "external";
153
- } catch {
154
- return "internal";
155
- }
156
- }, [href, onClick]);
157
- const normalizedHref = React4__namespace.useMemo(() => {
158
- if (!href || href.trim() === "") {
159
- return void 0;
160
- }
161
- const trimmed = href.trim();
162
- switch (linkType) {
163
- case "tel":
164
- return normalizePhoneNumber(trimmed);
165
- case "mailto":
166
- return normalizeEmail(trimmed);
167
- case "internal":
168
- return toRelativePath(trimmed);
169
- case "external":
170
- return trimmed;
171
- default:
172
- return trimmed;
173
- }
174
- }, [href, linkType]);
175
- const target = React4__namespace.useMemo(() => {
176
- switch (linkType) {
177
- case "external":
178
- return "_blank";
179
- case "internal":
180
- return "_self";
181
- case "mailto":
182
- case "tel":
183
- return void 0;
184
- default:
185
- return void 0;
186
- }
187
- }, [linkType]);
188
- const rel = React4__namespace.useMemo(() => {
189
- if (linkType === "external") {
190
- return "noopener noreferrer";
191
- }
192
- return void 0;
193
- }, [linkType]);
194
- const isExternal = linkType === "external";
195
- const isInternal = linkType === "internal";
196
- const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
197
- const handleClick = React4__namespace.useCallback(
198
- (event) => {
199
- if (onClick) {
200
- try {
201
- onClick(event);
202
- } catch (error) {
203
- console.error("Error in user onClick handler:", error);
204
- }
205
- }
206
- if (event.defaultPrevented) {
207
- return;
208
- }
209
- if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
210
- !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
211
- if (typeof window !== "undefined") {
212
- const handler = window.__opensiteNavigationHandler;
213
- if (typeof handler === "function") {
214
- try {
215
- const handled = handler(normalizedHref, event.nativeEvent || event);
216
- if (handled !== false) {
217
- event.preventDefault();
218
- }
219
- } catch (error) {
220
- console.error("Error in navigation handler:", error);
221
- }
222
- }
223
- }
224
- }
225
- },
226
- [onClick, shouldUseRouter, normalizedHref]
227
- );
228
- return {
229
- linkType,
230
- normalizedHref,
231
- target,
232
- rel,
233
- isExternal,
234
- isInternal,
235
- shouldUseRouter,
236
- handleClick
237
- };
238
- }
239
- var baseStyles = [
240
- // Layout
241
- "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
242
- // Typography - using CSS variables with sensible defaults
243
- "font-[var(--button-font-family,inherit)]",
244
- "font-[var(--button-font-weight,500)]",
245
- "tracking-[var(--button-letter-spacing,0)]",
246
- "leading-[var(--button-line-height,1.25)]",
247
- "[text-transform:var(--button-text-transform,none)]",
248
- "text-sm",
249
- // Border radius
250
- "rounded-[var(--button-radius,var(--radius,0.375rem))]",
251
- // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
252
- "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
253
- // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
254
- "[box-shadow:var(--button-shadow,none)]",
255
- "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
256
- // Disabled state
257
- "disabled:pointer-events-none disabled:opacity-50",
258
- // SVG handling
259
- "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
260
- // Focus styles
261
- "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
262
- // Invalid state
263
- "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
264
- ].join(" ");
265
- var buttonVariants = classVarianceAuthority.cva(baseStyles, {
266
- variants: {
267
- variant: {
268
- // Default (Primary) variant - full customization
269
- default: [
270
- "bg-[var(--button-default-bg,hsl(var(--primary)))]",
271
- "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
272
- "border-[length:var(--button-default-border-width,0px)]",
273
- "border-[color:var(--button-default-border,transparent)]",
274
- "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
275
- "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
276
- "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
277
- "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
278
- "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
279
- ].join(" "),
280
- // Destructive variant - full customization
281
- destructive: [
282
- "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
283
- "text-[var(--button-destructive-fg,white)]",
284
- "border-[length:var(--button-destructive-border-width,0px)]",
285
- "border-[color:var(--button-destructive-border,transparent)]",
286
- "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
287
- "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
288
- "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
289
- "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
290
- "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
291
- "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
292
- "dark:bg-destructive/60"
293
- ].join(" "),
294
- // Outline variant - full customization with proper border handling
295
- outline: [
296
- "bg-[var(--button-outline-bg,hsl(var(--background)))]",
297
- "text-[var(--button-outline-fg,inherit)]",
298
- "border-[length:var(--button-outline-border-width,1px)]",
299
- "border-[color:var(--button-outline-border,hsl(var(--border)))]",
300
- "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
301
- "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
302
- "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
303
- "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
304
- "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
305
- "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
306
- ].join(" "),
307
- // Secondary variant - full customization
308
- secondary: [
309
- "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
310
- "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
311
- "border-[length:var(--button-secondary-border-width,0px)]",
312
- "border-[color:var(--button-secondary-border,transparent)]",
313
- "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
314
- "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
315
- "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
316
- "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
317
- "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
318
- ].join(" "),
319
- // Ghost variant - full customization
320
- ghost: [
321
- "bg-[var(--button-ghost-bg,transparent)]",
322
- "text-[var(--button-ghost-fg,inherit)]",
323
- "border-[length:var(--button-ghost-border-width,0px)]",
324
- "border-[color:var(--button-ghost-border,transparent)]",
325
- "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
326
- "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
327
- "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
328
- "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
329
- "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
330
- "dark:hover:bg-accent/50"
331
- ].join(" "),
332
- // Link variant - full customization
333
- link: [
334
- "bg-[var(--button-link-bg,transparent)]",
335
- "text-[var(--button-link-fg,hsl(var(--primary)))]",
336
- "border-[length:var(--button-link-border-width,0px)]",
337
- "border-[color:var(--button-link-border,transparent)]",
338
- "[box-shadow:var(--button-link-shadow,none)]",
339
- "hover:bg-[var(--button-link-hover-bg,transparent)]",
340
- "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
341
- "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
342
- "underline-offset-4 hover:underline"
343
- ].join(" ")
344
- },
345
- size: {
346
- default: [
347
- "h-[var(--button-height-md,2.25rem)]",
348
- "px-[var(--button-padding-x-md,1rem)]",
349
- "py-[var(--button-padding-y-md,0.5rem)]",
350
- "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
351
- ].join(" "),
352
- sm: [
353
- "h-[var(--button-height-sm,2rem)]",
354
- "px-[var(--button-padding-x-sm,0.75rem)]",
355
- "py-[var(--button-padding-y-sm,0.25rem)]",
356
- "gap-1.5",
357
- "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
358
- ].join(" "),
359
- md: [
360
- "h-[var(--button-height-md,2.25rem)]",
361
- "px-[var(--button-padding-x-md,1rem)]",
362
- "py-[var(--button-padding-y-md,0.5rem)]",
363
- "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
364
- ].join(" "),
365
- lg: [
366
- "h-[var(--button-height-lg,2.5rem)]",
367
- "px-[var(--button-padding-x-lg,1.5rem)]",
368
- "py-[var(--button-padding-y-lg,0.5rem)]",
369
- "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
370
- ].join(" "),
371
- icon: "size-[var(--button-height-md,2.25rem)]",
372
- "icon-sm": "size-[var(--button-height-sm,2rem)]",
373
- "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
374
- }
375
- },
376
- defaultVariants: {
377
- variant: "default",
378
- size: "default"
379
- }
380
- });
381
- var Pressable = React4__namespace.forwardRef(
382
- ({
383
- children,
384
- className,
385
- href,
386
- onClick,
387
- variant,
388
- size,
389
- asButton = false,
390
- fallbackComponentType = "span",
391
- componentType,
392
- "aria-label": ariaLabel,
393
- "aria-describedby": ariaDescribedby,
394
- id,
395
- ...props
396
- }, ref) => {
397
- const navigation = useNavigation({ href, onClick });
398
- const {
399
- normalizedHref,
400
- target,
401
- rel,
402
- linkType,
403
- isInternal,
404
- handleClick
405
- } = navigation;
406
- const shouldRenderLink = normalizedHref && linkType !== "none";
407
- const shouldRenderButton = !shouldRenderLink && onClick;
408
- const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
409
- const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
410
- const shouldApplyButtonStyles = asButton || variant || size;
411
- const combinedClassName = cn(
412
- shouldApplyButtonStyles && buttonVariants({ variant, size }),
413
- className
414
- );
415
- const dataProps = Object.fromEntries(
416
- Object.entries(props).filter(([key]) => key.startsWith("data-"))
417
- );
418
- const buttonDataAttributes = shouldApplyButtonStyles ? {
419
- "data-slot": "button",
420
- "data-variant": variant ?? "default",
421
- "data-size": size ?? "default"
422
- } : {};
423
- const commonProps = {
424
- className: combinedClassName,
425
- onClick: handleClick,
426
- "aria-label": ariaLabel,
427
- "aria-describedby": ariaDescribedby,
428
- id,
429
- ...dataProps,
430
- ...buttonDataAttributes
431
- };
432
- if (finalComponentType === "a" && shouldRenderLink) {
433
- return /* @__PURE__ */ jsxRuntime.jsx(
434
- "a",
435
- {
436
- ref,
437
- href: normalizedHref,
438
- target,
439
- rel,
440
- ...commonProps,
441
- ...props,
442
- children
443
- }
444
- );
445
- }
446
- if (finalComponentType === "button") {
447
- return /* @__PURE__ */ jsxRuntime.jsx(
448
- "button",
449
- {
450
- ref,
451
- type: props.type || "button",
452
- ...commonProps,
453
- ...props,
454
- children
455
- }
456
- );
457
- }
458
- if (finalComponentType === "div") {
459
- return /* @__PURE__ */ jsxRuntime.jsx(
460
- "div",
461
- {
462
- ref,
463
- ...commonProps,
464
- children
465
- }
466
- );
467
- }
468
- return /* @__PURE__ */ jsxRuntime.jsx(
469
- "span",
470
- {
471
- ref,
472
- ...commonProps,
473
- children
474
- }
475
- );
476
- }
477
- );
478
- Pressable.displayName = "Pressable";
479
- var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
480
- var DynamicIcon = React4__namespace.memo(function DynamicIcon2({
481
- apiKey,
482
- ...props
483
- }) {
484
- return /* @__PURE__ */ jsxRuntime.jsx(icon.Icon, { ...props, apiKey: apiKey ?? DEFAULT_ICON_API_KEY });
485
- });
486
- DynamicIcon.displayName = "DynamicIcon";
487
- var PANEL_POSITION_CLASS = {
488
- "top-left": "left-4 top-4",
489
- "top-right": "right-4 top-4",
490
- "bottom-left": "bottom-4 left-4",
491
- "bottom-right": "bottom-4 right-4"
492
- };
493
- var DEFAULT_VIEW_STATE = {
494
- latitude: 39.5,
495
- longitude: -98.35,
496
- zoom: 3
497
- };
498
- var VIDEO_FILE_EXTENSION_REGEX = /\.(mp4|webm|ogg|mov|m4v|m3u8)(\?.*)?$/i;
499
- function resolveMediaType(item) {
500
- if (item.type) {
501
- return item.type;
502
- }
503
- return VIDEO_FILE_EXTENSION_REGEX.test(item.src) ? "video" : "image";
504
- }
505
- function normalizeId(value, fallback) {
506
- if (value === null || value === void 0 || value === "") {
507
- return fallback;
508
- }
509
- return String(value);
510
- }
511
- function buildClusterCenter(markers) {
512
- if (!markers.length) {
513
- return null;
514
- }
515
- const total = markers.reduce(
516
- (accumulator, marker) => ({
517
- latitude: accumulator.latitude + marker.latitude,
518
- longitude: accumulator.longitude + marker.longitude
519
- }),
520
- { latitude: 0, longitude: 0 }
521
- );
522
- return {
523
- latitude: total.latitude / markers.length,
524
- longitude: total.longitude / markers.length
525
- };
526
- }
527
- function resolveActionKey(action, index) {
528
- if (typeof action.label === "string" && action.label.trim().length > 0) {
529
- return `label:${action.label}:${index}`;
530
- }
531
- if (action.href) {
532
- return `href:${action.href}:${index}`;
533
- }
534
- return `action:${index}`;
535
- }
536
- function MarkerActions({ actions }) {
537
- if (!actions || actions.length === 0) {
538
- return null;
539
- }
540
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex flex-wrap gap-2", children: actions.map((action, index) => {
541
- const {
542
- label,
543
- icon,
544
- iconAfter,
545
- children,
546
- href,
547
- onClick,
548
- className: actionClassName,
549
- variant,
550
- size,
551
- asButton,
552
- ...rest
553
- } = action;
554
- return /* @__PURE__ */ jsxRuntime.jsx(
555
- Pressable,
556
- {
557
- href,
558
- onClick,
559
- variant: variant ?? (index === 0 ? "default" : "outline"),
560
- size: size ?? "sm",
561
- asButton: asButton ?? true,
562
- className: cn("inline-flex items-center gap-2", actionClassName),
563
- ...rest,
564
- children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
565
- icon,
566
- label,
567
- iconAfter
568
- ] })
569
- },
570
- resolveActionKey(action, index)
571
- );
572
- }) });
573
- }
574
- function MarkerMediaCarousel({
575
- mediaItems,
576
- optixFlowConfig
577
- }) {
578
- const [activeIndex, setActiveIndex] = React4__namespace.useState(0);
579
- const totalItems = mediaItems.length;
580
- const mediaResetKey = React4__namespace.useMemo(
581
- () => mediaItems.map((item, index) => {
582
- const itemId = normalizeId(item.id, `media-${index}`);
583
- return `${itemId}:${item.src}:${item.type ?? ""}:${item.poster ?? ""}`;
584
- }).join("|"),
585
- [mediaItems]
586
- );
587
- const activeItemIndex = Math.min(activeIndex, Math.max(0, totalItems - 1));
588
- React4__namespace.useEffect(() => {
589
- setActiveIndex(0);
590
- }, [mediaResetKey]);
591
- const activeMediaItem = mediaItems[activeItemIndex];
592
- const mediaType = resolveMediaType(activeMediaItem);
593
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative border-b border-border/60 bg-muted/40", children: [
594
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-44 w-full overflow-hidden", children: mediaType === "video" ? /* @__PURE__ */ jsxRuntime.jsx(
595
- "video",
596
- {
597
- className: "h-full w-full object-cover",
598
- controls: true,
599
- preload: "metadata",
600
- poster: activeMediaItem.poster,
601
- children: /* @__PURE__ */ jsxRuntime.jsx("source", { src: activeMediaItem.src })
602
- }
603
- ) : /* @__PURE__ */ jsxRuntime.jsx(
604
- img.Img,
605
- {
606
- src: activeMediaItem.src,
607
- alt: activeMediaItem.alt ?? "Map marker media",
608
- className: "h-full w-full object-cover",
609
- loading: "eager",
610
- optixFlowConfig
611
- }
612
- ) }),
613
- totalItems > 1 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
614
- /* @__PURE__ */ jsxRuntime.jsx(
615
- "button",
616
- {
617
- type: "button",
618
- "aria-label": "Show previous media",
619
- className: "absolute left-2 top-1/2 inline-flex size-8 -translate-y-1/2 items-center justify-center rounded-full bg-card text-card-foreground shadow-sm transition hover:bg-muted hover:text-muted-foreground",
620
- onClick: () => {
621
- setActiveIndex(
622
- (current) => (current - 1 + totalItems) % totalItems
623
- );
624
- },
625
- children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-left", size: 16 })
626
- }
627
- ),
628
- /* @__PURE__ */ jsxRuntime.jsx(
629
- "button",
630
- {
631
- type: "button",
632
- "aria-label": "Show next media",
633
- className: "absolute right-2 top-1/2 inline-flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full bg-card text-card-foreground shadow-sm transition hover:bg-muted hover:text-muted-foreground",
634
- onClick: () => {
635
- setActiveIndex((current) => (current + 1) % totalItems);
636
- },
637
- children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
638
- }
639
- ),
640
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-2 left-1/2 flex -translate-x-1/2 items-center gap-1.5", children: mediaItems.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
641
- "button",
642
- {
643
- type: "button",
644
- "aria-label": `Show media item ${index + 1}`,
645
- className: cn(
646
- "h-2 rounded-full transition-all",
647
- index === activeItemIndex ? "w-6 bg-card" : "w-2 bg-card opacity-50 hover:opacity-100"
648
- ),
649
- onClick: () => setActiveIndex(index)
650
- },
651
- normalizeId(item.id, `media-dot-${index}`)
652
- )) })
653
- ] }) : null
654
- ] });
655
- }
656
- function getMarkerTitle(marker, markerIndex) {
657
- if (marker.title !== void 0 && marker.title !== null) {
658
- return marker.title;
659
- }
660
- if (marker.label !== void 0 && marker.label !== null) {
661
- return marker.label;
662
- }
663
- return `Location ${markerIndex + 1}`;
664
- }
665
- function GeoMap({
666
- className,
667
- mapWrapperClassName,
668
- mapClassName,
669
- panelClassName,
670
- panelPosition = "top-left",
671
- stadiaApiKey = "",
672
- mapStyle = "osm-bright",
673
- styleUrl,
674
- mapLibreCssHref,
675
- markers = [],
676
- clusters = [],
677
- viewState,
678
- defaultViewState,
679
- onViewStateChange,
680
- onMapClick,
681
- onMarkerDrag,
682
- showNavigationControl = true,
683
- showGeolocateControl = false,
684
- navigationControlPosition = "top-right",
685
- geolocateControlPosition = "top-left",
686
- flyToOptions,
687
- markerFocusZoom = 14,
688
- clusterFocusZoom = 5,
689
- selectedMarkerId,
690
- initialSelectedMarkerId,
691
- onSelectionChange,
692
- clearSelectionOnMapClick = true,
693
- mapChildren,
694
- optixFlowConfig
695
- }) {
696
- const normalizedStandaloneMarkers = React4__namespace.useMemo(
697
- () => markers.map((marker, index) => ({
698
- ...marker,
699
- id: normalizeId(marker.id, `marker-${index}`)
700
- })),
701
- [markers]
702
- );
703
- const normalizedClusters = React4__namespace.useMemo(() => {
704
- const results = [];
705
- clusters.forEach((cluster, clusterIndex) => {
706
- const clusterId = normalizeId(cluster.id, `cluster-${clusterIndex}`);
707
- const normalizedClusterMarkers = cluster.markers.map(
708
- (marker, markerIndex) => ({
709
- ...marker,
710
- id: normalizeId(marker.id, `${clusterId}-marker-${markerIndex}`),
711
- clusterId
712
- })
713
- );
714
- const clusterCenter = cluster.latitude !== void 0 && cluster.longitude !== void 0 ? { latitude: cluster.latitude, longitude: cluster.longitude } : buildClusterCenter(normalizedClusterMarkers);
715
- if (!clusterCenter) {
716
- return;
717
- }
718
- results.push({
719
- ...cluster,
720
- id: clusterId,
721
- latitude: clusterCenter.latitude,
722
- longitude: clusterCenter.longitude,
723
- markers: normalizedClusterMarkers
724
- });
725
- });
726
- return results;
727
- }, [clusters]);
728
- const markerLookup = React4__namespace.useMemo(() => {
729
- const lookup = /* @__PURE__ */ new Map();
730
- normalizedStandaloneMarkers.forEach((marker) => {
731
- lookup.set(marker.id, marker);
732
- });
733
- normalizedClusters.forEach((cluster) => {
734
- cluster.markers.forEach((marker) => {
735
- lookup.set(marker.id, marker);
736
- });
737
- });
738
- return lookup;
739
- }, [normalizedClusters, normalizedStandaloneMarkers]);
740
- const clusterLookup = React4__namespace.useMemo(() => {
741
- const lookup = /* @__PURE__ */ new Map();
742
- normalizedClusters.forEach((cluster) => {
743
- lookup.set(cluster.id, cluster);
744
- });
745
- return lookup;
746
- }, [normalizedClusters]);
747
- const firstCoordinate = React4__namespace.useMemo(() => {
748
- if (normalizedStandaloneMarkers.length > 0) {
749
- const firstStandaloneMarker = normalizedStandaloneMarkers[0];
750
- return {
751
- latitude: firstStandaloneMarker.latitude,
752
- longitude: firstStandaloneMarker.longitude
753
- };
754
- }
755
- if (normalizedClusters.length > 0) {
756
- const firstCluster = normalizedClusters[0];
757
- return {
758
- latitude: firstCluster.latitude,
759
- longitude: firstCluster.longitude
760
- };
761
- }
762
- return {
763
- latitude: DEFAULT_VIEW_STATE.latitude,
764
- longitude: DEFAULT_VIEW_STATE.longitude
765
- };
766
- }, [normalizedClusters, normalizedStandaloneMarkers]);
767
- const [uncontrolledViewState, setUncontrolledViewState] = React4__namespace.useState({
768
- latitude: defaultViewState?.latitude ?? firstCoordinate.latitude,
769
- longitude: defaultViewState?.longitude ?? firstCoordinate.longitude,
770
- zoom: defaultViewState?.zoom ?? DEFAULT_VIEW_STATE.zoom
771
- });
772
- const isControlledViewState = viewState !== void 0;
773
- const resolvedViewState = isControlledViewState ? viewState : uncontrolledViewState;
774
- const applyViewState = React4__namespace.useCallback(
775
- (nextState) => {
776
- if (!isControlledViewState) {
777
- setUncontrolledViewState((current) => {
778
- const next = { ...current, ...nextState };
779
- const hasChanged = current.latitude !== next.latitude || current.longitude !== next.longitude || current.zoom !== next.zoom;
780
- return hasChanged ? next : current;
781
- });
782
- }
783
- onViewStateChange?.(nextState);
784
- },
785
- [isControlledViewState, onViewStateChange]
786
- );
787
- const [selection, setSelection] = React4__namespace.useState(() => {
788
- if (initialSelectedMarkerId !== void 0 && initialSelectedMarkerId !== null) {
789
- return {
790
- type: "marker",
791
- markerId: String(initialSelectedMarkerId)
792
- };
793
- }
794
- return { type: "none" };
795
- });
796
- React4__namespace.useEffect(() => {
797
- if (selectedMarkerId === void 0 || selectedMarkerId === null) {
798
- return;
799
- }
800
- setSelection({
801
- type: "marker",
802
- markerId: String(selectedMarkerId)
803
- });
804
- }, [selectedMarkerId]);
805
- const selectedMarker = selection.markerId ? markerLookup.get(selection.markerId) : void 0;
806
- const selectedCluster = selection.clusterId ? clusterLookup.get(selection.clusterId) : void 0;
807
- React4__namespace.useEffect(() => {
808
- if (selection.type === "marker" && selection.markerId && !selectedMarker) {
809
- setSelection({ type: "none" });
810
- onSelectionChange?.({ type: "none" });
811
- }
812
- }, [onSelectionChange, selectedMarker, selection]);
813
- const emitSelectionChange = React4__namespace.useCallback(
814
- (nextSelection) => {
815
- if (nextSelection.type === "none") {
816
- onSelectionChange?.({ type: "none" });
817
- return;
818
- }
819
- if (nextSelection.type === "marker") {
820
- const parentCluster = nextSelection.marker.clusterId ? clusterLookup.get(nextSelection.marker.clusterId) : void 0;
821
- onSelectionChange?.({
822
- type: "marker",
823
- marker: nextSelection.marker,
824
- cluster: parentCluster
825
- });
826
- return;
827
- }
828
- onSelectionChange?.({
829
- type: "cluster",
830
- cluster: nextSelection.cluster
831
- });
832
- },
833
- [clusterLookup, onSelectionChange]
834
- );
835
- const selectMarker = React4__namespace.useCallback(
836
- (marker) => {
837
- setSelection({
838
- type: "marker",
839
- markerId: marker.id,
840
- clusterId: marker.clusterId
841
- });
842
- applyViewState({
843
- latitude: marker.latitude,
844
- longitude: marker.longitude,
845
- zoom: markerFocusZoom
846
- });
847
- emitSelectionChange({ type: "marker", marker });
848
- },
849
- [applyViewState, emitSelectionChange, markerFocusZoom]
850
- );
851
- const selectCluster = React4__namespace.useCallback(
852
- (cluster) => {
853
- setSelection({
854
- type: "cluster",
855
- clusterId: cluster.id
856
- });
857
- applyViewState({
858
- latitude: cluster.latitude,
859
- longitude: cluster.longitude,
860
- zoom: clusterFocusZoom
861
- });
862
- emitSelectionChange({ type: "cluster", cluster });
863
- },
864
- [applyViewState, clusterFocusZoom, emitSelectionChange]
865
- );
866
- const clearSelection = React4__namespace.useCallback(() => {
867
- setSelection({ type: "none" });
868
- emitSelectionChange({ type: "none" });
869
- }, [emitSelectionChange]);
870
- const mapMarkers = React4__namespace.useMemo(() => {
871
- const resolvedMarkers = [];
872
- normalizedClusters.forEach((cluster) => {
873
- const isSelected = selection.type === "cluster" && selection.clusterId === cluster.id;
874
- resolvedMarkers.push({
875
- id: `cluster-pin:${cluster.id}`,
876
- latitude: cluster.latitude,
877
- longitude: cluster.longitude,
878
- element: () => {
879
- const customMarkerElement = cluster.markerElement;
880
- const markerBody = typeof customMarkerElement === "function" ? customMarkerElement({
881
- isSelected,
882
- count: cluster.markers.length
883
- }) : customMarkerElement;
884
- return /* @__PURE__ */ jsxRuntime.jsx(
885
- "button",
886
- {
887
- type: "button",
888
- className: "group cursor-pointer",
889
- onClick: (event) => {
890
- event.preventDefault();
891
- event.stopPropagation();
892
- selectCluster(cluster);
893
- },
894
- "aria-label": `View ${cluster.markers.length} clustered locations`,
895
- children: markerBody ?? /* @__PURE__ */ jsxRuntime.jsx(
896
- "span",
897
- {
898
- className: cn(
899
- "inline-flex min-h-10 min-w-10 items-center justify-center rounded-full border-2 border-white px-2 text-xs font-semibold text-white shadow-lg transition-transform duration-200 group-hover:scale-105",
900
- isSelected && "ring-4 ring-primary/30",
901
- cluster.pinClassName
902
- ),
903
- style: {
904
- backgroundColor: cluster.pinColor ?? "var(--foreground)"
905
- },
906
- children: cluster.markers.length
907
- }
908
- )
909
- }
910
- );
911
- }
912
- });
913
- });
914
- normalizedStandaloneMarkers.forEach((marker) => {
915
- const isSelected = selection.type === "marker" && selection.markerId === marker.id;
916
- const customMarkerElement = marker.markerElement;
917
- resolvedMarkers.push({
918
- id: marker.id,
919
- latitude: marker.latitude,
920
- longitude: marker.longitude,
921
- draggable: marker.draggable,
922
- element: () => {
923
- const markerBody = typeof customMarkerElement === "function" ? customMarkerElement({ isSelected }) : customMarkerElement;
924
- return /* @__PURE__ */ jsxRuntime.jsx(
925
- "button",
926
- {
927
- type: "button",
928
- className: "group cursor-pointer",
929
- onClick: (event) => {
930
- event.preventDefault();
931
- event.stopPropagation();
932
- selectMarker(marker);
933
- },
934
- "aria-label": typeof marker.title === "string" ? `View ${marker.title}` : "View location details",
935
- children: markerBody ?? /* @__PURE__ */ jsxRuntime.jsx(
936
- "span",
937
- {
938
- className: cn(
939
- "inline-flex h-4 w-4 rounded-full border-2 border-white shadow-md transition-transform duration-200 group-hover:scale-110",
940
- isSelected && "h-5 w-5 ring-4 ring-primary/30",
941
- marker.pinClassName
942
- ),
943
- style: {
944
- backgroundColor: marker.pinColor ?? "#f43f5e"
945
- }
946
- }
947
- )
948
- }
949
- );
950
- }
951
- });
952
- });
953
- return resolvedMarkers;
954
- }, [
955
- normalizedClusters,
956
- normalizedStandaloneMarkers,
957
- selectCluster,
958
- selectMarker,
959
- selection
960
- ]);
961
- const renderMarkerPanel = () => {
962
- if (selectedMarker) {
963
- const markerMediaItems = selectedMarker.mediaItems ?? [];
964
- return /* @__PURE__ */ jsxRuntime.jsxs(
965
- "div",
966
- {
967
- className: cn(
968
- "relative w-[min(24rem,calc(100vw-2rem))] overflow-hidden rounded-xl border border-border bg-card text-card-foreground shadow-2xl",
969
- panelClassName
970
- ),
971
- children: [
972
- /* @__PURE__ */ jsxRuntime.jsx(
973
- "button",
974
- {
975
- type: "button",
976
- "aria-label": "Close marker details",
977
- className: "flex size-8 items-center justify-center rounded-full border border-border bg-card text-card-foreground transition hover:bg-muted hover:text-foreground absolute top-2 right-2 z-10",
978
- onClick: clearSelection,
979
- children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/x", size: 16 })
980
- }
981
- ),
982
- markerMediaItems.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
983
- MarkerMediaCarousel,
984
- {
985
- mediaItems: markerMediaItems,
986
- optixFlowConfig
987
- }
988
- ) : null,
989
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 p-4", children: [
990
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-1", children: [
991
- selectedMarker.eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide", children: selectedMarker.eyebrow }) : null,
992
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold leading-tight", children: selectedMarker.title ?? selectedMarker.label ?? "Location" })
993
- ] }) }),
994
- selectedMarker.summary ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm leading-relaxed", children: selectedMarker.summary }) : null,
995
- selectedMarker.locationLine ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center justify-start text-sm gap-2", children: [
996
- /* @__PURE__ */ jsxRuntime.jsx(
997
- DynamicIcon,
998
- {
999
- name: "lucide:map-pin",
1000
- className: "opacity-50",
1001
- size: 14
1002
- }
1003
- ),
1004
- typeof selectedMarker.locationLine === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
1005
- Pressable,
1006
- {
1007
- href: selectedMarker.locationUrl,
1008
- className: cn(
1009
- "transition-all duration-500",
1010
- "font-medium opacity-75 hover:opacity-100",
1011
- selectedMarker.locationUrl ? "underline underline-offset-4" : ""
1012
- ),
1013
- children: selectedMarker.locationLine
1014
- }
1015
- ) : selectedMarker.locationLine
1016
- ] }) : null,
1017
- selectedMarker.hoursLine ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center justify-start text-sm gap-2", children: [
1018
- /* @__PURE__ */ jsxRuntime.jsx(
1019
- DynamicIcon,
1020
- {
1021
- name: "lucide:clock",
1022
- className: "opacity-50",
1023
- size: 14
1024
- }
1025
- ),
1026
- typeof selectedMarker.hoursLine === "string" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: selectedMarker.hoursLine }) : selectedMarker.hoursLine
1027
- ] }) : null,
1028
- selectedMarker.markerContentComponent ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: selectedMarker.markerContentComponent }) : null,
1029
- /* @__PURE__ */ jsxRuntime.jsx(MarkerActions, { actions: selectedMarker.actions })
1030
- ] })
1031
- ]
1032
- }
1033
- );
1034
- }
1035
- if (selectedCluster) {
1036
- return /* @__PURE__ */ jsxRuntime.jsxs(
1037
- "div",
1038
- {
1039
- className: cn(
1040
- "relative w-[min(24rem,calc(100vw-2rem))] overflow-hidden rounded-xl border border-border bg-card text-card-foreground p-4 shadow-2xl",
1041
- panelClassName
1042
- ),
1043
- children: [
1044
- /* @__PURE__ */ jsxRuntime.jsx(
1045
- "button",
1046
- {
1047
- type: "button",
1048
- "aria-label": "Close cluster details",
1049
- className: "flex size-8 items-center justify-center rounded-full border border-border bg-card text-card-foreground transition hover:bg-muted hover:text-foreground absolute top-2 right-2 z-10",
1050
- onClick: clearSelection,
1051
- children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/x", size: 16 })
1052
- }
1053
- ),
1054
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 flex items-start justify-between gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
1055
- selectedCluster.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: selectedCluster.label }) : null,
1056
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold leading-tight text-foreground", children: selectedCluster.title ?? "Clustered Locations" }),
1057
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: selectedCluster.summary ?? `${selectedCluster.markers.length} location${selectedCluster.markers.length === 1 ? "" : "s"} in this cluster.` })
1058
- ] }) }),
1059
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 space-y-2 overflow-y-auto pr-1", children: selectedCluster.markers.map((marker, markerIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
1060
- "button",
1061
- {
1062
- type: "button",
1063
- className: "w-full rounded-lg border border-border/60 p-3 text-left transition hover:border-border hover:bg-muted/50",
1064
- onClick: () => selectMarker(marker),
1065
- children: [
1066
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-1 text-sm font-semibold text-foreground", children: getMarkerTitle(marker, markerIndex) }),
1067
- marker.summary ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 line-clamp-2 text-xs text-muted-foreground", children: marker.summary }) : null
1068
- ]
1069
- },
1070
- marker.id
1071
- )) })
1072
- ]
1073
- }
1074
- );
1075
- }
1076
- return null;
1077
- };
1078
- return /* @__PURE__ */ jsxRuntime.jsxs(
1079
- "div",
1080
- {
1081
- className: cn(
1082
- "relative overflow-hidden rounded-2xl border border-border bg-background",
1083
- className
1084
- ),
1085
- children: [
1086
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-[520px] w-full", mapWrapperClassName), children: /* @__PURE__ */ jsxRuntime.jsx(
1087
- maps.MapLibre,
1088
- {
1089
- stadiaApiKey,
1090
- mapStyle,
1091
- styleUrl,
1092
- mapLibreCssHref,
1093
- viewState: resolvedViewState,
1094
- onViewStateChange: applyViewState,
1095
- markers: mapMarkers,
1096
- onClick: (coord) => {
1097
- onMapClick?.(coord);
1098
- if (clearSelectionOnMapClick) {
1099
- clearSelection();
1100
- }
1101
- },
1102
- onMarkerDrag,
1103
- showNavigationControl,
1104
- showGeolocateControl,
1105
- navigationControlPosition,
1106
- geolocateControlPosition,
1107
- flyToOptions,
1108
- className: cn("h-full w-full", mapClassName),
1109
- children: mapChildren
1110
- }
1111
- ) }),
1112
- selection.type !== "none" ? /* @__PURE__ */ jsxRuntime.jsx(
1113
- "div",
1114
- {
1115
- className: cn(
1116
- "pointer-events-none absolute z-20",
1117
- PANEL_POSITION_CLASS[panelPosition]
1118
- ),
1119
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto", children: renderMarkerPanel() })
1120
- }
1121
- ) : null
1122
- ]
1123
- }
1124
- );
1125
- }
1126
60
  var maxWidthStyles = {
1127
61
  sm: "max-w-screen-sm",
1128
62
  md: "max-w-screen-md",
@@ -1499,6 +433,14 @@ var Section = React4__namespace.default.forwardRef(
1499
433
  }
1500
434
  );
1501
435
  Section.displayName = "Section";
436
+ var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
437
+ var DynamicIcon = React4__namespace.memo(function DynamicIcon2({
438
+ apiKey,
439
+ ...props
440
+ }) {
441
+ return /* @__PURE__ */ jsxRuntime.jsx(icon.Icon, { ...props, apiKey: apiKey ?? DEFAULT_ICON_API_KEY });
442
+ });
443
+ DynamicIcon.displayName = "DynamicIcon";
1502
444
  var DEFAULT_STYLE_RULES = {
1503
445
  formContainer: "",
1504
446
  fieldsContainer: "",
@@ -1588,7 +530,10 @@ function ContactMap({
1588
530
  panelPosition: "top-left",
1589
531
  ...mapProps,
1590
532
  className: cn("h-full w-full", mapClassName, mapProps?.className),
1591
- optixFlowConfig
533
+ optixFlowConfig,
534
+ // Provide icon and image components for rich marker panels
535
+ IconComponent: DynamicIcon,
536
+ ImgComponent: img.Img
1592
537
  };
1593
538
  }, [mapClassName, mapProps, optixFlowConfig]);
1594
539
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1633,7 +578,7 @@ function ContactMap({
1633
578
  ] }),
1634
579
  renderForm
1635
580
  ] }) }),
1636
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-full", mapColumnClassName), children: /* @__PURE__ */ jsxRuntime.jsx(GeoMap, { ...resolvedMapProps }) })
581
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("h-full", mapColumnClassName), children: /* @__PURE__ */ jsxRuntime.jsx(maps.GeoMap, { ...resolvedMapProps }) })
1637
582
  ]
1638
583
  }
1639
584
  )