@zoyth/simple-site-framework 1.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.
- package/LICENSE +21 -0
- package/README.md +572 -0
- package/bin/create-simple-site.js +390 -0
- package/bin/simple-site.js +664 -0
- package/dist/client.js +135 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +107 -0
- package/dist/client.mjs.map +1 -0
- package/dist/components/index.d.mts +3936 -0
- package/dist/components/index.d.ts +3936 -0
- package/dist/components/index.js +38265 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +38173 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/index.d.mts +298 -0
- package/dist/config/index.d.ts +298 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +1 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/index.d.mts +2184 -0
- package/dist/index.d.ts +2184 -0
- package/dist/index.js +1713 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1605 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/i18n/index.js +665 -0
- package/dist/lib/i18n/index.js.map +1 -0
- package/dist/lib/i18n/index.mjs +621 -0
- package/dist/lib/i18n/index.mjs.map +1 -0
- package/docs/DOCUMENTATION-STRUCTURE.md +1156 -0
- package/docs/EXPORTS.md +125 -0
- package/docs/PERFORMANCE.md +757 -0
- package/docs/POLICY-PAGES.md +867 -0
- package/docs/ROADMAP.md +334 -0
- package/docs/SEO.md +455 -0
- package/docs/SITEMAP.md +708 -0
- package/docs/STRUCTURED-DATA.md +671 -0
- package/docs/accessibility/common-patterns.md +529 -0
- package/docs/accessibility/keyboard-navigation.md +263 -0
- package/docs/accessibility/overview.md +122 -0
- package/docs/accessibility/screen-readers.md +311 -0
- package/docs/accessibility/wcag-compliance.md +159 -0
- package/docs/api/README.md +164 -0
- package/docs/api/components/Accessibility.md +356 -0
- package/docs/api/components/Button.md +240 -0
- package/docs/api/components/HeroSection.md +306 -0
- package/docs/architecture/decisions.md +449 -0
- package/docs/components/AnalyticsTracker.md +58 -0
- package/docs/components/AnimatedCounter.md +48 -0
- package/docs/components/AnimatedSection.md +56 -0
- package/docs/components/BlogCard.md +42 -0
- package/docs/components/Checkbox.md +56 -0
- package/docs/components/CodeBlock.md +52 -0
- package/docs/components/ComparisonTable.md +40 -0
- package/docs/components/ComponentDemo.md +38 -0
- package/docs/components/CountdownTimer.md +51 -0
- package/docs/components/ExitIntentModal.md +56 -0
- package/docs/components/FAQAccordion.md +66 -0
- package/docs/components/FeaturesGrid.md +55 -0
- package/docs/components/FileUpload.md +54 -0
- package/docs/components/I18nMetaTags.md +55 -0
- package/docs/components/Icon.md +53 -0
- package/docs/components/LazySection.md +46 -0
- package/docs/components/LiveProof.md +53 -0
- package/docs/components/LoadingSpinner.md +46 -0
- package/docs/components/MultiStepForm.md +48 -0
- package/docs/components/PolicyLayout.md +55 -0
- package/docs/components/PricingTable.md +49 -0
- package/docs/components/Radio.md +59 -0
- package/docs/components/SEOMetaTags.md +58 -0
- package/docs/components/ScriptInjector.md +50 -0
- package/docs/components/Select.md +72 -0
- package/docs/components/Skeleton.md +47 -0
- package/docs/components/StatsSection.md +48 -0
- package/docs/components/StickyBar.md +62 -0
- package/docs/components/StructuredData.md +99 -0
- package/docs/components/StyleGuide.md +46 -0
- package/docs/components/TableOfContents.md +47 -0
- package/docs/components/TestimonialCarousel.md +42 -0
- package/docs/components/Timeline.md +51 -0
- package/docs/components/Toast.md +59 -0
- package/docs/components/TrackedLink.md +62 -0
- package/docs/components/TrustBadges.md +44 -0
- package/docs/components/conversion/MobileCTA.md +363 -0
- package/docs/components/forms/ContactForm.md +75 -0
- package/docs/components/forms/FormField.md +74 -0
- package/docs/components/layout/Footer.md +601 -0
- package/docs/components/layout/Header.md +549 -0
- package/docs/components/layout/LanguageSelector.md +54 -0
- package/docs/components/layout/LanguageSwitcher.md +24 -0
- package/docs/components/overview.md +447 -0
- package/docs/components/sections/AboutSection.md +48 -0
- package/docs/components/sections/CTASection.md +596 -0
- package/docs/components/sections/CaseStudySection.md +47 -0
- package/docs/components/sections/ContactSection.md +599 -0
- package/docs/components/sections/FeatureSection.md +44 -0
- package/docs/components/sections/HeroSection.md +404 -0
- package/docs/components/sections/LogosSection.md +47 -0
- package/docs/components/sections/PersonalTaxesSection.md +23 -0
- package/docs/components/sections/RecruitingSection.md +23 -0
- package/docs/components/sections/SecurePortalSection.md +23 -0
- package/docs/components/sections/ServicePageLayout.md +52 -0
- package/docs/components/sections/ServicesSection.md +49 -0
- package/docs/components/sections/TestimonialSection.md +44 -0
- package/docs/components/sections/WhyChooseUsSection.md +54 -0
- package/docs/components/ui/Breadcrumb.md +70 -0
- package/docs/components/ui/Button.md +514 -0
- package/docs/components/ui/Card.md +501 -0
- package/docs/components/ui/Input.md +54 -0
- package/docs/components/ui/MobileLinks.md +43 -0
- package/docs/components/ui/Modal.md +60 -0
- package/docs/components/ui/Tabs.md +62 -0
- package/docs/components/ui/Textarea.md +52 -0
- package/docs/core-concepts/configuration-driven.md +552 -0
- package/docs/core-concepts/overview.md +351 -0
- package/docs/features/accessibility/README.md +73 -0
- package/docs/features/accessibility/aria-support.md +177 -0
- package/docs/features/accessibility/color-contrast.md +155 -0
- package/docs/features/accessibility/focus-management.md +187 -0
- package/docs/features/accessibility/testing.md +196 -0
- package/docs/features/analytics/README.md +51 -0
- package/docs/features/analytics/ab-testing.md +171 -0
- package/docs/features/analytics/conversion-tracking.md +207 -0
- package/docs/features/analytics/custom-events.md +219 -0
- package/docs/features/analytics/privacy.md +198 -0
- package/docs/features/analytics/setup.md +114 -0
- package/docs/features/analytics/tracking-events.md +224 -0
- package/docs/features/i18n/README.md +51 -0
- package/docs/features/i18n/best-practices.md +273 -0
- package/docs/features/i18n/configuration.md +84 -0
- package/docs/features/i18n/formatting.md +133 -0
- package/docs/features/i18n/locale-detection.md +122 -0
- package/docs/features/i18n/routing.md +99 -0
- package/docs/features/i18n/rtl-support.md +191 -0
- package/docs/features/i18n/translations.md +129 -0
- package/docs/features/internationalization.md +595 -0
- package/docs/features/performance/README.md +77 -0
- package/docs/features/performance/bundle-size.md +134 -0
- package/docs/features/performance/caching.md +131 -0
- package/docs/features/performance/code-splitting.md +121 -0
- package/docs/features/performance/image-optimization.md +110 -0
- package/docs/features/performance/lazy-loading.md +92 -0
- package/docs/features/performance/monitoring.md +148 -0
- package/docs/features/seo/README.md +51 -0
- package/docs/features/seo/best-practices.md +184 -0
- package/docs/features/seo/canonical-urls.md +182 -0
- package/docs/features/seo/meta-tags.md +126 -0
- package/docs/features/seo/open-graph.md +166 -0
- package/docs/features/seo/robots-txt.md +146 -0
- package/docs/features/seo/sitemaps.md +162 -0
- package/docs/features/seo/structured-data.md +166 -0
- package/docs/getting-started/installation.md +292 -0
- package/docs/getting-started/introduction.md +195 -0
- package/docs/getting-started/quick-start.md +460 -0
- package/docs/guides/analytics-setup.md +616 -0
- package/docs/i18n/CONFIGURATION.md +353 -0
- package/docs/i18n/EXAMPLES.md +402 -0
- package/docs/i18n/MIGRATION.md +260 -0
- package/docs/i18n/SEO.md +392 -0
- package/docs/i18n/STATIC-GENERATION-FIX.md +71 -0
- package/docs/migration/changelog.md +136 -0
- package/docs/migration/overview.md +233 -0
- package/docs/recipes/adding-animations.md +475 -0
- package/docs/recipes/forms-with-validation.md +393 -0
- package/package.json +152 -0
|
@@ -0,0 +1,3936 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { ReactNode, InputHTMLAttributes, ReactElement, ComponentType, ButtonHTMLAttributes, HTMLAttributes, TextareaHTMLAttributes } from 'react';
|
|
4
|
+
import { FieldError } from 'react-hook-form';
|
|
5
|
+
import { LucideProps } from 'lucide-react';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Available animation types for AnimatedSection
|
|
9
|
+
* - fadeInUp: Fades in while moving up
|
|
10
|
+
* - fadeInDown: Fades in while moving down
|
|
11
|
+
* - fadeInLeft: Fades in while moving from left
|
|
12
|
+
* - fadeInRight: Fades in while moving from right
|
|
13
|
+
* - scaleIn: Fades in while scaling up
|
|
14
|
+
* - slideInLeft: Slides in from left
|
|
15
|
+
* - slideInRight: Slides in from right
|
|
16
|
+
* - none: No animation (used when prefers-reduced-motion is enabled)
|
|
17
|
+
*/
|
|
18
|
+
type AnimationType = 'fadeInUp' | 'fadeInDown' | 'fadeInLeft' | 'fadeInRight' | 'scaleIn' | 'slideInLeft' | 'slideInRight' | 'none';
|
|
19
|
+
interface AnimatedSectionProps {
|
|
20
|
+
/** Content to animate */
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
/** Animation type to use @default 'fadeInUp' */
|
|
23
|
+
animation?: AnimationType;
|
|
24
|
+
/** Delay before animation starts in seconds @default 0 */
|
|
25
|
+
delay?: number;
|
|
26
|
+
/** Animation duration in seconds @default 0.6 */
|
|
27
|
+
duration?: number;
|
|
28
|
+
/** Delay between animating children when using AnimatedItem @default 0 */
|
|
29
|
+
stagger?: number;
|
|
30
|
+
/** Percentage of element that must be visible to trigger (0-1) @default 0.1 */
|
|
31
|
+
threshold?: number;
|
|
32
|
+
/** Whether animation should only happen once @default true */
|
|
33
|
+
triggerOnce?: boolean;
|
|
34
|
+
/** Additional CSS classes */
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* AnimatedSection - Wrapper component for scroll-triggered entrance animations
|
|
39
|
+
*
|
|
40
|
+
* Automatically animates children when they scroll into view. Respects user's
|
|
41
|
+
* prefers-reduced-motion setting for accessibility.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // Basic usage
|
|
45
|
+
* <AnimatedSection animation="fadeInUp">
|
|
46
|
+
* <h1>This will fade in from below</h1>
|
|
47
|
+
* </AnimatedSection>
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // With stagger effect for children
|
|
51
|
+
* <AnimatedSection animation="fadeInLeft" stagger={0.1}>
|
|
52
|
+
* <AnimatedItem><div>Item 1</div></AnimatedItem>
|
|
53
|
+
* <AnimatedItem><div>Item 2</div></AnimatedItem>
|
|
54
|
+
* <AnimatedItem><div>Item 3</div></AnimatedItem>
|
|
55
|
+
* </AnimatedSection>
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* // Delayed animation
|
|
59
|
+
* <AnimatedSection animation="scaleIn" delay={0.3} duration={0.8}>
|
|
60
|
+
* <Card>Content</Card>
|
|
61
|
+
* </AnimatedSection>
|
|
62
|
+
*/
|
|
63
|
+
declare function AnimatedSection({ children, animation, delay, duration, stagger, threshold, triggerOnce, className }: AnimatedSectionProps): react_jsx_runtime.JSX.Element;
|
|
64
|
+
/**
|
|
65
|
+
* AnimatedItem - Individual item to be animated within AnimatedSection
|
|
66
|
+
*
|
|
67
|
+
* Use as children of AnimatedSection when you want stagger animations.
|
|
68
|
+
* Each AnimatedItem will animate in sequence based on the stagger delay.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* <AnimatedSection stagger={0.1}>
|
|
72
|
+
* <AnimatedItem><Feature1 /></AnimatedItem>
|
|
73
|
+
* <AnimatedItem><Feature2 /></AnimatedItem>
|
|
74
|
+
* <AnimatedItem><Feature3 /></AnimatedItem>
|
|
75
|
+
* </AnimatedSection>
|
|
76
|
+
*/
|
|
77
|
+
declare function AnimatedItem({ children, className }: {
|
|
78
|
+
/** Content to animate */
|
|
79
|
+
children: ReactNode;
|
|
80
|
+
/** Additional CSS classes */
|
|
81
|
+
className?: string;
|
|
82
|
+
}): react_jsx_runtime.JSX.Element;
|
|
83
|
+
|
|
84
|
+
type ToastType = 'success' | 'error' | 'warning' | 'info';
|
|
85
|
+
type ToastPosition = 'top-right' | 'top-center' | 'top-left' | 'bottom-right' | 'bottom-center' | 'bottom-left';
|
|
86
|
+
interface Toast {
|
|
87
|
+
id: string;
|
|
88
|
+
type: ToastType;
|
|
89
|
+
message: string;
|
|
90
|
+
duration?: number;
|
|
91
|
+
action?: {
|
|
92
|
+
label: string;
|
|
93
|
+
onClick: () => void;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
interface ToastContextType {
|
|
97
|
+
toasts: Toast[];
|
|
98
|
+
addToast: (toast: Omit<Toast, 'id'>) => void;
|
|
99
|
+
removeToast: (id: string) => void;
|
|
100
|
+
success: (message: string, options?: Omit<Toast, 'id' | 'type' | 'message'>) => void;
|
|
101
|
+
error: (message: string, options?: Omit<Toast, 'id' | 'type' | 'message'>) => void;
|
|
102
|
+
warning: (message: string, options?: Omit<Toast, 'id' | 'type' | 'message'>) => void;
|
|
103
|
+
info: (message: string, options?: Omit<Toast, 'id' | 'type' | 'message'>) => void;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Hook to access toast notifications
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* const toast = useToast()
|
|
110
|
+
* toast.success('Changes saved!')
|
|
111
|
+
* toast.error('Failed to submit form')
|
|
112
|
+
*/
|
|
113
|
+
declare function useToast(): ToastContextType;
|
|
114
|
+
interface ToastProviderProps {
|
|
115
|
+
/** Content to wrap */
|
|
116
|
+
children: ReactNode;
|
|
117
|
+
/** Position of toast notifications @default 'top-right' */
|
|
118
|
+
position?: ToastPosition;
|
|
119
|
+
/** Maximum number of toasts to show at once @default 5 */
|
|
120
|
+
maxToasts?: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* ToastProvider - Context provider for toast notifications
|
|
124
|
+
*
|
|
125
|
+
* Wrap your app with this provider to enable toast notifications.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* <ToastProvider position="top-right">
|
|
129
|
+
* <YourApp />
|
|
130
|
+
* </ToastProvider>
|
|
131
|
+
*/
|
|
132
|
+
declare function ToastProvider({ children, position, maxToasts }: ToastProviderProps): react_jsx_runtime.JSX.Element;
|
|
133
|
+
/**
|
|
134
|
+
* Simple toast function for quick notifications
|
|
135
|
+
* Note: Requires ToastProvider in parent tree
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* import { toast } from '@zoyth/simple-site-framework/components'
|
|
139
|
+
*
|
|
140
|
+
* toast.success('Saved!')
|
|
141
|
+
* toast.error('Failed to save')
|
|
142
|
+
* toast.warning('Unsaved changes')
|
|
143
|
+
* toast.info('New features available', {
|
|
144
|
+
* duration: 8000,
|
|
145
|
+
* action: { label: 'Learn more', onClick: () => {} }
|
|
146
|
+
* })
|
|
147
|
+
*/
|
|
148
|
+
declare const toast: {
|
|
149
|
+
success: (message: string, options?: Omit<Toast, "id" | "type" | "message">) => void;
|
|
150
|
+
error: (message: string, options?: Omit<Toast, "id" | "type" | "message">) => void;
|
|
151
|
+
warning: (message: string, options?: Omit<Toast, "id" | "type" | "message">) => void;
|
|
152
|
+
info: (message: string, options?: Omit<Toast, "id" | "type" | "message">) => void;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
type SpinnerStyle = 'circle' | 'dots' | 'pulse' | 'ring';
|
|
156
|
+
type SpinnerSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
157
|
+
interface LoadingSpinnerProps {
|
|
158
|
+
/** Spinner animation style @default 'circle' */
|
|
159
|
+
style?: SpinnerStyle;
|
|
160
|
+
/** Spinner size @default 'md' */
|
|
161
|
+
size?: SpinnerSize;
|
|
162
|
+
/** Optional loading text to display */
|
|
163
|
+
text?: string;
|
|
164
|
+
/** Additional CSS classes */
|
|
165
|
+
className?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* LoadingSpinner - Animated loading indicator
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* <LoadingSpinner size="lg" text="Loading..." />
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* // Inline spinner
|
|
175
|
+
* <LoadingSpinner size="sm" style="dots" />
|
|
176
|
+
*/
|
|
177
|
+
declare function LoadingSpinner({ style, size, text, className }: LoadingSpinnerProps): react_jsx_runtime.JSX.Element;
|
|
178
|
+
declare namespace LoadingSpinner {
|
|
179
|
+
var Overlay: typeof LoadingOverlay;
|
|
180
|
+
}
|
|
181
|
+
interface LoadingOverlayProps {
|
|
182
|
+
/** Content to display in overlay */
|
|
183
|
+
children: React.ReactNode;
|
|
184
|
+
/** Spinner style @default 'circle' */
|
|
185
|
+
style?: SpinnerStyle;
|
|
186
|
+
/** Blur backdrop @default true */
|
|
187
|
+
blur?: boolean;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* LoadingOverlay - Full-page loading overlay
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* <LoadingSpinner.Overlay>
|
|
194
|
+
* Processing payment...
|
|
195
|
+
* </LoadingSpinner.Overlay>
|
|
196
|
+
*/
|
|
197
|
+
declare function LoadingOverlay({ children, style, blur }: LoadingOverlayProps): react_jsx_runtime.JSX.Element;
|
|
198
|
+
|
|
199
|
+
type SkeletonAnimation = 'pulse' | 'shimmer';
|
|
200
|
+
interface SkeletonProps {
|
|
201
|
+
/** Width of skeleton (CSS value) @default '100%' */
|
|
202
|
+
width?: string | number;
|
|
203
|
+
/** Height of skeleton (CSS value) @default '1rem' */
|
|
204
|
+
height?: string | number;
|
|
205
|
+
/** Border radius @default '0.25rem' */
|
|
206
|
+
radius?: string | number;
|
|
207
|
+
/** Animation style @default 'shimmer' */
|
|
208
|
+
animation?: SkeletonAnimation;
|
|
209
|
+
/** Additional CSS classes */
|
|
210
|
+
className?: string;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Skeleton - Loading placeholder with animation
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* <Skeleton width="100%" height="200px" />
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* <Skeleton width={120} height={20} radius="9999px" />
|
|
220
|
+
*/
|
|
221
|
+
declare function Skeleton({ width, height, radius, animation, className }: SkeletonProps): react_jsx_runtime.JSX.Element;
|
|
222
|
+
declare namespace Skeleton {
|
|
223
|
+
var Text: typeof SkeletonText;
|
|
224
|
+
var Card: typeof SkeletonCard;
|
|
225
|
+
var Avatar: typeof SkeletonAvatar;
|
|
226
|
+
var Button: typeof SkeletonButton;
|
|
227
|
+
var Image: typeof SkeletonImage;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* SkeletonText - Multiple lines of text skeleton
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* <SkeletonText lines={3} />
|
|
234
|
+
*/
|
|
235
|
+
declare function SkeletonText({ lines, className }: {
|
|
236
|
+
/** Number of text lines @default 3 */
|
|
237
|
+
lines?: number;
|
|
238
|
+
/** Additional CSS classes */
|
|
239
|
+
className?: string;
|
|
240
|
+
}): react_jsx_runtime.JSX.Element;
|
|
241
|
+
/**
|
|
242
|
+
* SkeletonCard - Card layout skeleton
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* <SkeletonCard lines={3} />
|
|
246
|
+
*/
|
|
247
|
+
declare function SkeletonCard({ lines, showImage, className }: {
|
|
248
|
+
/** Number of text lines @default 3 */
|
|
249
|
+
lines?: number;
|
|
250
|
+
/** Show image placeholder @default true */
|
|
251
|
+
showImage?: boolean;
|
|
252
|
+
/** Additional CSS classes */
|
|
253
|
+
className?: string;
|
|
254
|
+
}): react_jsx_runtime.JSX.Element;
|
|
255
|
+
/**
|
|
256
|
+
* SkeletonAvatar - Circular avatar skeleton
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* <SkeletonAvatar size={48} />
|
|
260
|
+
*/
|
|
261
|
+
declare function SkeletonAvatar({ size, className }: {
|
|
262
|
+
/** Avatar size in pixels @default 40 */
|
|
263
|
+
size?: number;
|
|
264
|
+
/** Additional CSS classes */
|
|
265
|
+
className?: string;
|
|
266
|
+
}): react_jsx_runtime.JSX.Element;
|
|
267
|
+
/**
|
|
268
|
+
* SkeletonButton - Button skeleton
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* <SkeletonButton />
|
|
272
|
+
*/
|
|
273
|
+
declare function SkeletonButton({ width, height, className }: {
|
|
274
|
+
/** Button width @default 120 */
|
|
275
|
+
width?: number;
|
|
276
|
+
/** Button height @default 40 */
|
|
277
|
+
height?: number;
|
|
278
|
+
/** Additional CSS classes */
|
|
279
|
+
className?: string;
|
|
280
|
+
}): react_jsx_runtime.JSX.Element;
|
|
281
|
+
/**
|
|
282
|
+
* SkeletonImage - Image placeholder skeleton
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* <SkeletonImage width="100%" height="300px" />
|
|
286
|
+
*/
|
|
287
|
+
declare function SkeletonImage({ width, height, className }: {
|
|
288
|
+
/** Image width @default '100%' */
|
|
289
|
+
width?: string | number;
|
|
290
|
+
/** Image height @default '200px' */
|
|
291
|
+
height?: string | number;
|
|
292
|
+
/** Additional CSS classes */
|
|
293
|
+
className?: string;
|
|
294
|
+
}): react_jsx_runtime.JSX.Element;
|
|
295
|
+
|
|
296
|
+
interface FormFieldProps {
|
|
297
|
+
/** Field label text */
|
|
298
|
+
label?: string;
|
|
299
|
+
/** Field name (matches form schema) */
|
|
300
|
+
name: string;
|
|
301
|
+
/** Error object from React Hook Form */
|
|
302
|
+
error?: FieldError;
|
|
303
|
+
/** Optional hint text shown below input */
|
|
304
|
+
hint?: string;
|
|
305
|
+
/** Whether field is required */
|
|
306
|
+
required?: boolean;
|
|
307
|
+
/** Input element to render */
|
|
308
|
+
children: ReactNode;
|
|
309
|
+
/** Additional CSS classes */
|
|
310
|
+
className?: string;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* FormField - Wrapper for form inputs with label and error display
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* <FormField
|
|
317
|
+
* name="email"
|
|
318
|
+
* label="Email Address"
|
|
319
|
+
* error={errors.email}
|
|
320
|
+
* hint="We'll never share your email"
|
|
321
|
+
* required
|
|
322
|
+
* >
|
|
323
|
+
* <Input type="email" {...register('email')} />
|
|
324
|
+
* </FormField>
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* // With Controller for custom components
|
|
328
|
+
* <FormField name="country" label="Country" error={errors.country}>
|
|
329
|
+
* <Controller
|
|
330
|
+
* name="country"
|
|
331
|
+
* control={control}
|
|
332
|
+
* render={({ field }) => <Select {...field} options={countries} />}
|
|
333
|
+
* />
|
|
334
|
+
* </FormField>
|
|
335
|
+
*/
|
|
336
|
+
declare function FormField({ label, name, error, hint, required, children, className }: FormFieldProps): react_jsx_runtime.JSX.Element;
|
|
337
|
+
/**
|
|
338
|
+
* FormGroup - Group multiple fields with a common label
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* <FormGroup label="Address" description="Your billing address">
|
|
342
|
+
* <FormField name="street" label="Street">
|
|
343
|
+
* <Input {...register('street')} />
|
|
344
|
+
* </FormField>
|
|
345
|
+
* <FormField name="city" label="City">
|
|
346
|
+
* <Input {...register('city')} />
|
|
347
|
+
* </FormField>
|
|
348
|
+
* </FormGroup>
|
|
349
|
+
*/
|
|
350
|
+
declare function FormGroup({ label, description, children, className }: {
|
|
351
|
+
/** Group label */
|
|
352
|
+
label?: string;
|
|
353
|
+
/** Optional description text */
|
|
354
|
+
description?: string;
|
|
355
|
+
/** Form fields */
|
|
356
|
+
children: ReactNode;
|
|
357
|
+
/** Additional CSS classes */
|
|
358
|
+
className?: string;
|
|
359
|
+
}): react_jsx_runtime.JSX.Element;
|
|
360
|
+
|
|
361
|
+
type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
362
|
+
interface ModalProps {
|
|
363
|
+
/** Whether modal is open */
|
|
364
|
+
open: boolean;
|
|
365
|
+
/** Callback when open state changes */
|
|
366
|
+
onOpenChange: (open: boolean) => void;
|
|
367
|
+
/** Modal title */
|
|
368
|
+
title?: string;
|
|
369
|
+
/** Modal description */
|
|
370
|
+
description?: string;
|
|
371
|
+
/** Modal size @default 'md' */
|
|
372
|
+
size?: ModalSize;
|
|
373
|
+
/** Modal content */
|
|
374
|
+
children: ReactNode;
|
|
375
|
+
/** Whether clicking backdrop closes modal @default true */
|
|
376
|
+
closeOnBackdrop?: boolean;
|
|
377
|
+
/** Whether ESC key closes modal @default true */
|
|
378
|
+
closeOnEscape?: boolean;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Modal - Accessible dialog component
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* const [open, setOpen] = useState(false)
|
|
385
|
+
*
|
|
386
|
+
* <Modal
|
|
387
|
+
* open={open}
|
|
388
|
+
* onOpenChange={setOpen}
|
|
389
|
+
* title="Confirm Delete"
|
|
390
|
+
* description="This action cannot be undone"
|
|
391
|
+
* size="md"
|
|
392
|
+
* >
|
|
393
|
+
* <Modal.Content>
|
|
394
|
+
* <p>Are you sure you want to delete this item?</p>
|
|
395
|
+
* </Modal.Content>
|
|
396
|
+
* <Modal.Footer>
|
|
397
|
+
* <Button variant="outlined" onClick={() => setOpen(false)}>
|
|
398
|
+
* Cancel
|
|
399
|
+
* </Button>
|
|
400
|
+
* <Button variant="filled" onClick={handleDelete}>
|
|
401
|
+
* Delete
|
|
402
|
+
* </Button>
|
|
403
|
+
* </Modal.Footer>
|
|
404
|
+
* </Modal>
|
|
405
|
+
*/
|
|
406
|
+
declare function Modal({ open, onOpenChange, title, description, size, children, closeOnBackdrop, closeOnEscape }: ModalProps): react_jsx_runtime.JSX.Element;
|
|
407
|
+
declare namespace Modal {
|
|
408
|
+
var Content: typeof ModalContent;
|
|
409
|
+
var Footer: typeof ModalFooter;
|
|
410
|
+
var Trigger: any;
|
|
411
|
+
var Root: any;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* ModalContent - Content area of modal
|
|
415
|
+
*/
|
|
416
|
+
declare function ModalContent({ children, className }: {
|
|
417
|
+
children: ReactNode;
|
|
418
|
+
className?: string;
|
|
419
|
+
}): react_jsx_runtime.JSX.Element;
|
|
420
|
+
/**
|
|
421
|
+
* ModalFooter - Footer area with actions
|
|
422
|
+
*/
|
|
423
|
+
declare function ModalFooter({ children, className }: {
|
|
424
|
+
children: ReactNode;
|
|
425
|
+
className?: string;
|
|
426
|
+
}): react_jsx_runtime.JSX.Element;
|
|
427
|
+
/**
|
|
428
|
+
* ModalTrigger - Button that opens modal
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* <Modal.Root>
|
|
432
|
+
* <Modal.Trigger asChild>
|
|
433
|
+
* <Button>Open Modal</Button>
|
|
434
|
+
* </Modal.Trigger>
|
|
435
|
+
* <Modal.Content>...</Modal.Content>
|
|
436
|
+
* </Modal.Root>
|
|
437
|
+
*/
|
|
438
|
+
declare const ModalTrigger: any;
|
|
439
|
+
/**
|
|
440
|
+
* ModalRoot - Controlled modal root
|
|
441
|
+
* Use this when you want Radix to manage the open state
|
|
442
|
+
*/
|
|
443
|
+
declare const ModalRoot: any;
|
|
444
|
+
|
|
445
|
+
interface LocalizedString$2 {
|
|
446
|
+
[locale: string]: string;
|
|
447
|
+
}
|
|
448
|
+
interface HeroContent {
|
|
449
|
+
headline: LocalizedString$2;
|
|
450
|
+
subheadline: LocalizedString$2;
|
|
451
|
+
variant?: 'dark' | 'light' | 'split';
|
|
452
|
+
backgroundImage?: string;
|
|
453
|
+
backgroundVideo?: string;
|
|
454
|
+
overlayGradient?: {
|
|
455
|
+
from: string;
|
|
456
|
+
to: string;
|
|
457
|
+
};
|
|
458
|
+
cta: {
|
|
459
|
+
primary: {
|
|
460
|
+
text: LocalizedString$2;
|
|
461
|
+
href: string;
|
|
462
|
+
};
|
|
463
|
+
secondary?: {
|
|
464
|
+
text: LocalizedString$2;
|
|
465
|
+
href: string;
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
trustLine?: LocalizedString$2;
|
|
469
|
+
}
|
|
470
|
+
interface AboutContent {
|
|
471
|
+
heading: LocalizedString$2;
|
|
472
|
+
dividerLine?: boolean;
|
|
473
|
+
paragraphs: Array<LocalizedString$2>;
|
|
474
|
+
image?: {
|
|
475
|
+
src: string;
|
|
476
|
+
alt: LocalizedString$2;
|
|
477
|
+
placeholder?: string;
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
interface ServiceItem {
|
|
481
|
+
id: string;
|
|
482
|
+
name: LocalizedString$2;
|
|
483
|
+
description: LocalizedString$2;
|
|
484
|
+
href: string;
|
|
485
|
+
icon?: string;
|
|
486
|
+
}
|
|
487
|
+
interface ServicesContent {
|
|
488
|
+
heading: LocalizedString$2;
|
|
489
|
+
description: LocalizedString$2;
|
|
490
|
+
dividerLine?: boolean;
|
|
491
|
+
items: ServiceItem[];
|
|
492
|
+
image?: {
|
|
493
|
+
src: string;
|
|
494
|
+
alt: LocalizedString$2;
|
|
495
|
+
placeholder?: string;
|
|
496
|
+
};
|
|
497
|
+
cta?: {
|
|
498
|
+
text: LocalizedString$2;
|
|
499
|
+
subtext: LocalizedString$2;
|
|
500
|
+
button: {
|
|
501
|
+
text: LocalizedString$2;
|
|
502
|
+
href: string;
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
interface WhyChooseUsContent {
|
|
507
|
+
heading: LocalizedString$2;
|
|
508
|
+
dividerLine?: boolean;
|
|
509
|
+
paragraphs: Array<LocalizedString$2>;
|
|
510
|
+
image?: {
|
|
511
|
+
src: string;
|
|
512
|
+
alt: LocalizedString$2;
|
|
513
|
+
placeholder?: string;
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
interface FAQ {
|
|
518
|
+
/** Unique ID for the FAQ item */
|
|
519
|
+
id: string;
|
|
520
|
+
/** Question text (bilingual) */
|
|
521
|
+
question: LocalizedString$2;
|
|
522
|
+
/** Answer text (bilingual) or React node */
|
|
523
|
+
answer: LocalizedString$2 | ReactNode;
|
|
524
|
+
}
|
|
525
|
+
interface FAQAccordionProps {
|
|
526
|
+
/** Array of FAQ items */
|
|
527
|
+
faqs: FAQ[];
|
|
528
|
+
/** Current locale for display */
|
|
529
|
+
locale: 'en' | 'fr';
|
|
530
|
+
/** Allow multiple items open at once @default false */
|
|
531
|
+
allowMultiple?: boolean;
|
|
532
|
+
/** Default open item IDs */
|
|
533
|
+
defaultOpen?: string[];
|
|
534
|
+
/** Include Schema.org structured data @default true */
|
|
535
|
+
includeStructuredData?: boolean;
|
|
536
|
+
/** Additional CSS classes */
|
|
537
|
+
className?: string;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* FAQAccordion - Accessible FAQ accordion with SEO structured data
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* <FAQAccordion
|
|
544
|
+
* faqs={[
|
|
545
|
+
* {
|
|
546
|
+
* id: 'payment',
|
|
547
|
+
* question: { en: 'What payment methods...', fr: '...' },
|
|
548
|
+
* answer: { en: 'We accept...', fr: '...' }
|
|
549
|
+
* }
|
|
550
|
+
* ]}
|
|
551
|
+
* locale="en"
|
|
552
|
+
* allowMultiple={false}
|
|
553
|
+
* includeStructuredData
|
|
554
|
+
* />
|
|
555
|
+
*/
|
|
556
|
+
declare function FAQAccordion({ faqs, locale, allowMultiple, defaultOpen, includeStructuredData, className }: FAQAccordionProps): react_jsx_runtime.JSX.Element;
|
|
557
|
+
|
|
558
|
+
interface AnimatedCounterProps {
|
|
559
|
+
/** Starting value @default 0 */
|
|
560
|
+
from?: number;
|
|
561
|
+
/** Ending value */
|
|
562
|
+
to: number;
|
|
563
|
+
/** Animation duration in seconds @default 2 */
|
|
564
|
+
duration?: number;
|
|
565
|
+
/** Number of decimal places @default 0 */
|
|
566
|
+
decimals?: number;
|
|
567
|
+
/** Thousands separator @default ',' */
|
|
568
|
+
separator?: string;
|
|
569
|
+
/** Prefix (e.g., '$', '+') */
|
|
570
|
+
prefix?: string;
|
|
571
|
+
/** Suffix (e.g., '%', '+', 'K', 'M') */
|
|
572
|
+
suffix?: string;
|
|
573
|
+
/** Locale for number formatting @default 'en' */
|
|
574
|
+
locale?: 'en' | 'fr';
|
|
575
|
+
/** Additional CSS classes */
|
|
576
|
+
className?: string;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* AnimatedCounter - Number count-up animation component
|
|
580
|
+
*
|
|
581
|
+
* Animates from a starting value to an ending value when scrolled into view.
|
|
582
|
+
* Supports locale-aware formatting, prefixes, suffixes, and decimal places.
|
|
583
|
+
*
|
|
584
|
+
* @example
|
|
585
|
+
* // Simple counter
|
|
586
|
+
* <AnimatedCounter to={10000} suffix="+" />
|
|
587
|
+
*
|
|
588
|
+
* @example
|
|
589
|
+
* // Currency
|
|
590
|
+
* <AnimatedCounter to={2500000} prefix="$" suffix="M+" decimals={1} />
|
|
591
|
+
*
|
|
592
|
+
* @example
|
|
593
|
+
* // Percentage
|
|
594
|
+
* <AnimatedCounter to={99.9} suffix="%" decimals={1} />
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* // French formatting
|
|
598
|
+
* <AnimatedCounter to={1234.56} locale="fr" decimals={2} />
|
|
599
|
+
* // Displays: 1 234,56
|
|
600
|
+
*/
|
|
601
|
+
declare function AnimatedCounter({ from, to, duration, decimals, separator, prefix, suffix, locale, className }: AnimatedCounterProps): react_jsx_runtime.JSX.Element;
|
|
602
|
+
|
|
603
|
+
interface Stat {
|
|
604
|
+
/** Numeric value to display */
|
|
605
|
+
value: number;
|
|
606
|
+
/** Prefix (e.g., '$', '+') */
|
|
607
|
+
prefix?: string;
|
|
608
|
+
/** Suffix (e.g., '%', '+', 'K', 'M') */
|
|
609
|
+
suffix?: string;
|
|
610
|
+
/** Number of decimal places @default 0 */
|
|
611
|
+
decimals?: number;
|
|
612
|
+
/** Stat label (bilingual) */
|
|
613
|
+
label: LocalizedString$2;
|
|
614
|
+
/** Optional description (bilingual) */
|
|
615
|
+
description?: LocalizedString$2;
|
|
616
|
+
/** Optional icon */
|
|
617
|
+
icon?: ReactNode;
|
|
618
|
+
}
|
|
619
|
+
interface StatsSectionProps {
|
|
620
|
+
/** Section title (bilingual) */
|
|
621
|
+
title?: LocalizedString$2;
|
|
622
|
+
/** Section description (bilingual) */
|
|
623
|
+
description?: LocalizedString$2;
|
|
624
|
+
/** Array of statistics */
|
|
625
|
+
stats: Stat[];
|
|
626
|
+
/** Current locale */
|
|
627
|
+
locale: 'en' | 'fr';
|
|
628
|
+
/** Number of columns @default 3 */
|
|
629
|
+
columns?: 2 | 3 | 4;
|
|
630
|
+
/** Visual variant @default 'light' */
|
|
631
|
+
variant?: 'light' | 'dark' | 'gradient' | 'bordered';
|
|
632
|
+
/** Additional CSS classes */
|
|
633
|
+
className?: string;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* StatsSection - Display impressive statistics with animated counters
|
|
637
|
+
*
|
|
638
|
+
* Perfect for social proof: customer counts, uptime percentages, revenue processed, etc.
|
|
639
|
+
* Numbers animate when scrolled into view with stagger effect.
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* <StatsSection
|
|
643
|
+
* title={{ en: "Our Impact", fr: "Notre Impact" }}
|
|
644
|
+
* stats={[
|
|
645
|
+
* {
|
|
646
|
+
* value: 10000,
|
|
647
|
+
* suffix: "+",
|
|
648
|
+
* label: { en: "Happy Clients", fr: "Clients Satisfaits" },
|
|
649
|
+
* description: { en: "Across 50 countries", fr: "..." },
|
|
650
|
+
* icon: <UsersIcon />
|
|
651
|
+
* },
|
|
652
|
+
* {
|
|
653
|
+
* value: 99.9,
|
|
654
|
+
* suffix: "%",
|
|
655
|
+
* decimals: 1,
|
|
656
|
+
* label: { en: "Uptime", fr: "Disponibilité" },
|
|
657
|
+
* icon: <CheckIcon />
|
|
658
|
+
* }
|
|
659
|
+
* ]}
|
|
660
|
+
* locale="en"
|
|
661
|
+
* columns={3}
|
|
662
|
+
* variant="light"
|
|
663
|
+
* />
|
|
664
|
+
*/
|
|
665
|
+
declare function StatsSection({ title, description, stats, locale, columns, variant, className }: StatsSectionProps): react_jsx_runtime.JSX.Element;
|
|
666
|
+
|
|
667
|
+
type BadgeType = 'ssl-secure' | 'money-back-30' | 'money-back-60' | 'money-back-90' | 'bbb-accredited' | 'satisfaction-guaranteed' | 'free-shipping' | 'privacy-protected' | '24-7-support' | 'secure-payment';
|
|
668
|
+
interface CustomBadge {
|
|
669
|
+
type: 'custom';
|
|
670
|
+
image: string;
|
|
671
|
+
alt: string;
|
|
672
|
+
tooltip?: string;
|
|
673
|
+
}
|
|
674
|
+
type Badge = BadgeType | CustomBadge;
|
|
675
|
+
interface TrustBadgesProps {
|
|
676
|
+
/** Array of badge types or custom badges */
|
|
677
|
+
badges: Badge[];
|
|
678
|
+
/** Visual variant @default 'color' */
|
|
679
|
+
variant?: 'color' | 'grayscale';
|
|
680
|
+
/** Badge size @default 'md' */
|
|
681
|
+
size?: 'sm' | 'md' | 'lg';
|
|
682
|
+
/** Additional CSS classes */
|
|
683
|
+
className?: string;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* TrustBadges - Display trust indicators and credibility badges
|
|
687
|
+
*
|
|
688
|
+
* Reduces purchase anxiety and builds trust with pre-designed or custom badges.
|
|
689
|
+
*
|
|
690
|
+
* @example
|
|
691
|
+
* <TrustBadges
|
|
692
|
+
* badges={['ssl-secure', 'money-back-30', 'bbb-accredited']}
|
|
693
|
+
* variant="color"
|
|
694
|
+
* size="md"
|
|
695
|
+
* />
|
|
696
|
+
*
|
|
697
|
+
* @example
|
|
698
|
+
* // With custom badge
|
|
699
|
+
* <TrustBadges
|
|
700
|
+
* badges={[
|
|
701
|
+
* 'ssl-secure',
|
|
702
|
+
* {
|
|
703
|
+
* type: 'custom',
|
|
704
|
+
* image: '/badges/certified.png',
|
|
705
|
+
* alt: 'Industry Certified',
|
|
706
|
+
* tooltip: 'Certified by Industry Association'
|
|
707
|
+
* }
|
|
708
|
+
* ]}
|
|
709
|
+
* />
|
|
710
|
+
*/
|
|
711
|
+
declare function TrustBadges({ badges, variant, size, className }: TrustBadgesProps): react_jsx_runtime.JSX.Element;
|
|
712
|
+
|
|
713
|
+
interface PricingFeature {
|
|
714
|
+
/** Feature name (bilingual) */
|
|
715
|
+
name: LocalizedString$2;
|
|
716
|
+
/** Whether feature is included */
|
|
717
|
+
included: boolean;
|
|
718
|
+
/** Optional tooltip description */
|
|
719
|
+
tooltip?: LocalizedString$2;
|
|
720
|
+
}
|
|
721
|
+
interface PricingTier {
|
|
722
|
+
/** Tier name (bilingual) */
|
|
723
|
+
name: LocalizedString$2;
|
|
724
|
+
/** Description (bilingual) */
|
|
725
|
+
description?: LocalizedString$2;
|
|
726
|
+
/** Pricing per billing period */
|
|
727
|
+
price: {
|
|
728
|
+
monthly?: number;
|
|
729
|
+
annual?: number;
|
|
730
|
+
};
|
|
731
|
+
/** Currency symbol @default '$' */
|
|
732
|
+
currency?: string;
|
|
733
|
+
/** List of features */
|
|
734
|
+
features: PricingFeature[];
|
|
735
|
+
/** CTA configuration */
|
|
736
|
+
cta: {
|
|
737
|
+
label: LocalizedString$2;
|
|
738
|
+
href: string;
|
|
739
|
+
};
|
|
740
|
+
/** Highlight this tier as most popular @default false */
|
|
741
|
+
highlighted?: boolean;
|
|
742
|
+
/** Custom badge text */
|
|
743
|
+
badge?: LocalizedString$2;
|
|
744
|
+
}
|
|
745
|
+
type BillingPeriod = 'monthly' | 'annual';
|
|
746
|
+
interface PricingTableProps {
|
|
747
|
+
/** Array of pricing tiers (2-4 recommended) */
|
|
748
|
+
tiers: PricingTier[];
|
|
749
|
+
/** Current locale */
|
|
750
|
+
locale: 'en' | 'fr';
|
|
751
|
+
/** Available billing periods @default ['monthly', 'annual'] */
|
|
752
|
+
billingPeriods?: BillingPeriod[];
|
|
753
|
+
/** Default billing period @default 'monthly' */
|
|
754
|
+
defaultPeriod?: BillingPeriod;
|
|
755
|
+
/** Savings message for annual (bilingual) */
|
|
756
|
+
savings?: LocalizedString$2;
|
|
757
|
+
/** Additional CSS classes */
|
|
758
|
+
className?: string;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* PricingTable - Responsive pricing comparison table
|
|
762
|
+
*
|
|
763
|
+
* @example
|
|
764
|
+
* <PricingTable
|
|
765
|
+
* tiers={[
|
|
766
|
+
* {
|
|
767
|
+
* name: { en: 'Starter', fr: 'Démarrage' },
|
|
768
|
+
* description: { en: 'For small teams', fr: '...' },
|
|
769
|
+
* price: { monthly: 29, annual: 24 },
|
|
770
|
+
* features: [
|
|
771
|
+
* { name: { en: 'Up to 10 users', fr: '...' }, included: true },
|
|
772
|
+
* { name: { en: 'Basic support', fr: '...' }, included: true },
|
|
773
|
+
* { name: { en: 'Advanced analytics', fr: '...' }, included: false }
|
|
774
|
+
* ],
|
|
775
|
+
* cta: { label: { en: 'Start Trial', fr: '...' }, href: '/signup' }
|
|
776
|
+
* },
|
|
777
|
+
* {
|
|
778
|
+
* name: { en: 'Professional', fr: 'Professionnel' },
|
|
779
|
+
* price: { monthly: 99, annual: 79 },
|
|
780
|
+
* highlighted: true,
|
|
781
|
+
* badge: { en: 'Most Popular', fr: 'Plus populaire' },
|
|
782
|
+
* features: [...],
|
|
783
|
+
* cta: { label: { en: 'Get Started', fr: '...' }, href: '/signup?plan=pro' }
|
|
784
|
+
* }
|
|
785
|
+
* ]}
|
|
786
|
+
* locale="en"
|
|
787
|
+
* defaultPeriod="annual"
|
|
788
|
+
* savings={{ en: 'Save 20%', fr: 'Économisez 20%' }}
|
|
789
|
+
* />
|
|
790
|
+
*/
|
|
791
|
+
declare function PricingTable({ tiers, locale, billingPeriods, defaultPeriod, savings, className }: PricingTableProps): react_jsx_runtime.JSX.Element;
|
|
792
|
+
|
|
793
|
+
interface Testimonial {
|
|
794
|
+
/** Customer quote (bilingual) */
|
|
795
|
+
quote: LocalizedString$2;
|
|
796
|
+
/** Customer name */
|
|
797
|
+
author: string;
|
|
798
|
+
/** Customer role/title (bilingual) */
|
|
799
|
+
role?: LocalizedString$2;
|
|
800
|
+
/** Company name */
|
|
801
|
+
company?: string;
|
|
802
|
+
/** Customer photo URL */
|
|
803
|
+
photo?: string;
|
|
804
|
+
/** Company logo URL */
|
|
805
|
+
logo?: string;
|
|
806
|
+
/** Star rating (1-5) */
|
|
807
|
+
rating?: number;
|
|
808
|
+
/** Optional video URL */
|
|
809
|
+
video?: string;
|
|
810
|
+
}
|
|
811
|
+
interface TestimonialCarouselProps {
|
|
812
|
+
/** Array of testimonials */
|
|
813
|
+
testimonials: Testimonial[];
|
|
814
|
+
/** Current locale */
|
|
815
|
+
locale: 'en' | 'fr';
|
|
816
|
+
/** Auto-play interval in milliseconds @default 5000 */
|
|
817
|
+
interval?: number;
|
|
818
|
+
/** Enable auto-play @default true */
|
|
819
|
+
autoPlay?: boolean;
|
|
820
|
+
/** Show navigation arrows @default true */
|
|
821
|
+
showArrows?: boolean;
|
|
822
|
+
/** Show navigation dots @default true */
|
|
823
|
+
showDots?: boolean;
|
|
824
|
+
/** Visual variant @default 'card' */
|
|
825
|
+
variant?: 'card' | 'minimal' | 'split';
|
|
826
|
+
/** Additional CSS classes */
|
|
827
|
+
className?: string;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* TestimonialCarousel - Rotating customer testimonials
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* <TestimonialCarousel
|
|
834
|
+
* testimonials={[
|
|
835
|
+
* {
|
|
836
|
+
* quote: { en: "This product changed...", fr: "..." },
|
|
837
|
+
* author: "Jane Doe",
|
|
838
|
+
* role: { en: "CEO", fr: "PDG" },
|
|
839
|
+
* company: "Acme Corp",
|
|
840
|
+
* photo: "/testimonials/jane.jpg",
|
|
841
|
+
* rating: 5
|
|
842
|
+
* }
|
|
843
|
+
* ]}
|
|
844
|
+
* locale="en"
|
|
845
|
+
* autoPlay
|
|
846
|
+
* interval={5000}
|
|
847
|
+
* />
|
|
848
|
+
*/
|
|
849
|
+
declare function TestimonialCarousel({ testimonials, locale, interval, autoPlay, showArrows, showDots, variant, className }: TestimonialCarouselProps): react_jsx_runtime.JSX.Element | null;
|
|
850
|
+
|
|
851
|
+
interface StickyBarProps {
|
|
852
|
+
/** Message to display (bilingual) */
|
|
853
|
+
message: LocalizedString$2;
|
|
854
|
+
/** Current locale */
|
|
855
|
+
locale: 'en' | 'fr';
|
|
856
|
+
/** CTA configuration */
|
|
857
|
+
cta: {
|
|
858
|
+
label: LocalizedString$2;
|
|
859
|
+
href: string;
|
|
860
|
+
onClick?: () => void;
|
|
861
|
+
};
|
|
862
|
+
/** Position @default 'top' */
|
|
863
|
+
position?: 'top' | 'bottom';
|
|
864
|
+
/** Scroll trigger distance in pixels @default 300 */
|
|
865
|
+
trigger?: number;
|
|
866
|
+
/** Whether bar is dismissible @default true */
|
|
867
|
+
dismissible?: boolean;
|
|
868
|
+
/** Remember dismissal duration @default 'session' */
|
|
869
|
+
rememberDismissal?: 'session' | 'permanent' | 'none';
|
|
870
|
+
/** Hide on scroll up @default false */
|
|
871
|
+
hideOnScrollUp?: boolean;
|
|
872
|
+
/** Optional icon */
|
|
873
|
+
icon?: React.ReactNode;
|
|
874
|
+
/** Additional CSS classes */
|
|
875
|
+
className?: string;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* StickyBar - Persistent notification bar with CTA
|
|
879
|
+
*
|
|
880
|
+
* Appears after scrolling past a threshold to maintain CTA visibility.
|
|
881
|
+
* Perfect for maintaining conversion opportunities throughout the page.
|
|
882
|
+
*
|
|
883
|
+
* @example
|
|
884
|
+
* <StickyBar
|
|
885
|
+
* message={{ en: "Ready to get started?", fr: "..." }}
|
|
886
|
+
* cta={{
|
|
887
|
+
* label: { en: "Start Free Trial", fr: "..." },
|
|
888
|
+
* href: "/signup"
|
|
889
|
+
* }}
|
|
890
|
+
* locale="en"
|
|
891
|
+
* position="top"
|
|
892
|
+
* trigger={300}
|
|
893
|
+
* dismissible
|
|
894
|
+
* />
|
|
895
|
+
*/
|
|
896
|
+
declare function StickyBar({ message, locale, cta, position, trigger, dismissible, rememberDismissal, hideOnScrollUp, icon, className }: StickyBarProps): react_jsx_runtime.JSX.Element;
|
|
897
|
+
|
|
898
|
+
interface SelectOption {
|
|
899
|
+
value: string;
|
|
900
|
+
label: string;
|
|
901
|
+
disabled?: boolean;
|
|
902
|
+
}
|
|
903
|
+
interface SelectOptionGroup {
|
|
904
|
+
label: string;
|
|
905
|
+
options: SelectOption[];
|
|
906
|
+
}
|
|
907
|
+
interface SelectProps {
|
|
908
|
+
/** Options to display */
|
|
909
|
+
options: SelectOption[] | SelectOptionGroup[];
|
|
910
|
+
/** Selected value */
|
|
911
|
+
value?: string;
|
|
912
|
+
/** Callback when value changes */
|
|
913
|
+
onValueChange?: (value: string) => void;
|
|
914
|
+
/** Placeholder text */
|
|
915
|
+
placeholder?: string;
|
|
916
|
+
/** Whether select is disabled */
|
|
917
|
+
disabled?: boolean;
|
|
918
|
+
/** Additional CSS classes */
|
|
919
|
+
className?: string;
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Select - Accessible dropdown select component
|
|
923
|
+
*
|
|
924
|
+
* @example
|
|
925
|
+
* <Select
|
|
926
|
+
* options={[
|
|
927
|
+
* { value: 'us', label: 'United States' },
|
|
928
|
+
* { value: 'ca', label: 'Canada' }
|
|
929
|
+
* ]}
|
|
930
|
+
* placeholder="Select country..."
|
|
931
|
+
* value={country}
|
|
932
|
+
* onValueChange={setCountry}
|
|
933
|
+
* />
|
|
934
|
+
*
|
|
935
|
+
* @example
|
|
936
|
+
* // With option groups
|
|
937
|
+
* <Select
|
|
938
|
+
* options={[
|
|
939
|
+
* {
|
|
940
|
+
* label: 'North America',
|
|
941
|
+
* options: [
|
|
942
|
+
* { value: 'us', label: 'United States' },
|
|
943
|
+
* { value: 'ca', label: 'Canada' }
|
|
944
|
+
* ]
|
|
945
|
+
* }
|
|
946
|
+
* ]}
|
|
947
|
+
* />
|
|
948
|
+
*/
|
|
949
|
+
declare function Select({ options, value, onValueChange, placeholder, disabled, className }: SelectProps): react_jsx_runtime.JSX.Element;
|
|
950
|
+
|
|
951
|
+
interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'size'> {
|
|
952
|
+
/** Checkbox label */
|
|
953
|
+
label?: string;
|
|
954
|
+
/** Description text below label */
|
|
955
|
+
description?: string;
|
|
956
|
+
/** Error message */
|
|
957
|
+
error?: string;
|
|
958
|
+
/** Size variant @default 'md' */
|
|
959
|
+
size?: 'sm' | 'md' | 'lg';
|
|
960
|
+
}
|
|
961
|
+
interface CheckboxGroupOption {
|
|
962
|
+
value: string;
|
|
963
|
+
label: LocalizedString$2 | string;
|
|
964
|
+
description?: LocalizedString$2 | string;
|
|
965
|
+
disabled?: boolean;
|
|
966
|
+
}
|
|
967
|
+
interface CheckboxGroupProps {
|
|
968
|
+
/** Group label */
|
|
969
|
+
label?: LocalizedString$2 | string;
|
|
970
|
+
/** Current locale for bilingual labels */
|
|
971
|
+
locale?: 'en' | 'fr';
|
|
972
|
+
/** Array of checkbox options */
|
|
973
|
+
options: CheckboxGroupOption[];
|
|
974
|
+
/** Selected values */
|
|
975
|
+
value?: string[];
|
|
976
|
+
/** Callback when selection changes */
|
|
977
|
+
onChange?: (value: string[]) => void;
|
|
978
|
+
/** Error message */
|
|
979
|
+
error?: string;
|
|
980
|
+
/** Display layout @default 'vertical' */
|
|
981
|
+
layout?: 'vertical' | 'horizontal' | 'grid';
|
|
982
|
+
/** Grid columns (only for grid layout) @default 2 */
|
|
983
|
+
columns?: 2 | 3 | 4;
|
|
984
|
+
/** Disabled state for entire group */
|
|
985
|
+
disabled?: boolean;
|
|
986
|
+
/** Additional CSS classes */
|
|
987
|
+
className?: string;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Checkbox - Styled checkbox input with label and description
|
|
991
|
+
*
|
|
992
|
+
* Integrates with React Hook Form and supports validation states.
|
|
993
|
+
*
|
|
994
|
+
* @example
|
|
995
|
+
* // Basic usage
|
|
996
|
+
* <Checkbox
|
|
997
|
+
* label="Accept terms and conditions"
|
|
998
|
+
* {...register('terms')}
|
|
999
|
+
* />
|
|
1000
|
+
*
|
|
1001
|
+
* @example
|
|
1002
|
+
* // With description and error
|
|
1003
|
+
* <Checkbox
|
|
1004
|
+
* label="Subscribe to newsletter"
|
|
1005
|
+
* description="Get weekly updates about new features"
|
|
1006
|
+
* error={errors.newsletter?.message}
|
|
1007
|
+
* {...register('newsletter')}
|
|
1008
|
+
* />
|
|
1009
|
+
*
|
|
1010
|
+
* @example
|
|
1011
|
+
* // Different sizes
|
|
1012
|
+
* <Checkbox label="Small" size="sm" />
|
|
1013
|
+
* <Checkbox label="Medium" size="md" />
|
|
1014
|
+
* <Checkbox label="Large" size="lg" />
|
|
1015
|
+
*/
|
|
1016
|
+
declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLInputElement>>;
|
|
1017
|
+
/**
|
|
1018
|
+
* CheckboxGroup - Collection of related checkboxes
|
|
1019
|
+
*
|
|
1020
|
+
* Manages multiple checkbox selections with built-in state management.
|
|
1021
|
+
* Supports bilingual labels and responsive layouts.
|
|
1022
|
+
*
|
|
1023
|
+
* @example
|
|
1024
|
+
* // Basic usage with React Hook Form
|
|
1025
|
+
* const { watch, setValue } = useForm()
|
|
1026
|
+
* const selectedFeatures = watch('features') || []
|
|
1027
|
+
*
|
|
1028
|
+
* <CheckboxGroup
|
|
1029
|
+
* label={{ en: "Select Features", fr: "Sélectionner les fonctionnalités" }}
|
|
1030
|
+
* locale="en"
|
|
1031
|
+
* options={[
|
|
1032
|
+
* { value: 'analytics', label: { en: 'Analytics', fr: 'Analytique' } },
|
|
1033
|
+
* { value: 'reporting', label: { en: 'Reporting', fr: 'Rapports' } },
|
|
1034
|
+
* { value: 'api', label: 'API Access', disabled: true }
|
|
1035
|
+
* ]}
|
|
1036
|
+
* value={selectedFeatures}
|
|
1037
|
+
* onChange={(values) => setValue('features', values)}
|
|
1038
|
+
* />
|
|
1039
|
+
*
|
|
1040
|
+
* @example
|
|
1041
|
+
* // Grid layout
|
|
1042
|
+
* <CheckboxGroup
|
|
1043
|
+
* options={options}
|
|
1044
|
+
* layout="grid"
|
|
1045
|
+
* columns={3}
|
|
1046
|
+
* value={selected}
|
|
1047
|
+
* onChange={setSelected}
|
|
1048
|
+
* />
|
|
1049
|
+
*/
|
|
1050
|
+
declare function CheckboxGroup({ label, locale, options, value, onChange, error, layout, columns, disabled, className }: CheckboxGroupProps): react_jsx_runtime.JSX.Element;
|
|
1051
|
+
|
|
1052
|
+
interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'size'> {
|
|
1053
|
+
/** Radio label */
|
|
1054
|
+
label?: string;
|
|
1055
|
+
/** Description text below label */
|
|
1056
|
+
description?: string;
|
|
1057
|
+
/** Error message */
|
|
1058
|
+
error?: string;
|
|
1059
|
+
/** Size variant @default 'md' */
|
|
1060
|
+
size?: 'sm' | 'md' | 'lg';
|
|
1061
|
+
}
|
|
1062
|
+
interface RadioGroupOption {
|
|
1063
|
+
value: string;
|
|
1064
|
+
label: LocalizedString$2 | string;
|
|
1065
|
+
description?: LocalizedString$2 | string;
|
|
1066
|
+
disabled?: boolean;
|
|
1067
|
+
}
|
|
1068
|
+
interface RadioGroupProps {
|
|
1069
|
+
/** Group label */
|
|
1070
|
+
label?: LocalizedString$2 | string;
|
|
1071
|
+
/** Field name (for form integration) */
|
|
1072
|
+
name: string;
|
|
1073
|
+
/** Current locale for bilingual labels */
|
|
1074
|
+
locale?: 'en' | 'fr';
|
|
1075
|
+
/** Array of radio options */
|
|
1076
|
+
options: RadioGroupOption[];
|
|
1077
|
+
/** Selected value */
|
|
1078
|
+
value?: string;
|
|
1079
|
+
/** Callback when selection changes */
|
|
1080
|
+
onChange?: (value: string) => void;
|
|
1081
|
+
/** Error message */
|
|
1082
|
+
error?: string;
|
|
1083
|
+
/** Display layout @default 'vertical' */
|
|
1084
|
+
layout?: 'vertical' | 'horizontal' | 'grid';
|
|
1085
|
+
/** Grid columns (only for grid layout) @default 2 */
|
|
1086
|
+
columns?: 2 | 3 | 4;
|
|
1087
|
+
/** Disabled state for entire group */
|
|
1088
|
+
disabled?: boolean;
|
|
1089
|
+
/** Additional CSS classes */
|
|
1090
|
+
className?: string;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Radio - Styled radio button input with label and description
|
|
1094
|
+
*
|
|
1095
|
+
* Integrates with React Hook Form and supports validation states.
|
|
1096
|
+
*
|
|
1097
|
+
* @example
|
|
1098
|
+
* // Basic usage
|
|
1099
|
+
* <Radio
|
|
1100
|
+
* name="plan"
|
|
1101
|
+
* value="basic"
|
|
1102
|
+
* label="Basic Plan"
|
|
1103
|
+
* {...register('plan')}
|
|
1104
|
+
* />
|
|
1105
|
+
*
|
|
1106
|
+
* @example
|
|
1107
|
+
* // With description and error
|
|
1108
|
+
* <Radio
|
|
1109
|
+
* name="plan"
|
|
1110
|
+
* value="pro"
|
|
1111
|
+
* label="Pro Plan"
|
|
1112
|
+
* description="Includes advanced features and priority support"
|
|
1113
|
+
* error={errors.plan?.message}
|
|
1114
|
+
* {...register('plan')}
|
|
1115
|
+
* />
|
|
1116
|
+
*
|
|
1117
|
+
* @example
|
|
1118
|
+
* // Different sizes
|
|
1119
|
+
* <Radio name="size" value="s" label="Small" size="sm" />
|
|
1120
|
+
* <Radio name="size" value="m" label="Medium" size="md" />
|
|
1121
|
+
* <Radio name="size" value="l" label="Large" size="lg" />
|
|
1122
|
+
*/
|
|
1123
|
+
declare const Radio: react.ForwardRefExoticComponent<RadioProps & react.RefAttributes<HTMLInputElement>>;
|
|
1124
|
+
/**
|
|
1125
|
+
* RadioGroup - Collection of mutually exclusive radio buttons
|
|
1126
|
+
*
|
|
1127
|
+
* Manages radio button selection with built-in state management.
|
|
1128
|
+
* Supports bilingual labels and responsive layouts.
|
|
1129
|
+
*
|
|
1130
|
+
* @example
|
|
1131
|
+
* // Basic usage with React Hook Form
|
|
1132
|
+
* const { watch, setValue } = useForm()
|
|
1133
|
+
* const selectedPlan = watch('plan')
|
|
1134
|
+
*
|
|
1135
|
+
* <RadioGroup
|
|
1136
|
+
* name="plan"
|
|
1137
|
+
* label={{ en: "Choose Plan", fr: "Choisir le plan" }}
|
|
1138
|
+
* locale="en"
|
|
1139
|
+
* options={[
|
|
1140
|
+
* {
|
|
1141
|
+
* value: 'basic',
|
|
1142
|
+
* label: { en: 'Basic', fr: 'Basique' },
|
|
1143
|
+
* description: { en: '$10/month', fr: '10$/mois' }
|
|
1144
|
+
* },
|
|
1145
|
+
* {
|
|
1146
|
+
* value: 'pro',
|
|
1147
|
+
* label: { en: 'Pro', fr: 'Pro' },
|
|
1148
|
+
* description: { en: '$25/month', fr: '25$/mois' }
|
|
1149
|
+
* },
|
|
1150
|
+
* {
|
|
1151
|
+
* value: 'enterprise',
|
|
1152
|
+
* label: 'Enterprise',
|
|
1153
|
+
* description: 'Custom pricing',
|
|
1154
|
+
* disabled: true
|
|
1155
|
+
* }
|
|
1156
|
+
* ]}
|
|
1157
|
+
* value={selectedPlan}
|
|
1158
|
+
* onChange={(value) => setValue('plan', value)}
|
|
1159
|
+
* />
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* // Horizontal layout
|
|
1163
|
+
* <RadioGroup
|
|
1164
|
+
* name="color"
|
|
1165
|
+
* options={colorOptions}
|
|
1166
|
+
* layout="horizontal"
|
|
1167
|
+
* value={color}
|
|
1168
|
+
* onChange={setColor}
|
|
1169
|
+
* />
|
|
1170
|
+
*
|
|
1171
|
+
* @example
|
|
1172
|
+
* // Grid layout
|
|
1173
|
+
* <RadioGroup
|
|
1174
|
+
* name="option"
|
|
1175
|
+
* options={options}
|
|
1176
|
+
* layout="grid"
|
|
1177
|
+
* columns={3}
|
|
1178
|
+
* value={selected}
|
|
1179
|
+
* onChange={setSelected}
|
|
1180
|
+
* />
|
|
1181
|
+
*/
|
|
1182
|
+
declare function RadioGroup({ label, name, locale, options, value, onChange, error, layout, columns, disabled, className }: RadioGroupProps): react_jsx_runtime.JSX.Element;
|
|
1183
|
+
|
|
1184
|
+
interface FileUploadProps {
|
|
1185
|
+
/** Current locale */
|
|
1186
|
+
locale?: 'en' | 'fr';
|
|
1187
|
+
/** Label text (bilingual) */
|
|
1188
|
+
label?: LocalizedString$2 | string;
|
|
1189
|
+
/** Description text (bilingual) */
|
|
1190
|
+
description?: LocalizedString$2 | string;
|
|
1191
|
+
/** Allow multiple files @default false */
|
|
1192
|
+
multiple?: boolean;
|
|
1193
|
+
/** Accepted file types (e.g., 'image/*', '.pdf,.doc') */
|
|
1194
|
+
accept?: string;
|
|
1195
|
+
/** Max file size in bytes @default 10MB */
|
|
1196
|
+
maxSize?: number;
|
|
1197
|
+
/** Max number of files @default Infinity */
|
|
1198
|
+
maxFiles?: number;
|
|
1199
|
+
/** Current files */
|
|
1200
|
+
value?: File[];
|
|
1201
|
+
/** Callback when files change */
|
|
1202
|
+
onChange?: (files: File[]) => void;
|
|
1203
|
+
/** Error message */
|
|
1204
|
+
error?: string;
|
|
1205
|
+
/** Disabled state */
|
|
1206
|
+
disabled?: boolean;
|
|
1207
|
+
/** Show file previews @default true */
|
|
1208
|
+
showPreviews?: boolean;
|
|
1209
|
+
/** Additional CSS classes */
|
|
1210
|
+
className?: string;
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* FileUpload - Drag & drop file upload component
|
|
1214
|
+
*
|
|
1215
|
+
* Supports multiple files, file type restrictions, size limits, and previews.
|
|
1216
|
+
* Integrates with React Hook Form for validation.
|
|
1217
|
+
*
|
|
1218
|
+
* @example
|
|
1219
|
+
* // Basic usage
|
|
1220
|
+
* const [files, setFiles] = useState<File[]>([])
|
|
1221
|
+
*
|
|
1222
|
+
* <FileUpload
|
|
1223
|
+
* label={{ en: "Upload Documents", fr: "Téléverser des documents" }}
|
|
1224
|
+
* locale="en"
|
|
1225
|
+
* value={files}
|
|
1226
|
+
* onChange={setFiles}
|
|
1227
|
+
* />
|
|
1228
|
+
*
|
|
1229
|
+
* @example
|
|
1230
|
+
* // With restrictions and React Hook Form
|
|
1231
|
+
* const { setValue, formState: { errors } } = useForm()
|
|
1232
|
+
*
|
|
1233
|
+
* <FileUpload
|
|
1234
|
+
* label="Profile Photo"
|
|
1235
|
+
* accept="image/*"
|
|
1236
|
+
* maxSize={5 * 1024 * 1024} // 5MB
|
|
1237
|
+
* maxFiles={1}
|
|
1238
|
+
* onChange={(files) => setValue('photo', files[0])}
|
|
1239
|
+
* error={errors.photo?.message}
|
|
1240
|
+
* />
|
|
1241
|
+
*
|
|
1242
|
+
* @example
|
|
1243
|
+
* // Multiple files
|
|
1244
|
+
* <FileUpload
|
|
1245
|
+
* label="Upload Attachments"
|
|
1246
|
+
* multiple
|
|
1247
|
+
* accept=".pdf,.doc,.docx"
|
|
1248
|
+
* maxFiles={5}
|
|
1249
|
+
* maxSize={10 * 1024 * 1024}
|
|
1250
|
+
* value={attachments}
|
|
1251
|
+
* onChange={setAttachments}
|
|
1252
|
+
* />
|
|
1253
|
+
*/
|
|
1254
|
+
declare function FileUpload({ locale, label, description, multiple, accept, maxSize, // 10MB default
|
|
1255
|
+
maxFiles, value, onChange, error, disabled, showPreviews, className }: FileUploadProps): react_jsx_runtime.JSX.Element;
|
|
1256
|
+
|
|
1257
|
+
interface MultiStepFormProps {
|
|
1258
|
+
/** Current locale */
|
|
1259
|
+
locale?: 'en' | 'fr';
|
|
1260
|
+
/** Form steps */
|
|
1261
|
+
children: ReactElement<StepProps>[];
|
|
1262
|
+
/** Callback when form is completed */
|
|
1263
|
+
onComplete?: (data: any) => void | Promise<void>;
|
|
1264
|
+
/** Show progress bar @default true */
|
|
1265
|
+
showProgress?: boolean;
|
|
1266
|
+
/** Allow navigation to previous steps @default true */
|
|
1267
|
+
allowBack?: boolean;
|
|
1268
|
+
/** Additional CSS classes */
|
|
1269
|
+
className?: string;
|
|
1270
|
+
}
|
|
1271
|
+
interface StepProps {
|
|
1272
|
+
/** Step title (bilingual) */
|
|
1273
|
+
title: LocalizedString$2 | string;
|
|
1274
|
+
/** Step description (bilingual) */
|
|
1275
|
+
description?: LocalizedString$2 | string;
|
|
1276
|
+
/** Validation function - return true if valid, error message if invalid */
|
|
1277
|
+
validate?: () => boolean | string | Promise<boolean | string>;
|
|
1278
|
+
/** Step content */
|
|
1279
|
+
children: ReactNode;
|
|
1280
|
+
}
|
|
1281
|
+
interface MultiStepFormContextValue {
|
|
1282
|
+
currentStep: number;
|
|
1283
|
+
totalSteps: number;
|
|
1284
|
+
goToNext: () => void;
|
|
1285
|
+
goToPrevious: () => void;
|
|
1286
|
+
goToStep: (step: number) => void;
|
|
1287
|
+
isFirstStep: boolean;
|
|
1288
|
+
isLastStep: boolean;
|
|
1289
|
+
locale: 'en' | 'fr';
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* MultiStepForm - Multi-step form with progress tracking
|
|
1293
|
+
*
|
|
1294
|
+
* Manages form state across multiple steps with validation, navigation,
|
|
1295
|
+
* and smooth transitions between steps.
|
|
1296
|
+
*
|
|
1297
|
+
* @example
|
|
1298
|
+
* // Basic usage
|
|
1299
|
+
* <MultiStepForm
|
|
1300
|
+
* locale="en"
|
|
1301
|
+
* onComplete={(data) => console.log('Form completed', data)}
|
|
1302
|
+
* >
|
|
1303
|
+
* <MultiStepForm.Step
|
|
1304
|
+
* title={{ en: "Personal Info", fr: "Informations personnelles" }}
|
|
1305
|
+
* description="Tell us about yourself"
|
|
1306
|
+
* >
|
|
1307
|
+
* <FormField label="Name">
|
|
1308
|
+
* <input type="text" {...register('name')} />
|
|
1309
|
+
* </FormField>
|
|
1310
|
+
* </MultiStepForm.Step>
|
|
1311
|
+
*
|
|
1312
|
+
* <MultiStepForm.Step
|
|
1313
|
+
* title="Contact"
|
|
1314
|
+
* validate={async () => {
|
|
1315
|
+
* const isValid = await validateEmail(email)
|
|
1316
|
+
* return isValid || 'Invalid email'
|
|
1317
|
+
* }}
|
|
1318
|
+
* >
|
|
1319
|
+
* <FormField label="Email">
|
|
1320
|
+
* <input type="email" {...register('email')} />
|
|
1321
|
+
* </FormField>
|
|
1322
|
+
* </MultiStepForm.Step>
|
|
1323
|
+
*
|
|
1324
|
+
* <MultiStepForm.Step title="Confirm">
|
|
1325
|
+
* <p>Review your information...</p>
|
|
1326
|
+
* </MultiStepForm.Step>
|
|
1327
|
+
* </MultiStepForm>
|
|
1328
|
+
*
|
|
1329
|
+
* @example
|
|
1330
|
+
* // With custom navigation
|
|
1331
|
+
* <MultiStepForm
|
|
1332
|
+
* showProgress
|
|
1333
|
+
* allowBack
|
|
1334
|
+
* onComplete={handleSubmit}
|
|
1335
|
+
* >
|
|
1336
|
+
* <MultiStepForm.Step title="Step 1">
|
|
1337
|
+
* ...
|
|
1338
|
+
* </MultiStepForm.Step>
|
|
1339
|
+
* </MultiStepForm>
|
|
1340
|
+
*/
|
|
1341
|
+
declare function MultiStepForm({ locale, children, onComplete, showProgress, allowBack, className }: MultiStepFormProps): react_jsx_runtime.JSX.Element;
|
|
1342
|
+
declare namespace MultiStepForm {
|
|
1343
|
+
var Step: ({ title, description, children }: StepProps) => react_jsx_runtime.JSX.Element;
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Hook to access multi-step form context
|
|
1347
|
+
*
|
|
1348
|
+
* Provides access to current step, navigation functions, and form state.
|
|
1349
|
+
*
|
|
1350
|
+
* @example
|
|
1351
|
+
* function CustomStep() {
|
|
1352
|
+
* const { currentStep, goToNext, goToPrevious } = useMultiStepForm()
|
|
1353
|
+
*
|
|
1354
|
+
* return (
|
|
1355
|
+
* <div>
|
|
1356
|
+
* <p>Current step: {currentStep}</p>
|
|
1357
|
+
* <button onClick={goToPrevious}>Back</button>
|
|
1358
|
+
* <button onClick={goToNext}>Next</button>
|
|
1359
|
+
* </div>
|
|
1360
|
+
* )
|
|
1361
|
+
* }
|
|
1362
|
+
*/
|
|
1363
|
+
declare function useMultiStepForm(): MultiStepFormContextValue;
|
|
1364
|
+
|
|
1365
|
+
interface CountdownTimerProps {
|
|
1366
|
+
/** Current locale */
|
|
1367
|
+
locale?: 'en' | 'fr';
|
|
1368
|
+
/** Target date/time */
|
|
1369
|
+
targetDate: Date | string;
|
|
1370
|
+
/** Label above timer (bilingual) */
|
|
1371
|
+
label?: LocalizedString$2 | string;
|
|
1372
|
+
/** Message shown when countdown ends (bilingual) */
|
|
1373
|
+
completionMessage?: LocalizedString$2 | string;
|
|
1374
|
+
/** Callback when countdown ends */
|
|
1375
|
+
onComplete?: () => void;
|
|
1376
|
+
/** Display format @default 'blocks' */
|
|
1377
|
+
format?: 'blocks' | 'inline' | 'minimal';
|
|
1378
|
+
/** Show labels for time units @default true */
|
|
1379
|
+
showLabels?: boolean;
|
|
1380
|
+
/** Show days @default true */
|
|
1381
|
+
showDays?: boolean;
|
|
1382
|
+
/** Show hours @default true */
|
|
1383
|
+
showHours?: boolean;
|
|
1384
|
+
/** Show minutes @default true */
|
|
1385
|
+
showMinutes?: boolean;
|
|
1386
|
+
/** Show seconds @default true */
|
|
1387
|
+
showSeconds?: boolean;
|
|
1388
|
+
/** Size variant @default 'md' */
|
|
1389
|
+
size?: 'sm' | 'md' | 'lg';
|
|
1390
|
+
/** Additional CSS classes */
|
|
1391
|
+
className?: string;
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* CountdownTimer - Countdown timer for urgency and deadlines
|
|
1395
|
+
*
|
|
1396
|
+
* Creates urgency with time-limited offers, event countdowns, or flash sales.
|
|
1397
|
+
* Supports multiple display formats and automatic completion callbacks.
|
|
1398
|
+
*
|
|
1399
|
+
* @example
|
|
1400
|
+
* // Basic usage
|
|
1401
|
+
* <CountdownTimer
|
|
1402
|
+
* targetDate={new Date('2024-12-31T23:59:59')}
|
|
1403
|
+
* label={{ en: "Sale Ends In", fr: "La vente se termine dans" }}
|
|
1404
|
+
* locale="en"
|
|
1405
|
+
* />
|
|
1406
|
+
*
|
|
1407
|
+
* @example
|
|
1408
|
+
* // Minimal inline format
|
|
1409
|
+
* <CountdownTimer
|
|
1410
|
+
* targetDate="2024-06-15T12:00:00"
|
|
1411
|
+
* format="inline"
|
|
1412
|
+
* showDays={false}
|
|
1413
|
+
* completionMessage="Offer expired!"
|
|
1414
|
+
* onComplete={() => {
|
|
1415
|
+
* console.log('Timer ended!')
|
|
1416
|
+
* // Redirect, show message, etc.
|
|
1417
|
+
* }}
|
|
1418
|
+
* />
|
|
1419
|
+
*
|
|
1420
|
+
* @example
|
|
1421
|
+
* // Large blocks format
|
|
1422
|
+
* <CountdownTimer
|
|
1423
|
+
* targetDate={eventDate}
|
|
1424
|
+
* label="Event Starts In"
|
|
1425
|
+
* format="blocks"
|
|
1426
|
+
* size="lg"
|
|
1427
|
+
* showLabels
|
|
1428
|
+
* />
|
|
1429
|
+
*/
|
|
1430
|
+
declare function CountdownTimer({ locale, targetDate, label, completionMessage, onComplete, format, showLabels, showDays, showHours, showMinutes, showSeconds, size, className }: CountdownTimerProps): react_jsx_runtime.JSX.Element;
|
|
1431
|
+
|
|
1432
|
+
interface ExitIntentModalProps {
|
|
1433
|
+
/** Current locale */
|
|
1434
|
+
locale?: 'en' | 'fr';
|
|
1435
|
+
/** Modal title (bilingual) */
|
|
1436
|
+
title: LocalizedString$2 | string;
|
|
1437
|
+
/** Modal content */
|
|
1438
|
+
children: ReactNode;
|
|
1439
|
+
/** Enable exit intent detection @default true */
|
|
1440
|
+
enabled?: boolean;
|
|
1441
|
+
/** Delay before showing modal (ms) @default 0 */
|
|
1442
|
+
delay?: number;
|
|
1443
|
+
/** Show only once per session @default true */
|
|
1444
|
+
oncePerSession?: boolean;
|
|
1445
|
+
/** Show only once ever (localStorage) @default false */
|
|
1446
|
+
onceEver?: boolean;
|
|
1447
|
+
/** Cookie/storage key for "once" tracking @default 'exit-intent-shown' */
|
|
1448
|
+
storageKey?: string;
|
|
1449
|
+
/** Sensitivity (distance from top in px before triggering) @default 50 */
|
|
1450
|
+
sensitivity?: number;
|
|
1451
|
+
/** Callback when modal is shown */
|
|
1452
|
+
onShow?: () => void;
|
|
1453
|
+
/** Callback when modal is dismissed */
|
|
1454
|
+
onDismiss?: () => void;
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* ExitIntentModal - Capture abandoning visitors with targeted message
|
|
1458
|
+
*
|
|
1459
|
+
* Detects when user's mouse leaves the viewport (exit intent) and shows
|
|
1460
|
+
* a modal with a retention offer, discount, or message.
|
|
1461
|
+
*
|
|
1462
|
+
* @example
|
|
1463
|
+
* // Basic usage
|
|
1464
|
+
* <ExitIntentModal
|
|
1465
|
+
* title={{ en: "Wait! Don't Leave Yet", fr: "Attendez! Ne partez pas encore" }}
|
|
1466
|
+
* locale="en"
|
|
1467
|
+
* >
|
|
1468
|
+
* <div className="text-center">
|
|
1469
|
+
* <p className="mb-4">Get 10% off your first order!</p>
|
|
1470
|
+
* <input
|
|
1471
|
+
* type="email"
|
|
1472
|
+
* placeholder="Enter your email"
|
|
1473
|
+
* className="w-full px-4 py-2 border rounded mb-4"
|
|
1474
|
+
* />
|
|
1475
|
+
* <Button variant="filled" fullWidth>
|
|
1476
|
+
* Get My Discount
|
|
1477
|
+
* </Button>
|
|
1478
|
+
* </div>
|
|
1479
|
+
* </ExitIntentModal>
|
|
1480
|
+
*
|
|
1481
|
+
* @example
|
|
1482
|
+
* // Show only once ever with custom settings
|
|
1483
|
+
* <ExitIntentModal
|
|
1484
|
+
* title="Special Offer Just for You"
|
|
1485
|
+
* onceEver
|
|
1486
|
+
* delay={2000}
|
|
1487
|
+
* sensitivity={30}
|
|
1488
|
+
* onShow={() => {
|
|
1489
|
+
* console.log('Exit intent triggered')
|
|
1490
|
+
* // Track analytics event
|
|
1491
|
+
* }}
|
|
1492
|
+
* >
|
|
1493
|
+
* <SpecialOfferContent />
|
|
1494
|
+
* </ExitIntentModal>
|
|
1495
|
+
*
|
|
1496
|
+
* @example
|
|
1497
|
+
* // Conditional exit intent
|
|
1498
|
+
* const [showExitIntent, setShowExitIntent] = useState(true)
|
|
1499
|
+
*
|
|
1500
|
+
* <ExitIntentModal
|
|
1501
|
+
* enabled={showExitIntent && !userIsSubscribed}
|
|
1502
|
+
* title="Before You Go..."
|
|
1503
|
+
* onDismiss={() => {
|
|
1504
|
+
* console.log('User dismissed exit intent')
|
|
1505
|
+
* setShowExitIntent(false)
|
|
1506
|
+
* }}
|
|
1507
|
+
* >
|
|
1508
|
+
* <NewsletterSignup />
|
|
1509
|
+
* </ExitIntentModal>
|
|
1510
|
+
*/
|
|
1511
|
+
declare function ExitIntentModal({ locale, title, children, enabled, delay, oncePerSession, onceEver, storageKey, sensitivity, onShow, onDismiss }: ExitIntentModalProps): react_jsx_runtime.JSX.Element;
|
|
1512
|
+
|
|
1513
|
+
interface Tab {
|
|
1514
|
+
/** Unique tab identifier */
|
|
1515
|
+
value: string;
|
|
1516
|
+
/** Tab label (bilingual) */
|
|
1517
|
+
label: LocalizedString$2 | string;
|
|
1518
|
+
/** Tab content */
|
|
1519
|
+
content: ReactNode;
|
|
1520
|
+
/** Disabled state */
|
|
1521
|
+
disabled?: boolean;
|
|
1522
|
+
}
|
|
1523
|
+
interface TabsProps {
|
|
1524
|
+
/** Current locale */
|
|
1525
|
+
locale?: 'en' | 'fr';
|
|
1526
|
+
/** Array of tabs */
|
|
1527
|
+
tabs: Tab[];
|
|
1528
|
+
/** Default active tab value */
|
|
1529
|
+
defaultValue?: string;
|
|
1530
|
+
/** Controlled active tab value */
|
|
1531
|
+
value?: string;
|
|
1532
|
+
/** Callback when tab changes */
|
|
1533
|
+
onValueChange?: (value: string) => void;
|
|
1534
|
+
/** Sync active tab with URL query param @default false */
|
|
1535
|
+
syncWithUrl?: boolean;
|
|
1536
|
+
/** URL query param name @default 'tab' */
|
|
1537
|
+
urlParam?: string;
|
|
1538
|
+
/** Tab variant @default 'underline' */
|
|
1539
|
+
variant?: 'underline' | 'pills' | 'bordered';
|
|
1540
|
+
/** Tab orientation @default 'horizontal' */
|
|
1541
|
+
orientation?: 'horizontal' | 'vertical';
|
|
1542
|
+
/** Additional CSS classes */
|
|
1543
|
+
className?: string;
|
|
1544
|
+
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Tabs - Organize content into switchable panels
|
|
1547
|
+
*
|
|
1548
|
+
* Built on Radix UI with keyboard navigation, optional URL sync,
|
|
1549
|
+
* and multiple visual variants. Perfect for feature comparisons,
|
|
1550
|
+
* FAQs, documentation, and multi-section content.
|
|
1551
|
+
*
|
|
1552
|
+
* @example
|
|
1553
|
+
* // Basic usage
|
|
1554
|
+
* <Tabs
|
|
1555
|
+
* tabs={[
|
|
1556
|
+
* {
|
|
1557
|
+
* value: 'features',
|
|
1558
|
+
* label: { en: 'Features', fr: 'Fonctionnalités' },
|
|
1559
|
+
* content: <FeaturesContent />
|
|
1560
|
+
* },
|
|
1561
|
+
* {
|
|
1562
|
+
* value: 'pricing',
|
|
1563
|
+
* label: 'Pricing',
|
|
1564
|
+
* content: <PricingContent />
|
|
1565
|
+
* }
|
|
1566
|
+
* ]}
|
|
1567
|
+
* locale="en"
|
|
1568
|
+
* />
|
|
1569
|
+
*
|
|
1570
|
+
* @example
|
|
1571
|
+
* // With URL synchronization
|
|
1572
|
+
* <Tabs
|
|
1573
|
+
* tabs={tabs}
|
|
1574
|
+
* syncWithUrl
|
|
1575
|
+
* urlParam="section"
|
|
1576
|
+
* variant="pills"
|
|
1577
|
+
* onValueChange={(value) => {
|
|
1578
|
+
* console.log('Tab changed to:', value)
|
|
1579
|
+
* }}
|
|
1580
|
+
* />
|
|
1581
|
+
*
|
|
1582
|
+
* @example
|
|
1583
|
+
* // Vertical orientation
|
|
1584
|
+
* <Tabs
|
|
1585
|
+
* tabs={tabs}
|
|
1586
|
+
* orientation="vertical"
|
|
1587
|
+
* variant="bordered"
|
|
1588
|
+
* locale="fr"
|
|
1589
|
+
* />
|
|
1590
|
+
*/
|
|
1591
|
+
declare function Tabs({ locale, tabs, defaultValue, value: controlledValue, onValueChange, syncWithUrl, urlParam, variant, orientation, className }: TabsProps): react_jsx_runtime.JSX.Element;
|
|
1592
|
+
|
|
1593
|
+
interface TimelineItem {
|
|
1594
|
+
/** Item title (bilingual) */
|
|
1595
|
+
title: LocalizedString$2 | string;
|
|
1596
|
+
/** Item description (bilingual) */
|
|
1597
|
+
description?: LocalizedString$2 | string;
|
|
1598
|
+
/** Date or step label */
|
|
1599
|
+
date?: string;
|
|
1600
|
+
/** Optional icon */
|
|
1601
|
+
icon?: ReactNode;
|
|
1602
|
+
/** Custom content (overrides description) */
|
|
1603
|
+
content?: ReactNode;
|
|
1604
|
+
}
|
|
1605
|
+
interface TimelineProps {
|
|
1606
|
+
/** Current locale */
|
|
1607
|
+
locale?: 'en' | 'fr';
|
|
1608
|
+
/** Timeline items */
|
|
1609
|
+
items: TimelineItem[];
|
|
1610
|
+
/** Layout orientation @default 'vertical' */
|
|
1611
|
+
orientation?: 'vertical' | 'horizontal';
|
|
1612
|
+
/** Visual variant @default 'default' */
|
|
1613
|
+
variant?: 'default' | 'simple' | 'filled';
|
|
1614
|
+
/** Position (vertical only) @default 'left' */
|
|
1615
|
+
position?: 'left' | 'center' | 'right' | 'alternating';
|
|
1616
|
+
/** Show connector line @default true */
|
|
1617
|
+
showConnector?: boolean;
|
|
1618
|
+
/** Animate on scroll @default true */
|
|
1619
|
+
animate?: boolean;
|
|
1620
|
+
/** Additional CSS classes */
|
|
1621
|
+
className?: string;
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Timeline - Display chronological events or step-by-step processes
|
|
1625
|
+
*
|
|
1626
|
+
* Perfect for company history, project milestones, how-it-works sections,
|
|
1627
|
+
* and onboarding flows. Supports multiple layouts and visual styles.
|
|
1628
|
+
*
|
|
1629
|
+
* @example
|
|
1630
|
+
* // Company history timeline
|
|
1631
|
+
* <Timeline
|
|
1632
|
+
* items={[
|
|
1633
|
+
* {
|
|
1634
|
+
* date: '2020',
|
|
1635
|
+
* title: { en: 'Company Founded', fr: 'Fondation de l\'entreprise' },
|
|
1636
|
+
* description: { en: 'Started in a garage...', fr: '...' },
|
|
1637
|
+
* icon: <RocketIcon />
|
|
1638
|
+
* },
|
|
1639
|
+
* {
|
|
1640
|
+
* date: '2022',
|
|
1641
|
+
* title: 'Series A Funding',
|
|
1642
|
+
* description: 'Raised $5M to scale operations',
|
|
1643
|
+
* icon: <ChartIcon />
|
|
1644
|
+
* }
|
|
1645
|
+
* ]}
|
|
1646
|
+
* locale="en"
|
|
1647
|
+
* variant="default"
|
|
1648
|
+
* />
|
|
1649
|
+
*
|
|
1650
|
+
* @example
|
|
1651
|
+
* // Process steps (horizontal)
|
|
1652
|
+
* <Timeline
|
|
1653
|
+
* items={steps}
|
|
1654
|
+
* orientation="horizontal"
|
|
1655
|
+
* variant="filled"
|
|
1656
|
+
* position="center"
|
|
1657
|
+
* />
|
|
1658
|
+
*
|
|
1659
|
+
* @example
|
|
1660
|
+
* // Alternating timeline
|
|
1661
|
+
* <Timeline
|
|
1662
|
+
* items={milestones}
|
|
1663
|
+
* position="alternating"
|
|
1664
|
+
* showConnector
|
|
1665
|
+
* animate
|
|
1666
|
+
* />
|
|
1667
|
+
*/
|
|
1668
|
+
declare function Timeline({ locale, items, orientation, variant, position, showConnector, animate, className }: TimelineProps): react_jsx_runtime.JSX.Element;
|
|
1669
|
+
|
|
1670
|
+
interface ComparisonFeature {
|
|
1671
|
+
/** Feature name (bilingual) */
|
|
1672
|
+
name: LocalizedString$2 | string;
|
|
1673
|
+
/** Feature values for each option (boolean for checkmark, string for custom value) */
|
|
1674
|
+
values: (boolean | string | ReactNode)[];
|
|
1675
|
+
/** Feature description/tooltip (bilingual) */
|
|
1676
|
+
description?: LocalizedString$2 | string;
|
|
1677
|
+
}
|
|
1678
|
+
interface ComparisonOption {
|
|
1679
|
+
/** Option name (bilingual) */
|
|
1680
|
+
name: LocalizedString$2 | string;
|
|
1681
|
+
/** Optional badge (e.g., "Popular", "Best Value") */
|
|
1682
|
+
badge?: LocalizedString$2 | string;
|
|
1683
|
+
/** Highlight this column @default false */
|
|
1684
|
+
highlighted?: boolean;
|
|
1685
|
+
/** Call to action */
|
|
1686
|
+
cta?: {
|
|
1687
|
+
label: LocalizedString$2 | string;
|
|
1688
|
+
href?: string;
|
|
1689
|
+
onClick?: () => void;
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
interface ComparisonTableProps {
|
|
1693
|
+
/** Current locale */
|
|
1694
|
+
locale?: 'en' | 'fr';
|
|
1695
|
+
/** Table title (bilingual) */
|
|
1696
|
+
title?: LocalizedString$2 | string;
|
|
1697
|
+
/** Table description (bilingual) */
|
|
1698
|
+
description?: LocalizedString$2 | string;
|
|
1699
|
+
/** Options/products to compare */
|
|
1700
|
+
options: ComparisonOption[];
|
|
1701
|
+
/** Features to compare */
|
|
1702
|
+
features: ComparisonFeature[];
|
|
1703
|
+
/** Show checkmarks for boolean values @default true */
|
|
1704
|
+
showCheckmarks?: boolean;
|
|
1705
|
+
/** Sticky header @default true */
|
|
1706
|
+
stickyHeader?: boolean;
|
|
1707
|
+
/** Additional CSS classes */
|
|
1708
|
+
className?: string;
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* ComparisonTable - Compare features across products or plans
|
|
1712
|
+
*
|
|
1713
|
+
* Perfect for pricing plan comparisons, feature matrices, and product
|
|
1714
|
+
* comparisons. Supports highlighting, badges, and CTAs per option.
|
|
1715
|
+
*
|
|
1716
|
+
* @example
|
|
1717
|
+
* // Basic plan comparison
|
|
1718
|
+
* <ComparisonTable
|
|
1719
|
+
* title={{ en: "Compare Plans", fr: "Comparer les forfaits" }}
|
|
1720
|
+
* locale="en"
|
|
1721
|
+
* options={[
|
|
1722
|
+
* {
|
|
1723
|
+
* name: 'Basic',
|
|
1724
|
+
* cta: { label: 'Get Started', href: '/signup?plan=basic' }
|
|
1725
|
+
* },
|
|
1726
|
+
* {
|
|
1727
|
+
* name: 'Pro',
|
|
1728
|
+
* badge: 'Popular',
|
|
1729
|
+
* highlighted: true,
|
|
1730
|
+
* cta: { label: 'Start Free Trial', href: '/signup?plan=pro' }
|
|
1731
|
+
* },
|
|
1732
|
+
* {
|
|
1733
|
+
* name: 'Enterprise',
|
|
1734
|
+
* cta: { label: 'Contact Sales', onClick: () => openContact() }
|
|
1735
|
+
* }
|
|
1736
|
+
* ]}
|
|
1737
|
+
* features={[
|
|
1738
|
+
* {
|
|
1739
|
+
* name: 'Users',
|
|
1740
|
+
* values: ['5', '20', 'Unlimited']
|
|
1741
|
+
* },
|
|
1742
|
+
* {
|
|
1743
|
+
* name: 'Storage',
|
|
1744
|
+
* values: ['10 GB', '100 GB', '1 TB']
|
|
1745
|
+
* },
|
|
1746
|
+
* {
|
|
1747
|
+
* name: 'API Access',
|
|
1748
|
+
* values: [false, true, true],
|
|
1749
|
+
* description: 'Programmatic access to your data'
|
|
1750
|
+
* }
|
|
1751
|
+
* ]}
|
|
1752
|
+
* />
|
|
1753
|
+
*
|
|
1754
|
+
* @example
|
|
1755
|
+
* // Product comparison
|
|
1756
|
+
* <ComparisonTable
|
|
1757
|
+
* options={products}
|
|
1758
|
+
* features={productFeatures}
|
|
1759
|
+
* showCheckmarks
|
|
1760
|
+
* stickyHeader
|
|
1761
|
+
* />
|
|
1762
|
+
*/
|
|
1763
|
+
declare function ComparisonTable({ locale, title, description, options, features, showCheckmarks, stickyHeader, className }: ComparisonTableProps): react_jsx_runtime.JSX.Element;
|
|
1764
|
+
|
|
1765
|
+
interface BlogCardProps {
|
|
1766
|
+
/** Current locale */
|
|
1767
|
+
locale?: 'en' | 'fr';
|
|
1768
|
+
/** Article title (bilingual) */
|
|
1769
|
+
title: LocalizedString$2 | string;
|
|
1770
|
+
/** Article excerpt (bilingual) */
|
|
1771
|
+
excerpt?: LocalizedString$2 | string;
|
|
1772
|
+
/** Featured image URL */
|
|
1773
|
+
image?: string;
|
|
1774
|
+
/** Image alt text */
|
|
1775
|
+
imageAlt?: string;
|
|
1776
|
+
/** Article URL */
|
|
1777
|
+
href: string;
|
|
1778
|
+
/** Author name */
|
|
1779
|
+
author?: string;
|
|
1780
|
+
/** Author avatar URL */
|
|
1781
|
+
authorAvatar?: string;
|
|
1782
|
+
/** Publication date */
|
|
1783
|
+
date?: string;
|
|
1784
|
+
/** Read time in minutes */
|
|
1785
|
+
readTime?: number;
|
|
1786
|
+
/** Tags/categories */
|
|
1787
|
+
tags?: string[];
|
|
1788
|
+
/** Card variant @default 'default' */
|
|
1789
|
+
variant?: 'default' | 'horizontal' | 'minimal';
|
|
1790
|
+
/** Additional CSS classes */
|
|
1791
|
+
className?: string;
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* BlogCard - Article preview card for blog listings
|
|
1795
|
+
*
|
|
1796
|
+
* Displays article previews with images, metadata, and hover effects.
|
|
1797
|
+
* Perfect for blog indexes, related posts, and content grids.
|
|
1798
|
+
*
|
|
1799
|
+
* @example
|
|
1800
|
+
* // Basic usage
|
|
1801
|
+
* <BlogCard
|
|
1802
|
+
* title={{ en: "10 Tips for Better UX", fr: "10 conseils pour une meilleure UX" }}
|
|
1803
|
+
* excerpt="Improve your user experience with these proven strategies..."
|
|
1804
|
+
* image="/blog/ux-tips.jpg"
|
|
1805
|
+
* href="/blog/ux-tips"
|
|
1806
|
+
* author="Jane Doe"
|
|
1807
|
+
* date="Jan 15, 2024"
|
|
1808
|
+
* readTime={5}
|
|
1809
|
+
* tags={['UX', 'Design']}
|
|
1810
|
+
* locale="en"
|
|
1811
|
+
* />
|
|
1812
|
+
*
|
|
1813
|
+
* @example
|
|
1814
|
+
* // Horizontal variant
|
|
1815
|
+
* <BlogCard
|
|
1816
|
+
* title="Latest Product Updates"
|
|
1817
|
+
* excerpt="See what's new in our latest release"
|
|
1818
|
+
* image="/blog/updates.jpg"
|
|
1819
|
+
* href="/blog/updates"
|
|
1820
|
+
* variant="horizontal"
|
|
1821
|
+
* author="Product Team"
|
|
1822
|
+
* authorAvatar="/team/product.jpg"
|
|
1823
|
+
* date="2024-01-20"
|
|
1824
|
+
* />
|
|
1825
|
+
*
|
|
1826
|
+
* @example
|
|
1827
|
+
* // Minimal variant (no image)
|
|
1828
|
+
* <BlogCard
|
|
1829
|
+
* title="Quick Announcement"
|
|
1830
|
+
* excerpt="Brief update about our services"
|
|
1831
|
+
* href="/blog/announcement"
|
|
1832
|
+
* variant="minimal"
|
|
1833
|
+
* date="Today"
|
|
1834
|
+
* readTime={2}
|
|
1835
|
+
* />
|
|
1836
|
+
*/
|
|
1837
|
+
declare function BlogCard({ locale, title, excerpt, image, imageAlt, href, author, authorAvatar, date, readTime, tags, variant, className }: BlogCardProps): react_jsx_runtime.JSX.Element;
|
|
1838
|
+
|
|
1839
|
+
interface LazySectionProps {
|
|
1840
|
+
/** Component to lazy load */
|
|
1841
|
+
component: () => Promise<{
|
|
1842
|
+
default: ComponentType<any>;
|
|
1843
|
+
}>;
|
|
1844
|
+
/** Props to pass to the lazy component */
|
|
1845
|
+
componentProps?: Record<string, any>;
|
|
1846
|
+
/** Custom loading component */
|
|
1847
|
+
fallback?: ReactNode;
|
|
1848
|
+
/** Load when in viewport @default true */
|
|
1849
|
+
loadOnView?: boolean;
|
|
1850
|
+
/** Viewport intersection threshold @default 0.1 */
|
|
1851
|
+
threshold?: number;
|
|
1852
|
+
/** Additional CSS classes */
|
|
1853
|
+
className?: string;
|
|
1854
|
+
}
|
|
1855
|
+
/**
|
|
1856
|
+
* LazySection - Code-split sections with lazy loading
|
|
1857
|
+
*
|
|
1858
|
+
* Automatically lazy loads components when they enter the viewport,
|
|
1859
|
+
* reducing initial bundle size and improving performance. Perfect for
|
|
1860
|
+
* below-the-fold content, heavy components, and conditional features.
|
|
1861
|
+
*
|
|
1862
|
+
* @example
|
|
1863
|
+
* // Lazy load a heavy features section
|
|
1864
|
+
* <LazySection
|
|
1865
|
+
* component={() => import('./sections/FeaturesSection')}
|
|
1866
|
+
* componentProps={{
|
|
1867
|
+
* title: "Our Features",
|
|
1868
|
+
* features: featuresData
|
|
1869
|
+
* }}
|
|
1870
|
+
* />
|
|
1871
|
+
*
|
|
1872
|
+
* @example
|
|
1873
|
+
* // With custom loading skeleton
|
|
1874
|
+
* <LazySection
|
|
1875
|
+
* component={() => import('./sections/TestimonialsSection')}
|
|
1876
|
+
* fallback={
|
|
1877
|
+
* <div className="py-16">
|
|
1878
|
+
* <Skeleton.Card count={3} />
|
|
1879
|
+
* </div>
|
|
1880
|
+
* }
|
|
1881
|
+
* loadOnView
|
|
1882
|
+
* threshold={0.2}
|
|
1883
|
+
* />
|
|
1884
|
+
*
|
|
1885
|
+
* @example
|
|
1886
|
+
* // Load immediately (no viewport detection)
|
|
1887
|
+
* <LazySection
|
|
1888
|
+
* component={() => import('./sections/PricingSection')}
|
|
1889
|
+
* loadOnView={false}
|
|
1890
|
+
* componentProps={{ locale: 'en' }}
|
|
1891
|
+
* />
|
|
1892
|
+
*/
|
|
1893
|
+
declare function LazySection({ component, componentProps, fallback, loadOnView, threshold, className }: LazySectionProps): react_jsx_runtime.JSX.Element;
|
|
1894
|
+
/**
|
|
1895
|
+
* Higher-order component to make any component lazy-loadable
|
|
1896
|
+
*
|
|
1897
|
+
* @example
|
|
1898
|
+
* // Create a lazy version of any component
|
|
1899
|
+
* const LazyFeatures = withLazyLoad(() => import('./FeaturesSection'))
|
|
1900
|
+
*
|
|
1901
|
+
* // Use it like the original component
|
|
1902
|
+
* <LazyFeatures title="Features" features={data} />
|
|
1903
|
+
*
|
|
1904
|
+
* @example
|
|
1905
|
+
* // With custom fallback
|
|
1906
|
+
* const LazyPricing = withLazyLoad(
|
|
1907
|
+
* () => import('./PricingSection'),
|
|
1908
|
+
* <div>Loading pricing...</div>
|
|
1909
|
+
* )
|
|
1910
|
+
*/
|
|
1911
|
+
declare function withLazyLoad<P extends object>(importFunc: () => Promise<{
|
|
1912
|
+
default: ComponentType<P>;
|
|
1913
|
+
}>, fallback?: ReactNode): ComponentType<P>;
|
|
1914
|
+
|
|
1915
|
+
interface CodeBlockProps {
|
|
1916
|
+
/** Code to display */
|
|
1917
|
+
code: string;
|
|
1918
|
+
/** Language for syntax highlighting @default 'tsx' */
|
|
1919
|
+
language?: string;
|
|
1920
|
+
/** Show line numbers @default false */
|
|
1921
|
+
showLineNumbers?: boolean;
|
|
1922
|
+
/** Show copy button @default true */
|
|
1923
|
+
showCopy?: boolean;
|
|
1924
|
+
/** Additional CSS classes */
|
|
1925
|
+
className?: string;
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* CodeBlock - Display code with syntax highlighting
|
|
1929
|
+
*
|
|
1930
|
+
* Shows formatted code with syntax highlighting and optional copy button.
|
|
1931
|
+
* Perfect for documentation, examples, and style guides.
|
|
1932
|
+
*
|
|
1933
|
+
* @example
|
|
1934
|
+
* <CodeBlock
|
|
1935
|
+
* code={`<Button variant="filled">Click me</Button>`}
|
|
1936
|
+
* language="tsx"
|
|
1937
|
+
* />
|
|
1938
|
+
*/
|
|
1939
|
+
declare function CodeBlock({ code, language, showLineNumbers, showCopy, className }: CodeBlockProps): react_jsx_runtime.JSX.Element;
|
|
1940
|
+
/**
|
|
1941
|
+
* InlineCode - Inline code snippet
|
|
1942
|
+
*
|
|
1943
|
+
* @example
|
|
1944
|
+
* <InlineCode>npm install</InlineCode>
|
|
1945
|
+
*/
|
|
1946
|
+
declare function InlineCode({ children }: {
|
|
1947
|
+
children: string;
|
|
1948
|
+
}): react_jsx_runtime.JSX.Element;
|
|
1949
|
+
|
|
1950
|
+
interface ComponentDemoProps {
|
|
1951
|
+
/** Component title */
|
|
1952
|
+
title: string;
|
|
1953
|
+
/** Component description */
|
|
1954
|
+
description?: string;
|
|
1955
|
+
/** Live component preview */
|
|
1956
|
+
children: ReactNode;
|
|
1957
|
+
/** Code example */
|
|
1958
|
+
code: string;
|
|
1959
|
+
/** Props documentation */
|
|
1960
|
+
props?: Array<{
|
|
1961
|
+
name: string;
|
|
1962
|
+
type: string;
|
|
1963
|
+
default?: string;
|
|
1964
|
+
description: string;
|
|
1965
|
+
}>;
|
|
1966
|
+
/** Show code by default @default false */
|
|
1967
|
+
defaultShowCode?: boolean;
|
|
1968
|
+
/** Additional CSS classes */
|
|
1969
|
+
className?: string;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* ComponentDemo - Show component with live preview and code
|
|
1973
|
+
*
|
|
1974
|
+
* Displays a component example with its code and optional props documentation.
|
|
1975
|
+
* Used in StyleGuide and documentation.
|
|
1976
|
+
*
|
|
1977
|
+
* @example
|
|
1978
|
+
* <ComponentDemo
|
|
1979
|
+
* title="Button"
|
|
1980
|
+
* description="Primary action button"
|
|
1981
|
+
* code={`<Button variant="filled">Click me</Button>`}
|
|
1982
|
+
* props={[
|
|
1983
|
+
* { name: 'variant', type: 'string', default: 'outlined', description: 'Visual style' }
|
|
1984
|
+
* ]}
|
|
1985
|
+
* >
|
|
1986
|
+
* <Button variant="filled">Click me</Button>
|
|
1987
|
+
* </ComponentDemo>
|
|
1988
|
+
*/
|
|
1989
|
+
declare function ComponentDemo({ title, description, children, code, props, defaultShowCode, className }: ComponentDemoProps): react_jsx_runtime.JSX.Element;
|
|
1990
|
+
|
|
1991
|
+
/**
|
|
1992
|
+
* Slug translations mapping for bilingual/multilingual routes
|
|
1993
|
+
* Maps slugs from one locale to another
|
|
1994
|
+
*
|
|
1995
|
+
* @example
|
|
1996
|
+
* {
|
|
1997
|
+
* fr: {
|
|
1998
|
+
* '/a-propos': '/about',
|
|
1999
|
+
* '/nous-contacter': '/contact'
|
|
2000
|
+
* },
|
|
2001
|
+
* en: {
|
|
2002
|
+
* '/about': '/a-propos',
|
|
2003
|
+
* '/contact': '/nous-contacter'
|
|
2004
|
+
* }
|
|
2005
|
+
* }
|
|
2006
|
+
*/
|
|
2007
|
+
interface SlugTranslations {
|
|
2008
|
+
[locale: string]: {
|
|
2009
|
+
[slug: string]: string;
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* Type-safe localized string object
|
|
2014
|
+
* Maps locale codes to translated strings
|
|
2015
|
+
*
|
|
2016
|
+
* @example
|
|
2017
|
+
* const title: LocalizedString = {
|
|
2018
|
+
* en: 'Welcome',
|
|
2019
|
+
* fr: 'Bienvenue',
|
|
2020
|
+
* es: 'Bienvenido'
|
|
2021
|
+
* };
|
|
2022
|
+
*/
|
|
2023
|
+
interface LocalizedString$1 {
|
|
2024
|
+
[locale: string]: string;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
/**
|
|
2028
|
+
* @deprecated Import from config schemas instead
|
|
2029
|
+
*/
|
|
2030
|
+
type Locale = 'fr' | 'en';
|
|
2031
|
+
|
|
2032
|
+
interface LocalizedString {
|
|
2033
|
+
[locale: string]: string;
|
|
2034
|
+
}
|
|
2035
|
+
interface NavLink {
|
|
2036
|
+
id: string;
|
|
2037
|
+
label: LocalizedString;
|
|
2038
|
+
href: string | LocalizedString;
|
|
2039
|
+
external?: boolean;
|
|
2040
|
+
icon?: string;
|
|
2041
|
+
}
|
|
2042
|
+
interface NavDropdownItem extends NavLink {
|
|
2043
|
+
description?: LocalizedString;
|
|
2044
|
+
}
|
|
2045
|
+
interface NavDropdown {
|
|
2046
|
+
id: string;
|
|
2047
|
+
label: LocalizedString;
|
|
2048
|
+
type: 'dropdown';
|
|
2049
|
+
children: NavDropdownItem[];
|
|
2050
|
+
cta?: {
|
|
2051
|
+
label: LocalizedString;
|
|
2052
|
+
href: string;
|
|
2053
|
+
external?: boolean;
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
type NavItem = NavLink | NavDropdown;
|
|
2057
|
+
interface LogoConfig {
|
|
2058
|
+
text?: LocalizedString;
|
|
2059
|
+
image?: string;
|
|
2060
|
+
imageAlt?: LocalizedString;
|
|
2061
|
+
href: string;
|
|
2062
|
+
width?: number;
|
|
2063
|
+
height?: number;
|
|
2064
|
+
displayHeight?: number;
|
|
2065
|
+
}
|
|
2066
|
+
interface HeaderConfig {
|
|
2067
|
+
logo: LogoConfig;
|
|
2068
|
+
mainNav: NavItem[];
|
|
2069
|
+
utilityNav: NavLink[];
|
|
2070
|
+
dropdownStyle?: 'mega' | 'simple';
|
|
2071
|
+
}
|
|
2072
|
+
interface FooterSection {
|
|
2073
|
+
heading?: LocalizedString;
|
|
2074
|
+
links: NavLink[];
|
|
2075
|
+
}
|
|
2076
|
+
interface SocialLink {
|
|
2077
|
+
platform: string;
|
|
2078
|
+
url: string;
|
|
2079
|
+
icon: string;
|
|
2080
|
+
label: LocalizedString;
|
|
2081
|
+
}
|
|
2082
|
+
interface PoweredByConfig {
|
|
2083
|
+
text: LocalizedString;
|
|
2084
|
+
logo?: {
|
|
2085
|
+
src: string;
|
|
2086
|
+
alt: string;
|
|
2087
|
+
width: number;
|
|
2088
|
+
height: number;
|
|
2089
|
+
};
|
|
2090
|
+
href?: string;
|
|
2091
|
+
}
|
|
2092
|
+
interface FooterConfig {
|
|
2093
|
+
sections?: FooterSection[];
|
|
2094
|
+
copyright: LocalizedString;
|
|
2095
|
+
tagline?: LocalizedString;
|
|
2096
|
+
social?: SocialLink[];
|
|
2097
|
+
poweredBy?: PoweredByConfig;
|
|
2098
|
+
backgroundColor?: string;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
interface HeaderProps {
|
|
2102
|
+
locale: Locale;
|
|
2103
|
+
config: HeaderConfig;
|
|
2104
|
+
}
|
|
2105
|
+
declare function Header({ locale, config }: HeaderProps): react_jsx_runtime.JSX.Element;
|
|
2106
|
+
|
|
2107
|
+
interface FooterProps {
|
|
2108
|
+
locale: Locale;
|
|
2109
|
+
config: FooterConfig;
|
|
2110
|
+
}
|
|
2111
|
+
declare function Footer({ locale, config }: FooterProps): react_jsx_runtime.JSX.Element;
|
|
2112
|
+
|
|
2113
|
+
interface LanguageSelectorProps {
|
|
2114
|
+
/** Current locale */
|
|
2115
|
+
currentLocale: string;
|
|
2116
|
+
/** Additional CSS classes */
|
|
2117
|
+
className?: string;
|
|
2118
|
+
/** Display variant @default 'auto' */
|
|
2119
|
+
variant?: 'text' | 'dropdown' | 'auto';
|
|
2120
|
+
/** Custom slug translations */
|
|
2121
|
+
customSlugTranslations?: SlugTranslations;
|
|
2122
|
+
}
|
|
2123
|
+
/**
|
|
2124
|
+
* LanguageSelector - Scalable language switcher component
|
|
2125
|
+
*
|
|
2126
|
+
* Automatically adapts between text toggle (2 languages) and dropdown (3+)
|
|
2127
|
+
* Supports all 3 locale prefix modes and slug translation
|
|
2128
|
+
*
|
|
2129
|
+
* @example
|
|
2130
|
+
* ```tsx
|
|
2131
|
+
* // Auto-detects variant
|
|
2132
|
+
* <LanguageSelector currentLocale={locale} />
|
|
2133
|
+
*
|
|
2134
|
+
* // Force dropdown
|
|
2135
|
+
* <LanguageSelector currentLocale={locale} variant="dropdown" />
|
|
2136
|
+
*
|
|
2137
|
+
* // With custom slug translations
|
|
2138
|
+
* <LanguageSelector
|
|
2139
|
+
* currentLocale={locale}
|
|
2140
|
+
* customSlugTranslations={myTranslations}
|
|
2141
|
+
* />
|
|
2142
|
+
* ```
|
|
2143
|
+
*/
|
|
2144
|
+
declare function LanguageSelector({ currentLocale, className, variant, customSlugTranslations, }: LanguageSelectorProps): react_jsx_runtime.JSX.Element;
|
|
2145
|
+
|
|
2146
|
+
interface LanguageSwitcherProps {
|
|
2147
|
+
currentLocale: string;
|
|
2148
|
+
className?: string;
|
|
2149
|
+
customSlugTranslations?: SlugTranslations;
|
|
2150
|
+
}
|
|
2151
|
+
/**
|
|
2152
|
+
* @deprecated Use LanguageSelector instead. This component will be removed in v1.0.0
|
|
2153
|
+
*
|
|
2154
|
+
* This is now a thin wrapper around LanguageSelector for backward compatibility.
|
|
2155
|
+
* Update your code to use LanguageSelector:
|
|
2156
|
+
*
|
|
2157
|
+
* ```tsx
|
|
2158
|
+
* import { LanguageSelector } from 'simple-site-framework/components/layout/LanguageSelector';
|
|
2159
|
+
* <LanguageSelector currentLocale={locale} />
|
|
2160
|
+
* ```
|
|
2161
|
+
*/
|
|
2162
|
+
declare function LanguageSwitcher({ currentLocale, className, customSlugTranslations, }: LanguageSwitcherProps): react_jsx_runtime.JSX.Element;
|
|
2163
|
+
|
|
2164
|
+
interface HeroAnimations {
|
|
2165
|
+
/** Animation type for headline */
|
|
2166
|
+
headline?: 'fadeInUp' | 'fadeIn' | 'slideInLeft' | 'none';
|
|
2167
|
+
/** Animation type for CTA buttons */
|
|
2168
|
+
cta?: 'fadeInUp' | 'fadeIn' | 'none';
|
|
2169
|
+
/** Stagger delay between elements (seconds) */
|
|
2170
|
+
stagger?: number;
|
|
2171
|
+
/** Show scroll indicator */
|
|
2172
|
+
scrollIndicator?: boolean;
|
|
2173
|
+
}
|
|
2174
|
+
interface HeroSectionProps {
|
|
2175
|
+
locale: Locale;
|
|
2176
|
+
content: HeroContent;
|
|
2177
|
+
/** Animation configuration */
|
|
2178
|
+
animations?: HeroAnimations;
|
|
2179
|
+
/** Show sticky CTA after scrolling past hero */
|
|
2180
|
+
stickyCtaAfterScroll?: boolean;
|
|
2181
|
+
/** Trust badges to display */
|
|
2182
|
+
trustBadges?: Badge[];
|
|
2183
|
+
/** Background effect variant */
|
|
2184
|
+
backgroundEffect?: 'none' | 'particles' | 'gradient-shift' | 'mesh';
|
|
2185
|
+
}
|
|
2186
|
+
declare function HeroSection({ locale, content, animations, stickyCtaAfterScroll, trustBadges, backgroundEffect, }: HeroSectionProps): react_jsx_runtime.JSX.Element;
|
|
2187
|
+
|
|
2188
|
+
interface AboutSectionProps {
|
|
2189
|
+
locale: Locale;
|
|
2190
|
+
content: AboutContent;
|
|
2191
|
+
}
|
|
2192
|
+
declare function AboutSection({ locale, content }: AboutSectionProps): react_jsx_runtime.JSX.Element;
|
|
2193
|
+
|
|
2194
|
+
interface WhyChooseUsSectionProps {
|
|
2195
|
+
locale: Locale;
|
|
2196
|
+
content: WhyChooseUsContent;
|
|
2197
|
+
}
|
|
2198
|
+
declare function WhyChooseUsSection({ locale, content }: WhyChooseUsSectionProps): react_jsx_runtime.JSX.Element;
|
|
2199
|
+
|
|
2200
|
+
interface ServicesSectionProps {
|
|
2201
|
+
locale: Locale;
|
|
2202
|
+
content: ServicesContent;
|
|
2203
|
+
}
|
|
2204
|
+
declare function ServicesSection({ locale, content }: ServicesSectionProps): react_jsx_runtime.JSX.Element;
|
|
2205
|
+
|
|
2206
|
+
interface OfficeHours {
|
|
2207
|
+
monday?: {
|
|
2208
|
+
open: string;
|
|
2209
|
+
close: string;
|
|
2210
|
+
};
|
|
2211
|
+
tuesday?: {
|
|
2212
|
+
open: string;
|
|
2213
|
+
close: string;
|
|
2214
|
+
};
|
|
2215
|
+
wednesday?: {
|
|
2216
|
+
open: string;
|
|
2217
|
+
close: string;
|
|
2218
|
+
};
|
|
2219
|
+
thursday?: {
|
|
2220
|
+
open: string;
|
|
2221
|
+
close: string;
|
|
2222
|
+
};
|
|
2223
|
+
friday?: {
|
|
2224
|
+
open: string;
|
|
2225
|
+
close: string;
|
|
2226
|
+
};
|
|
2227
|
+
saturday?: {
|
|
2228
|
+
open: string;
|
|
2229
|
+
close: string;
|
|
2230
|
+
};
|
|
2231
|
+
sunday?: {
|
|
2232
|
+
open: string;
|
|
2233
|
+
close: string;
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
interface Location {
|
|
2237
|
+
name: LocalizedString$2 | string;
|
|
2238
|
+
address: string;
|
|
2239
|
+
phone?: string;
|
|
2240
|
+
email?: string;
|
|
2241
|
+
hours?: OfficeHours;
|
|
2242
|
+
coordinates?: {
|
|
2243
|
+
lat: number;
|
|
2244
|
+
lng: number;
|
|
2245
|
+
};
|
|
2246
|
+
}
|
|
2247
|
+
interface MapConfig {
|
|
2248
|
+
provider?: 'google' | 'static' | 'link';
|
|
2249
|
+
apiKey?: string;
|
|
2250
|
+
zoom?: number;
|
|
2251
|
+
}
|
|
2252
|
+
interface SpamProtection {
|
|
2253
|
+
honeypot?: boolean;
|
|
2254
|
+
recaptcha?: string;
|
|
2255
|
+
}
|
|
2256
|
+
interface FormIntegration {
|
|
2257
|
+
type: 'sendgrid' | 'mailgun' | 'webhook' | 'custom';
|
|
2258
|
+
config: Record<string, any>;
|
|
2259
|
+
}
|
|
2260
|
+
interface ContactFormConfig {
|
|
2261
|
+
enabled?: boolean;
|
|
2262
|
+
fields?: Array<'name' | 'email' | 'phone' | 'subject' | 'message' | 'attachment'>;
|
|
2263
|
+
requiredFields?: Array<'name' | 'email' | 'phone' | 'subject' | 'message'>;
|
|
2264
|
+
onSubmit?: (data: ContactFormData$1) => Promise<void>;
|
|
2265
|
+
spamProtection?: SpamProtection;
|
|
2266
|
+
integration?: FormIntegration;
|
|
2267
|
+
}
|
|
2268
|
+
interface ContactSectionProps {
|
|
2269
|
+
locale: Locale;
|
|
2270
|
+
title?: LocalizedString$2 | string;
|
|
2271
|
+
description?: LocalizedString$2 | string;
|
|
2272
|
+
form?: ContactFormConfig;
|
|
2273
|
+
locations?: Location[];
|
|
2274
|
+
defaultLocation?: number;
|
|
2275
|
+
map?: MapConfig;
|
|
2276
|
+
showMap?: boolean;
|
|
2277
|
+
showInfo?: boolean;
|
|
2278
|
+
timezone?: string;
|
|
2279
|
+
showStatus?: boolean;
|
|
2280
|
+
className?: string;
|
|
2281
|
+
}
|
|
2282
|
+
interface ContactFormData$1 {
|
|
2283
|
+
name: string;
|
|
2284
|
+
email: string;
|
|
2285
|
+
phone?: string;
|
|
2286
|
+
subject?: string;
|
|
2287
|
+
message: string;
|
|
2288
|
+
attachment?: File;
|
|
2289
|
+
_honeypot?: string;
|
|
2290
|
+
}
|
|
2291
|
+
declare function ContactSection({ locale, title, description, form, locations, defaultLocation, map, showMap, showInfo, timezone, showStatus, className, }: ContactSectionProps): react_jsx_runtime.JSX.Element;
|
|
2292
|
+
|
|
2293
|
+
interface SecurePortalSectionProps {
|
|
2294
|
+
locale: Locale;
|
|
2295
|
+
portalUrl: string;
|
|
2296
|
+
}
|
|
2297
|
+
declare function SecurePortalSection({ locale, portalUrl }: SecurePortalSectionProps): react_jsx_runtime.JSX.Element;
|
|
2298
|
+
|
|
2299
|
+
interface PersonalTaxesSectionProps {
|
|
2300
|
+
locale: Locale;
|
|
2301
|
+
}
|
|
2302
|
+
declare function PersonalTaxesSection({ locale }: PersonalTaxesSectionProps): react_jsx_runtime.JSX.Element;
|
|
2303
|
+
|
|
2304
|
+
interface RecruitingSectionProps {
|
|
2305
|
+
locale: Locale;
|
|
2306
|
+
}
|
|
2307
|
+
declare function RecruitingSection({ locale }: RecruitingSectionProps): react_jsx_runtime.JSX.Element;
|
|
2308
|
+
|
|
2309
|
+
interface BreadcrumbItem {
|
|
2310
|
+
label: string;
|
|
2311
|
+
href?: string;
|
|
2312
|
+
}
|
|
2313
|
+
interface BreadcrumbProps {
|
|
2314
|
+
items: BreadcrumbItem[];
|
|
2315
|
+
className?: string;
|
|
2316
|
+
}
|
|
2317
|
+
declare function Breadcrumb({ items, className }: BreadcrumbProps): react_jsx_runtime.JSX.Element;
|
|
2318
|
+
|
|
2319
|
+
interface ServicePageLayoutProps {
|
|
2320
|
+
locale: Locale;
|
|
2321
|
+
title: string;
|
|
2322
|
+
description: string;
|
|
2323
|
+
children?: ReactNode;
|
|
2324
|
+
breadcrumbItems: BreadcrumbItem[];
|
|
2325
|
+
showCTA?: boolean;
|
|
2326
|
+
}
|
|
2327
|
+
declare function ServicePageLayout({ locale, title, description, children, breadcrumbItems, showCTA, }: ServicePageLayoutProps): react_jsx_runtime.JSX.Element;
|
|
2328
|
+
|
|
2329
|
+
interface Logo {
|
|
2330
|
+
name: string;
|
|
2331
|
+
image: string;
|
|
2332
|
+
url?: string;
|
|
2333
|
+
}
|
|
2334
|
+
interface LogosContent {
|
|
2335
|
+
heading: {
|
|
2336
|
+
[locale: string]: string;
|
|
2337
|
+
};
|
|
2338
|
+
description?: {
|
|
2339
|
+
[locale: string]: string;
|
|
2340
|
+
};
|
|
2341
|
+
logos: Logo[];
|
|
2342
|
+
}
|
|
2343
|
+
interface LogosSectionProps {
|
|
2344
|
+
locale: Locale;
|
|
2345
|
+
content: LogosContent;
|
|
2346
|
+
}
|
|
2347
|
+
declare function LogosSection({ locale, content }: LogosSectionProps): react_jsx_runtime.JSX.Element;
|
|
2348
|
+
|
|
2349
|
+
interface TestimonialContent {
|
|
2350
|
+
quote: {
|
|
2351
|
+
[locale: string]: string;
|
|
2352
|
+
};
|
|
2353
|
+
author?: {
|
|
2354
|
+
[locale: string]: string;
|
|
2355
|
+
};
|
|
2356
|
+
role?: {
|
|
2357
|
+
[locale: string]: string;
|
|
2358
|
+
};
|
|
2359
|
+
company?: {
|
|
2360
|
+
[locale: string]: string;
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
interface TestimonialSectionProps {
|
|
2364
|
+
locale: Locale;
|
|
2365
|
+
content: TestimonialContent;
|
|
2366
|
+
}
|
|
2367
|
+
declare function TestimonialSection({ locale, content }: TestimonialSectionProps): react_jsx_runtime.JSX.Element;
|
|
2368
|
+
|
|
2369
|
+
interface FeatureSectionContent {
|
|
2370
|
+
id: string;
|
|
2371
|
+
heading: {
|
|
2372
|
+
[locale: string]: string;
|
|
2373
|
+
};
|
|
2374
|
+
subheading?: {
|
|
2375
|
+
[locale: string]: string;
|
|
2376
|
+
};
|
|
2377
|
+
description: {
|
|
2378
|
+
[locale: string]: string;
|
|
2379
|
+
};
|
|
2380
|
+
image: string;
|
|
2381
|
+
cta?: {
|
|
2382
|
+
text: {
|
|
2383
|
+
[locale: string]: string;
|
|
2384
|
+
};
|
|
2385
|
+
href: string;
|
|
2386
|
+
};
|
|
2387
|
+
imagePosition?: 'left' | 'right';
|
|
2388
|
+
}
|
|
2389
|
+
interface FeatureSectionProps {
|
|
2390
|
+
locale: Locale;
|
|
2391
|
+
content: FeatureSectionContent;
|
|
2392
|
+
backgroundColor?: string;
|
|
2393
|
+
}
|
|
2394
|
+
declare function FeatureSection({ locale, content, backgroundColor }: FeatureSectionProps): react_jsx_runtime.JSX.Element;
|
|
2395
|
+
|
|
2396
|
+
/**
|
|
2397
|
+
* Metric for displaying results/improvements
|
|
2398
|
+
*/
|
|
2399
|
+
interface CaseStudyMetric {
|
|
2400
|
+
/** Metric label (e.g., "Revenue Growth", "Time Saved") */
|
|
2401
|
+
label: LocalizedString$1 | string;
|
|
2402
|
+
/** Metric value (e.g., "150%", "$2M", "20 hours/week") */
|
|
2403
|
+
value: LocalizedString$1 | string;
|
|
2404
|
+
/** Optional icon name from lucide-react */
|
|
2405
|
+
icon?: string;
|
|
2406
|
+
}
|
|
2407
|
+
/**
|
|
2408
|
+
* Individual case study data
|
|
2409
|
+
*/
|
|
2410
|
+
interface CaseStudy {
|
|
2411
|
+
/** Unique identifier */
|
|
2412
|
+
id: string;
|
|
2413
|
+
/** Company/customer name */
|
|
2414
|
+
company: LocalizedString$1 | string;
|
|
2415
|
+
/** Company logo URL */
|
|
2416
|
+
logo?: string;
|
|
2417
|
+
/** Customer photo/avatar URL */
|
|
2418
|
+
image?: string;
|
|
2419
|
+
/** Industry or category */
|
|
2420
|
+
industry?: LocalizedString$1 | string;
|
|
2421
|
+
/** Quote or testimonial */
|
|
2422
|
+
quote: LocalizedString$1 | string;
|
|
2423
|
+
/** Person who gave the quote */
|
|
2424
|
+
author?: {
|
|
2425
|
+
name: string;
|
|
2426
|
+
title?: LocalizedString$1 | string;
|
|
2427
|
+
avatar?: string;
|
|
2428
|
+
};
|
|
2429
|
+
/** Key metrics or results */
|
|
2430
|
+
metrics?: CaseStudyMetric[];
|
|
2431
|
+
/** Challenge or problem statement */
|
|
2432
|
+
challenge?: LocalizedString$1 | string;
|
|
2433
|
+
/** Solution description */
|
|
2434
|
+
solution?: LocalizedString$1 | string;
|
|
2435
|
+
/** Full case study URL */
|
|
2436
|
+
url?: string;
|
|
2437
|
+
/** Call to action text */
|
|
2438
|
+
ctaText?: LocalizedString$1 | string;
|
|
2439
|
+
}
|
|
2440
|
+
interface CaseStudySectionProps {
|
|
2441
|
+
/** Section title */
|
|
2442
|
+
title?: LocalizedString$1 | string;
|
|
2443
|
+
/** Section description */
|
|
2444
|
+
description?: LocalizedString$1 | string;
|
|
2445
|
+
/** Array of case studies to display */
|
|
2446
|
+
caseStudies: CaseStudy[];
|
|
2447
|
+
/** Current locale for i18n */
|
|
2448
|
+
locale?: string;
|
|
2449
|
+
/** Layout variant */
|
|
2450
|
+
variant?: 'grid' | 'carousel' | 'featured';
|
|
2451
|
+
/** Number of columns for grid layout */
|
|
2452
|
+
columns?: 2 | 3 | 4;
|
|
2453
|
+
/** Additional CSS classes */
|
|
2454
|
+
className?: string;
|
|
2455
|
+
/** Show metrics section */
|
|
2456
|
+
showMetrics?: boolean;
|
|
2457
|
+
/** Show challenge/solution sections */
|
|
2458
|
+
showDetails?: boolean;
|
|
2459
|
+
/** Custom CTA renderer */
|
|
2460
|
+
renderCTA?: (caseStudy: CaseStudy) => ReactNode;
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Case Study Section Component
|
|
2464
|
+
*
|
|
2465
|
+
* Displays customer success stories and testimonials to build trust.
|
|
2466
|
+
* Supports multiple layouts and customizable content.
|
|
2467
|
+
*
|
|
2468
|
+
* @example Basic usage
|
|
2469
|
+
* ```tsx
|
|
2470
|
+
* <CaseStudySection
|
|
2471
|
+
* title="Customer Success Stories"
|
|
2472
|
+
* description="See how companies achieve results with our platform"
|
|
2473
|
+
* caseStudies={[
|
|
2474
|
+
* {
|
|
2475
|
+
* id: '1',
|
|
2476
|
+
* company: 'Acme Corp',
|
|
2477
|
+
* logo: '/logos/acme.png',
|
|
2478
|
+
* quote: 'Increased our email ROI by 300% in just 3 months',
|
|
2479
|
+
* author: {
|
|
2480
|
+
* name: 'Jane Doe',
|
|
2481
|
+
* title: 'Marketing Director'
|
|
2482
|
+
* },
|
|
2483
|
+
* metrics: [
|
|
2484
|
+
* { label: 'ROI Increase', value: '300%' },
|
|
2485
|
+
* { label: 'Time Saved', value: '15 hrs/week' }
|
|
2486
|
+
* ]
|
|
2487
|
+
* }
|
|
2488
|
+
* ]}
|
|
2489
|
+
* />
|
|
2490
|
+
* ```
|
|
2491
|
+
*
|
|
2492
|
+
* @example With challenge/solution
|
|
2493
|
+
* ```tsx
|
|
2494
|
+
* <CaseStudySection
|
|
2495
|
+
* caseStudies={[
|
|
2496
|
+
* {
|
|
2497
|
+
* id: '1',
|
|
2498
|
+
* company: 'TechStart Inc',
|
|
2499
|
+
* challenge: 'Struggled with low email engagement and deliverability',
|
|
2500
|
+
* solution: 'Implemented our automation and segmentation features',
|
|
2501
|
+
* metrics: [
|
|
2502
|
+
* { label: 'Open Rate', value: '+45%' },
|
|
2503
|
+
* { label: 'Click Rate', value: '+120%' }
|
|
2504
|
+
* ]
|
|
2505
|
+
* }
|
|
2506
|
+
* ]}
|
|
2507
|
+
* showDetails={true}
|
|
2508
|
+
* />
|
|
2509
|
+
* ```
|
|
2510
|
+
*/
|
|
2511
|
+
declare function CaseStudySection({ title, description, caseStudies, locale, variant, columns, className, showMetrics, showDetails, renderCTA, }: CaseStudySectionProps): react_jsx_runtime.JSX.Element;
|
|
2512
|
+
|
|
2513
|
+
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
2514
|
+
/**
|
|
2515
|
+
* Visual variant of the button
|
|
2516
|
+
* - outlined: Rounded with border (primary brand style)
|
|
2517
|
+
* - filled: Solid background with shadow
|
|
2518
|
+
* - text: Text-only button without border
|
|
2519
|
+
* - ghost: Transparent background, visible on hover
|
|
2520
|
+
* - link: Styled like a link, but button semantics
|
|
2521
|
+
* - destructive: Red variant for delete/remove actions
|
|
2522
|
+
*/
|
|
2523
|
+
variant?: 'outlined' | 'filled' | 'text' | 'ghost' | 'link' | 'destructive';
|
|
2524
|
+
/**
|
|
2525
|
+
* Size of the button
|
|
2526
|
+
*/
|
|
2527
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
2528
|
+
/**
|
|
2529
|
+
* Full width button
|
|
2530
|
+
*/
|
|
2531
|
+
fullWidth?: boolean;
|
|
2532
|
+
/**
|
|
2533
|
+
* Loading state - shows spinner and disables button
|
|
2534
|
+
*/
|
|
2535
|
+
loading?: boolean;
|
|
2536
|
+
/**
|
|
2537
|
+
* Custom text to show during loading
|
|
2538
|
+
*/
|
|
2539
|
+
loadingText?: string;
|
|
2540
|
+
/**
|
|
2541
|
+
* Success state - shows checkmark animation
|
|
2542
|
+
*/
|
|
2543
|
+
success?: boolean;
|
|
2544
|
+
/**
|
|
2545
|
+
* Custom text to show during success
|
|
2546
|
+
*/
|
|
2547
|
+
successText?: string;
|
|
2548
|
+
/**
|
|
2549
|
+
* Duration to show success state before reverting (ms)
|
|
2550
|
+
*/
|
|
2551
|
+
successDuration?: number;
|
|
2552
|
+
/**
|
|
2553
|
+
* Icon element to display
|
|
2554
|
+
*/
|
|
2555
|
+
icon?: ReactNode;
|
|
2556
|
+
/**
|
|
2557
|
+
* Position of the icon
|
|
2558
|
+
*/
|
|
2559
|
+
iconPosition?: 'left' | 'right';
|
|
2560
|
+
/**
|
|
2561
|
+
* Icon-only button (no text)
|
|
2562
|
+
*/
|
|
2563
|
+
iconOnly?: boolean;
|
|
2564
|
+
/**
|
|
2565
|
+
* Tooltip text to show when button is disabled
|
|
2566
|
+
*/
|
|
2567
|
+
disabledTooltip?: string;
|
|
2568
|
+
/**
|
|
2569
|
+
* Enable ripple effect on click
|
|
2570
|
+
*/
|
|
2571
|
+
ripple?: boolean;
|
|
2572
|
+
/**
|
|
2573
|
+
* Analytics event name to track on click
|
|
2574
|
+
* Automatically tracks button clicks with this event name
|
|
2575
|
+
*/
|
|
2576
|
+
trackingEvent?: string;
|
|
2577
|
+
/**
|
|
2578
|
+
* Additional properties to send with tracking event
|
|
2579
|
+
* Merged with automatic button properties (variant, text, href)
|
|
2580
|
+
*/
|
|
2581
|
+
trackingProps?: Record<string, unknown>;
|
|
2582
|
+
/**
|
|
2583
|
+
* Link href (for navigation buttons)
|
|
2584
|
+
*/
|
|
2585
|
+
href?: string;
|
|
2586
|
+
}
|
|
2587
|
+
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
|
|
2588
|
+
|
|
2589
|
+
interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
2590
|
+
/**
|
|
2591
|
+
* Padding variant
|
|
2592
|
+
*/
|
|
2593
|
+
padding?: 'none' | 'sm' | 'md' | 'lg';
|
|
2594
|
+
/**
|
|
2595
|
+
* Whether to show a border
|
|
2596
|
+
*/
|
|
2597
|
+
bordered?: boolean;
|
|
2598
|
+
/**
|
|
2599
|
+
* Whether to show a shadow
|
|
2600
|
+
*/
|
|
2601
|
+
shadow?: boolean;
|
|
2602
|
+
}
|
|
2603
|
+
declare const Card: react.ForwardRefExoticComponent<CardProps & react.RefAttributes<HTMLDivElement>>;
|
|
2604
|
+
|
|
2605
|
+
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
2606
|
+
/**
|
|
2607
|
+
* Label text for the input
|
|
2608
|
+
*/
|
|
2609
|
+
label?: string;
|
|
2610
|
+
/**
|
|
2611
|
+
* Error message to display
|
|
2612
|
+
*/
|
|
2613
|
+
error?: string;
|
|
2614
|
+
/**
|
|
2615
|
+
* Helper text to display below input
|
|
2616
|
+
*/
|
|
2617
|
+
helperText?: string;
|
|
2618
|
+
/**
|
|
2619
|
+
* Full width input
|
|
2620
|
+
*/
|
|
2621
|
+
fullWidth?: boolean;
|
|
2622
|
+
}
|
|
2623
|
+
declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
|
|
2624
|
+
|
|
2625
|
+
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
2626
|
+
/**
|
|
2627
|
+
* Label text for the textarea
|
|
2628
|
+
*/
|
|
2629
|
+
label?: string;
|
|
2630
|
+
/**
|
|
2631
|
+
* Error message to display
|
|
2632
|
+
*/
|
|
2633
|
+
error?: string;
|
|
2634
|
+
/**
|
|
2635
|
+
* Helper text to display below textarea
|
|
2636
|
+
*/
|
|
2637
|
+
helperText?: string;
|
|
2638
|
+
/**
|
|
2639
|
+
* Full width textarea
|
|
2640
|
+
*/
|
|
2641
|
+
fullWidth?: boolean;
|
|
2642
|
+
}
|
|
2643
|
+
declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
|
|
2644
|
+
|
|
2645
|
+
interface PhoneLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
2646
|
+
/** Phone number (will be formatted for tel: protocol) */
|
|
2647
|
+
phone: string;
|
|
2648
|
+
/** Link content (defaults to phone number) */
|
|
2649
|
+
children?: ReactNode;
|
|
2650
|
+
}
|
|
2651
|
+
/**
|
|
2652
|
+
* PhoneLink - Creates a clickable phone link for mobile devices
|
|
2653
|
+
*
|
|
2654
|
+
* Automatically formats phone number for tel: protocol and enables
|
|
2655
|
+
* one-tap calling on mobile devices.
|
|
2656
|
+
*
|
|
2657
|
+
* @example
|
|
2658
|
+
* ```tsx
|
|
2659
|
+
* <PhoneLink phone="+1-555-123-4567">
|
|
2660
|
+
* Call Us Now
|
|
2661
|
+
* </PhoneLink>
|
|
2662
|
+
* ```
|
|
2663
|
+
*/
|
|
2664
|
+
declare function PhoneLink({ phone, children, className, ...props }: PhoneLinkProps): react_jsx_runtime.JSX.Element;
|
|
2665
|
+
interface EmailLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
2666
|
+
/** Email address */
|
|
2667
|
+
email: string;
|
|
2668
|
+
/** Optional email subject */
|
|
2669
|
+
subject?: string;
|
|
2670
|
+
/** Optional email body */
|
|
2671
|
+
body?: string;
|
|
2672
|
+
/** Link content (defaults to email address) */
|
|
2673
|
+
children?: ReactNode;
|
|
2674
|
+
}
|
|
2675
|
+
/**
|
|
2676
|
+
* EmailLink - Creates a mailto: link for email
|
|
2677
|
+
*
|
|
2678
|
+
* Opens email client with pre-filled recipient, subject, and body.
|
|
2679
|
+
*
|
|
2680
|
+
* @example
|
|
2681
|
+
* ```tsx
|
|
2682
|
+
* <EmailLink
|
|
2683
|
+
* email="hello@example.com"
|
|
2684
|
+
* subject="Contact from website"
|
|
2685
|
+
* >
|
|
2686
|
+
* Email Us
|
|
2687
|
+
* </EmailLink>
|
|
2688
|
+
* ```
|
|
2689
|
+
*/
|
|
2690
|
+
declare function EmailLink({ email, subject, body, children, className, ...props }: EmailLinkProps): react_jsx_runtime.JSX.Element;
|
|
2691
|
+
interface AddressLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
2692
|
+
/** Physical address */
|
|
2693
|
+
address: string;
|
|
2694
|
+
/** Link content (defaults to address) */
|
|
2695
|
+
children?: ReactNode;
|
|
2696
|
+
}
|
|
2697
|
+
/**
|
|
2698
|
+
* AddressLink - Creates a link to Google Maps for an address
|
|
2699
|
+
*
|
|
2700
|
+
* Opens address in Google Maps (works on both iOS and Android).
|
|
2701
|
+
* Opens in new tab for desktop convenience.
|
|
2702
|
+
*
|
|
2703
|
+
* @example
|
|
2704
|
+
* ```tsx
|
|
2705
|
+
* <AddressLink address="123 Main St, New York, NY 10001">
|
|
2706
|
+
* Get Directions
|
|
2707
|
+
* </AddressLink>
|
|
2708
|
+
* ```
|
|
2709
|
+
*/
|
|
2710
|
+
declare function AddressLink({ address, children, className, ...props }: AddressLinkProps): react_jsx_runtime.JSX.Element;
|
|
2711
|
+
|
|
2712
|
+
/**
|
|
2713
|
+
* Contact form field configuration
|
|
2714
|
+
*/
|
|
2715
|
+
interface ContactFormField {
|
|
2716
|
+
/** Field name/id */
|
|
2717
|
+
name: string;
|
|
2718
|
+
/** Field label */
|
|
2719
|
+
label: LocalizedString$1 | string;
|
|
2720
|
+
/** Field type */
|
|
2721
|
+
type?: 'text' | 'email' | 'tel' | 'url' | 'textarea';
|
|
2722
|
+
/** Placeholder text */
|
|
2723
|
+
placeholder?: LocalizedString$1 | string;
|
|
2724
|
+
/** Whether field is required */
|
|
2725
|
+
required?: boolean;
|
|
2726
|
+
/** Number of rows for textarea */
|
|
2727
|
+
rows?: number;
|
|
2728
|
+
/** Help text */
|
|
2729
|
+
helperText?: LocalizedString$1 | string;
|
|
2730
|
+
}
|
|
2731
|
+
/**
|
|
2732
|
+
* Contact form submission data
|
|
2733
|
+
*/
|
|
2734
|
+
interface ContactFormData {
|
|
2735
|
+
[key: string]: string;
|
|
2736
|
+
}
|
|
2737
|
+
/**
|
|
2738
|
+
* Contact form submission response
|
|
2739
|
+
*/
|
|
2740
|
+
interface ContactFormResponse {
|
|
2741
|
+
/** Whether submission was successful */
|
|
2742
|
+
success: boolean;
|
|
2743
|
+
/** Response message */
|
|
2744
|
+
message?: string;
|
|
2745
|
+
/** Error details if failed */
|
|
2746
|
+
error?: string;
|
|
2747
|
+
}
|
|
2748
|
+
interface ContactFormProps {
|
|
2749
|
+
/** Form title */
|
|
2750
|
+
title?: LocalizedString$1 | string;
|
|
2751
|
+
/** Form description */
|
|
2752
|
+
description?: LocalizedString$1 | string;
|
|
2753
|
+
/** Array of form fields */
|
|
2754
|
+
fields?: ContactFormField[];
|
|
2755
|
+
/** Submit button text */
|
|
2756
|
+
submitText?: LocalizedString$1 | string;
|
|
2757
|
+
/** Success message */
|
|
2758
|
+
successMessage?: LocalizedString$1 | string;
|
|
2759
|
+
/** Error message */
|
|
2760
|
+
errorMessage?: LocalizedString$1 | string;
|
|
2761
|
+
/** Form submission handler */
|
|
2762
|
+
onSubmit: (data: ContactFormData) => Promise<ContactFormResponse>;
|
|
2763
|
+
/** Current locale for i18n */
|
|
2764
|
+
locale?: string;
|
|
2765
|
+
/** Additional CSS classes */
|
|
2766
|
+
className?: string;
|
|
2767
|
+
/** Show privacy notice */
|
|
2768
|
+
showPrivacyNotice?: boolean;
|
|
2769
|
+
/** Privacy notice text */
|
|
2770
|
+
privacyNoticeText?: LocalizedString$1 | string;
|
|
2771
|
+
/** Privacy policy URL */
|
|
2772
|
+
privacyPolicyUrl?: string;
|
|
2773
|
+
/** Enable honeypot spam protection */
|
|
2774
|
+
enableHoneypot?: boolean;
|
|
2775
|
+
}
|
|
2776
|
+
/**
|
|
2777
|
+
* Contact Form Component
|
|
2778
|
+
*
|
|
2779
|
+
* Production-ready contact form with validation, accessibility,
|
|
2780
|
+
* and spam protection.
|
|
2781
|
+
*
|
|
2782
|
+
* @example Basic usage
|
|
2783
|
+
* ```tsx
|
|
2784
|
+
* <ContactForm
|
|
2785
|
+
* onSubmit={async (data) => {
|
|
2786
|
+
* const response = await fetch('/api/contact', {
|
|
2787
|
+
* method: 'POST',
|
|
2788
|
+
* body: JSON.stringify(data),
|
|
2789
|
+
* });
|
|
2790
|
+
* return response.json();
|
|
2791
|
+
* }}
|
|
2792
|
+
* />
|
|
2793
|
+
* ```
|
|
2794
|
+
*
|
|
2795
|
+
* @example Custom fields
|
|
2796
|
+
* ```tsx
|
|
2797
|
+
* <ContactForm
|
|
2798
|
+
* fields={[
|
|
2799
|
+
* { name: 'name', label: 'Name', type: 'text', required: true },
|
|
2800
|
+
* { name: 'email', label: 'Email', type: 'email', required: true },
|
|
2801
|
+
* { name: 'company', label: 'Company', type: 'text', required: false },
|
|
2802
|
+
* { name: 'message', label: 'Message', type: 'textarea', required: true, rows: 6 }
|
|
2803
|
+
* ]}
|
|
2804
|
+
* onSubmit={handleSubmit}
|
|
2805
|
+
* />
|
|
2806
|
+
* ```
|
|
2807
|
+
*
|
|
2808
|
+
* @example With privacy notice
|
|
2809
|
+
* ```tsx
|
|
2810
|
+
* <ContactForm
|
|
2811
|
+
* showPrivacyNotice={true}
|
|
2812
|
+
* privacyPolicyUrl="/privacy"
|
|
2813
|
+
* onSubmit={handleSubmit}
|
|
2814
|
+
* />
|
|
2815
|
+
* ```
|
|
2816
|
+
*/
|
|
2817
|
+
declare function ContactForm({ title, description, fields, submitText, successMessage, errorMessage, onSubmit, locale, className, showPrivacyNotice, privacyNoticeText, privacyPolicyUrl, enableHoneypot, }: ContactFormProps): react_jsx_runtime.JSX.Element;
|
|
2818
|
+
|
|
2819
|
+
interface ThemeConfig {
|
|
2820
|
+
brand: {
|
|
2821
|
+
name: string;
|
|
2822
|
+
colors: {
|
|
2823
|
+
primary: string;
|
|
2824
|
+
primaryHover: string;
|
|
2825
|
+
primaryLight: string;
|
|
2826
|
+
primaryDark: string;
|
|
2827
|
+
primaryGradientStart: string;
|
|
2828
|
+
primaryGradientEnd: string;
|
|
2829
|
+
heroGradientStart: string;
|
|
2830
|
+
heroGradientEnd: string;
|
|
2831
|
+
footerGradientStart: string;
|
|
2832
|
+
footerGradientEnd: string;
|
|
2833
|
+
};
|
|
2834
|
+
fonts: {
|
|
2835
|
+
heading: {
|
|
2836
|
+
family: string;
|
|
2837
|
+
weights: number[];
|
|
2838
|
+
fallback: string;
|
|
2839
|
+
};
|
|
2840
|
+
body: {
|
|
2841
|
+
family: string;
|
|
2842
|
+
weights: number[];
|
|
2843
|
+
fallback: string;
|
|
2844
|
+
};
|
|
2845
|
+
};
|
|
2846
|
+
};
|
|
2847
|
+
design: {
|
|
2848
|
+
borderRadius: 'sharp' | 'rounded' | 'pill';
|
|
2849
|
+
shadows: 'flat' | 'subtle' | 'prominent';
|
|
2850
|
+
spacing: 'compact' | 'comfortable' | 'spacious';
|
|
2851
|
+
};
|
|
2852
|
+
animations?: {
|
|
2853
|
+
speed?: 'slow' | 'normal' | 'fast';
|
|
2854
|
+
reduceMotion?: boolean;
|
|
2855
|
+
};
|
|
2856
|
+
colors: {
|
|
2857
|
+
slate: {
|
|
2858
|
+
50: string;
|
|
2859
|
+
100: string;
|
|
2860
|
+
200: string;
|
|
2861
|
+
300: string;
|
|
2862
|
+
400: string;
|
|
2863
|
+
500: string;
|
|
2864
|
+
600: string;
|
|
2865
|
+
700: string;
|
|
2866
|
+
800: string;
|
|
2867
|
+
900: string;
|
|
2868
|
+
};
|
|
2869
|
+
};
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2872
|
+
interface StyleGuideProps {
|
|
2873
|
+
locale: Locale;
|
|
2874
|
+
theme: ThemeConfig;
|
|
2875
|
+
logo?: LogoConfig;
|
|
2876
|
+
favicon?: string;
|
|
2877
|
+
/** Show code examples @default false */
|
|
2878
|
+
showCode?: boolean;
|
|
2879
|
+
/** Show interactive props editor @default false */
|
|
2880
|
+
interactive?: boolean;
|
|
2881
|
+
/** Show component search @default false */
|
|
2882
|
+
searchable?: boolean;
|
|
2883
|
+
}
|
|
2884
|
+
declare function StyleGuide({ locale, theme, logo, favicon, showCode, interactive, searchable }: StyleGuideProps): react_jsx_runtime.JSX.Element;
|
|
2885
|
+
|
|
2886
|
+
interface HeadScriptsProps {
|
|
2887
|
+
/**
|
|
2888
|
+
* Array of HTML strings to inject in <head>
|
|
2889
|
+
* Can include <script>, <link>, <meta>, etc.
|
|
2890
|
+
*/
|
|
2891
|
+
scripts?: string[];
|
|
2892
|
+
}
|
|
2893
|
+
interface BodyEndScriptsProps {
|
|
2894
|
+
/**
|
|
2895
|
+
* Array of HTML strings to inject before </body>
|
|
2896
|
+
* Typically chat widgets, tracking pixels, etc.
|
|
2897
|
+
*/
|
|
2898
|
+
scripts?: string[];
|
|
2899
|
+
}
|
|
2900
|
+
/**
|
|
2901
|
+
* Injects scripts into document head
|
|
2902
|
+
* Use in your root layout's <head> section
|
|
2903
|
+
*/
|
|
2904
|
+
declare function HeadScripts({ scripts }: HeadScriptsProps): react_jsx_runtime.JSX.Element | null;
|
|
2905
|
+
/**
|
|
2906
|
+
* Injects scripts at end of body
|
|
2907
|
+
* Use in your root layout before closing </body>
|
|
2908
|
+
*/
|
|
2909
|
+
declare function BodyEndScripts({ scripts }: BodyEndScriptsProps): null;
|
|
2910
|
+
|
|
2911
|
+
interface Feature {
|
|
2912
|
+
id: string;
|
|
2913
|
+
icon?: ReactNode;
|
|
2914
|
+
name: string;
|
|
2915
|
+
description: string;
|
|
2916
|
+
benefits?: string[];
|
|
2917
|
+
useCases?: string[];
|
|
2918
|
+
learnMoreHref?: string;
|
|
2919
|
+
}
|
|
2920
|
+
interface FeatureCategory {
|
|
2921
|
+
id: string;
|
|
2922
|
+
name: string;
|
|
2923
|
+
description: string;
|
|
2924
|
+
features: Feature[];
|
|
2925
|
+
}
|
|
2926
|
+
interface FeaturesGridProps {
|
|
2927
|
+
categories: FeatureCategory[];
|
|
2928
|
+
className?: string;
|
|
2929
|
+
locale?: 'fr' | 'en';
|
|
2930
|
+
}
|
|
2931
|
+
declare function FeaturesGrid({ categories, className, locale }: FeaturesGridProps): react_jsx_runtime.JSX.Element;
|
|
2932
|
+
|
|
2933
|
+
type IconName = string;
|
|
2934
|
+
interface IconProps extends Omit<LucideProps, 'ref'> {
|
|
2935
|
+
/** Icon name from Lucide React */
|
|
2936
|
+
name: IconName;
|
|
2937
|
+
/** Icon size in pixels @default 24 */
|
|
2938
|
+
size?: number;
|
|
2939
|
+
/** Additional CSS classes */
|
|
2940
|
+
className?: string;
|
|
2941
|
+
}
|
|
2942
|
+
/**
|
|
2943
|
+
* Icon - Lucide React icon wrapper
|
|
2944
|
+
*
|
|
2945
|
+
* Type-safe wrapper for Lucide React icons with preset configurations.
|
|
2946
|
+
* Supports all 1000+ Lucide icons with tree-shaking.
|
|
2947
|
+
*
|
|
2948
|
+
* @example
|
|
2949
|
+
* // Basic usage
|
|
2950
|
+
* <Icon name="Check" size={24} />
|
|
2951
|
+
*
|
|
2952
|
+
* @example
|
|
2953
|
+
* // With styling
|
|
2954
|
+
* <Icon
|
|
2955
|
+
* name="ChevronDown"
|
|
2956
|
+
* size={20}
|
|
2957
|
+
* className="text-primary"
|
|
2958
|
+
* />
|
|
2959
|
+
*
|
|
2960
|
+
* @example
|
|
2961
|
+
* // With animation
|
|
2962
|
+
* <Icon
|
|
2963
|
+
* name="Loader2"
|
|
2964
|
+
* className="animate-spin text-white"
|
|
2965
|
+
* />
|
|
2966
|
+
*/
|
|
2967
|
+
declare const Icon: react.ForwardRefExoticComponent<IconProps & react.RefAttributes<SVGSVGElement>>;
|
|
2968
|
+
declare const Icons: {
|
|
2969
|
+
ChevronDown: react.ComponentType<Omit<IconProps, "name">>;
|
|
2970
|
+
ChevronUp: react.ComponentType<Omit<IconProps, "name">>;
|
|
2971
|
+
ChevronLeft: react.ComponentType<Omit<IconProps, "name">>;
|
|
2972
|
+
ChevronRight: react.ComponentType<Omit<IconProps, "name">>;
|
|
2973
|
+
Menu: react.ComponentType<Omit<IconProps, "name">>;
|
|
2974
|
+
X: react.ComponentType<Omit<IconProps, "name">>;
|
|
2975
|
+
Check: react.ComponentType<Omit<IconProps, "name">>;
|
|
2976
|
+
CheckCircle: react.ComponentType<Omit<IconProps, "name">>;
|
|
2977
|
+
Plus: react.ComponentType<Omit<IconProps, "name">>;
|
|
2978
|
+
Minus: react.ComponentType<Omit<IconProps, "name">>;
|
|
2979
|
+
Edit: react.ComponentType<Omit<IconProps, "name">>;
|
|
2980
|
+
Trash: react.ComponentType<Omit<IconProps, "name">>;
|
|
2981
|
+
Copy: react.ComponentType<Omit<IconProps, "name">>;
|
|
2982
|
+
Download: react.ComponentType<Omit<IconProps, "name">>;
|
|
2983
|
+
Upload: react.ComponentType<Omit<IconProps, "name">>;
|
|
2984
|
+
Loader: react.ComponentType<Omit<IconProps, "name">>;
|
|
2985
|
+
AlertCircle: react.ComponentType<Omit<IconProps, "name">>;
|
|
2986
|
+
AlertTriangle: react.ComponentType<Omit<IconProps, "name">>;
|
|
2987
|
+
Info: react.ComponentType<Omit<IconProps, "name">>;
|
|
2988
|
+
Mail: react.ComponentType<Omit<IconProps, "name">>;
|
|
2989
|
+
Phone: react.ComponentType<Omit<IconProps, "name">>;
|
|
2990
|
+
MessageCircle: react.ComponentType<Omit<IconProps, "name">>;
|
|
2991
|
+
Send: react.ComponentType<Omit<IconProps, "name">>;
|
|
2992
|
+
Image: react.ComponentType<Omit<IconProps, "name">>;
|
|
2993
|
+
Video: react.ComponentType<Omit<IconProps, "name">>;
|
|
2994
|
+
Play: react.ComponentType<Omit<IconProps, "name">>;
|
|
2995
|
+
Pause: react.ComponentType<Omit<IconProps, "name">>;
|
|
2996
|
+
Calendar: react.ComponentType<Omit<IconProps, "name">>;
|
|
2997
|
+
Clock: react.ComponentType<Omit<IconProps, "name">>;
|
|
2998
|
+
DollarSign: react.ComponentType<Omit<IconProps, "name">>;
|
|
2999
|
+
CreditCard: react.ComponentType<Omit<IconProps, "name">>;
|
|
3000
|
+
ShoppingCart: react.ComponentType<Omit<IconProps, "name">>;
|
|
3001
|
+
Twitter: react.ComponentType<Omit<IconProps, "name">>;
|
|
3002
|
+
Facebook: react.ComponentType<Omit<IconProps, "name">>;
|
|
3003
|
+
Linkedin: react.ComponentType<Omit<IconProps, "name">>;
|
|
3004
|
+
Instagram: react.ComponentType<Omit<IconProps, "name">>;
|
|
3005
|
+
Github: react.ComponentType<Omit<IconProps, "name">>;
|
|
3006
|
+
File: react.ComponentType<Omit<IconProps, "name">>;
|
|
3007
|
+
FileText: react.ComponentType<Omit<IconProps, "name">>;
|
|
3008
|
+
Folder: react.ComponentType<Omit<IconProps, "name">>;
|
|
3009
|
+
Settings: react.ComponentType<Omit<IconProps, "name">>;
|
|
3010
|
+
Search: react.ComponentType<Omit<IconProps, "name">>;
|
|
3011
|
+
Filter: react.ComponentType<Omit<IconProps, "name">>;
|
|
3012
|
+
ArrowRight: react.ComponentType<Omit<IconProps, "name">>;
|
|
3013
|
+
ArrowLeft: react.ComponentType<Omit<IconProps, "name">>;
|
|
3014
|
+
ArrowUp: react.ComponentType<Omit<IconProps, "name">>;
|
|
3015
|
+
ArrowDown: react.ComponentType<Omit<IconProps, "name">>;
|
|
3016
|
+
Heart: react.ComponentType<Omit<IconProps, "name">>;
|
|
3017
|
+
Star: react.ComponentType<Omit<IconProps, "name">>;
|
|
3018
|
+
Lock: react.ComponentType<Omit<IconProps, "name">>;
|
|
3019
|
+
Unlock: react.ComponentType<Omit<IconProps, "name">>;
|
|
3020
|
+
Eye: react.ComponentType<Omit<IconProps, "name">>;
|
|
3021
|
+
EyeOff: react.ComponentType<Omit<IconProps, "name">>;
|
|
3022
|
+
Home: react.ComponentType<Omit<IconProps, "name">>;
|
|
3023
|
+
User: react.ComponentType<Omit<IconProps, "name">>;
|
|
3024
|
+
Users: react.ComponentType<Omit<IconProps, "name">>;
|
|
3025
|
+
Bell: react.ComponentType<Omit<IconProps, "name">>;
|
|
3026
|
+
MapPin: react.ComponentType<Omit<IconProps, "name">>;
|
|
3027
|
+
Globe: react.ComponentType<Omit<IconProps, "name">>;
|
|
3028
|
+
Zap: react.ComponentType<Omit<IconProps, "name">>;
|
|
3029
|
+
Award: react.ComponentType<Omit<IconProps, "name">>;
|
|
3030
|
+
Shield: react.ComponentType<Omit<IconProps, "name">>;
|
|
3031
|
+
TrendingUp: react.ComponentType<Omit<IconProps, "name">>;
|
|
3032
|
+
ExternalLink: react.ComponentType<Omit<IconProps, "name">>;
|
|
3033
|
+
};
|
|
3034
|
+
|
|
3035
|
+
interface FormFieldARIAProps {
|
|
3036
|
+
/** Field label text */
|
|
3037
|
+
label?: string;
|
|
3038
|
+
/** Field name (matches form schema and input id) */
|
|
3039
|
+
name: string;
|
|
3040
|
+
/** Error object from React Hook Form */
|
|
3041
|
+
error?: FieldError;
|
|
3042
|
+
/** Optional hint text shown below input */
|
|
3043
|
+
hint?: string;
|
|
3044
|
+
/** Whether field is required */
|
|
3045
|
+
required?: boolean;
|
|
3046
|
+
/** Whether field is disabled */
|
|
3047
|
+
disabled?: boolean;
|
|
3048
|
+
/** Input element to render */
|
|
3049
|
+
children: ReactElement;
|
|
3050
|
+
/** Additional CSS classes */
|
|
3051
|
+
className?: string;
|
|
3052
|
+
}
|
|
3053
|
+
/**
|
|
3054
|
+
* FormFieldARIA - ARIA-enhanced form field wrapper
|
|
3055
|
+
*
|
|
3056
|
+
* Provides comprehensive accessibility support including:
|
|
3057
|
+
* - aria-required for required fields
|
|
3058
|
+
* - aria-invalid for error states
|
|
3059
|
+
* - aria-describedby linking to hints and errors
|
|
3060
|
+
* - Live regions for error announcements
|
|
3061
|
+
* - Proper label association
|
|
3062
|
+
* - Screen reader optimizations
|
|
3063
|
+
*
|
|
3064
|
+
* @example Basic usage
|
|
3065
|
+
* ```tsx
|
|
3066
|
+
* <FormFieldARIA
|
|
3067
|
+
* name="email"
|
|
3068
|
+
* label="Email Address"
|
|
3069
|
+
* error={errors.email}
|
|
3070
|
+
* hint="We'll never share your email"
|
|
3071
|
+
* required
|
|
3072
|
+
* >
|
|
3073
|
+
* <input type="email" id="email" {...register('email')} />
|
|
3074
|
+
* </FormFieldARIA>
|
|
3075
|
+
* ```
|
|
3076
|
+
*
|
|
3077
|
+
* @example With textarea
|
|
3078
|
+
* ```tsx
|
|
3079
|
+
* <FormFieldARIA name="message" label="Message" required>
|
|
3080
|
+
* <textarea id="message" {...register('message')} />
|
|
3081
|
+
* </FormFieldARIA>
|
|
3082
|
+
* ```
|
|
3083
|
+
*
|
|
3084
|
+
* @example With custom component
|
|
3085
|
+
* ```tsx
|
|
3086
|
+
* <FormFieldARIA name="country" label="Country" error={errors.country}>
|
|
3087
|
+
* <Select id="country" options={countries} {...field} />
|
|
3088
|
+
* </FormFieldARIA>
|
|
3089
|
+
* ```
|
|
3090
|
+
*/
|
|
3091
|
+
declare function FormFieldARIA({ label, name, error, hint, required, disabled, children, className, }: FormFieldARIAProps): react_jsx_runtime.JSX.Element;
|
|
3092
|
+
|
|
3093
|
+
interface CheckboxGroupARIAOption {
|
|
3094
|
+
value: string;
|
|
3095
|
+
label: LocalizedString$1 | string;
|
|
3096
|
+
description?: LocalizedString$1 | string;
|
|
3097
|
+
disabled?: boolean;
|
|
3098
|
+
}
|
|
3099
|
+
interface CheckboxGroupARIAProps {
|
|
3100
|
+
/** Field name (for form integration) */
|
|
3101
|
+
name: string;
|
|
3102
|
+
/** Group label */
|
|
3103
|
+
label: LocalizedString$1 | string;
|
|
3104
|
+
/** Current locale for localized labels */
|
|
3105
|
+
locale?: string;
|
|
3106
|
+
/** Array of checkbox options */
|
|
3107
|
+
options: CheckboxGroupARIAOption[];
|
|
3108
|
+
/** Selected values */
|
|
3109
|
+
value?: string[];
|
|
3110
|
+
/** Callback when selection changes */
|
|
3111
|
+
onChange?: (value: string[]) => void;
|
|
3112
|
+
/** Error message */
|
|
3113
|
+
error?: string;
|
|
3114
|
+
/** Whether group is required */
|
|
3115
|
+
required?: boolean;
|
|
3116
|
+
/** Disabled state for entire group */
|
|
3117
|
+
disabled?: boolean;
|
|
3118
|
+
/** Display layout */
|
|
3119
|
+
layout?: 'vertical' | 'horizontal' | 'grid';
|
|
3120
|
+
/** Grid columns (only for grid layout) */
|
|
3121
|
+
columns?: 2 | 3 | 4;
|
|
3122
|
+
/** Additional CSS classes */
|
|
3123
|
+
className?: string;
|
|
3124
|
+
}
|
|
3125
|
+
/**
|
|
3126
|
+
* CheckboxGroupARIA - ARIA-enhanced checkbox group
|
|
3127
|
+
*
|
|
3128
|
+
* Provides comprehensive accessibility for checkbox groups including:
|
|
3129
|
+
* - Proper fieldset/legend structure
|
|
3130
|
+
* - role="group" with aria-labelledby
|
|
3131
|
+
* - aria-required for required groups
|
|
3132
|
+
* - aria-invalid for error states
|
|
3133
|
+
* - aria-describedby linking to errors
|
|
3134
|
+
* - Individual checkbox ARIA support
|
|
3135
|
+
* - Screen reader announcements
|
|
3136
|
+
*
|
|
3137
|
+
* @example Basic usage
|
|
3138
|
+
* ```tsx
|
|
3139
|
+
* <CheckboxGroupARIA
|
|
3140
|
+
* name="features"
|
|
3141
|
+
* label="Select Features"
|
|
3142
|
+
* options={[
|
|
3143
|
+
* { value: 'analytics', label: 'Analytics' },
|
|
3144
|
+
* { value: 'reporting', label: 'Reporting' },
|
|
3145
|
+
* { value: 'api', label: 'API Access' }
|
|
3146
|
+
* ]}
|
|
3147
|
+
* value={selectedFeatures}
|
|
3148
|
+
* onChange={setSelectedFeatures}
|
|
3149
|
+
* />
|
|
3150
|
+
* ```
|
|
3151
|
+
*
|
|
3152
|
+
* @example With error and required
|
|
3153
|
+
* ```tsx
|
|
3154
|
+
* <CheckboxGroupARIA
|
|
3155
|
+
* name="features"
|
|
3156
|
+
* label="Select Features"
|
|
3157
|
+
* options={options}
|
|
3158
|
+
* value={selected}
|
|
3159
|
+
* onChange={setSelected}
|
|
3160
|
+
* required
|
|
3161
|
+
* error="Please select at least one feature"
|
|
3162
|
+
* />
|
|
3163
|
+
* ```
|
|
3164
|
+
*
|
|
3165
|
+
* @example With localization
|
|
3166
|
+
* ```tsx
|
|
3167
|
+
* <CheckboxGroupARIA
|
|
3168
|
+
* name="features"
|
|
3169
|
+
* label={{ en: 'Select Features', fr: 'Sélectionner les fonctionnalités' }}
|
|
3170
|
+
* locale="fr"
|
|
3171
|
+
* options={[
|
|
3172
|
+
* { value: 'analytics', label: { en: 'Analytics', fr: 'Analytique' } }
|
|
3173
|
+
* ]}
|
|
3174
|
+
* />
|
|
3175
|
+
* ```
|
|
3176
|
+
*/
|
|
3177
|
+
declare function CheckboxGroupARIA({ name, label, locale, options, value, onChange, error, required, disabled, layout, columns, className, }: CheckboxGroupARIAProps): react_jsx_runtime.JSX.Element;
|
|
3178
|
+
|
|
3179
|
+
interface RadioGroupARIAOption {
|
|
3180
|
+
value: string;
|
|
3181
|
+
label: LocalizedString$1 | string;
|
|
3182
|
+
description?: LocalizedString$1 | string;
|
|
3183
|
+
disabled?: boolean;
|
|
3184
|
+
}
|
|
3185
|
+
interface RadioGroupARIAProps {
|
|
3186
|
+
/** Field name (for form integration) */
|
|
3187
|
+
name: string;
|
|
3188
|
+
/** Group label */
|
|
3189
|
+
label: LocalizedString$1 | string;
|
|
3190
|
+
/** Current locale for localized labels */
|
|
3191
|
+
locale?: string;
|
|
3192
|
+
/** Array of radio options */
|
|
3193
|
+
options: RadioGroupARIAOption[];
|
|
3194
|
+
/** Selected value */
|
|
3195
|
+
value?: string;
|
|
3196
|
+
/** Callback when selection changes */
|
|
3197
|
+
onChange?: (value: string) => void;
|
|
3198
|
+
/** Error message */
|
|
3199
|
+
error?: string;
|
|
3200
|
+
/** Whether group is required */
|
|
3201
|
+
required?: boolean;
|
|
3202
|
+
/** Disabled state for entire group */
|
|
3203
|
+
disabled?: boolean;
|
|
3204
|
+
/** Display layout */
|
|
3205
|
+
layout?: 'vertical' | 'horizontal' | 'grid';
|
|
3206
|
+
/** Grid columns (only for grid layout) */
|
|
3207
|
+
columns?: 2 | 3 | 4;
|
|
3208
|
+
/** Additional CSS classes */
|
|
3209
|
+
className?: string;
|
|
3210
|
+
}
|
|
3211
|
+
/**
|
|
3212
|
+
* RadioGroupARIA - ARIA-enhanced radio button group
|
|
3213
|
+
*
|
|
3214
|
+
* Provides comprehensive accessibility for radio groups including:
|
|
3215
|
+
* - Proper fieldset/legend structure
|
|
3216
|
+
* - role="radiogroup" with aria-labelledby
|
|
3217
|
+
* - aria-required for required groups
|
|
3218
|
+
* - aria-invalid for error states
|
|
3219
|
+
* - aria-describedby linking to errors
|
|
3220
|
+
* - Individual radio ARIA support
|
|
3221
|
+
* - Screen reader announcements
|
|
3222
|
+
*
|
|
3223
|
+
* @example Basic usage
|
|
3224
|
+
* ```tsx
|
|
3225
|
+
* <RadioGroupARIA
|
|
3226
|
+
* name="plan"
|
|
3227
|
+
* label="Choose Plan"
|
|
3228
|
+
* options={[
|
|
3229
|
+
* { value: 'basic', label: 'Basic Plan' },
|
|
3230
|
+
* { value: 'pro', label: 'Pro Plan' },
|
|
3231
|
+
* { value: 'enterprise', label: 'Enterprise Plan' }
|
|
3232
|
+
* ]}
|
|
3233
|
+
* value={selectedPlan}
|
|
3234
|
+
* onChange={setSelectedPlan}
|
|
3235
|
+
* />
|
|
3236
|
+
* ```
|
|
3237
|
+
*
|
|
3238
|
+
* @example With error and required
|
|
3239
|
+
* ```tsx
|
|
3240
|
+
* <RadioGroupARIA
|
|
3241
|
+
* name="plan"
|
|
3242
|
+
* label="Choose Plan"
|
|
3243
|
+
* options={options}
|
|
3244
|
+
* value={selected}
|
|
3245
|
+
* onChange={setSelected}
|
|
3246
|
+
* required
|
|
3247
|
+
* error="Please select a plan"
|
|
3248
|
+
* />
|
|
3249
|
+
* ```
|
|
3250
|
+
*
|
|
3251
|
+
* @example With localization
|
|
3252
|
+
* ```tsx
|
|
3253
|
+
* <RadioGroupARIA
|
|
3254
|
+
* name="plan"
|
|
3255
|
+
* label={{ en: 'Choose Plan', fr: 'Choisir le plan' }}
|
|
3256
|
+
* locale="fr"
|
|
3257
|
+
* options={[
|
|
3258
|
+
* { value: 'basic', label: { en: 'Basic Plan', fr: 'Plan Basique' } }
|
|
3259
|
+
* ]}
|
|
3260
|
+
* />
|
|
3261
|
+
* ```
|
|
3262
|
+
*/
|
|
3263
|
+
declare function RadioGroupARIA({ name, label, locale, options, value, onChange, error, required, disabled, layout, columns, className, }: RadioGroupARIAProps): react_jsx_runtime.JSX.Element;
|
|
3264
|
+
|
|
3265
|
+
interface I18nMetaTagsProps {
|
|
3266
|
+
/** Current locale */
|
|
3267
|
+
currentLocale: string;
|
|
3268
|
+
/** Current pathname (without locale prefix) */
|
|
3269
|
+
pathname: string;
|
|
3270
|
+
/** Base URL of the site (e.g., 'https://example.com') */
|
|
3271
|
+
baseUrl: string;
|
|
3272
|
+
}
|
|
3273
|
+
/**
|
|
3274
|
+
* I18nMetaTags - Generate SEO-critical meta tags for multi-language sites
|
|
3275
|
+
*
|
|
3276
|
+
* Generates:
|
|
3277
|
+
* - hreflang tags for all supported locales
|
|
3278
|
+
* - x-default tag for language selection
|
|
3279
|
+
* - Canonical URL for current page
|
|
3280
|
+
* - OpenGraph locale and alternate tags
|
|
3281
|
+
*
|
|
3282
|
+
* @example
|
|
3283
|
+
* ```tsx
|
|
3284
|
+
* // In layout.tsx or page.tsx
|
|
3285
|
+
* import { I18nMetaTags } from 'simple-site-framework';
|
|
3286
|
+
*
|
|
3287
|
+
* export default function Layout({ children, params }) {
|
|
3288
|
+
* return (
|
|
3289
|
+
* <html>
|
|
3290
|
+
* <head>
|
|
3291
|
+
* <I18nMetaTags
|
|
3292
|
+
* currentLocale={params.locale}
|
|
3293
|
+
* pathname="/about"
|
|
3294
|
+
* baseUrl="https://example.com"
|
|
3295
|
+
* />
|
|
3296
|
+
* </head>
|
|
3297
|
+
* <body>{children}</body>
|
|
3298
|
+
* </html>
|
|
3299
|
+
* );
|
|
3300
|
+
* }
|
|
3301
|
+
* ```
|
|
3302
|
+
*
|
|
3303
|
+
* @see https://developers.google.com/search/docs/specialty/international/localized-versions
|
|
3304
|
+
* @see https://ogp.me/#optional
|
|
3305
|
+
*/
|
|
3306
|
+
declare function I18nMetaTags({ currentLocale, pathname, baseUrl }: I18nMetaTagsProps): react_jsx_runtime.JSX.Element;
|
|
3307
|
+
|
|
3308
|
+
/**
|
|
3309
|
+
* Open Graph metadata for social sharing
|
|
3310
|
+
* @see https://ogp.me/
|
|
3311
|
+
*/
|
|
3312
|
+
interface OpenGraphMetadata {
|
|
3313
|
+
/** Page title for social sharing */
|
|
3314
|
+
title?: string;
|
|
3315
|
+
/** Page description for social sharing */
|
|
3316
|
+
description?: string;
|
|
3317
|
+
/** Absolute URL to preview image (min 1200x630px recommended) */
|
|
3318
|
+
image?: string;
|
|
3319
|
+
/** Image alt text for accessibility */
|
|
3320
|
+
imageAlt?: string;
|
|
3321
|
+
/** Page type (website, article, product, etc.) */
|
|
3322
|
+
type?: 'website' | 'article' | 'product' | 'profile' | string;
|
|
3323
|
+
/** Canonical URL of the page */
|
|
3324
|
+
url?: string;
|
|
3325
|
+
/** Site name */
|
|
3326
|
+
siteName?: string;
|
|
3327
|
+
/** Locale (e.g., en_US, fr_FR) */
|
|
3328
|
+
locale?: string;
|
|
3329
|
+
/** Alternate locales */
|
|
3330
|
+
alternateLocales?: string[];
|
|
3331
|
+
/** Article-specific: publication date (ISO 8601) */
|
|
3332
|
+
publishedTime?: string;
|
|
3333
|
+
/** Article-specific: modified date (ISO 8601) */
|
|
3334
|
+
modifiedTime?: string;
|
|
3335
|
+
/** Article-specific: author profile URLs */
|
|
3336
|
+
authors?: string[];
|
|
3337
|
+
/** Article-specific: section/category */
|
|
3338
|
+
section?: string;
|
|
3339
|
+
/** Article-specific: tags */
|
|
3340
|
+
tags?: string[];
|
|
3341
|
+
}
|
|
3342
|
+
/**
|
|
3343
|
+
* Twitter Card metadata for Twitter sharing
|
|
3344
|
+
* @see https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards
|
|
3345
|
+
*/
|
|
3346
|
+
interface TwitterMetadata {
|
|
3347
|
+
/** Card type */
|
|
3348
|
+
card?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
3349
|
+
/** Twitter handle of the site (with @) */
|
|
3350
|
+
site?: string;
|
|
3351
|
+
/** Twitter handle of the content creator (with @) */
|
|
3352
|
+
creator?: string;
|
|
3353
|
+
/** Page title for Twitter */
|
|
3354
|
+
title?: string;
|
|
3355
|
+
/** Page description for Twitter */
|
|
3356
|
+
description?: string;
|
|
3357
|
+
/** Absolute URL to preview image */
|
|
3358
|
+
image?: string;
|
|
3359
|
+
/** Image alt text */
|
|
3360
|
+
imageAlt?: string;
|
|
3361
|
+
}
|
|
3362
|
+
/**
|
|
3363
|
+
* Props for SEOMetaTags component
|
|
3364
|
+
*/
|
|
3365
|
+
interface SEOMetaTagsProps {
|
|
3366
|
+
/** Page title (used in <title> tag and as fallback for OG/Twitter) */
|
|
3367
|
+
title: string;
|
|
3368
|
+
/** Page description (used in meta description and as fallback for OG/Twitter) */
|
|
3369
|
+
description: string;
|
|
3370
|
+
/** Keywords for meta keywords tag (optional, less important for modern SEO) */
|
|
3371
|
+
keywords?: string[];
|
|
3372
|
+
/** Canonical URL (absolute URL to prevent duplicate content issues) */
|
|
3373
|
+
canonical?: string;
|
|
3374
|
+
/** Prevent search engines from indexing this page */
|
|
3375
|
+
noIndex?: boolean;
|
|
3376
|
+
/** Prevent search engines from following links on this page */
|
|
3377
|
+
noFollow?: boolean;
|
|
3378
|
+
/** Open Graph metadata for social sharing */
|
|
3379
|
+
openGraph?: OpenGraphMetadata;
|
|
3380
|
+
/** Twitter Card metadata */
|
|
3381
|
+
twitter?: TwitterMetadata;
|
|
3382
|
+
/** Additional custom meta tags */
|
|
3383
|
+
additionalMetaTags?: Array<{
|
|
3384
|
+
name?: string;
|
|
3385
|
+
property?: string;
|
|
3386
|
+
content: string;
|
|
3387
|
+
}>;
|
|
3388
|
+
/** Additional link tags */
|
|
3389
|
+
additionalLinkTags?: Array<{
|
|
3390
|
+
rel: string;
|
|
3391
|
+
href: string;
|
|
3392
|
+
[key: string]: string;
|
|
3393
|
+
}>;
|
|
3394
|
+
}
|
|
3395
|
+
/**
|
|
3396
|
+
* SEO metadata component for page-level optimization.
|
|
3397
|
+
*
|
|
3398
|
+
* Generates essential meta tags for search engines and social media platforms:
|
|
3399
|
+
* - Title and description
|
|
3400
|
+
* - Open Graph tags (Facebook, LinkedIn)
|
|
3401
|
+
* - Twitter Cards
|
|
3402
|
+
* - Canonical URLs
|
|
3403
|
+
* - Robots directives
|
|
3404
|
+
*
|
|
3405
|
+
* @example
|
|
3406
|
+
* ```tsx
|
|
3407
|
+
* import { SEOMetaTags } from 'simple-site-framework/components';
|
|
3408
|
+
*
|
|
3409
|
+
* export default function Page() {
|
|
3410
|
+
* return (
|
|
3411
|
+
* <>
|
|
3412
|
+
* <SEOMetaTags
|
|
3413
|
+
* title="Best Email Marketing Platform | Acme"
|
|
3414
|
+
* description="Send beautiful email campaigns that convert. Start free today."
|
|
3415
|
+
* canonical="https://example.com/features"
|
|
3416
|
+
* openGraph={{
|
|
3417
|
+
* image: 'https://example.com/og-image.jpg',
|
|
3418
|
+
* type: 'website',
|
|
3419
|
+
* siteName: 'Acme'
|
|
3420
|
+
* }}
|
|
3421
|
+
* twitter={{
|
|
3422
|
+
* card: 'summary_large_image',
|
|
3423
|
+
* site: '@acme'
|
|
3424
|
+
* }}
|
|
3425
|
+
* />
|
|
3426
|
+
* <main>...</main>
|
|
3427
|
+
* </>
|
|
3428
|
+
* );
|
|
3429
|
+
* }
|
|
3430
|
+
* ```
|
|
3431
|
+
*/
|
|
3432
|
+
declare function SEOMetaTags({ title, description, keywords, canonical, noIndex, noFollow, openGraph, twitter, additionalMetaTags, additionalLinkTags, }: SEOMetaTagsProps): ReactElement;
|
|
3433
|
+
|
|
3434
|
+
/**
|
|
3435
|
+
* Base schema.org Thing type
|
|
3436
|
+
* @see https://schema.org/Thing
|
|
3437
|
+
*/
|
|
3438
|
+
interface Thing {
|
|
3439
|
+
'@type': string;
|
|
3440
|
+
'@id'?: string;
|
|
3441
|
+
name?: string;
|
|
3442
|
+
description?: string;
|
|
3443
|
+
image?: string | string[];
|
|
3444
|
+
url?: string;
|
|
3445
|
+
[key: string]: unknown;
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3448
|
+
interface StructuredDataProps {
|
|
3449
|
+
/** Structured data object or array of objects */
|
|
3450
|
+
data: Thing | Thing[];
|
|
3451
|
+
}
|
|
3452
|
+
/**
|
|
3453
|
+
* Renders JSON-LD structured data in a script tag.
|
|
3454
|
+
*
|
|
3455
|
+
* Use this component to add schema.org markup to your pages for better SEO
|
|
3456
|
+
* and rich search results (rich snippets, knowledge panels, etc.).
|
|
3457
|
+
*
|
|
3458
|
+
* @example Basic usage with Organization
|
|
3459
|
+
* ```tsx
|
|
3460
|
+
* import { StructuredData } from 'simple-site-framework/components';
|
|
3461
|
+
* import { createOrganization } from 'simple-site-framework/lib/seo/structured-data';
|
|
3462
|
+
*
|
|
3463
|
+
* const orgData = createOrganization({
|
|
3464
|
+
* name: 'Acme Inc',
|
|
3465
|
+
* url: 'https://acme.com',
|
|
3466
|
+
* logo: 'https://acme.com/logo.png',
|
|
3467
|
+
* sameAs: ['https://twitter.com/acme']
|
|
3468
|
+
* });
|
|
3469
|
+
*
|
|
3470
|
+
* export default function Layout() {
|
|
3471
|
+
* return (
|
|
3472
|
+
* <>
|
|
3473
|
+
* <StructuredData data={orgData} />
|
|
3474
|
+
* <main>...</main>
|
|
3475
|
+
* </>
|
|
3476
|
+
* );
|
|
3477
|
+
* }
|
|
3478
|
+
* ```
|
|
3479
|
+
*
|
|
3480
|
+
* @example Multiple structured data objects
|
|
3481
|
+
* ```tsx
|
|
3482
|
+
* import { StructuredData } from 'simple-site-framework/components';
|
|
3483
|
+
* import {
|
|
3484
|
+
* createOrganization,
|
|
3485
|
+
* createWebSite,
|
|
3486
|
+
* createBreadcrumbList
|
|
3487
|
+
* } from 'simple-site-framework/lib/seo/structured-data';
|
|
3488
|
+
*
|
|
3489
|
+
* const organization = createOrganization({ name: 'Acme' });
|
|
3490
|
+
* const website = createWebSite({
|
|
3491
|
+
* name: 'Acme',
|
|
3492
|
+
* url: 'https://acme.com',
|
|
3493
|
+
* searchUrlTemplate: 'https://acme.com/search?q={search_term_string}'
|
|
3494
|
+
* });
|
|
3495
|
+
* const breadcrumbs = createBreadcrumbList([
|
|
3496
|
+
* { name: 'Home', url: 'https://acme.com' },
|
|
3497
|
+
* { name: 'Products', url: 'https://acme.com/products' }
|
|
3498
|
+
* ]);
|
|
3499
|
+
*
|
|
3500
|
+
* export default function Page() {
|
|
3501
|
+
* return (
|
|
3502
|
+
* <>
|
|
3503
|
+
* <StructuredData data={[organization, website, breadcrumbs]} />
|
|
3504
|
+
* <main>...</main>
|
|
3505
|
+
* </>
|
|
3506
|
+
* );
|
|
3507
|
+
* }
|
|
3508
|
+
* ```
|
|
3509
|
+
*
|
|
3510
|
+
* @example FAQ Page
|
|
3511
|
+
* ```tsx
|
|
3512
|
+
* import { StructuredData } from 'simple-site-framework/components';
|
|
3513
|
+
* import { createFAQPage } from 'simple-site-framework/lib/seo/structured-data';
|
|
3514
|
+
*
|
|
3515
|
+
* const faqData = createFAQPage([
|
|
3516
|
+
* {
|
|
3517
|
+
* question: 'What is your refund policy?',
|
|
3518
|
+
* answer: 'We offer a 30-day money-back guarantee on all plans.'
|
|
3519
|
+
* },
|
|
3520
|
+
* {
|
|
3521
|
+
* question: 'Do you offer customer support?',
|
|
3522
|
+
* answer: 'Yes, we provide 24/7 email and chat support to all customers.'
|
|
3523
|
+
* }
|
|
3524
|
+
* ]);
|
|
3525
|
+
*
|
|
3526
|
+
* export default function FAQPage() {
|
|
3527
|
+
* return (
|
|
3528
|
+
* <>
|
|
3529
|
+
* <StructuredData data={faqData} />
|
|
3530
|
+
* <main>...</main>
|
|
3531
|
+
* </>
|
|
3532
|
+
* );
|
|
3533
|
+
* }
|
|
3534
|
+
* ```
|
|
3535
|
+
*/
|
|
3536
|
+
declare function StructuredData({ data }: StructuredDataProps): ReactElement;
|
|
3537
|
+
|
|
3538
|
+
interface PolicyLayoutProps {
|
|
3539
|
+
/** Policy title */
|
|
3540
|
+
title: string;
|
|
3541
|
+
/** Last updated date (ISO string or formatted) */
|
|
3542
|
+
lastUpdated: string;
|
|
3543
|
+
/** Current locale for date formatting */
|
|
3544
|
+
locale: string;
|
|
3545
|
+
/** Policy content (from MDX) */
|
|
3546
|
+
children: ReactNode;
|
|
3547
|
+
/** Show table of contents sidebar @default true */
|
|
3548
|
+
showToc?: boolean;
|
|
3549
|
+
/** Additional CSS classes */
|
|
3550
|
+
className?: string;
|
|
3551
|
+
/** Optional contact link text */
|
|
3552
|
+
contactText?: string;
|
|
3553
|
+
/** Optional contact link href */
|
|
3554
|
+
contactHref?: string;
|
|
3555
|
+
}
|
|
3556
|
+
/**
|
|
3557
|
+
* PolicyLayout - Layout component for policy and legal document pages
|
|
3558
|
+
*
|
|
3559
|
+
* Designed for rendering markdown/MDX content with proper structure,
|
|
3560
|
+
* typography, table of contents, and SEO.
|
|
3561
|
+
*
|
|
3562
|
+
* @example
|
|
3563
|
+
* ```tsx
|
|
3564
|
+
* import { loadPolicy } from '@/lib/content/policies';
|
|
3565
|
+
* import { PolicyLayout } from 'simple-site-framework';
|
|
3566
|
+
*
|
|
3567
|
+
* export default async function PrivacyPage({ params }) {
|
|
3568
|
+
* const { content, metadata } = await loadPolicy('privacy-policy', params.locale);
|
|
3569
|
+
*
|
|
3570
|
+
* return (
|
|
3571
|
+
* <PolicyLayout
|
|
3572
|
+
* title={metadata.title}
|
|
3573
|
+
* lastUpdated={metadata.lastUpdated}
|
|
3574
|
+
* locale={params.locale}
|
|
3575
|
+
* >
|
|
3576
|
+
* {content}
|
|
3577
|
+
* </PolicyLayout>
|
|
3578
|
+
* );
|
|
3579
|
+
* }
|
|
3580
|
+
* ```
|
|
3581
|
+
*
|
|
3582
|
+
* @see docs/POLICY-PAGES.md for complete usage guide
|
|
3583
|
+
*/
|
|
3584
|
+
declare function PolicyLayout({ title, lastUpdated, locale, children, showToc, className, contactText, contactHref, }: PolicyLayoutProps): react_jsx_runtime.JSX.Element;
|
|
3585
|
+
|
|
3586
|
+
interface Heading {
|
|
3587
|
+
id: string;
|
|
3588
|
+
text: string;
|
|
3589
|
+
level: number;
|
|
3590
|
+
}
|
|
3591
|
+
interface TableOfContentsProps {
|
|
3592
|
+
/** CSS selector for content container @default 'article' */
|
|
3593
|
+
containerSelector?: string;
|
|
3594
|
+
/** Heading levels to include @default [2, 3] */
|
|
3595
|
+
includeLevels?: number[];
|
|
3596
|
+
/** Additional CSS classes */
|
|
3597
|
+
className?: string;
|
|
3598
|
+
/** Title for TOC @default 'Table of Contents' */
|
|
3599
|
+
title?: string;
|
|
3600
|
+
}
|
|
3601
|
+
/**
|
|
3602
|
+
* TableOfContents - Auto-generated navigation for long-form content
|
|
3603
|
+
*
|
|
3604
|
+
* Automatically extracts headings from the page, generates a navigation menu,
|
|
3605
|
+
* and highlights the currently visible section.
|
|
3606
|
+
*
|
|
3607
|
+
* @example
|
|
3608
|
+
* ```tsx
|
|
3609
|
+
* <aside className="sticky top-24">
|
|
3610
|
+
* <TableOfContents />
|
|
3611
|
+
* </aside>
|
|
3612
|
+
* ```
|
|
3613
|
+
*
|
|
3614
|
+
* @example
|
|
3615
|
+
* ```tsx
|
|
3616
|
+
* // Custom configuration
|
|
3617
|
+
* <TableOfContents
|
|
3618
|
+
* title="On This Page"
|
|
3619
|
+
* includeLevels={[2, 3, 4]}
|
|
3620
|
+
* containerSelector="main"
|
|
3621
|
+
* />
|
|
3622
|
+
* ```
|
|
3623
|
+
*/
|
|
3624
|
+
declare function TableOfContents({ containerSelector, includeLevels, className, title, }: TableOfContentsProps): react_jsx_runtime.JSX.Element | null;
|
|
3625
|
+
|
|
3626
|
+
/**
|
|
3627
|
+
* Position of the notification on screen
|
|
3628
|
+
*/
|
|
3629
|
+
type NotificationPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'top-center' | 'bottom-center';
|
|
3630
|
+
/**
|
|
3631
|
+
* Individual notification data
|
|
3632
|
+
*/
|
|
3633
|
+
interface LiveProofNotification {
|
|
3634
|
+
/** Unique identifier */
|
|
3635
|
+
id: string;
|
|
3636
|
+
/** User/customer name */
|
|
3637
|
+
name?: string;
|
|
3638
|
+
/** User location (city, country) */
|
|
3639
|
+
location?: string;
|
|
3640
|
+
/** Action performed (e.g., "signed up", "made a purchase") */
|
|
3641
|
+
action: LocalizedString$1 | string;
|
|
3642
|
+
/** Time ago (e.g., "2 minutes ago") */
|
|
3643
|
+
timeAgo?: LocalizedString$1 | string;
|
|
3644
|
+
/** Optional avatar URL */
|
|
3645
|
+
avatar?: string;
|
|
3646
|
+
/** Optional icon (lucide-react name) */
|
|
3647
|
+
icon?: string;
|
|
3648
|
+
/** Custom message (overrides name/location/action format) */
|
|
3649
|
+
message?: LocalizedString$1 | string;
|
|
3650
|
+
/** Link URL when clicked */
|
|
3651
|
+
link?: string;
|
|
3652
|
+
/** Custom data for tracking */
|
|
3653
|
+
data?: Record<string, unknown>;
|
|
3654
|
+
}
|
|
3655
|
+
interface LiveProofProps {
|
|
3656
|
+
/** Array of notifications to display */
|
|
3657
|
+
notifications: LiveProofNotification[];
|
|
3658
|
+
/** Position on screen */
|
|
3659
|
+
position?: NotificationPosition;
|
|
3660
|
+
/** Auto-dismiss duration in milliseconds (0 = never) */
|
|
3661
|
+
autoHideDuration?: number;
|
|
3662
|
+
/** Maximum number of visible notifications */
|
|
3663
|
+
maxVisible?: number;
|
|
3664
|
+
/** Delay between showing notifications in milliseconds */
|
|
3665
|
+
showDelay?: number;
|
|
3666
|
+
/** Enable click to dismiss */
|
|
3667
|
+
clickToDismiss?: boolean;
|
|
3668
|
+
/** Custom close button */
|
|
3669
|
+
showCloseButton?: boolean;
|
|
3670
|
+
/** Current locale for i18n */
|
|
3671
|
+
locale?: string;
|
|
3672
|
+
/** Additional CSS classes */
|
|
3673
|
+
className?: string;
|
|
3674
|
+
/** Callback when notification is clicked */
|
|
3675
|
+
onNotificationClick?: (notification: LiveProofNotification) => void;
|
|
3676
|
+
/** Callback when notification is dismissed */
|
|
3677
|
+
onNotificationDismiss?: (notification: LiveProofNotification) => void;
|
|
3678
|
+
}
|
|
3679
|
+
/**
|
|
3680
|
+
* LiveProof Notification System
|
|
3681
|
+
*
|
|
3682
|
+
* Displays real-time social proof notifications to build trust and create urgency.
|
|
3683
|
+
* Shows messages like "John from NYC just signed up" to demonstrate activity.
|
|
3684
|
+
*
|
|
3685
|
+
* @example Basic usage
|
|
3686
|
+
* ```tsx
|
|
3687
|
+
* const notifications = [
|
|
3688
|
+
* {
|
|
3689
|
+
* id: '1',
|
|
3690
|
+
* name: 'John D.',
|
|
3691
|
+
* location: 'New York, NY',
|
|
3692
|
+
* action: 'signed up for a trial',
|
|
3693
|
+
* timeAgo: '2 minutes ago'
|
|
3694
|
+
* },
|
|
3695
|
+
* {
|
|
3696
|
+
* id: '2',
|
|
3697
|
+
* name: 'Sarah M.',
|
|
3698
|
+
* location: 'San Francisco, CA',
|
|
3699
|
+
* action: 'upgraded to Premium',
|
|
3700
|
+
* timeAgo: '5 minutes ago'
|
|
3701
|
+
* }
|
|
3702
|
+
* ];
|
|
3703
|
+
*
|
|
3704
|
+
* <LiveProof notifications={notifications} />
|
|
3705
|
+
* ```
|
|
3706
|
+
*
|
|
3707
|
+
* @example Custom message
|
|
3708
|
+
* ```tsx
|
|
3709
|
+
* <LiveProof
|
|
3710
|
+
* notifications={[
|
|
3711
|
+
* {
|
|
3712
|
+
* id: '1',
|
|
3713
|
+
* message: '🎉 127 people signed up today!',
|
|
3714
|
+
* icon: 'TrendingUp'
|
|
3715
|
+
* }
|
|
3716
|
+
* ]}
|
|
3717
|
+
* position="bottom-left"
|
|
3718
|
+
* autoHideDuration={5000}
|
|
3719
|
+
* />
|
|
3720
|
+
* ```
|
|
3721
|
+
*
|
|
3722
|
+
* @example With avatar and link
|
|
3723
|
+
* ```tsx
|
|
3724
|
+
* <LiveProof
|
|
3725
|
+
* notifications={[
|
|
3726
|
+
* {
|
|
3727
|
+
* id: '1',
|
|
3728
|
+
* name: 'Alex Chen',
|
|
3729
|
+
* action: 'left a 5-star review',
|
|
3730
|
+
* avatar: '/avatars/alex.jpg',
|
|
3731
|
+
* link: '/reviews',
|
|
3732
|
+
* timeAgo: 'Just now'
|
|
3733
|
+
* }
|
|
3734
|
+
* ]}
|
|
3735
|
+
* />
|
|
3736
|
+
* ```
|
|
3737
|
+
*/
|
|
3738
|
+
declare function LiveProof({ notifications, position, autoHideDuration, maxVisible, showDelay, clickToDismiss, showCloseButton, locale, className, onNotificationClick, onNotificationDismiss, }: LiveProofProps): react_jsx_runtime.JSX.Element | null;
|
|
3739
|
+
/**
|
|
3740
|
+
* Generate mock notifications for demo/testing
|
|
3741
|
+
*
|
|
3742
|
+
* @param count - Number of notifications to generate
|
|
3743
|
+
* @param locale - Locale for localized strings
|
|
3744
|
+
* @returns Array of mock notifications
|
|
3745
|
+
*
|
|
3746
|
+
* @example
|
|
3747
|
+
* ```tsx
|
|
3748
|
+
* const mockData = generateMockNotifications(5);
|
|
3749
|
+
* <LiveProof notifications={mockData} />
|
|
3750
|
+
* ```
|
|
3751
|
+
*/
|
|
3752
|
+
declare function generateMockNotifications(count?: number, locale?: string): LiveProofNotification[];
|
|
3753
|
+
|
|
3754
|
+
interface MobileCTAProps {
|
|
3755
|
+
/** Localized CTA text */
|
|
3756
|
+
text: LocalizedString$1 | string;
|
|
3757
|
+
/** CTA destination URL */
|
|
3758
|
+
href: string;
|
|
3759
|
+
/** Current locale */
|
|
3760
|
+
locale: string;
|
|
3761
|
+
/** Scroll distance in pixels before showing (default: 300) */
|
|
3762
|
+
threshold?: number;
|
|
3763
|
+
/** Breakpoint to hide on larger screens (default: 'lg') */
|
|
3764
|
+
hideAbove?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
3765
|
+
/** Optional click handler (for tracking) */
|
|
3766
|
+
onClick?: () => void;
|
|
3767
|
+
/** Additional CSS classes */
|
|
3768
|
+
className?: string;
|
|
3769
|
+
/** Z-index value (default: 50) */
|
|
3770
|
+
zIndex?: number;
|
|
3771
|
+
}
|
|
3772
|
+
/**
|
|
3773
|
+
* MobileCTA - Mobile-only sticky CTA button
|
|
3774
|
+
*
|
|
3775
|
+
* A scroll-triggered CTA button that appears at the bottom of the screen
|
|
3776
|
+
* after the user scrolls past a threshold. Improves mobile conversion rates
|
|
3777
|
+
* by keeping primary CTAs accessible without cluttering the viewport.
|
|
3778
|
+
*
|
|
3779
|
+
* Features:
|
|
3780
|
+
* - Scroll-triggered visibility (configurable threshold)
|
|
3781
|
+
* - Mobile-only display (hidden on desktop)
|
|
3782
|
+
* - Smooth slide-up animation
|
|
3783
|
+
* - 44px minimum tap target (accessibility)
|
|
3784
|
+
* - Optional click tracking
|
|
3785
|
+
* - Theme integration with className override
|
|
3786
|
+
* - Reduced motion support
|
|
3787
|
+
*
|
|
3788
|
+
* @example Basic usage
|
|
3789
|
+
* ```tsx
|
|
3790
|
+
* <MobileCTA
|
|
3791
|
+
* text="Start Free Trial"
|
|
3792
|
+
* href="https://app.example.com/signup"
|
|
3793
|
+
* locale="en"
|
|
3794
|
+
* />
|
|
3795
|
+
* ```
|
|
3796
|
+
*
|
|
3797
|
+
* @example With localization and tracking
|
|
3798
|
+
* ```tsx
|
|
3799
|
+
* <MobileCTA
|
|
3800
|
+
* text={{
|
|
3801
|
+
* en: 'Start Free Trial - No Card Required',
|
|
3802
|
+
* fr: 'Essai gratuit - Aucune carte requise'
|
|
3803
|
+
* }}
|
|
3804
|
+
* href="https://app.example.com/signup"
|
|
3805
|
+
* locale="en"
|
|
3806
|
+
* threshold={300}
|
|
3807
|
+
* onClick={() => trackEvent('mobile_cta_click')}
|
|
3808
|
+
* />
|
|
3809
|
+
* ```
|
|
3810
|
+
*
|
|
3811
|
+
* @example Custom styling and breakpoint
|
|
3812
|
+
* ```tsx
|
|
3813
|
+
* <MobileCTA
|
|
3814
|
+
* text="Get Started"
|
|
3815
|
+
* href="/signup"
|
|
3816
|
+
* locale="en"
|
|
3817
|
+
* hideAbove="md"
|
|
3818
|
+
* className="bg-gradient-to-r from-blue-500 to-purple-600"
|
|
3819
|
+
* zIndex={100}
|
|
3820
|
+
* />
|
|
3821
|
+
* ```
|
|
3822
|
+
*/
|
|
3823
|
+
declare function MobileCTA({ text, href, locale, threshold, hideAbove, onClick, className, zIndex, }: MobileCTAProps): react_jsx_runtime.JSX.Element;
|
|
3824
|
+
|
|
3825
|
+
interface CTAButtonConfig {
|
|
3826
|
+
/** Localized button text */
|
|
3827
|
+
text: LocalizedString$1 | string;
|
|
3828
|
+
/** Destination URL */
|
|
3829
|
+
href: string;
|
|
3830
|
+
/** Optional click handler (for tracking) */
|
|
3831
|
+
onClick?: () => void;
|
|
3832
|
+
/** Button variant (uses framework Button variants) */
|
|
3833
|
+
variant?: 'outlined' | 'filled' | 'text' | 'ghost' | 'link' | 'destructive';
|
|
3834
|
+
/** Button size */
|
|
3835
|
+
size?: 'sm' | 'md' | 'lg';
|
|
3836
|
+
}
|
|
3837
|
+
interface CTASectionProps {
|
|
3838
|
+
/** Localized heading text */
|
|
3839
|
+
heading: LocalizedString$1 | string;
|
|
3840
|
+
/** Localized description/subheading */
|
|
3841
|
+
description?: LocalizedString$1 | string;
|
|
3842
|
+
/** Primary CTA configuration */
|
|
3843
|
+
primaryCTA: CTAButtonConfig;
|
|
3844
|
+
/** Optional secondary CTA */
|
|
3845
|
+
secondaryCTA?: CTAButtonConfig;
|
|
3846
|
+
/** Current locale */
|
|
3847
|
+
locale: string;
|
|
3848
|
+
/** Layout variant */
|
|
3849
|
+
variant?: 'centered' | 'split' | 'inline';
|
|
3850
|
+
/** Button arrangement */
|
|
3851
|
+
buttonLayout?: 'horizontal' | 'vertical';
|
|
3852
|
+
/** Background color class */
|
|
3853
|
+
backgroundColor?: string;
|
|
3854
|
+
/** Text alignment */
|
|
3855
|
+
align?: 'left' | 'center' | 'right';
|
|
3856
|
+
/** Maximum content width */
|
|
3857
|
+
maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | 'full';
|
|
3858
|
+
/** Additional CSS classes */
|
|
3859
|
+
className?: string;
|
|
3860
|
+
}
|
|
3861
|
+
/**
|
|
3862
|
+
* CTASection - Full-width call-to-action section
|
|
3863
|
+
*
|
|
3864
|
+
* A configurable CTA section component with dual-button layout.
|
|
3865
|
+
* Provides consistent conversion patterns across marketing pages
|
|
3866
|
+
* with support for multiple content variants.
|
|
3867
|
+
*
|
|
3868
|
+
* Features:
|
|
3869
|
+
* - Dual-button layout (primary + optional secondary)
|
|
3870
|
+
* - Multiple layout variants (centered, split, inline)
|
|
3871
|
+
* - Uses framework Button component
|
|
3872
|
+
* - Optional click tracking
|
|
3873
|
+
* - Theme integration with className override
|
|
3874
|
+
* - Responsive button stacking
|
|
3875
|
+
* - Localization support
|
|
3876
|
+
* - Accessibility compliant
|
|
3877
|
+
*
|
|
3878
|
+
* @example Basic usage
|
|
3879
|
+
* ```tsx
|
|
3880
|
+
* <CTASection
|
|
3881
|
+
* heading="Create Your Free Account"
|
|
3882
|
+
* primaryCTA={{
|
|
3883
|
+
* text: 'Sign Up',
|
|
3884
|
+
* href: 'https://app.example.com/signup'
|
|
3885
|
+
* }}
|
|
3886
|
+
* locale="en"
|
|
3887
|
+
* />
|
|
3888
|
+
* ```
|
|
3889
|
+
*
|
|
3890
|
+
* @example With localization and description
|
|
3891
|
+
* ```tsx
|
|
3892
|
+
* <CTASection
|
|
3893
|
+
* heading={{
|
|
3894
|
+
* en: 'Create Your Free Account',
|
|
3895
|
+
* fr: 'Créez votre compte gratuit'
|
|
3896
|
+
* }}
|
|
3897
|
+
* description={{
|
|
3898
|
+
* en: 'No credit card required • Set up in 2 minutes',
|
|
3899
|
+
* fr: 'Aucune carte de crédit requise • Configuration en 2 minutes'
|
|
3900
|
+
* }}
|
|
3901
|
+
* primaryCTA={{
|
|
3902
|
+
* text: { en: 'Create Free Account', fr: 'Créer mon compte' },
|
|
3903
|
+
* href: 'https://app.example.com/signup',
|
|
3904
|
+
* onClick: () => trackCTAClick('signup', 'cta_section')
|
|
3905
|
+
* }}
|
|
3906
|
+
* secondaryCTA={{
|
|
3907
|
+
* text: { en: 'See Pricing', fr: 'Voir les forfaits' },
|
|
3908
|
+
* href: '/pricing'
|
|
3909
|
+
* }}
|
|
3910
|
+
* locale="en"
|
|
3911
|
+
* backgroundColor="bg-warm-gray"
|
|
3912
|
+
* />
|
|
3913
|
+
* ```
|
|
3914
|
+
*
|
|
3915
|
+
* @example Custom layout and styling
|
|
3916
|
+
* ```tsx
|
|
3917
|
+
* <CTASection
|
|
3918
|
+
* heading="Get Started Today"
|
|
3919
|
+
* variant="split"
|
|
3920
|
+
* buttonLayout="vertical"
|
|
3921
|
+
* align="left"
|
|
3922
|
+
* maxWidth="4xl"
|
|
3923
|
+
* className="border-t-4 border-primary"
|
|
3924
|
+
* primaryCTA={{
|
|
3925
|
+
* text: 'Start Free Trial',
|
|
3926
|
+
* href: '/signup',
|
|
3927
|
+
* variant: 'filled',
|
|
3928
|
+
* size: 'lg'
|
|
3929
|
+
* }}
|
|
3930
|
+
* locale="en"
|
|
3931
|
+
* />
|
|
3932
|
+
* ```
|
|
3933
|
+
*/
|
|
3934
|
+
declare function CTASection({ heading, description, primaryCTA, secondaryCTA, locale, variant, buttonLayout, backgroundColor, align, maxWidth, className, }: CTASectionProps): react_jsx_runtime.JSX.Element;
|
|
3935
|
+
|
|
3936
|
+
export { AboutSection, AddressLink, type AddressLinkProps, AnimatedCounter, type AnimatedCounterProps, AnimatedItem, AnimatedSection, type AnimatedSectionProps, type AnimationType, type Badge, type BadgeType, type BillingPeriod, BlogCard, type BlogCardProps, BodyEndScripts, type BodyEndScriptsProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, type CTAButtonConfig, CTASection, type CTASectionProps, Card, type CardProps, CaseStudySection, Checkbox, CheckboxGroup, CheckboxGroupARIA, type CheckboxGroupARIAOption, type CheckboxGroupARIAProps, type CheckboxGroupOption, type CheckboxGroupProps, type CheckboxProps, CodeBlock, type CodeBlockProps, type ComparisonFeature, type ComparisonOption, ComparisonTable, type ComparisonTableProps, ComponentDemo, type ComponentDemoProps, ContactForm, type ContactFormData, type ContactFormField, type ContactFormProps, type ContactFormResponse, ContactSection, CountdownTimer, type CountdownTimerProps, type CustomBadge, EmailLink, type EmailLinkProps, ExitIntentModal, type ExitIntentModalProps, type FAQ, FAQAccordion, type FAQAccordionProps, type Feature, type FeatureCategory, FeatureSection, FeaturesGrid, FileUpload, type FileUploadProps, Footer, type FooterProps, FormField, FormFieldARIA, type FormFieldARIAProps, type FormFieldProps, FormGroup, HeadScripts, type HeadScriptsProps, Header, type HeaderProps, type Heading, HeroSection, I18nMetaTags, type I18nMetaTagsProps, Icon, type IconName, type IconProps, Icons, InlineCode, Input, type InputProps, LanguageSelector, type LanguageSelectorProps, LanguageSwitcher, type LanguageSwitcherProps, LazySection, type LazySectionProps, LiveProof, type LiveProofNotification, type LiveProofProps, LoadingOverlay, type LoadingOverlayProps, LoadingSpinner, type LoadingSpinnerProps, LogosSection, MobileCTA, type MobileCTAProps, Modal, ModalContent, ModalFooter, type ModalProps, ModalRoot, type ModalSize, ModalTrigger, MultiStepForm, type MultiStepFormProps, type NotificationPosition, type OpenGraphMetadata, PersonalTaxesSection, PhoneLink, type PhoneLinkProps, PolicyLayout, type PolicyLayoutProps, type PricingFeature, PricingTable, type PricingTableProps, type PricingTier, Radio, RadioGroup, RadioGroupARIA, type RadioGroupARIAOption, type RadioGroupARIAProps, type RadioGroupOption, type RadioGroupProps, type RadioProps, RecruitingSection, SEOMetaTags, type SEOMetaTagsProps, SecurePortalSection, Select, type SelectOption, type SelectOptionGroup, type SelectProps, ServicePageLayout, ServicesSection, Skeleton, type SkeletonAnimation, SkeletonAvatar, SkeletonButton, SkeletonCard, SkeletonImage, type SkeletonProps, SkeletonText, type SpinnerSize, type SpinnerStyle, type Stat, StatsSection, type StatsSectionProps, type StepProps, StickyBar, type StickyBarProps, StructuredData, type StructuredDataProps, StyleGuide, type StyleGuideProps, type Tab, TableOfContents, type TableOfContentsProps, Tabs, type TabsProps, type Testimonial, TestimonialCarousel, type TestimonialCarouselProps, TestimonialSection, Textarea, type TextareaProps, Timeline, type TimelineItem, type TimelineProps, type Toast, type ToastPosition, ToastProvider, type ToastProviderProps, type ToastType, TrustBadges, type TrustBadgesProps, type TwitterMetadata, WhyChooseUsSection, generateMockNotifications, toast, useMultiStepForm, useToast, withLazyLoad };
|