@bailierich/booking-components 2.0.0

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 (83) hide show
  1. package/README.md +319 -0
  2. package/TENANT_DATA_INTEGRATION.md +402 -0
  3. package/TENANT_SETUP.md +316 -0
  4. package/components/BookingFlow/BookingFlow.tsx +790 -0
  5. package/components/BookingFlow/index.ts +5 -0
  6. package/components/BookingFlow/steps/AddonsSelection.tsx +118 -0
  7. package/components/BookingFlow/steps/Confirmation.tsx +185 -0
  8. package/components/BookingFlow/steps/ContactForm.tsx +292 -0
  9. package/components/BookingFlow/steps/CycleAwareDateSelection.tsx +277 -0
  10. package/components/BookingFlow/steps/DateSelection.tsx +473 -0
  11. package/components/BookingFlow/steps/ServiceSelection.tsx +315 -0
  12. package/components/BookingFlow/steps/TimeSelection.tsx +230 -0
  13. package/components/BookingFlow/steps/index.ts +10 -0
  14. package/components/BottomSheet/index.tsx +120 -0
  15. package/components/Forms/FormBlock.tsx +283 -0
  16. package/components/Forms/FormField.tsx +385 -0
  17. package/components/Forms/FormRenderer.tsx +216 -0
  18. package/components/Forms/FormValidation.ts +122 -0
  19. package/components/Forms/index.ts +4 -0
  20. package/components/HoldTimer/HoldTimer.tsx +266 -0
  21. package/components/HoldTimer/index.ts +2 -0
  22. package/components/SectionRenderer.tsx +558 -0
  23. package/components/Sections/About.tsx +145 -0
  24. package/components/Sections/BeforeAfter.tsx +81 -0
  25. package/components/Sections/BookingSection.tsx +76 -0
  26. package/components/Sections/Contact.tsx +103 -0
  27. package/components/Sections/FAQSection.tsx +239 -0
  28. package/components/Sections/FeatureContent.tsx +113 -0
  29. package/components/Sections/FeaturedLink.tsx +103 -0
  30. package/components/Sections/FixedInfoCard.tsx +189 -0
  31. package/components/Sections/Gallery.tsx +83 -0
  32. package/components/Sections/Header.tsx +78 -0
  33. package/components/Sections/Hero.tsx +178 -0
  34. package/components/Sections/ImageSection.tsx +147 -0
  35. package/components/Sections/InstagramFeed.tsx +38 -0
  36. package/components/Sections/LinkList.tsx +76 -0
  37. package/components/Sections/LocationMap.tsx +202 -0
  38. package/components/Sections/Logo.tsx +61 -0
  39. package/components/Sections/MinimalFooter.tsx +78 -0
  40. package/components/Sections/MinimalHeader.tsx +81 -0
  41. package/components/Sections/MinimalNavigation.tsx +63 -0
  42. package/components/Sections/Navbar.tsx +258 -0
  43. package/components/Sections/PricingTable.tsx +106 -0
  44. package/components/Sections/ScrollingTextDivider.tsx +138 -0
  45. package/components/Sections/ScrollingTextDivider.tsx.bak +138 -0
  46. package/components/Sections/ServicesPreview.tsx +129 -0
  47. package/components/Sections/SocialBar.tsx +177 -0
  48. package/components/Sections/Team.tsx +80 -0
  49. package/components/Sections/Testimonials.tsx +92 -0
  50. package/components/Sections/TextSection.tsx +116 -0
  51. package/components/Sections/VideoSection.tsx +178 -0
  52. package/components/Sections/index.ts +57 -0
  53. package/components/index.ts +21 -0
  54. package/dist/index-DAai7Glf.d.mts +474 -0
  55. package/dist/index-DAai7Glf.d.ts +474 -0
  56. package/dist/index.d.mts +1075 -0
  57. package/dist/index.d.ts +1075 -0
  58. package/dist/index.js +22 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/index.mjs +22 -0
  61. package/dist/index.mjs.map +1 -0
  62. package/dist/styles/index.d.mts +1 -0
  63. package/dist/styles/index.d.ts +1 -0
  64. package/dist/styles/index.js +2 -0
  65. package/dist/styles/index.js.map +1 -0
  66. package/dist/styles/index.mjs +2 -0
  67. package/dist/styles/index.mjs.map +1 -0
  68. package/docs/API.md +849 -0
  69. package/docs/CALLBACKS.md +760 -0
  70. package/docs/COMPLETE_SESSION_SUMMARY.md +404 -0
  71. package/docs/DATA_SHAPES.md +684 -0
  72. package/docs/MIGRATION.md +662 -0
  73. package/docs/PAYMENT_INTEGRATION.md +766 -0
  74. package/docs/SESSION_SUMMARY.md +185 -0
  75. package/docs/STYLING.md +735 -0
  76. package/index.ts +4 -0
  77. package/lib/storage.ts +239 -0
  78. package/package.json +59 -0
  79. package/styles/animations.ts +210 -0
  80. package/styles/index.ts +1 -0
  81. package/tsconfig.json +32 -0
  82. package/tsup.config.ts +13 -0
  83. package/types/index.ts +369 -0
@@ -0,0 +1,1075 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { H as HoldTimerConfig, C as CreateHoldFn, E as ExtendHoldFn, R as ReleaseHoldFn, O as OptInModule, S as Service, a as ServiceCategory, b as ServiceSelectionSettings, D as DateSelectionSettings, T as TimeSelectionSettings, A as Addon, c as AddonSelectionSettings, d as ContactInfo, e as ContactFormSettings, P as PaymentConfig, f as CyclePhase, F as FetchCycleDataFn, g as CycleClient, h as CycleWarningCallback, B as BottomSheetProps, i as HoldStatus } from './index-DAai7Glf.mjs';
3
+ export { v as AddonSelectionStepProps, I as AnimationVariants, l as BackgroundConfig, k as BookingData, x as ConfirmationStepProps, w as ContactFormStepProps, y as CyclePhaseMap, q as DataProviders, t as DateSelectionStepProps, j as FormField, z as HoldManagerCallbacks, p as PolicyImage, n as ProgressBarConfig, s as ServiceSelectionStepProps, r as StepComponentProps, o as StepConfig, u as TimeSelectionStepProps, m as TransitionConfig, G as TransitionDirection, N as animations, V as createEntranceAnimation, U as createStaggerAnimation, J as getAnimationDuration, L as getFadeVariants, K as getSlideVariants, M as getTransitionVariants, Q as shouldReduceMotion } from './index-DAai7Glf.mjs';
4
+ import React$1 from 'react';
5
+
6
+ interface LogoProps {
7
+ logoUrl?: string;
8
+ fallbackText?: string;
9
+ size?: 'small' | 'medium' | 'large';
10
+ alignment?: 'left' | 'center' | 'right';
11
+ colors: {
12
+ primary: string;
13
+ };
14
+ enableInlineEditing?: boolean;
15
+ sectionId?: string;
16
+ }
17
+ declare function Logo({ logoUrl, fallbackText, size, alignment, colors, enableInlineEditing, sectionId }: LogoProps): react_jsx_runtime.JSX.Element;
18
+
19
+ interface HeaderProps {
20
+ name?: string;
21
+ title?: string;
22
+ bio?: string;
23
+ showName?: boolean;
24
+ showTitle?: boolean;
25
+ showBio?: boolean;
26
+ colors: {
27
+ text: string;
28
+ };
29
+ typography: {
30
+ headingFont?: string;
31
+ };
32
+ enableInlineEditing?: boolean;
33
+ sectionId?: string;
34
+ }
35
+ declare function Header({ name, title, bio, showName, showTitle, showBio, colors, typography, enableInlineEditing, sectionId }: HeaderProps): react_jsx_runtime.JSX.Element;
36
+
37
+ interface FeaturedLinkProps {
38
+ text?: string;
39
+ url?: string;
40
+ style?: 'gradient' | 'solid' | 'outline';
41
+ size?: 'small' | 'medium' | 'large';
42
+ colors: {
43
+ primary: string;
44
+ secondary: string;
45
+ };
46
+ enableInlineEditing?: boolean;
47
+ sectionId?: string;
48
+ }
49
+ declare function FeaturedLink({ text, url, style, size, colors, enableInlineEditing, sectionId }: FeaturedLinkProps): react_jsx_runtime.JSX.Element;
50
+
51
+ interface Link {
52
+ id: string;
53
+ label: string;
54
+ url: string;
55
+ }
56
+ interface LinkListProps {
57
+ links: Link[];
58
+ style?: 'pill' | 'square' | 'outline';
59
+ colors: {
60
+ primary: string;
61
+ linkBackground?: string;
62
+ linkText?: string;
63
+ };
64
+ enableInlineEditing?: boolean;
65
+ sectionId?: string;
66
+ }
67
+ declare function LinkList({ links, style, colors, enableInlineEditing, sectionId }: LinkListProps): react_jsx_runtime.JSX.Element;
68
+
69
+ interface SocialBarProps {
70
+ platforms: string[];
71
+ socialLinks?: Record<string, string>;
72
+ style?: 'filled' | 'outline' | 'ghost';
73
+ size?: 'small' | 'medium' | 'large';
74
+ position?: 'center' | 'left-vertical' | 'right-vertical';
75
+ invertIcons?: boolean;
76
+ colors: {
77
+ primary: string;
78
+ };
79
+ enableInlineEditing?: boolean;
80
+ sectionId?: string;
81
+ }
82
+ declare function SocialBar({ platforms, socialLinks, style, size, position, invertIcons, colors, enableInlineEditing, sectionId }: SocialBarProps): react_jsx_runtime.JSX.Element;
83
+
84
+ interface HeroProps {
85
+ headline?: string;
86
+ subheadline?: string;
87
+ heroImage?: string;
88
+ ctaButton?: {
89
+ text: string;
90
+ url: string;
91
+ };
92
+ layout?: 'split' | 'full';
93
+ imagePosition?: 'left' | 'right';
94
+ contentDisplay?: 'side' | 'overlay';
95
+ colors: {
96
+ primary: string;
97
+ text: string;
98
+ };
99
+ typography: {
100
+ headingFont?: string;
101
+ };
102
+ enableInlineEditing?: boolean;
103
+ sectionId?: string;
104
+ }
105
+ declare function Hero({ headline, subheadline, heroImage, ctaButton, layout, imagePosition, contentDisplay, colors, typography, enableInlineEditing, sectionId }: HeroProps): react_jsx_runtime.JSX.Element;
106
+
107
+ interface AboutProps {
108
+ title?: string;
109
+ content?: string;
110
+ image?: string;
111
+ layout?: 'centered' | 'split' | 'wide';
112
+ colors: {
113
+ primary: string;
114
+ text: string;
115
+ };
116
+ typography: {
117
+ headingFont?: string;
118
+ };
119
+ enableInlineEditing?: boolean;
120
+ sectionId?: string;
121
+ }
122
+ declare function About({ title, content, image, layout, colors, typography, enableInlineEditing, sectionId }: AboutProps): react_jsx_runtime.JSX.Element;
123
+
124
+ interface ServicePreview {
125
+ id: number;
126
+ name: string;
127
+ description: string;
128
+ price: number;
129
+ duration: number;
130
+ }
131
+ interface ServicesPreviewProps {
132
+ title?: string;
133
+ services?: ServicePreview[];
134
+ layout?: 'grid' | 'list' | 'carousel';
135
+ columns?: 2 | 3 | 4;
136
+ showPrices?: boolean;
137
+ showDuration?: boolean;
138
+ colors: {
139
+ primary: string;
140
+ text: string;
141
+ };
142
+ typography: {
143
+ headingFont?: string;
144
+ };
145
+ enableInlineEditing?: boolean;
146
+ sectionId?: string;
147
+ }
148
+ declare function ServicesPreview({ title, services, layout, columns, showPrices, showDuration, colors, typography, enableInlineEditing, sectionId }: ServicesPreviewProps): react_jsx_runtime.JSX.Element;
149
+
150
+ interface GalleryImage {
151
+ id: string | number;
152
+ url?: string;
153
+ alt?: string;
154
+ }
155
+ interface GalleryProps {
156
+ title?: string;
157
+ images?: GalleryImage[];
158
+ columns?: 2 | 3 | 4;
159
+ colors: {
160
+ primary: string;
161
+ text: string;
162
+ };
163
+ typography: {
164
+ headingFont?: string;
165
+ };
166
+ enableInlineEditing?: boolean;
167
+ sectionId?: string;
168
+ }
169
+ declare function Gallery({ title, images, columns, colors, typography, enableInlineEditing, sectionId }: GalleryProps): react_jsx_runtime.JSX.Element;
170
+
171
+ interface Testimonial {
172
+ id: string | number;
173
+ text: string;
174
+ author: string;
175
+ rating: number;
176
+ }
177
+ interface TestimonialsProps {
178
+ title?: string;
179
+ testimonials?: Testimonial[];
180
+ layout?: 'grid' | 'carousel';
181
+ colors: {
182
+ primary: string;
183
+ text: string;
184
+ };
185
+ typography: {
186
+ headingFont?: string;
187
+ };
188
+ enableInlineEditing?: boolean;
189
+ sectionId?: string;
190
+ }
191
+ declare function Testimonials({ title, testimonials, layout, colors, typography, enableInlineEditing, sectionId }: TestimonialsProps): react_jsx_runtime.JSX.Element;
192
+
193
+ interface TeamMember {
194
+ id: string | number;
195
+ name: string;
196
+ role: string;
197
+ bio: string;
198
+ image?: string;
199
+ }
200
+ interface TeamProps {
201
+ title?: string;
202
+ members?: TeamMember[];
203
+ colors: {
204
+ primary: string;
205
+ text: string;
206
+ };
207
+ typography: {
208
+ headingFont?: string;
209
+ };
210
+ enableInlineEditing?: boolean;
211
+ sectionId?: string;
212
+ }
213
+ declare function Team({ title, members, colors, typography, enableInlineEditing, sectionId }: TeamProps): react_jsx_runtime.JSX.Element;
214
+
215
+ interface ContactProps {
216
+ title?: string;
217
+ email?: string;
218
+ phone?: string;
219
+ address?: string;
220
+ showForm?: boolean;
221
+ colors: {
222
+ primary: string;
223
+ text: string;
224
+ };
225
+ typography: {
226
+ headingFont?: string;
227
+ };
228
+ enableInlineEditing?: boolean;
229
+ sectionId?: string;
230
+ }
231
+ declare function Contact({ title, email, phone, address, showForm, colors, typography, enableInlineEditing, sectionId }: ContactProps): react_jsx_runtime.JSX.Element;
232
+
233
+ interface MinimalHeaderProps {
234
+ brandName?: string;
235
+ logoUrl?: string;
236
+ style?: 'logo' | 'text' | 'both';
237
+ alignment?: 'left' | 'center' | 'right';
238
+ sticky?: boolean;
239
+ colors: {
240
+ primary: string;
241
+ text: string;
242
+ };
243
+ typography: {
244
+ headingFont?: string;
245
+ };
246
+ enableInlineEditing?: boolean;
247
+ sectionId?: string;
248
+ }
249
+ declare function MinimalHeader({ brandName, logoUrl, style, alignment, sticky, colors, typography, enableInlineEditing, sectionId }: MinimalHeaderProps): react_jsx_runtime.JSX.Element;
250
+
251
+ interface NavLink {
252
+ id: string;
253
+ label: string;
254
+ url: string;
255
+ linkType?: 'internal' | 'external';
256
+ }
257
+ interface MinimalNavigationProps {
258
+ links: NavLink[];
259
+ style?: 'horizontal' | 'vertical';
260
+ colors: {
261
+ text: string;
262
+ };
263
+ enableInlineEditing?: boolean;
264
+ sectionId?: string;
265
+ }
266
+ declare function MinimalNavigation({ links, style, colors, enableInlineEditing, sectionId }: MinimalNavigationProps): react_jsx_runtime.JSX.Element;
267
+
268
+ interface MinimalFooterProps {
269
+ footerText?: string;
270
+ alignment?: 'left' | 'center' | 'right';
271
+ showSocial?: boolean;
272
+ showContact?: boolean;
273
+ showLinks?: boolean;
274
+ colors: {
275
+ primary: string;
276
+ text: string;
277
+ };
278
+ enableInlineEditing?: boolean;
279
+ sectionId?: string;
280
+ }
281
+ declare function MinimalFooter({ footerText, alignment, showSocial, showContact, showLinks, colors, enableInlineEditing, sectionId }: MinimalFooterProps): react_jsx_runtime.JSX.Element;
282
+
283
+ interface FeatureContentProps {
284
+ headline?: string;
285
+ description?: string;
286
+ image?: string;
287
+ buttonText?: string;
288
+ buttonUrl?: string;
289
+ layout?: 'image-left' | 'image-right' | 'image-top';
290
+ showButton?: boolean;
291
+ colors: {
292
+ primary: string;
293
+ text: string;
294
+ };
295
+ typography: {
296
+ headingFont?: string;
297
+ };
298
+ enableInlineEditing?: boolean;
299
+ sectionId?: string;
300
+ }
301
+ declare function FeatureContent({ headline, description, image, buttonText, buttonUrl, layout, showButton, colors, typography, enableInlineEditing, sectionId }: FeatureContentProps): react_jsx_runtime.JSX.Element;
302
+
303
+ interface Comparison {
304
+ id: string | number;
305
+ title?: string;
306
+ beforeImage?: string;
307
+ afterImage?: string;
308
+ }
309
+ interface BeforeAfterProps {
310
+ title?: string;
311
+ comparisons?: Comparison[];
312
+ colors: {
313
+ primary: string;
314
+ text: string;
315
+ };
316
+ typography: {
317
+ headingFont?: string;
318
+ };
319
+ enableInlineEditing?: boolean;
320
+ sectionId?: string;
321
+ }
322
+ declare function BeforeAfter({ title, comparisons, colors, typography, enableInlineEditing, sectionId }: BeforeAfterProps): react_jsx_runtime.JSX.Element;
323
+
324
+ interface PricingPlan {
325
+ id: string | number;
326
+ name: string;
327
+ price: number;
328
+ features: string[];
329
+ featured?: boolean;
330
+ }
331
+ interface PricingTableProps {
332
+ title?: string;
333
+ plans?: PricingPlan[];
334
+ colors: {
335
+ primary: string;
336
+ text: string;
337
+ };
338
+ typography: {
339
+ headingFont?: string;
340
+ };
341
+ enableInlineEditing?: boolean;
342
+ sectionId?: string;
343
+ }
344
+ declare function PricingTable({ title, plans, colors, typography, enableInlineEditing, sectionId }: PricingTableProps): react_jsx_runtime.JSX.Element;
345
+
346
+ interface InstagramFeedProps {
347
+ username?: string;
348
+ colors: {
349
+ primary: string;
350
+ };
351
+ enableInlineEditing?: boolean;
352
+ sectionId?: string;
353
+ }
354
+ declare function InstagramFeed({ username, colors, enableInlineEditing, sectionId }: InstagramFeedProps): react_jsx_runtime.JSX.Element;
355
+
356
+ interface CardLink {
357
+ id: string;
358
+ label: string;
359
+ url: string;
360
+ }
361
+ interface FixedInfoCardProps {
362
+ name?: string;
363
+ subheading?: string;
364
+ bio?: string;
365
+ links?: CardLink[];
366
+ bookingButtonText?: string;
367
+ bookingButtonUrl?: string;
368
+ showBookingButton?: boolean;
369
+ position?: 'bottom-left' | 'bottom-right' | 'bottom-center';
370
+ cardWidth?: 'small' | 'medium' | 'large';
371
+ cardColor?: string;
372
+ colors: {
373
+ primary: string;
374
+ text: string;
375
+ buttonText?: string;
376
+ };
377
+ typography: {
378
+ headingFont?: string;
379
+ };
380
+ enableInlineEditing?: boolean;
381
+ sectionId?: string;
382
+ }
383
+ declare function FixedInfoCard({ name, subheading, bio, links, bookingButtonText, bookingButtonUrl, showBookingButton, position, cardWidth, cardColor, colors, typography, enableInlineEditing, sectionId }: FixedInfoCardProps): react_jsx_runtime.JSX.Element;
384
+
385
+ interface BookingConfig {
386
+ theme?: {
387
+ colors?: {
388
+ primary: string;
389
+ secondary: string;
390
+ text: string;
391
+ bookingText?: string;
392
+ };
393
+ typography?: {
394
+ headingFont?: string;
395
+ bodyFont?: string;
396
+ bodySize?: string;
397
+ };
398
+ };
399
+ bookingSettings?: any;
400
+ }
401
+ interface BookingSectionProps {
402
+ config: BookingConfig;
403
+ colors: {
404
+ primary: string;
405
+ secondary: string;
406
+ text: string;
407
+ bookingText?: string;
408
+ };
409
+ BookingFlowComponent?: React.ComponentType<any>;
410
+ enableInlineEditing?: boolean;
411
+ sectionId?: string;
412
+ }
413
+ declare function BookingSection({ config, colors, BookingFlowComponent, enableInlineEditing, sectionId }: BookingSectionProps): react_jsx_runtime.JSX.Element;
414
+
415
+ interface VideoSectionProps {
416
+ videoUrl: string;
417
+ aspectRatio?: '16:9' | '4:3' | '1:1' | '9:16';
418
+ autoplay?: boolean;
419
+ loop?: boolean;
420
+ muted?: boolean;
421
+ controls?: boolean;
422
+ allowFullScreen?: boolean;
423
+ coverImage?: string;
424
+ maxWidth?: 'full' | 'large' | 'medium' | 'small';
425
+ alignment?: 'left' | 'center' | 'right';
426
+ borderRadius?: number;
427
+ colors: {
428
+ primary: string;
429
+ text: string;
430
+ };
431
+ typography?: {
432
+ headingFont?: string;
433
+ };
434
+ enableInlineEditing?: boolean;
435
+ sectionId?: string;
436
+ }
437
+ declare function VideoSection({ videoUrl, aspectRatio, autoplay, loop, muted, controls, allowFullScreen, coverImage, maxWidth, alignment, borderRadius, colors, enableInlineEditing, sectionId }: VideoSectionProps): react_jsx_runtime.JSX.Element;
438
+
439
+ interface ScrollingTextDividerProps {
440
+ text: string;
441
+ scrollDirection?: 'left' | 'right';
442
+ scrollSpeed?: 'slow' | 'medium' | 'fast' | number;
443
+ orientation?: 'horizontal' | 'diagonal-left' | 'diagonal-right';
444
+ dividerIcon?: 'bullet' | 'star' | 'diamond' | 'custom' | 'none';
445
+ customIcon?: string;
446
+ textSize?: 'small' | 'medium' | 'large' | 'xl';
447
+ textColor?: string;
448
+ fontWeight?: 'light' | 'normal' | 'bold';
449
+ backgroundColor?: string;
450
+ backgroundGradient?: string;
451
+ pauseOnHover?: boolean;
452
+ colors: {
453
+ primary: string;
454
+ text: string;
455
+ };
456
+ typography?: {
457
+ headingFont?: string;
458
+ };
459
+ enableInlineEditing?: boolean;
460
+ sectionId?: string;
461
+ }
462
+ declare function ScrollingTextDivider({ text, scrollDirection, scrollSpeed, orientation, dividerIcon, customIcon, textSize, textColor, fontWeight, backgroundColor, backgroundGradient, pauseOnHover, colors, typography, enableInlineEditing, sectionId }: ScrollingTextDividerProps): react_jsx_runtime.JSX.Element;
463
+
464
+ interface LocationMapProps {
465
+ address: string;
466
+ displayType?: 'map-only' | 'address-only' | 'both';
467
+ mapHeight?: 'small' | 'medium' | 'large';
468
+ mapStyle?: 'roadmap' | 'satellite';
469
+ zoom?: number;
470
+ showMarker?: boolean;
471
+ borderRadius?: number;
472
+ directionsButtonText?: string;
473
+ colors: {
474
+ primary: string;
475
+ text: string;
476
+ };
477
+ typography?: {
478
+ headingFont?: string;
479
+ bodyFont?: string;
480
+ };
481
+ enableInlineEditing?: boolean;
482
+ sectionId?: string;
483
+ }
484
+ declare function LocationMap({ address, displayType, mapHeight, mapStyle, zoom, showMarker, borderRadius, directionsButtonText, colors, typography, enableInlineEditing, sectionId }: LocationMapProps): react_jsx_runtime.JSX.Element;
485
+
486
+ interface ImageSectionProps {
487
+ imageUrl: string;
488
+ altText?: string;
489
+ caption?: string;
490
+ maxWidth?: 'full' | 'large' | 'medium' | 'small';
491
+ alignment?: 'left' | 'center' | 'right';
492
+ aspectRatio?: 'auto' | '16:9' | '4:3' | '1:1' | '3:2';
493
+ borderRadius?: number;
494
+ linkUrl?: string;
495
+ openInNewTab?: boolean;
496
+ colors: {
497
+ primary: string;
498
+ text: string;
499
+ };
500
+ typography?: {
501
+ bodyFont?: string;
502
+ };
503
+ enableInlineEditing?: boolean;
504
+ sectionId?: string;
505
+ }
506
+ declare function ImageSection({ imageUrl, altText, caption, maxWidth, alignment, aspectRatio, borderRadius, linkUrl, openInNewTab, colors, typography, enableInlineEditing, sectionId }: ImageSectionProps): react_jsx_runtime.JSX.Element;
507
+
508
+ interface FAQItem {
509
+ question: string;
510
+ answer: string;
511
+ }
512
+ interface FAQSectionProps {
513
+ title?: string;
514
+ faqs: FAQItem[];
515
+ layout?: 'accordion' | 'stacked';
516
+ maxWidth?: 'full' | 'large' | 'medium' | 'small';
517
+ colors: {
518
+ primary: string;
519
+ text: string;
520
+ };
521
+ typography?: {
522
+ headingFont?: string;
523
+ bodyFont?: string;
524
+ };
525
+ enableInlineEditing?: boolean;
526
+ sectionId?: string;
527
+ }
528
+ declare function FAQSection({ title, faqs, layout, maxWidth, colors, typography, enableInlineEditing, sectionId }: FAQSectionProps): react_jsx_runtime.JSX.Element;
529
+
530
+ interface NavbarLink {
531
+ id: string;
532
+ label: string;
533
+ url: string;
534
+ linkType?: 'internal' | 'external';
535
+ }
536
+ interface NavbarProps {
537
+ brandName?: string;
538
+ logoUrl?: string;
539
+ showLogo?: boolean;
540
+ showBrandName?: boolean;
541
+ links: NavbarLink[];
542
+ ctaText?: string;
543
+ ctaUrl?: string;
544
+ sticky?: boolean;
545
+ transparentOnTop?: boolean;
546
+ colors: {
547
+ primary: string;
548
+ text: string;
549
+ buttonText?: string;
550
+ };
551
+ typography?: {
552
+ headingFont?: string;
553
+ bodyFont?: string;
554
+ };
555
+ enableInlineEditing?: boolean;
556
+ sectionId?: string;
557
+ }
558
+ declare function Navbar({ brandName, logoUrl, showLogo, showBrandName, links, ctaText, ctaUrl, sticky, transparentOnTop, colors, typography, enableInlineEditing, sectionId }: NavbarProps): react_jsx_runtime.JSX.Element;
559
+
560
+ interface TextSectionProps {
561
+ title?: string;
562
+ content: string;
563
+ alignment?: 'left' | 'center' | 'right';
564
+ maxWidth?: 'full' | 'large' | 'medium' | 'small';
565
+ textSize?: 'small' | 'medium' | 'large';
566
+ backgroundColor?: string;
567
+ textColor?: string;
568
+ paddingY?: 'none' | 'small' | 'medium' | 'large';
569
+ colors: {
570
+ primary: string;
571
+ text: string;
572
+ };
573
+ typography?: {
574
+ headingFont?: string;
575
+ bodyFont?: string;
576
+ };
577
+ enableInlineEditing?: boolean;
578
+ sectionId?: string;
579
+ }
580
+ declare function TextSection({ title, content, alignment, maxWidth, textSize, backgroundColor, textColor, paddingY, colors, typography, enableInlineEditing, sectionId }: TextSectionProps): react_jsx_runtime.JSX.Element;
581
+
582
+ interface BookingFlowConfig {
583
+ steps: {
584
+ service_selection?: {
585
+ enabled: boolean;
586
+ settings?: any;
587
+ };
588
+ date_selection?: {
589
+ enabled: boolean;
590
+ settings?: any;
591
+ };
592
+ time_selection?: {
593
+ enabled: boolean;
594
+ settings?: any;
595
+ };
596
+ addon_selection?: {
597
+ enabled: boolean;
598
+ settings?: any;
599
+ };
600
+ contact_form?: {
601
+ enabled: boolean;
602
+ settings?: any;
603
+ };
604
+ confirmation?: {
605
+ enabled: boolean;
606
+ settings?: any;
607
+ };
608
+ };
609
+ progressBar?: {
610
+ style?: 'dots' | 'bar' | 'minimal';
611
+ };
612
+ transitions?: {
613
+ style?: 'slide' | 'fade';
614
+ speed?: 'fast' | 'normal' | 'slow';
615
+ };
616
+ background?: {
617
+ type: 'color' | 'gradient' | 'image';
618
+ value: string;
619
+ };
620
+ }
621
+ interface BookingFlowProps {
622
+ config: BookingFlowConfig;
623
+ colors: {
624
+ primary: string;
625
+ secondary: string;
626
+ text?: string;
627
+ bookingText?: string;
628
+ };
629
+ services?: any[];
630
+ categories?: any[];
631
+ dates?: string[];
632
+ times?: string[];
633
+ addons?: any[];
634
+ paymentProvider?: 'square' | 'stripe';
635
+ paymentConfig?: any;
636
+ isPreview?: boolean;
637
+ onComplete?: (bookingData: any) => void;
638
+ onStepChange?: (stepIndex: number, stepId: string) => void;
639
+ onServiceSelect?: (serviceId: string) => void;
640
+ onDateSelect?: (date: string) => void;
641
+ onContactInfoChange?: (contactInfo: any) => void;
642
+ validateStep?: (stepId: string, data: any) => boolean;
643
+ holdTimer?: {
644
+ enabled: boolean;
645
+ config: Partial<HoldTimerConfig>;
646
+ createHold: CreateHoldFn;
647
+ extendHold: ExtendHoldFn;
648
+ releaseHold: ReleaseHoldFn;
649
+ };
650
+ stepOrder?: string[];
651
+ optInModules?: OptInModule[];
652
+ onOptInData?: (moduleId: string, data: any) => void;
653
+ customPaymentForm?: React$1.ComponentType<any>;
654
+ cyclePhases?: Record<string, string>;
655
+ }
656
+ /**
657
+ * BookingFlow - Main orchestrator component for multi-step booking
658
+ *
659
+ * Manages flow state, navigation, and renders appropriate step components.
660
+ *
661
+ * @example
662
+ * ```tsx
663
+ * <BookingFlow
664
+ * config={{
665
+ * steps: {
666
+ * service_selection: { enabled: true, settings: {} },
667
+ * date_selection: { enabled: true, settings: {} },
668
+ * time_selection: { enabled: true, settings: {} },
669
+ * contact_form: { enabled: true, settings: {} }
670
+ * },
671
+ * progressBar: { style: 'dots' },
672
+ * transitions: { style: 'slide', speed: 'normal' }
673
+ * }}
674
+ * colors={{ primary: '#BCB4FF', secondary: '#CAC426' }}
675
+ * services={services}
676
+ * onComplete={(data) => console.log('Booking complete!', data)}
677
+ * />
678
+ * ```
679
+ */
680
+ declare function BookingFlow({ config, colors, services, categories, dates, times, addons, paymentProvider, paymentConfig, isPreview, onComplete, onStepChange, onServiceSelect, onDateSelect, onContactInfoChange, validateStep, holdTimer, stepOrder, optInModules, onOptInData, customPaymentForm, cyclePhases }: BookingFlowProps): react_jsx_runtime.JSX.Element;
681
+
682
+ interface ServiceSelectionProps {
683
+ services: Service[];
684
+ categories?: ServiceCategory[];
685
+ selectedService: string | null;
686
+ onServiceSelect: (serviceId: string) => void;
687
+ settings: ServiceSelectionSettings;
688
+ colors: {
689
+ primary: string;
690
+ secondary: string;
691
+ };
692
+ }
693
+ declare function ServiceSelection({ services, categories, selectedService, onServiceSelect, settings, colors }: ServiceSelectionProps): react_jsx_runtime.JSX.Element;
694
+
695
+ interface DateSelectionProps {
696
+ availableDates: string[];
697
+ selectedDate: string | null;
698
+ onDateSelect: (date: string) => void;
699
+ settings: DateSelectionSettings;
700
+ colors: {
701
+ primary: string;
702
+ secondary: string;
703
+ };
704
+ cyclePhases?: Record<string, string>;
705
+ selectedService?: any;
706
+ addons?: any[];
707
+ selectedAddons?: string[];
708
+ onAddonsChange?: (addonIds: string[]) => void;
709
+ addonPlacement?: string;
710
+ }
711
+ declare function DateSelection({ availableDates, selectedDate, onDateSelect, settings, colors, cyclePhases, selectedService, addons, selectedAddons, onAddonsChange, addonPlacement }: DateSelectionProps): react_jsx_runtime.JSX.Element;
712
+
713
+ interface TimeSelectionProps {
714
+ availableTimes: string[];
715
+ selectedTime: string | null;
716
+ onTimeSelect: (time: string) => void;
717
+ settings: TimeSelectionSettings;
718
+ serviceDuration?: number;
719
+ colors: {
720
+ primary: string;
721
+ secondary: string;
722
+ };
723
+ selectedService?: any;
724
+ selectedDate?: string | null;
725
+ selectedAddons?: string[];
726
+ addons?: any[];
727
+ }
728
+ declare function TimeSelection({ availableTimes, selectedTime, onTimeSelect, settings, serviceDuration, colors, selectedService, selectedDate, selectedAddons, addons }: TimeSelectionProps): react_jsx_runtime.JSX.Element;
729
+
730
+ interface AddonsSelectionProps {
731
+ addons: Addon[];
732
+ selectedAddons: string[];
733
+ onAddonsChange: (addonIds: string[]) => void;
734
+ settings: AddonSelectionSettings;
735
+ colors: {
736
+ primary: string;
737
+ secondary: string;
738
+ };
739
+ }
740
+ declare function AddonsSelection({ addons, selectedAddons, onAddonsChange, settings, colors }: AddonsSelectionProps): react_jsx_runtime.JSX.Element;
741
+
742
+ interface ContactFormProps {
743
+ contactInfo: Partial<ContactInfo>;
744
+ onContactInfoChange: (info: Partial<ContactInfo>) => void;
745
+ settings: ContactFormSettings;
746
+ optInModules?: OptInModule[];
747
+ onOptInData?: (moduleId: string, data: any) => void;
748
+ colors: {
749
+ primary: string;
750
+ secondary: string;
751
+ };
752
+ isPreview?: boolean;
753
+ }
754
+ declare function ContactForm({ contactInfo, onContactInfoChange, settings, optInModules, onOptInData, colors, isPreview }: ContactFormProps): react_jsx_runtime.JSX.Element;
755
+
756
+ interface ConfirmationProps {
757
+ service?: Service;
758
+ addons?: Addon[];
759
+ selectedDate?: string;
760
+ selectedTime?: string;
761
+ paymentProvider: 'square' | 'stripe';
762
+ paymentConfig: PaymentConfig;
763
+ onConfirm: () => Promise<void>;
764
+ colors: {
765
+ primary: string;
766
+ secondary: string;
767
+ };
768
+ isPreview?: boolean;
769
+ }
770
+ declare function Confirmation({ service, addons, selectedDate, selectedTime, paymentProvider, paymentConfig, onConfirm, colors, isPreview }: ConfirmationProps): react_jsx_runtime.JSX.Element;
771
+
772
+ /**
773
+ * Cycle phase definitions matching tenant backend
774
+ */
775
+ declare const CYCLE_PHASES: Record<string, Omit<CyclePhase, 'daysSinceStart' | 'confidence'>>;
776
+ interface CycleAwareDateSelectionProps {
777
+ availableDates: string[];
778
+ selectedDate: string | null;
779
+ onDateSelect: (date: string, cyclePhase?: CyclePhase) => void;
780
+ settings: DateSelectionSettings;
781
+ colors: {
782
+ primary: string;
783
+ secondary: string;
784
+ };
785
+ /** Tenant-provided function to fetch cycle data */
786
+ fetchCycleData?: FetchCycleDataFn;
787
+ /** Selected client (must have cycle_opt_in = true to show cycle features) */
788
+ selectedClient?: CycleClient;
789
+ /** Callback when a warning should be shown (e.g., avoid phase selected) */
790
+ onCycleWarning?: CycleWarningCallback;
791
+ /** Override to force enable/disable cycle features */
792
+ cycleAwareEnabled?: boolean;
793
+ }
794
+ /**
795
+ * CycleAwareDateSelection - Enhanced date picker with cycle phase indicators
796
+ *
797
+ * Wraps the base DateSelection component with cycle-aware features:
798
+ * - Visual indicators for each cycle phase
799
+ * - Color-coded calendar days
800
+ * - Legend explaining phases
801
+ * - Warnings for non-optimal dates
802
+ *
803
+ * @example
804
+ * ```tsx
805
+ * const fetchCycleData = async (client, dates) => {
806
+ * const res = await fetch(`/api/cycle?clientId=${client.id}`);
807
+ * const data = await res.json();
808
+ * return transformToCyclePhases(data, dates);
809
+ * };
810
+ *
811
+ * <CycleAwareDateSelection
812
+ * availableDates={dates}
813
+ * selectedDate={selectedDate}
814
+ * onDateSelect={(date, phase) => {
815
+ * setSelectedDate(date);
816
+ * if (phase?.phase === 'avoid') {
817
+ * showWarning('This date may be uncomfortable');
818
+ * }
819
+ * }}
820
+ * settings={settings}
821
+ * colors={colors}
822
+ * fetchCycleData={fetchCycleData}
823
+ * selectedClient={client}
824
+ * onCycleWarning={(phase, date) => console.log('Warning:', phase, date)}
825
+ * />
826
+ * ```
827
+ */
828
+ declare function CycleAwareDateSelection({ availableDates, selectedDate, onDateSelect, settings, colors, fetchCycleData, selectedClient, onCycleWarning, cycleAwareEnabled }: CycleAwareDateSelectionProps): react_jsx_runtime.JSX.Element;
829
+
830
+ /**
831
+ * BottomSheet - Reusable slide-up modal component
832
+ *
833
+ * Perfect for custom forms, terms of service, or any content that needs
834
+ * to slide up from the bottom of the screen.
835
+ *
836
+ * @example
837
+ * ```tsx
838
+ * <BottomSheet
839
+ * isOpen={isOpen}
840
+ * onClose={() => setIsOpen(false)}
841
+ * title="Color Consultation Form"
842
+ * isRequired={false}
843
+ * >
844
+ * <YourFormContent />
845
+ * </BottomSheet>
846
+ * ```
847
+ */
848
+ declare function BottomSheet({ isOpen, onClose, title, children, isRequired, maxHeight }: BottomSheetProps): react_jsx_runtime.JSX.Element;
849
+
850
+ interface HoldTimerProps {
851
+ /** Current hold status */
852
+ holdStatus: HoldStatus | null;
853
+ /** Configuration for timer behavior */
854
+ config?: Partial<HoldTimerConfig>;
855
+ /** Theme colors */
856
+ colors: {
857
+ primary: string;
858
+ secondary: string;
859
+ text?: string;
860
+ };
861
+ /** Callback when user clicks extend button */
862
+ onExtend?: () => void | Promise<void>;
863
+ /** Callback when user clicks release button */
864
+ onRelease?: () => void | Promise<void>;
865
+ /** Callback when timer enters warning state */
866
+ onWarning?: (timeRemaining: number) => void;
867
+ /** Callback when timer expires */
868
+ onExpired?: () => void;
869
+ /** Additional CSS classes */
870
+ className?: string;
871
+ }
872
+ /**
873
+ * HoldTimer - Countdown timer for time slot reservations
874
+ *
875
+ * Shows a countdown for how long a time slot is reserved, with
876
+ * visual warning states and optional extension/release actions.
877
+ *
878
+ * @example
879
+ * ```tsx
880
+ * <HoldTimer
881
+ * holdStatus={activeHold}
882
+ * config={{
883
+ * duration: 600000, // 10 minutes
884
+ * warningThreshold: 120000, // 2 minutes
885
+ * maxExtensions: 2
886
+ * }}
887
+ * colors={{ primary: '#8B5CF6', secondary: '#EC4899' }}
888
+ * onExtend={() => extendHold(activeHold.holdId)}
889
+ * onRelease={() => releaseHold(activeHold.holdId)}
890
+ * onExpired={() => {
891
+ * // Handle expiration - usually go back to time selection
892
+ * setSelectedTime(null);
893
+ * setStep('time');
894
+ * }}
895
+ * />
896
+ * ```
897
+ */
898
+ declare function HoldTimer({ holdStatus, config: userConfig, colors, onExtend, onRelease, onWarning, onExpired, className }: HoldTimerProps): react_jsx_runtime.JSX.Element | null;
899
+
900
+ interface SectionRendererProps {
901
+ section: {
902
+ id: string;
903
+ type: string;
904
+ settings: any;
905
+ enabled?: boolean;
906
+ position?: number;
907
+ };
908
+ theme: {
909
+ colors: {
910
+ primary: string;
911
+ secondary: string;
912
+ text: string;
913
+ bookingText?: string;
914
+ linkBackground?: string;
915
+ linkText?: string;
916
+ buttonText?: string;
917
+ };
918
+ typography: {
919
+ headingFont?: string;
920
+ bodyFont?: string;
921
+ bodySize?: string;
922
+ };
923
+ };
924
+ BookingFlowComponent?: React$1.ComponentType<any>;
925
+ config?: any;
926
+ enableInlineEditing?: boolean;
927
+ }
928
+ /**
929
+ * SectionRenderer - Universal renderer for all section types
930
+ *
931
+ * Maps section configuration objects to the appropriate component
932
+ * and passes through theme/styling props.
933
+ *
934
+ * @example
935
+ * ```tsx
936
+ * <SectionRenderer
937
+ * section={{
938
+ * id: 'hero-1',
939
+ * type: 'hero',
940
+ * settings: {
941
+ * headline: 'Welcome',
942
+ * subheadline: 'Transform your look',
943
+ * heroImage: '/hero.jpg',
944
+ * layout: 'split'
945
+ * }
946
+ * }}
947
+ * theme={{
948
+ * colors: { primary: '#BCB4FF', secondary: '#CAC426', text: '#000000' },
949
+ * typography: { headingFont: 'Geist Sans' }
950
+ * }}
951
+ * />
952
+ * ```
953
+ */
954
+ declare function SectionRenderer({ section, theme, BookingFlowComponent, config, enableInlineEditing }: SectionRendererProps): react_jsx_runtime.JSX.Element;
955
+
956
+ interface FormField$1 {
957
+ id: string;
958
+ label: string;
959
+ type: 'text' | 'email' | 'tel' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'date' | 'photo' | 'image';
960
+ placeholder?: string;
961
+ required: boolean;
962
+ options?: Array<{
963
+ value: string;
964
+ label: string;
965
+ }>;
966
+ }
967
+ interface FormBlockData$1 {
968
+ id: string;
969
+ type: 'section' | 'text' | 'image';
970
+ title?: string;
971
+ description?: string;
972
+ content?: string;
973
+ alignment?: 'left' | 'center' | 'right';
974
+ imageUrl?: string;
975
+ fields?: FormField$1[];
976
+ }
977
+ interface FormSettings {
978
+ title: string;
979
+ description: string;
980
+ submitButtonText: string;
981
+ successMessage: string;
982
+ blocks: FormBlockData$1[];
983
+ styling?: {
984
+ alignment?: 'left' | 'center' | 'right';
985
+ fieldStyle?: 'outlined' | 'filled' | 'underlined' | 'minimal';
986
+ sectionBackground?: string;
987
+ fieldBorder?: string;
988
+ buttonColor?: string;
989
+ labelColor?: string;
990
+ textColor?: string;
991
+ };
992
+ notifications: {
993
+ enabled: boolean;
994
+ adminEmail: string;
995
+ emailSubject: string;
996
+ };
997
+ }
998
+ interface FormRendererProps {
999
+ form: {
1000
+ id: string;
1001
+ name: string;
1002
+ slug: string;
1003
+ type: string;
1004
+ settings: FormSettings;
1005
+ };
1006
+ businessId: string;
1007
+ onSuccess?: () => void;
1008
+ }
1009
+ declare function FormRenderer({ form, businessId, onSuccess }: FormRendererProps): react_jsx_runtime.JSX.Element;
1010
+
1011
+ interface FormFieldData {
1012
+ id: string;
1013
+ label: string;
1014
+ type: 'text' | 'email' | 'tel' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'date' | 'photo' | 'image';
1015
+ placeholder?: string;
1016
+ required: boolean;
1017
+ options?: Array<{
1018
+ value: string;
1019
+ label: string;
1020
+ }>;
1021
+ }
1022
+ interface FormBlockData {
1023
+ id: string;
1024
+ type: 'section' | 'text' | 'image';
1025
+ title?: string;
1026
+ description?: string;
1027
+ content?: string;
1028
+ alignment?: 'left' | 'center' | 'right';
1029
+ imageUrl?: string;
1030
+ fields?: FormFieldData[];
1031
+ }
1032
+ interface FormBlockProps {
1033
+ block: FormBlockData;
1034
+ formData: Record<string, any>;
1035
+ errors: Record<string, string>;
1036
+ onChange: (fieldId: string, value: any, field: FormFieldData) => void;
1037
+ businessId?: string;
1038
+ formId?: string;
1039
+ styling?: {
1040
+ alignment?: 'left' | 'center' | 'right';
1041
+ fieldStyle?: 'outlined' | 'filled' | 'underlined' | 'minimal';
1042
+ sectionBackground?: string;
1043
+ fieldBorder?: string;
1044
+ buttonColor?: string;
1045
+ labelColor?: string;
1046
+ textColor?: string;
1047
+ };
1048
+ previewMode?: boolean;
1049
+ onFieldReorder?: (blockId: string, oldIndex: number, newIndex: number) => void;
1050
+ }
1051
+ declare function FormBlock({ block, formData, errors, onChange, businessId, formId, styling, previewMode, onFieldReorder }: FormBlockProps): react_jsx_runtime.JSX.Element | null;
1052
+
1053
+ interface FormField {
1054
+ id: string;
1055
+ label: string;
1056
+ type: 'text' | 'email' | 'tel' | 'textarea' | 'select' | 'radio' | 'checkbox' | 'date' | 'photo' | 'image';
1057
+ required: boolean;
1058
+ options?: Array<{
1059
+ value: string;
1060
+ label: string;
1061
+ }>;
1062
+ }
1063
+ interface ValidationResult {
1064
+ isValid: boolean;
1065
+ error?: string;
1066
+ }
1067
+ interface FormValidationResult {
1068
+ isValid: boolean;
1069
+ errors: Record<string, string>;
1070
+ }
1071
+ declare function validateField(value: any, field: FormField): ValidationResult;
1072
+ declare function validateForm(formData: Record<string, any>, fields: FormField[]): FormValidationResult;
1073
+ declare function sanitizeFormData(formData: Record<string, any>): Record<string, any>;
1074
+
1075
+ export { About, type AboutProps, Addon, AddonSelectionSettings, AddonsSelection, BeforeAfter, type BeforeAfterProps, type BookingConfig, BookingFlow, type BookingFlowConfig, type BookingFlowProps, BookingSection, type BookingSectionProps, BottomSheet, BottomSheetProps, CYCLE_PHASES, type CardLink, type Comparison, Confirmation, Contact, ContactForm, ContactFormSettings, ContactInfo, type ContactProps, CreateHoldFn, CycleAwareDateSelection, type CycleAwareDateSelectionProps, CycleClient, CyclePhase, CycleWarningCallback, DateSelection, DateSelectionSettings, ExtendHoldFn, type FAQItem, FAQSection, type FAQSectionProps, FeatureContent, type FeatureContentProps, FeaturedLink, type FeaturedLinkProps, FetchCycleDataFn, FixedInfoCard, type FixedInfoCardProps, FormBlock, FormRenderer, Gallery, type GalleryImage, type GalleryProps, Header, type HeaderProps, Hero, type HeroProps, HoldStatus, HoldTimer, HoldTimerConfig, type HoldTimerProps, ImageSection, type ImageSectionProps, InstagramFeed, type InstagramFeedProps, type Link, LinkList, type LinkListProps, LocationMap, type LocationMapProps, Logo, type LogoProps, MinimalFooter, type MinimalFooterProps, MinimalHeader, type MinimalHeaderProps, MinimalNavigation, type MinimalNavigationProps, type NavLink, Navbar, type NavbarLink, type NavbarProps, OptInModule, PaymentConfig, type PricingPlan, PricingTable, type PricingTableProps, ReleaseHoldFn, ScrollingTextDivider, type ScrollingTextDividerProps, SectionRenderer, type SectionRendererProps, Service, ServiceCategory, ServiceSelection, ServiceSelectionSettings, ServicesPreview, type ServicesPreviewProps, SocialBar, type SocialBarProps, Team, type TeamMember, type TeamProps, type Testimonial, Testimonials, type TestimonialsProps, TextSection, type TextSectionProps, TimeSelection, TimeSelectionSettings, VideoSection, type VideoSectionProps, sanitizeFormData, validateField, validateForm };