@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.
Files changed (166) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +572 -0
  3. package/bin/create-simple-site.js +390 -0
  4. package/bin/simple-site.js +664 -0
  5. package/dist/client.js +135 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/client.mjs +107 -0
  8. package/dist/client.mjs.map +1 -0
  9. package/dist/components/index.d.mts +3936 -0
  10. package/dist/components/index.d.ts +3936 -0
  11. package/dist/components/index.js +38265 -0
  12. package/dist/components/index.js.map +1 -0
  13. package/dist/components/index.mjs +38173 -0
  14. package/dist/components/index.mjs.map +1 -0
  15. package/dist/config/index.d.mts +298 -0
  16. package/dist/config/index.d.ts +298 -0
  17. package/dist/config/index.js +19 -0
  18. package/dist/config/index.js.map +1 -0
  19. package/dist/config/index.mjs +1 -0
  20. package/dist/config/index.mjs.map +1 -0
  21. package/dist/index.d.mts +2184 -0
  22. package/dist/index.d.ts +2184 -0
  23. package/dist/index.js +1713 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/index.mjs +1605 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/lib/i18n/index.js +665 -0
  28. package/dist/lib/i18n/index.js.map +1 -0
  29. package/dist/lib/i18n/index.mjs +621 -0
  30. package/dist/lib/i18n/index.mjs.map +1 -0
  31. package/docs/DOCUMENTATION-STRUCTURE.md +1156 -0
  32. package/docs/EXPORTS.md +125 -0
  33. package/docs/PERFORMANCE.md +757 -0
  34. package/docs/POLICY-PAGES.md +867 -0
  35. package/docs/ROADMAP.md +334 -0
  36. package/docs/SEO.md +455 -0
  37. package/docs/SITEMAP.md +708 -0
  38. package/docs/STRUCTURED-DATA.md +671 -0
  39. package/docs/accessibility/common-patterns.md +529 -0
  40. package/docs/accessibility/keyboard-navigation.md +263 -0
  41. package/docs/accessibility/overview.md +122 -0
  42. package/docs/accessibility/screen-readers.md +311 -0
  43. package/docs/accessibility/wcag-compliance.md +159 -0
  44. package/docs/api/README.md +164 -0
  45. package/docs/api/components/Accessibility.md +356 -0
  46. package/docs/api/components/Button.md +240 -0
  47. package/docs/api/components/HeroSection.md +306 -0
  48. package/docs/architecture/decisions.md +449 -0
  49. package/docs/components/AnalyticsTracker.md +58 -0
  50. package/docs/components/AnimatedCounter.md +48 -0
  51. package/docs/components/AnimatedSection.md +56 -0
  52. package/docs/components/BlogCard.md +42 -0
  53. package/docs/components/Checkbox.md +56 -0
  54. package/docs/components/CodeBlock.md +52 -0
  55. package/docs/components/ComparisonTable.md +40 -0
  56. package/docs/components/ComponentDemo.md +38 -0
  57. package/docs/components/CountdownTimer.md +51 -0
  58. package/docs/components/ExitIntentModal.md +56 -0
  59. package/docs/components/FAQAccordion.md +66 -0
  60. package/docs/components/FeaturesGrid.md +55 -0
  61. package/docs/components/FileUpload.md +54 -0
  62. package/docs/components/I18nMetaTags.md +55 -0
  63. package/docs/components/Icon.md +53 -0
  64. package/docs/components/LazySection.md +46 -0
  65. package/docs/components/LiveProof.md +53 -0
  66. package/docs/components/LoadingSpinner.md +46 -0
  67. package/docs/components/MultiStepForm.md +48 -0
  68. package/docs/components/PolicyLayout.md +55 -0
  69. package/docs/components/PricingTable.md +49 -0
  70. package/docs/components/Radio.md +59 -0
  71. package/docs/components/SEOMetaTags.md +58 -0
  72. package/docs/components/ScriptInjector.md +50 -0
  73. package/docs/components/Select.md +72 -0
  74. package/docs/components/Skeleton.md +47 -0
  75. package/docs/components/StatsSection.md +48 -0
  76. package/docs/components/StickyBar.md +62 -0
  77. package/docs/components/StructuredData.md +99 -0
  78. package/docs/components/StyleGuide.md +46 -0
  79. package/docs/components/TableOfContents.md +47 -0
  80. package/docs/components/TestimonialCarousel.md +42 -0
  81. package/docs/components/Timeline.md +51 -0
  82. package/docs/components/Toast.md +59 -0
  83. package/docs/components/TrackedLink.md +62 -0
  84. package/docs/components/TrustBadges.md +44 -0
  85. package/docs/components/conversion/MobileCTA.md +363 -0
  86. package/docs/components/forms/ContactForm.md +75 -0
  87. package/docs/components/forms/FormField.md +74 -0
  88. package/docs/components/layout/Footer.md +601 -0
  89. package/docs/components/layout/Header.md +549 -0
  90. package/docs/components/layout/LanguageSelector.md +54 -0
  91. package/docs/components/layout/LanguageSwitcher.md +24 -0
  92. package/docs/components/overview.md +447 -0
  93. package/docs/components/sections/AboutSection.md +48 -0
  94. package/docs/components/sections/CTASection.md +596 -0
  95. package/docs/components/sections/CaseStudySection.md +47 -0
  96. package/docs/components/sections/ContactSection.md +599 -0
  97. package/docs/components/sections/FeatureSection.md +44 -0
  98. package/docs/components/sections/HeroSection.md +404 -0
  99. package/docs/components/sections/LogosSection.md +47 -0
  100. package/docs/components/sections/PersonalTaxesSection.md +23 -0
  101. package/docs/components/sections/RecruitingSection.md +23 -0
  102. package/docs/components/sections/SecurePortalSection.md +23 -0
  103. package/docs/components/sections/ServicePageLayout.md +52 -0
  104. package/docs/components/sections/ServicesSection.md +49 -0
  105. package/docs/components/sections/TestimonialSection.md +44 -0
  106. package/docs/components/sections/WhyChooseUsSection.md +54 -0
  107. package/docs/components/ui/Breadcrumb.md +70 -0
  108. package/docs/components/ui/Button.md +514 -0
  109. package/docs/components/ui/Card.md +501 -0
  110. package/docs/components/ui/Input.md +54 -0
  111. package/docs/components/ui/MobileLinks.md +43 -0
  112. package/docs/components/ui/Modal.md +60 -0
  113. package/docs/components/ui/Tabs.md +62 -0
  114. package/docs/components/ui/Textarea.md +52 -0
  115. package/docs/core-concepts/configuration-driven.md +552 -0
  116. package/docs/core-concepts/overview.md +351 -0
  117. package/docs/features/accessibility/README.md +73 -0
  118. package/docs/features/accessibility/aria-support.md +177 -0
  119. package/docs/features/accessibility/color-contrast.md +155 -0
  120. package/docs/features/accessibility/focus-management.md +187 -0
  121. package/docs/features/accessibility/testing.md +196 -0
  122. package/docs/features/analytics/README.md +51 -0
  123. package/docs/features/analytics/ab-testing.md +171 -0
  124. package/docs/features/analytics/conversion-tracking.md +207 -0
  125. package/docs/features/analytics/custom-events.md +219 -0
  126. package/docs/features/analytics/privacy.md +198 -0
  127. package/docs/features/analytics/setup.md +114 -0
  128. package/docs/features/analytics/tracking-events.md +224 -0
  129. package/docs/features/i18n/README.md +51 -0
  130. package/docs/features/i18n/best-practices.md +273 -0
  131. package/docs/features/i18n/configuration.md +84 -0
  132. package/docs/features/i18n/formatting.md +133 -0
  133. package/docs/features/i18n/locale-detection.md +122 -0
  134. package/docs/features/i18n/routing.md +99 -0
  135. package/docs/features/i18n/rtl-support.md +191 -0
  136. package/docs/features/i18n/translations.md +129 -0
  137. package/docs/features/internationalization.md +595 -0
  138. package/docs/features/performance/README.md +77 -0
  139. package/docs/features/performance/bundle-size.md +134 -0
  140. package/docs/features/performance/caching.md +131 -0
  141. package/docs/features/performance/code-splitting.md +121 -0
  142. package/docs/features/performance/image-optimization.md +110 -0
  143. package/docs/features/performance/lazy-loading.md +92 -0
  144. package/docs/features/performance/monitoring.md +148 -0
  145. package/docs/features/seo/README.md +51 -0
  146. package/docs/features/seo/best-practices.md +184 -0
  147. package/docs/features/seo/canonical-urls.md +182 -0
  148. package/docs/features/seo/meta-tags.md +126 -0
  149. package/docs/features/seo/open-graph.md +166 -0
  150. package/docs/features/seo/robots-txt.md +146 -0
  151. package/docs/features/seo/sitemaps.md +162 -0
  152. package/docs/features/seo/structured-data.md +166 -0
  153. package/docs/getting-started/installation.md +292 -0
  154. package/docs/getting-started/introduction.md +195 -0
  155. package/docs/getting-started/quick-start.md +460 -0
  156. package/docs/guides/analytics-setup.md +616 -0
  157. package/docs/i18n/CONFIGURATION.md +353 -0
  158. package/docs/i18n/EXAMPLES.md +402 -0
  159. package/docs/i18n/MIGRATION.md +260 -0
  160. package/docs/i18n/SEO.md +392 -0
  161. package/docs/i18n/STATIC-GENERATION-FIX.md +71 -0
  162. package/docs/migration/changelog.md +136 -0
  163. package/docs/migration/overview.md +233 -0
  164. package/docs/recipes/adding-animations.md +475 -0
  165. package/docs/recipes/forms-with-validation.md +393 -0
  166. package/package.json +152 -0
@@ -0,0 +1,2184 @@
1
+ import { ThemeConfig, HeroContent, LocalizedString, AboutContent, ServicesContent, HeaderConfig, FooterConfig } from './config/index.js';
2
+ export { FooterSection, LogoConfig, NavDropdown, NavDropdownItem, NavItem, NavLink, NavigationConfig, ScriptsConfig, ServiceItem, SiteContent, SiteMetadata, WhyChooseUsContent } from './config/index.js';
3
+ import { NextRequest, NextResponse } from 'next/server';
4
+ import { ClassValue } from 'clsx';
5
+ import { Metadata } from 'next';
6
+ import * as react_jsx_runtime from 'react/jsx-runtime';
7
+ import { ReactNode, ButtonHTMLAttributes, HTMLAttributes, InputHTMLAttributes, TextareaHTMLAttributes, ComponentType } from 'react';
8
+ import { LucideProps } from 'lucide-react';
9
+ import { FieldError } from 'react-hook-form';
10
+
11
+ declare function generateThemeCSS(theme: ThemeConfig): string;
12
+ declare function generateDesignTokens(theme: ThemeConfig): string;
13
+
14
+ /**
15
+ * Gets the font import configuration for Next.js
16
+ * This prepares the data needed to dynamically import fonts
17
+ */
18
+ declare function getFontConfig(theme: ThemeConfig): {
19
+ heading: {
20
+ family: string;
21
+ weights: string[];
22
+ variable: string;
23
+ };
24
+ body: {
25
+ family: string;
26
+ weights: string[];
27
+ variable: string;
28
+ };
29
+ };
30
+ /**
31
+ * Generates CSS variable names from theme fonts
32
+ */
33
+ declare function getFontVariables(theme: ThemeConfig): string;
34
+
35
+ /**
36
+ * Helper to get localized string from content
37
+ */
38
+ declare function getLocalizedString(localizedString: {
39
+ [locale: string]: string;
40
+ }, locale: string): string;
41
+
42
+ interface PolicyMetadata {
43
+ /** Policy title */
44
+ title: string;
45
+ /** Last updated date (ISO string) */
46
+ lastUpdated: string;
47
+ /** Optional description for SEO */
48
+ description?: string;
49
+ /** Additional custom fields */
50
+ [key: string]: string | undefined;
51
+ }
52
+ interface Policy {
53
+ /** Compiled MDX content */
54
+ content: JSX.Element;
55
+ /** Frontmatter metadata */
56
+ metadata: PolicyMetadata;
57
+ /** Policy slug (filename without locale/extension) */
58
+ slug: string;
59
+ /** Locale */
60
+ locale: string;
61
+ }
62
+ /**
63
+ * Load a policy markdown file and compile it to React
64
+ *
65
+ * @param slug - Policy slug (e.g., 'privacy-policy', 'terms-of-service')
66
+ * @param locale - Locale code (e.g., 'en', 'fr')
67
+ * @param contentDir - Directory containing policy files @default 'src/content/policies'
68
+ * @returns Compiled policy with content and metadata
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const { content, metadata } = await loadPolicy('privacy-policy', 'en');
73
+ *
74
+ * return (
75
+ * <PolicyLayout
76
+ * title={metadata.title}
77
+ * lastUpdated={metadata.lastUpdated}
78
+ * >
79
+ * {content}
80
+ * </PolicyLayout>
81
+ * );
82
+ * ```
83
+ */
84
+ declare function loadPolicy(slug: string, locale: string, contentDir?: string): Promise<Policy>;
85
+ /**
86
+ * Get all unique policy slugs (without locale suffix)
87
+ *
88
+ * @param contentDir - Directory containing policy files @default 'src/content/policies'
89
+ * @returns Array of policy slugs
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * const slugs = getPolicySlugs(); // ['privacy-policy', 'terms-of-service']
94
+ * ```
95
+ */
96
+ declare function getPolicySlugs(contentDir?: string): string[];
97
+ /**
98
+ * Get all policies for a specific locale with their metadata
99
+ *
100
+ * @param locale - Locale code
101
+ * @param contentDir - Directory containing policy files @default 'src/content/policies'
102
+ * @returns Array of policies with metadata
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const policies = await getAllPolicies('en');
107
+ *
108
+ * // Render policy list
109
+ * policies.map(policy => (
110
+ * <Link key={policy.slug} href={`/policies/${policy.slug}`}>
111
+ * {policy.metadata.title}
112
+ * </Link>
113
+ * ));
114
+ * ```
115
+ */
116
+ declare function getAllPolicies(locale: string, contentDir?: string): Promise<Omit<Policy, 'content'>[]>;
117
+ /**
118
+ * Get available locales for a specific policy
119
+ *
120
+ * @param slug - Policy slug
121
+ * @param contentDir - Directory containing policy files @default 'src/content/policies'
122
+ * @returns Array of locale codes
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * const locales = getPolicyLocales('privacy-policy'); // ['en', 'fr']
127
+ * ```
128
+ */
129
+ declare function getPolicyLocales(slug: string, contentDir?: string): string[];
130
+
131
+ /**
132
+ * Helper to get localized string from navigation
133
+ */
134
+ declare function getNavigationString(localizedString: {
135
+ [locale: string]: string;
136
+ }, locale: string): string;
137
+ /**
138
+ * Helper to replace placeholders in strings
139
+ */
140
+ declare function replaceVariables(text: string, variables: Record<string, string>): string;
141
+
142
+ /**
143
+ * Locale prefix mode determines how locale appears in URLs
144
+ *
145
+ * - 'always': All routes have locale prefix (/en/about, /fr/about)
146
+ * - 'as-needed': Only non-default locales have prefix (/about, /fr/about)
147
+ * - 'never': No locale prefixes, detection via cookie/header only
148
+ */
149
+ type LocalePrefix = 'always' | 'as-needed' | 'never';
150
+ /**
151
+ * Cookie configuration for locale persistence
152
+ */
153
+ interface LocaleCookieConfig {
154
+ /** Cookie name @default 'NEXT_LOCALE' */
155
+ name?: string;
156
+ /** Cookie max age in seconds @default 31536000 (1 year) */
157
+ maxAge?: number;
158
+ /** Cookie SameSite attribute @default 'lax' */
159
+ sameSite?: 'lax' | 'strict' | 'none';
160
+ }
161
+ /**
162
+ * Slug translations mapping for bilingual/multilingual routes
163
+ * Maps slugs from one locale to another
164
+ *
165
+ * @example
166
+ * {
167
+ * fr: {
168
+ * '/a-propos': '/about',
169
+ * '/nous-contacter': '/contact'
170
+ * },
171
+ * en: {
172
+ * '/about': '/a-propos',
173
+ * '/contact': '/nous-contacter'
174
+ * }
175
+ * }
176
+ */
177
+ interface SlugTranslations {
178
+ [locale: string]: {
179
+ [slug: string]: string;
180
+ };
181
+ }
182
+ /**
183
+ * Complete i18n configuration for a project
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * export const i18nConfig: I18nConfig = {
188
+ * locales: ['en', 'fr', 'es'],
189
+ * defaultLocale: 'en',
190
+ * localePrefix: 'as-needed',
191
+ * localeDetection: true,
192
+ * localeNames: {
193
+ * en: 'English',
194
+ * fr: 'Français',
195
+ * es: 'Español'
196
+ * }
197
+ * };
198
+ * ```
199
+ */
200
+ interface I18nConfig {
201
+ /**
202
+ * Array of supported locale codes (ISO 639-1)
203
+ * @example ['en', 'fr', 'es', 'de', 'ja']
204
+ */
205
+ locales: readonly string[];
206
+ /**
207
+ * Default locale to use when none is specified
208
+ * Must be one of the locales in the locales array
209
+ */
210
+ defaultLocale: string;
211
+ /**
212
+ * Locale prefix mode for URL routing
213
+ * @default 'as-needed'
214
+ */
215
+ localePrefix?: LocalePrefix;
216
+ /**
217
+ * Enable automatic locale detection from browser headers
218
+ * @default true
219
+ */
220
+ localeDetection?: boolean;
221
+ /**
222
+ * Full locale names for display in UI
223
+ * @example { en: 'English', fr: 'Français' }
224
+ */
225
+ localeNames?: Record<string, string>;
226
+ /**
227
+ * Short locale labels for compact display (e.g., language selector)
228
+ * @example { en: 'EN', fr: 'FR' }
229
+ */
230
+ localeLabels?: Record<string, string>;
231
+ /**
232
+ * Locales that use right-to-left text direction
233
+ * @example ['ar', 'he', 'fa']
234
+ */
235
+ rtlLocales?: readonly string[];
236
+ /**
237
+ * Cookie configuration for locale persistence
238
+ */
239
+ localeCookie?: LocaleCookieConfig;
240
+ /**
241
+ * Custom slug translations for multilingual routes
242
+ * If not provided, no slug translation will occur
243
+ */
244
+ slugTranslations?: SlugTranslations;
245
+ }
246
+ /**
247
+ * Type guard to validate locale string
248
+ */
249
+ type ValidLocale<T extends I18nConfig> = T['locales'][number];
250
+ /**
251
+ * Browser language preference with quality value (from Accept-Language header)
252
+ */
253
+ interface LanguagePreference {
254
+ locale: string;
255
+ quality: number;
256
+ }
257
+
258
+ /**
259
+ * Initialize the i18n configuration
260
+ * Must be called before using any i18n features
261
+ *
262
+ * @param config - Complete i18n configuration
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * import { setI18nConfig } from 'simple-site-framework/lib/i18n';
267
+ * import { i18nConfig } from './config/i18n';
268
+ *
269
+ * setI18nConfig(i18nConfig);
270
+ * ```
271
+ */
272
+ declare function setI18nConfig(config: I18nConfig): void;
273
+ /**
274
+ * Get the current i18n configuration
275
+ * Returns legacy default config if not initialized (for build compatibility)
276
+ *
277
+ * @deprecated Calling without initialization - will throw in v1.0.0
278
+ */
279
+ declare function getI18nConfig(): I18nConfig;
280
+ /**
281
+ * Check if i18n config has been initialized
282
+ */
283
+ declare function isI18nConfigInitialized(): boolean;
284
+ /**
285
+ * Get supported locales array
286
+ */
287
+ declare function getLocales(): readonly string[];
288
+ /**
289
+ * Get default locale
290
+ */
291
+ declare function getDefaultLocale(): string;
292
+ /**
293
+ * Get locale prefix mode
294
+ */
295
+ declare function getLocalePrefix(): LocalePrefix;
296
+ /**
297
+ * Get locale names mapping
298
+ */
299
+ declare function getLocaleNames(): Record<string, string>;
300
+ /**
301
+ * Get locale labels mapping
302
+ */
303
+ declare function getLocaleLabels(): Record<string, string>;
304
+ /**
305
+ * Get RTL locales array
306
+ */
307
+ declare function getRtlLocales(): readonly string[];
308
+ /**
309
+ * Check if locale detection is enabled
310
+ */
311
+ declare function isLocaleDetectionEnabled(): boolean;
312
+ /**
313
+ * Get locale cookie configuration
314
+ */
315
+ declare function getLocaleCookieConfig(): {
316
+ name: string;
317
+ maxAge: number;
318
+ sameSite: "none" | "lax" | "strict";
319
+ };
320
+ /**
321
+ * Check if a locale is supported
322
+ */
323
+ declare function isSupportedLocale(locale: string): boolean;
324
+ /**
325
+ * Get full locale name for display
326
+ */
327
+ declare function getLocaleName(locale: string): string;
328
+ /**
329
+ * Get short locale label for compact display
330
+ */
331
+ declare function getLocaleLabel(locale: string): string;
332
+ /**
333
+ * @deprecated Use getLocales() instead. This export will be removed in v1.0.0
334
+ */
335
+ declare const locales: readonly ["fr", "en"];
336
+ /**
337
+ * @deprecated Import from config schemas instead
338
+ */
339
+ type Locale = 'fr' | 'en';
340
+ /**
341
+ * @deprecated Use getDefaultLocale() instead. This export will be removed in v1.0.0
342
+ */
343
+ declare const defaultLocale: Locale;
344
+
345
+ declare const LOCALE_COOKIE_NAME = "NEXT_LOCALE";
346
+ /**
347
+ * Get locale from cookie
348
+ * Returns null if cookie not found or locale not supported
349
+ */
350
+ declare function getLocaleFromCookie(): string | null;
351
+ /**
352
+ * Set locale cookie
353
+ * Uses configuration from i18n config
354
+ */
355
+ declare function setLocaleCookie(locale: string): void;
356
+
357
+ declare const defaultSlugTranslations: SlugTranslations;
358
+ /**
359
+ * Translates a path from one locale to another
360
+ *
361
+ * Merges translations in this priority order:
362
+ * 1. Custom translations passed as parameter (highest priority)
363
+ * 2. Translations from i18n config (if configured)
364
+ * 3. Default translations (lowest priority)
365
+ *
366
+ * @param path - The current path (without locale prefix)
367
+ * @param fromLocale - The current locale
368
+ * @param toLocale - The target locale
369
+ * @param customTranslations - Optional custom translations to merge with defaults
370
+ * @returns The translated path
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * // With config translations
375
+ * translateSlug('/about', 'en', 'fr')
376
+ * // Returns: '/a-propos' (from config or defaults)
377
+ *
378
+ * // With custom override
379
+ * translateSlug('/about', 'en', 'fr', {
380
+ * en: { '/about': '/notre-equipe' }
381
+ * })
382
+ * // Returns: '/notre-equipe' (custom override)
383
+ *
384
+ * // Nested paths
385
+ * translateSlug('/about/team', 'en', 'fr')
386
+ * // Returns: '/a-propos/team' (translates base, keeps rest)
387
+ * ```
388
+ */
389
+ declare function translateSlug(path: string, fromLocale: string, toLocale: string, customTranslations?: SlugTranslations): string;
390
+
391
+ /**
392
+ * Format a date according to locale
393
+ *
394
+ * @param date - Date to format
395
+ * @param locale - Locale code (e.g., 'en', 'fr', 'es')
396
+ * @param options - Intl.DateTimeFormat options
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * formatDate(new Date('2026-02-01'), 'fr', { dateStyle: 'long' })
401
+ * // "1 février 2026"
402
+ *
403
+ * formatDate(new Date('2026-02-01'), 'en', { dateStyle: 'long' })
404
+ * // "February 1, 2026"
405
+ *
406
+ * formatDate(new Date(), 'fr', {
407
+ * weekday: 'long',
408
+ * year: 'numeric',
409
+ * month: 'long',
410
+ * day: 'numeric'
411
+ * })
412
+ * // "samedi 1 février 2026"
413
+ * ```
414
+ */
415
+ declare function formatDate(date: Date, locale: string, options?: Intl.DateTimeFormatOptions): string;
416
+ /**
417
+ * Format a number according to locale
418
+ *
419
+ * @param value - Number to format
420
+ * @param locale - Locale code
421
+ * @param options - Intl.NumberFormat options
422
+ *
423
+ * @example
424
+ * ```typescript
425
+ * formatNumber(1234567.89, 'en')
426
+ * // "1,234,567.89"
427
+ *
428
+ * formatNumber(1234567.89, 'fr')
429
+ * // "1 234 567,89"
430
+ *
431
+ * formatNumber(0.42, 'en', { style: 'percent' })
432
+ * // "42%"
433
+ *
434
+ * formatNumber(1234, 'en', { minimumFractionDigits: 2 })
435
+ * // "1,234.00"
436
+ * ```
437
+ */
438
+ declare function formatNumber(value: number, locale: string, options?: Intl.NumberFormatOptions): string;
439
+ /**
440
+ * Format a currency amount according to locale
441
+ *
442
+ * @param amount - Amount to format
443
+ * @param locale - Locale code
444
+ * @param currency - ISO 4217 currency code (e.g., 'USD', 'EUR', 'CAD')
445
+ * @param options - Additional Intl.NumberFormat options
446
+ *
447
+ * @example
448
+ * ```typescript
449
+ * formatCurrency(1299.99, 'en', 'USD')
450
+ * // "$1,299.99"
451
+ *
452
+ * formatCurrency(1299.99, 'fr', 'EUR')
453
+ * // "1 299,99 €"
454
+ *
455
+ * formatCurrency(1299.99, 'fr-CA', 'CAD')
456
+ * // "1 299,99 $"
457
+ *
458
+ * formatCurrency(1299.99, 'ja', 'JPY')
459
+ * // "¥1,300"
460
+ *
461
+ * formatCurrency(0.99, 'en', 'USD', { currencyDisplay: 'name' })
462
+ * // "0.99 US dollars"
463
+ * ```
464
+ */
465
+ declare function formatCurrency(amount: number, locale: string, currency: string, options?: Intl.NumberFormatOptions): string;
466
+ /**
467
+ * Format relative time (e.g., "2 hours ago", "in 3 days")
468
+ *
469
+ * @param value - Numeric value (negative for past, positive for future)
470
+ * @param unit - Time unit
471
+ * @param locale - Locale code
472
+ * @param options - Intl.RelativeTimeFormat options
473
+ *
474
+ * @example
475
+ * ```typescript
476
+ * formatRelativeTime(-2, 'hour', 'en')
477
+ * // "2 hours ago"
478
+ *
479
+ * formatRelativeTime(-2, 'hour', 'fr')
480
+ * // "il y a 2 heures"
481
+ *
482
+ * formatRelativeTime(3, 'day', 'en')
483
+ * // "in 3 days"
484
+ *
485
+ * formatRelativeTime(-1, 'week', 'es')
486
+ * // "hace 1 semana"
487
+ *
488
+ * formatRelativeTime(-5, 'minute', 'en', { numeric: 'auto' })
489
+ * // "5 minutes ago"
490
+ * ```
491
+ */
492
+ declare function formatRelativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, locale: string, options?: Intl.RelativeTimeFormatOptions): string;
493
+ /**
494
+ * Format a date range according to locale
495
+ * Note: formatRange requires newer TypeScript/Node versions
496
+ *
497
+ * @param startDate - Start date
498
+ * @param endDate - End date
499
+ * @param locale - Locale code
500
+ * @param options - Intl.DateTimeFormat options
501
+ *
502
+ * @example
503
+ * ```typescript
504
+ * formatDateRange(
505
+ * new Date('2026-02-01'),
506
+ * new Date('2026-02-15'),
507
+ * 'en',
508
+ * { month: 'long', day: 'numeric' }
509
+ * )
510
+ * // "February 1 – 15"
511
+ * ```
512
+ */
513
+ declare function formatDateRange(startDate: Date, endDate: Date, locale: string, options?: Intl.DateTimeFormatOptions): string;
514
+ /**
515
+ * Format a list of items according to locale
516
+ * Falls back to simple comma-separated list if Intl.ListFormat not available
517
+ *
518
+ * @param items - Array of items to format
519
+ * @param locale - Locale code
520
+ *
521
+ * @example
522
+ * ```typescript
523
+ * formatList(['apples', 'oranges', 'bananas'], 'en')
524
+ * // "apples, oranges, and bananas"
525
+ *
526
+ * formatList(['pommes', 'oranges', 'bananes'], 'fr')
527
+ * // "pommes, oranges et bananes"
528
+ * ```
529
+ */
530
+ declare function formatList(items: string[], locale: string): string;
531
+ /**
532
+ * Format file size in bytes to human-readable format
533
+ * Not using Intl, but useful for internationalized apps
534
+ *
535
+ * @param bytes - File size in bytes
536
+ * @param locale - Locale code
537
+ * @param decimals - Number of decimal places @default 2
538
+ *
539
+ * @example
540
+ * ```typescript
541
+ * formatFileSize(1024, 'en')
542
+ * // "1.00 KB"
543
+ *
544
+ * formatFileSize(1048576, 'fr')
545
+ * // "1,00 Mo"
546
+ *
547
+ * formatFileSize(1073741824, 'en', 1)
548
+ * // "1.0 GB"
549
+ * ```
550
+ */
551
+ declare function formatFileSize(bytes: number, locale: string, decimals?: number): string;
552
+ /**
553
+ * Get relative time from a date (auto-selects best unit)
554
+ *
555
+ * @param date - Date to compare against now
556
+ * @param locale - Locale code
557
+ * @param options - Intl.RelativeTimeFormat options
558
+ *
559
+ * @example
560
+ * ```typescript
561
+ * // If date is 2 hours ago
562
+ * getRelativeTime(pastDate, 'en')
563
+ * // "2 hours ago"
564
+ *
565
+ * // If date is 3 days from now
566
+ * getRelativeTime(futureDate, 'en')
567
+ * // "in 3 days"
568
+ *
569
+ * // If date is 45 seconds ago
570
+ * getRelativeTime(recentDate, 'fr')
571
+ * // "il y a 45 secondes"
572
+ * ```
573
+ */
574
+ declare function getRelativeTime(date: Date, locale: string, options?: Intl.RelativeTimeFormatOptions): string;
575
+
576
+ /**
577
+ * Create Next.js middleware for i18n routing
578
+ *
579
+ * @param config - i18n configuration
580
+ * @returns Middleware function
581
+ *
582
+ * @example
583
+ * ```typescript
584
+ * // middleware.ts
585
+ * import { createI18nMiddleware } from 'simple-site-framework/lib/i18n';
586
+ * import { i18nConfig } from './src/config/i18n';
587
+ *
588
+ * export default createI18nMiddleware(i18nConfig);
589
+ *
590
+ * export const config = {
591
+ * matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
592
+ * };
593
+ * ```
594
+ */
595
+ declare function createI18nMiddleware(config: I18nConfig): (request: NextRequest) => NextResponse;
596
+
597
+ /**
598
+ * Check if a locale uses right-to-left text direction
599
+ *
600
+ * @param locale - Locale code to check
601
+ * @returns true if locale is RTL, false otherwise
602
+ *
603
+ * @example
604
+ * ```typescript
605
+ * isRtlLocale('ar') // true (Arabic)
606
+ * isRtlLocale('he') // true (Hebrew)
607
+ * isRtlLocale('en') // false (English)
608
+ * isRtlLocale('fr') // false (French)
609
+ * ```
610
+ */
611
+ declare function isRtlLocale(locale: string): boolean;
612
+ /**
613
+ * Get text direction for a locale
614
+ *
615
+ * @param locale - Locale code
616
+ * @returns 'rtl' for right-to-left locales, 'ltr' for left-to-right
617
+ *
618
+ * @example
619
+ * ```tsx
620
+ * // In layout
621
+ * <html lang={locale} dir={getTextDirection(locale)}>
622
+ *
623
+ * // Results:
624
+ * getTextDirection('ar') // 'rtl'
625
+ * getTextDirection('en') // 'ltr'
626
+ * ```
627
+ */
628
+ declare function getTextDirection(locale: string): 'ltr' | 'rtl';
629
+ /**
630
+ * Validate if a locale is supported
631
+ *
632
+ * @param locale - Locale code to validate
633
+ * @returns true if locale is supported, false otherwise
634
+ *
635
+ * @example
636
+ * ```typescript
637
+ * // With config: locales: ['en', 'fr', 'es']
638
+ * validateLocale('en') // true
639
+ * validateLocale('fr') // true
640
+ * validateLocale('de') // false
641
+ * validateLocale('invalid') // false
642
+ * ```
643
+ */
644
+ declare function validateLocale(locale: string): boolean;
645
+ /**
646
+ * Get all supported locales except the current one
647
+ *
648
+ * @param currentLocale - Current locale to exclude
649
+ * @returns Array of alternate locales
650
+ *
651
+ * @example
652
+ * ```typescript
653
+ * // With config: locales: ['en', 'fr', 'es', 'de']
654
+ * getAlternateLocales('en') // ['fr', 'es', 'de']
655
+ * getAlternateLocales('fr') // ['en', 'es', 'de']
656
+ * ```
657
+ */
658
+ declare function getAlternateLocales(currentLocale: string): string[];
659
+ /**
660
+ * Normalize locale code to lowercase
661
+ * Handles variants like 'en-US' -> 'en', 'zh-CN' -> 'zh'
662
+ *
663
+ * @param locale - Locale code (can include region)
664
+ * @returns Normalized locale code
665
+ *
666
+ * @example
667
+ * ```typescript
668
+ * normalizeLocale('en-US') // 'en'
669
+ * normalizeLocale('zh-CN') // 'zh'
670
+ * normalizeLocale('FR') // 'fr'
671
+ * normalizeLocale('es') // 'es'
672
+ * ```
673
+ */
674
+ declare function normalizeLocale(locale: string): string;
675
+ /**
676
+ * Check if a locale code matches a supported locale
677
+ * Handles locale variants (e.g., 'en-US' matches 'en')
678
+ *
679
+ * @param locale - Locale code to check (can include region)
680
+ * @returns Matching supported locale or null
681
+ *
682
+ * @example
683
+ * ```typescript
684
+ * // With config: locales: ['en', 'fr', 'es']
685
+ * matchLocale('en-US') // 'en'
686
+ * matchLocale('fr-CA') // 'fr'
687
+ * matchLocale('de-DE') // null
688
+ * ```
689
+ */
690
+ declare function matchLocale(locale: string): string | null;
691
+ /**
692
+ * Get locale display name in its own language (autonym)
693
+ *
694
+ * @param locale - Locale code
695
+ * @returns Display name or locale code if not found
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * getLocaleAutonym('en') // 'English'
700
+ * getLocaleAutonym('fr') // 'Français'
701
+ * getLocaleAutonym('es') // 'Español'
702
+ * ```
703
+ */
704
+ declare function getLocaleAutonym(locale: string): string;
705
+ /**
706
+ * Format locale for display (e.g., for language selector)
707
+ *
708
+ * @param locale - Locale code
709
+ * @param format - Display format
710
+ * @returns Formatted locale string
711
+ *
712
+ * @example
713
+ * ```typescript
714
+ * formatLocaleDisplay('en', 'name') // 'English'
715
+ * formatLocaleDisplay('fr', 'label') // 'FR'
716
+ * formatLocaleDisplay('es', 'code') // 'es'
717
+ * ```
718
+ */
719
+ declare function formatLocaleDisplay(locale: string, format?: 'name' | 'label' | 'code'): string;
720
+
721
+ /**
722
+ * Combines class names using clsx and merges Tailwind classes intelligently
723
+ * @param inputs - Class names to combine
724
+ * @returns Merged class string
725
+ */
726
+ declare function cn(...inputs: ClassValue[]): string;
727
+
728
+ type EventCategory = 'cta' | 'form' | 'navigation' | 'engagement' | 'conversion' | 'ab_test';
729
+ type CTAType = 'signup' | 'trial' | 'contact' | 'download' | 'other';
730
+ type FormAction = 'start' | 'submit' | 'error' | 'abandon';
731
+ type PricingAction = 'view' | 'calculate' | 'plan_select' | 'currency_change';
732
+ type FeatureAction = 'view' | 'video_play' | 'video_complete' | 'cta_click';
733
+ type VideoAction = 'play' | 'pause' | 'complete' | '25%' | '50%' | '75%';
734
+ type NavigationLocation = 'header' | 'footer' | 'content' | 'mobile';
735
+ type ConversionType = 'trial_signup' | 'contact' | 'newsletter' | 'other';
736
+ type ScrollDepth = 25 | 50 | 75 | 100;
737
+ interface AnalyticsEvent {
738
+ event: string;
739
+ event_category?: EventCategory;
740
+ event_label?: string;
741
+ value?: number;
742
+ [key: string]: unknown;
743
+ }
744
+ interface CTAClickEvent extends AnalyticsEvent {
745
+ event: 'cta_click';
746
+ event_category: 'cta';
747
+ cta_location: string;
748
+ cta_text: string;
749
+ cta_type: CTAType;
750
+ }
751
+ interface FormEvent extends AnalyticsEvent {
752
+ event: `form_${FormAction}`;
753
+ event_category: 'form';
754
+ form_name: string;
755
+ form_action: FormAction;
756
+ }
757
+ interface PricingEvent extends AnalyticsEvent {
758
+ event: 'pricing_interaction';
759
+ event_category: 'engagement';
760
+ pricing_action: PricingAction;
761
+ }
762
+ interface FeatureEvent extends AnalyticsEvent {
763
+ event: 'feature_engagement';
764
+ event_category: 'engagement';
765
+ feature_name: string;
766
+ feature_action: FeatureAction;
767
+ }
768
+ interface VideoEvent extends AnalyticsEvent {
769
+ event: 'video_interaction';
770
+ event_category: 'engagement';
771
+ video_title: string;
772
+ video_action: VideoAction;
773
+ }
774
+ interface NavigationEvent extends AnalyticsEvent {
775
+ event: 'navigation_click';
776
+ event_category: 'navigation';
777
+ link_text: string;
778
+ link_url: string;
779
+ link_location: NavigationLocation;
780
+ }
781
+ interface ConversionEvent extends AnalyticsEvent {
782
+ event: 'conversion';
783
+ event_category: 'conversion';
784
+ conversion_type: ConversionType;
785
+ }
786
+ interface ABTestEvent extends AnalyticsEvent {
787
+ event: 'ab_test_event';
788
+ event_category: 'ab_test';
789
+ test_id: string;
790
+ variant: 'A' | 'B';
791
+ test_event: string;
792
+ }
793
+ interface ScrollDepthEvent extends AnalyticsEvent {
794
+ event: 'scroll_depth';
795
+ event_category: 'engagement';
796
+ scroll_percentage: ScrollDepth;
797
+ page_path: string;
798
+ }
799
+ interface PageViewEvent extends AnalyticsEvent {
800
+ event: 'page_view';
801
+ page_path: string;
802
+ page_title: string;
803
+ }
804
+
805
+ declare global {
806
+ interface Window {
807
+ dataLayer: unknown[];
808
+ }
809
+ }
810
+
811
+ /**
812
+ * Generic event tracking function
813
+ * Use this for custom events not covered by specific tracking functions
814
+ *
815
+ * @param eventName - Name of the event
816
+ * @param properties - Additional event properties
817
+ *
818
+ * @example
819
+ * ```typescript
820
+ * trackEvent('button_click', {
821
+ * button_text: 'Sign Up',
822
+ * button_location: 'hero',
823
+ * button_variant: 'primary'
824
+ * });
825
+ * ```
826
+ */
827
+ declare function trackEvent(eventName: string, properties?: Record<string, unknown>): void;
828
+ /**
829
+ * Track CTA click events
830
+ * @param ctaLocation - Where the CTA appears (e.g., 'hero', 'pricing', 'mobile_sticky')
831
+ * @param ctaText - The text on the CTA button
832
+ * @param ctaType - Type of CTA (e.g., 'signup', 'trial', 'contact')
833
+ */
834
+ declare function trackCTAClick(ctaLocation: string, ctaText: string, ctaType?: 'signup' | 'trial' | 'contact' | 'download' | 'other'): void;
835
+ /**
836
+ * Track form interactions
837
+ * @param formName - Identifier for the form
838
+ * @param action - Form action (start, submit, error, abandon)
839
+ */
840
+ declare function trackFormEvent(formName: string, action: 'start' | 'submit' | 'error' | 'abandon', metadata?: Record<string, unknown>): void;
841
+ /**
842
+ * Track page view (for SPAs and custom tracking)
843
+ * @param pagePath - The page path
844
+ * @param pageTitle - The page title
845
+ */
846
+ declare function trackPageView(pagePath: string, pageTitle: string): void;
847
+ /**
848
+ * Track pricing page interactions
849
+ * @param action - Type of interaction
850
+ */
851
+ declare function trackPricingEvent(action: 'view' | 'calculate' | 'plan_select' | 'currency_change', metadata?: Record<string, unknown>): void;
852
+ /**
853
+ * Track feature page engagement
854
+ * @param featureName - Name of the feature being viewed
855
+ * @param action - Type of engagement
856
+ */
857
+ declare function trackFeatureEngagement(featureName: string, action: 'view' | 'video_play' | 'video_complete' | 'cta_click', metadata?: Record<string, unknown>): void;
858
+ /**
859
+ * Track resource downloads
860
+ * @param resourceName - Name of the resource
861
+ * @param resourceType - Type of resource (pdf, video, etc.)
862
+ */
863
+ declare function trackResourceDownload(resourceName: string, resourceType: string): void;
864
+ /**
865
+ * Track video interactions
866
+ * @param videoTitle - Title of the video
867
+ * @param action - Video action
868
+ */
869
+ declare function trackVideoEvent(videoTitle: string, action: 'play' | 'pause' | 'complete' | '25%' | '50%' | '75%', metadata?: Record<string, unknown>): void;
870
+ /**
871
+ * Track navigation events
872
+ * @param linkText - Text of the link clicked
873
+ * @param linkUrl - URL of the link
874
+ * @param linkLocation - Where the link appears (header, footer, content)
875
+ */
876
+ declare function trackNavigation(linkText: string, linkUrl: string, linkLocation: 'header' | 'footer' | 'content' | 'mobile'): void;
877
+ /**
878
+ * Track A/B test variant assignment and events
879
+ * @param testId - ID of the A/B test
880
+ * @param variant - Variant assigned (A or B)
881
+ * @param eventName - Name of the event
882
+ */
883
+ declare function trackABTestEvent(testId: string, variant: 'A' | 'B', eventName: string, metadata?: Record<string, unknown>): void;
884
+ /**
885
+ * Track conversion events (trial signups, purchases, etc.)
886
+ * @param conversionType - Type of conversion
887
+ * @param value - Monetary value (optional)
888
+ */
889
+ declare function trackConversion(conversionType: 'trial_signup' | 'contact' | 'newsletter' | 'other', value?: number, metadata?: Record<string, unknown>): void;
890
+ /**
891
+ * Track scroll depth
892
+ * @param percentage - Scroll depth percentage (25, 50, 75, 100)
893
+ * @param pagePath - The page path
894
+ */
895
+ declare function trackScrollDepth(percentage: 25 | 50 | 75 | 100, pagePath: string): void;
896
+ /**
897
+ * Track search events
898
+ * @param searchTerm - The search term
899
+ * @param resultCount - Number of results (optional)
900
+ */
901
+ declare function trackSearch(searchTerm: string, resultCount?: number): void;
902
+ /**
903
+ * Track outbound link clicks
904
+ * @param url - The external URL
905
+ * @param linkText - Text of the link
906
+ */
907
+ declare function trackOutboundLink(url: string, linkText: string): void;
908
+ /**
909
+ * Track error events
910
+ * @param errorType - Type of error
911
+ * @param errorMessage - Error message or description
912
+ */
913
+ declare function trackError(errorType: string, errorMessage: string): void;
914
+
915
+ /**
916
+ * Email validation schema
917
+ * @example
918
+ * const schema = z.object({ email: emailSchema })
919
+ */
920
+ declare const emailSchema: any;
921
+ /**
922
+ * Phone number validation (international format)
923
+ * Accepts formats: +1234567890, +1 (234) 567-8900, etc.
924
+ */
925
+ declare const phoneSchema: any;
926
+ /**
927
+ * US/Canada postal code validation
928
+ * Accepts: 12345, 12345-6789, A1A 1A1, A1A1A1
929
+ */
930
+ declare const postalCodeSchema: any;
931
+ /**
932
+ * Password strength validation
933
+ * Requires: min 8 chars, 1 uppercase, 1 lowercase, 1 number
934
+ */
935
+ declare const passwordSchema: any;
936
+ /**
937
+ * URL validation schema
938
+ */
939
+ declare const urlSchema: any;
940
+ /**
941
+ * Credit card number validation (Luhn algorithm)
942
+ */
943
+ declare const creditCardSchema: any;
944
+ /**
945
+ * File upload schema with type and size validation
946
+ * @param acceptedTypes - MIME types (e.g., ['image/jpeg', 'image/png'])
947
+ * @param maxSizeMB - Maximum file size in megabytes
948
+ */
949
+ declare function fileSchema(acceptedTypes: string[], maxSizeMB: number): any;
950
+ /**
951
+ * Image file schema (JPEG, PNG, WebP)
952
+ * @param maxSizeMB - Maximum file size in megabytes (default: 5)
953
+ */
954
+ declare function imageSchema(maxSizeMB?: number): any;
955
+ /**
956
+ * Required string field (non-empty)
957
+ */
958
+ declare const requiredString: any;
959
+ /**
960
+ * Optional string field (empty string converted to undefined)
961
+ */
962
+ declare const optionalString: any;
963
+ /**
964
+ * Numeric string (e.g., for phone inputs)
965
+ */
966
+ declare const numericString: any;
967
+ /**
968
+ * Date string in ISO format
969
+ */
970
+ declare const dateString: any;
971
+ /**
972
+ * Checkbox boolean (must be true)
973
+ * Useful for "I agree to terms" checkboxes
974
+ */
975
+ declare const mustBeTrue: any;
976
+
977
+ declare const formErrorMessages: {
978
+ readonly required: {
979
+ readonly en: "This field is required";
980
+ readonly fr: "Ce champ est obligatoire";
981
+ };
982
+ readonly email: {
983
+ readonly en: "Please enter a valid email address";
984
+ readonly fr: "Veuillez entrer une adresse e-mail valide";
985
+ };
986
+ readonly phone: {
987
+ readonly en: "Please enter a valid phone number";
988
+ readonly fr: "Veuillez entrer un numéro de téléphone valide";
989
+ };
990
+ readonly url: {
991
+ readonly en: "Please enter a valid URL";
992
+ readonly fr: "Veuillez entrer une URL valide";
993
+ };
994
+ readonly password: {
995
+ readonly tooShort: {
996
+ readonly en: "Password must be at least 8 characters";
997
+ readonly fr: "Le mot de passe doit contenir au moins 8 caractères";
998
+ };
999
+ readonly noUppercase: {
1000
+ readonly en: "Password must contain at least one uppercase letter";
1001
+ readonly fr: "Le mot de passe doit contenir au moins une lettre majuscule";
1002
+ };
1003
+ readonly noLowercase: {
1004
+ readonly en: "Password must contain at least one lowercase letter";
1005
+ readonly fr: "Le mot de passe doit contenir au moins une lettre minuscule";
1006
+ };
1007
+ readonly noNumber: {
1008
+ readonly en: "Password must contain at least one number";
1009
+ readonly fr: "Le mot de passe doit contenir au moins un chiffre";
1010
+ };
1011
+ };
1012
+ readonly postalCode: {
1013
+ readonly en: "Invalid postal code";
1014
+ readonly fr: "Code postal invalide";
1015
+ };
1016
+ readonly creditCard: {
1017
+ readonly en: "Invalid credit card number";
1018
+ readonly fr: "Numéro de carte de crédit invalide";
1019
+ };
1020
+ readonly file: {
1021
+ readonly tooLarge: {
1022
+ readonly en: (maxSize: number) => string;
1023
+ readonly fr: (maxSize: number) => string;
1024
+ };
1025
+ readonly invalidType: {
1026
+ readonly en: (types: string[]) => string;
1027
+ readonly fr: (types: string[]) => string;
1028
+ };
1029
+ };
1030
+ readonly mustAccept: {
1031
+ readonly en: "You must accept to continue";
1032
+ readonly fr: "Vous devez accepter pour continuer";
1033
+ };
1034
+ readonly minLength: {
1035
+ readonly en: (min: number) => string;
1036
+ readonly fr: (min: number) => string;
1037
+ };
1038
+ readonly maxLength: {
1039
+ readonly en: (max: number) => string;
1040
+ readonly fr: (max: number) => string;
1041
+ };
1042
+ readonly min: {
1043
+ readonly en: (min: number) => string;
1044
+ readonly fr: (min: number) => string;
1045
+ };
1046
+ readonly max: {
1047
+ readonly en: (max: number) => string;
1048
+ readonly fr: (max: number) => string;
1049
+ };
1050
+ readonly invalidFormat: {
1051
+ readonly en: "Invalid format";
1052
+ readonly fr: "Format invalide";
1053
+ };
1054
+ };
1055
+ /**
1056
+ * Get localized error message
1057
+ * @param key - Error message key
1058
+ * @param locale - Current locale
1059
+ * @param params - Optional parameters for dynamic messages
1060
+ */
1061
+ declare function getErrorMessage(key: keyof typeof formErrorMessages, locale?: Locale, params?: any): string;
1062
+
1063
+ interface MetadataOptions {
1064
+ /** Page title */
1065
+ title: string;
1066
+ /** Page description */
1067
+ description: string;
1068
+ /** Canonical URL */
1069
+ url?: string;
1070
+ /** Open Graph image */
1071
+ image?: string;
1072
+ /** Image alt text */
1073
+ imageAlt?: string;
1074
+ /** Page type @default 'website' */
1075
+ type?: 'website' | 'article';
1076
+ /** Article specific metadata */
1077
+ article?: {
1078
+ publishedTime?: string;
1079
+ modifiedTime?: string;
1080
+ author?: string;
1081
+ tags?: string[];
1082
+ };
1083
+ /** Twitter card type @default 'summary_large_image' */
1084
+ twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player';
1085
+ /** Twitter handle (without @) */
1086
+ twitterSite?: string;
1087
+ /** Twitter creator handle (without @) */
1088
+ twitterCreator?: string;
1089
+ /** Locale @default 'en' */
1090
+ locale?: string;
1091
+ /** Alternate locales */
1092
+ alternateLocales?: string[];
1093
+ /** Site name */
1094
+ siteName?: string;
1095
+ /** Robots directives */
1096
+ robots?: {
1097
+ index?: boolean;
1098
+ follow?: boolean;
1099
+ googleBot?: {
1100
+ index?: boolean;
1101
+ follow?: boolean;
1102
+ };
1103
+ };
1104
+ /** Keywords */
1105
+ keywords?: string[];
1106
+ /** Author */
1107
+ author?: string;
1108
+ /** Additional metadata */
1109
+ other?: Record<string, string>;
1110
+ }
1111
+ /**
1112
+ * Generate Next.js metadata object for SEO
1113
+ *
1114
+ * Creates a complete Metadata object with Open Graph, Twitter Card,
1115
+ * and other SEO metadata. Compatible with Next.js 13+ App Router.
1116
+ *
1117
+ * @example
1118
+ * // In app/page.tsx
1119
+ * export const metadata = generateMetadata({
1120
+ * title: 'Home - My Company',
1121
+ * description: 'Leading provider of professional services',
1122
+ * url: 'https://example.com',
1123
+ * image: 'https://example.com/og-image.jpg',
1124
+ * siteName: 'My Company',
1125
+ * twitterSite: 'mycompany'
1126
+ * })
1127
+ *
1128
+ * @example
1129
+ * // Article page
1130
+ * export const metadata = generateMetadata({
1131
+ * title: 'Blog Post Title',
1132
+ * description: 'Article description...',
1133
+ * type: 'article',
1134
+ * article: {
1135
+ * publishedTime: '2024-01-15T00:00:00Z',
1136
+ * author: 'Jane Doe',
1137
+ * tags: ['JavaScript', 'React']
1138
+ * },
1139
+ * image: '/blog/post-image.jpg'
1140
+ * })
1141
+ *
1142
+ * @example
1143
+ * // With alternates for i18n
1144
+ * export const metadata = generateMetadata({
1145
+ * title: 'Welcome',
1146
+ * description: 'Description',
1147
+ * locale: 'en',
1148
+ * alternateLocales: ['fr', 'es'],
1149
+ * url: 'https://example.com'
1150
+ * })
1151
+ */
1152
+ declare function generateMetadata({ title, description, url, image, imageAlt, type, article, twitterCard, twitterSite, twitterCreator, locale, alternateLocales, siteName, robots, keywords, author, other }: MetadataOptions): Metadata;
1153
+ /**
1154
+ * Generate metadata for a blog post or article
1155
+ *
1156
+ * Specialized helper for article pages with publication metadata.
1157
+ *
1158
+ * @example
1159
+ * export const metadata = generateArticleMetadata({
1160
+ * title: 'My Blog Post',
1161
+ * description: 'Post description',
1162
+ * image: '/blog/post.jpg',
1163
+ * publishedTime: '2024-01-15T00:00:00Z',
1164
+ * author: 'Jane Doe',
1165
+ * tags: ['JavaScript', 'Web Development']
1166
+ * })
1167
+ */
1168
+ declare function generateArticleMetadata({ title, description, image, publishedTime, modifiedTime, author, tags, url, siteName, twitterSite }: {
1169
+ title: string;
1170
+ description: string;
1171
+ image?: string;
1172
+ publishedTime?: string;
1173
+ modifiedTime?: string;
1174
+ author?: string;
1175
+ tags?: string[];
1176
+ url?: string;
1177
+ siteName?: string;
1178
+ twitterSite?: string;
1179
+ }): Metadata;
1180
+
1181
+ /**
1182
+ * Base schema.org Thing type
1183
+ * @see https://schema.org/Thing
1184
+ */
1185
+ interface Thing {
1186
+ '@type': string;
1187
+ '@id'?: string;
1188
+ name?: string;
1189
+ description?: string;
1190
+ image?: string | string[];
1191
+ url?: string;
1192
+ [key: string]: unknown;
1193
+ }
1194
+ /**
1195
+ * Organization schema
1196
+ * @see https://schema.org/Organization
1197
+ */
1198
+ interface Organization extends Thing {
1199
+ '@type': 'Organization';
1200
+ name: string;
1201
+ url?: string;
1202
+ logo?: string;
1203
+ description?: string;
1204
+ email?: string;
1205
+ telephone?: string;
1206
+ address?: PostalAddress;
1207
+ sameAs?: string[];
1208
+ contactPoint?: ContactPoint[];
1209
+ foundingDate?: string;
1210
+ founders?: Person[];
1211
+ }
1212
+ /**
1213
+ * Postal address schema
1214
+ * @see https://schema.org/PostalAddress
1215
+ */
1216
+ interface PostalAddress extends Thing {
1217
+ '@type': 'PostalAddress';
1218
+ streetAddress?: string;
1219
+ addressLocality?: string;
1220
+ addressRegion?: string;
1221
+ postalCode?: string;
1222
+ addressCountry?: string;
1223
+ }
1224
+ /**
1225
+ * Contact point schema
1226
+ * @see https://schema.org/ContactPoint
1227
+ */
1228
+ interface ContactPoint extends Thing {
1229
+ '@type': 'ContactPoint';
1230
+ telephone?: string;
1231
+ email?: string;
1232
+ contactType?: string;
1233
+ availableLanguage?: string[];
1234
+ areaServed?: string[];
1235
+ }
1236
+ /**
1237
+ * Person schema
1238
+ * @see https://schema.org/Person
1239
+ */
1240
+ interface Person extends Thing {
1241
+ '@type': 'Person';
1242
+ name: string;
1243
+ email?: string;
1244
+ jobTitle?: string;
1245
+ image?: string;
1246
+ sameAs?: string[];
1247
+ url?: string;
1248
+ }
1249
+ /**
1250
+ * WebSite schema with search action
1251
+ * @see https://schema.org/WebSite
1252
+ */
1253
+ interface WebSite extends Thing {
1254
+ '@type': 'WebSite';
1255
+ name: string;
1256
+ url: string;
1257
+ description?: string;
1258
+ publisher?: Organization;
1259
+ potentialAction?: SearchAction;
1260
+ }
1261
+ /**
1262
+ * Search action for site search
1263
+ * @see https://schema.org/SearchAction
1264
+ */
1265
+ interface SearchAction {
1266
+ '@type': 'SearchAction';
1267
+ target: {
1268
+ '@type': 'EntryPoint';
1269
+ urlTemplate: string;
1270
+ };
1271
+ 'query-input': string;
1272
+ }
1273
+ /**
1274
+ * Product schema
1275
+ * @see https://schema.org/Product
1276
+ */
1277
+ interface Product extends Thing {
1278
+ '@type': 'Product' | 'SoftwareApplication';
1279
+ name: string;
1280
+ description?: string;
1281
+ image?: string | string[];
1282
+ brand?: Organization | string;
1283
+ offers?: Offer | Offer[];
1284
+ aggregateRating?: AggregateRating;
1285
+ review?: Review[];
1286
+ }
1287
+ /**
1288
+ * Offer schema for products/services
1289
+ * @see https://schema.org/Offer
1290
+ */
1291
+ interface Offer extends Thing {
1292
+ '@type': 'Offer';
1293
+ price: string | number;
1294
+ priceCurrency: string;
1295
+ priceValidUntil?: string;
1296
+ availability?: 'InStock' | 'OutOfStock' | 'PreOrder' | 'Discontinued';
1297
+ url?: string;
1298
+ seller?: Organization;
1299
+ }
1300
+ /**
1301
+ * Aggregate rating schema
1302
+ * @see https://schema.org/AggregateRating
1303
+ */
1304
+ interface AggregateRating extends Thing {
1305
+ '@type': 'AggregateRating';
1306
+ ratingValue: number | string;
1307
+ reviewCount?: number;
1308
+ bestRating?: number | string;
1309
+ worstRating?: number | string;
1310
+ }
1311
+ /**
1312
+ * Review schema
1313
+ * @see https://schema.org/Review
1314
+ */
1315
+ interface Review extends Thing {
1316
+ '@type': 'Review';
1317
+ author: Person | Organization | string;
1318
+ datePublished?: string;
1319
+ reviewBody?: string;
1320
+ reviewRating?: Rating;
1321
+ }
1322
+ /**
1323
+ * Rating schema
1324
+ * @see https://schema.org/Rating
1325
+ */
1326
+ interface Rating extends Thing {
1327
+ '@type': 'Rating';
1328
+ ratingValue: number | string;
1329
+ bestRating?: number | string;
1330
+ worstRating?: number | string;
1331
+ }
1332
+ /**
1333
+ * FAQ Page schema
1334
+ * @see https://schema.org/FAQPage
1335
+ */
1336
+ interface FAQPage extends Thing {
1337
+ '@type': 'FAQPage';
1338
+ mainEntity: Question[];
1339
+ }
1340
+ /**
1341
+ * Question schema for FAQ
1342
+ * @see https://schema.org/Question
1343
+ */
1344
+ interface Question extends Thing {
1345
+ '@type': 'Question';
1346
+ name: string;
1347
+ acceptedAnswer: Answer;
1348
+ }
1349
+ /**
1350
+ * Answer schema for FAQ
1351
+ * @see https://schema.org/Answer
1352
+ */
1353
+ interface Answer extends Thing {
1354
+ '@type': 'Answer';
1355
+ text: string;
1356
+ }
1357
+ /**
1358
+ * Article schema
1359
+ * @see https://schema.org/Article
1360
+ */
1361
+ interface Article extends Thing {
1362
+ '@type': 'Article' | 'BlogPosting' | 'NewsArticle';
1363
+ headline: string;
1364
+ description?: string;
1365
+ image?: string | string[];
1366
+ author: Person | Organization | string;
1367
+ publisher: Organization;
1368
+ datePublished: string;
1369
+ dateModified?: string;
1370
+ mainEntityOfPage?: string;
1371
+ }
1372
+ /**
1373
+ * Breadcrumb list schema
1374
+ * @see https://schema.org/BreadcrumbList
1375
+ */
1376
+ interface BreadcrumbList extends Thing {
1377
+ '@type': 'BreadcrumbList';
1378
+ itemListElement: ListItem[];
1379
+ }
1380
+ /**
1381
+ * List item for breadcrumbs
1382
+ * @see https://schema.org/ListItem
1383
+ */
1384
+ interface ListItem extends Thing {
1385
+ '@type': 'ListItem';
1386
+ position: number;
1387
+ name: string;
1388
+ item?: string;
1389
+ }
1390
+ /**
1391
+ * Create Organization structured data
1392
+ *
1393
+ * @example
1394
+ * ```tsx
1395
+ * const org = createOrganization({
1396
+ * name: 'Acme Inc',
1397
+ * url: 'https://acme.com',
1398
+ * logo: 'https://acme.com/logo.png',
1399
+ * sameAs: [
1400
+ * 'https://twitter.com/acme',
1401
+ * 'https://linkedin.com/company/acme'
1402
+ * ]
1403
+ * });
1404
+ * ```
1405
+ */
1406
+ declare function createOrganization(data: Omit<Organization, '@type'>): Organization;
1407
+ /**
1408
+ * Create WebSite structured data with search action
1409
+ *
1410
+ * @example
1411
+ * ```tsx
1412
+ * const website = createWebSite({
1413
+ * name: 'Acme',
1414
+ * url: 'https://acme.com',
1415
+ * searchUrlTemplate: 'https://acme.com/search?q={search_term_string}'
1416
+ * });
1417
+ * ```
1418
+ */
1419
+ declare function createWebSite(data: {
1420
+ name: string;
1421
+ url: string;
1422
+ description?: string;
1423
+ publisher?: Organization;
1424
+ searchUrlTemplate?: string;
1425
+ }): WebSite;
1426
+ /**
1427
+ * Create Product structured data
1428
+ *
1429
+ * @example
1430
+ * ```tsx
1431
+ * const product = createProduct({
1432
+ * name: 'Premium Email Plan',
1433
+ * description: 'Unlimited emails, advanced features',
1434
+ * image: 'https://acme.com/premium.jpg',
1435
+ * offers: {
1436
+ * price: '99.00',
1437
+ * priceCurrency: 'USD',
1438
+ * availability: 'InStock'
1439
+ * }
1440
+ * });
1441
+ * ```
1442
+ */
1443
+ declare function createProduct(data: Omit<Product, '@type'>): Product;
1444
+ /**
1445
+ * Create FAQ Page structured data
1446
+ *
1447
+ * @example
1448
+ * ```tsx
1449
+ * const faq = createFAQPage([
1450
+ * {
1451
+ * question: 'What is your refund policy?',
1452
+ * answer: 'We offer a 30-day money-back guarantee.'
1453
+ * },
1454
+ * {
1455
+ * question: 'Do you offer support?',
1456
+ * answer: 'Yes, 24/7 email and chat support is included.'
1457
+ * }
1458
+ * ]);
1459
+ * ```
1460
+ */
1461
+ declare function createFAQPage(faqs: Array<{
1462
+ question: string;
1463
+ answer: string;
1464
+ }>): FAQPage;
1465
+ /**
1466
+ * Create Article structured data
1467
+ *
1468
+ * @example
1469
+ * ```tsx
1470
+ * const article = createArticle({
1471
+ * headline: '10 Email Marketing Tips',
1472
+ * description: 'Learn how to improve your email campaigns',
1473
+ * author: { name: 'Jane Doe' },
1474
+ * publisher: {
1475
+ * name: 'Acme',
1476
+ * logo: 'https://acme.com/logo.png'
1477
+ * },
1478
+ * datePublished: '2024-01-15T10:00:00Z',
1479
+ * image: 'https://acme.com/blog/tips.jpg'
1480
+ * });
1481
+ * ```
1482
+ */
1483
+ declare function createArticle(data: {
1484
+ headline: string;
1485
+ description?: string;
1486
+ image?: string | string[];
1487
+ author: Person | string;
1488
+ publisher: Organization;
1489
+ datePublished: string;
1490
+ dateModified?: string;
1491
+ mainEntityOfPage?: string;
1492
+ type?: 'Article' | 'BlogPosting' | 'NewsArticle';
1493
+ }): Article;
1494
+ /**
1495
+ * Create Breadcrumb List structured data
1496
+ *
1497
+ * @example
1498
+ * ```tsx
1499
+ * const breadcrumbs = createBreadcrumbList([
1500
+ * { name: 'Home', url: 'https://acme.com' },
1501
+ * { name: 'Blog', url: 'https://acme.com/blog' },
1502
+ * { name: 'Email Tips', url: 'https://acme.com/blog/email-tips' }
1503
+ * ]);
1504
+ * ```
1505
+ */
1506
+ declare function createBreadcrumbList(items: Array<{
1507
+ name: string;
1508
+ url?: string;
1509
+ }>): BreadcrumbList;
1510
+ /**
1511
+ * Serialize structured data to JSON-LD string
1512
+ * Safe for use in script tags
1513
+ */
1514
+ declare function serializeStructuredData(data: Thing | Thing[]): string;
1515
+
1516
+ /**
1517
+ * Change frequency for sitemap entries
1518
+ * @see https://www.sitemaps.org/protocol.html
1519
+ */
1520
+ type ChangeFrequency = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
1521
+ /**
1522
+ * A single URL entry in the sitemap
1523
+ */
1524
+ interface SitemapEntry {
1525
+ /** Absolute URL of the page */
1526
+ url: string;
1527
+ /** Last modification date (ISO 8601 format) */
1528
+ lastModified?: string | Date;
1529
+ /** How frequently the page is likely to change */
1530
+ changeFrequency?: ChangeFrequency;
1531
+ /** Priority of this URL relative to other URLs (0.0 to 1.0) */
1532
+ priority?: number;
1533
+ /** Alternate language versions of this URL */
1534
+ alternates?: Array<{
1535
+ /** Language/locale code (e.g., 'en', 'fr', 'en-US') */
1536
+ hreflang: string;
1537
+ /** Absolute URL for this language version */
1538
+ href: string;
1539
+ }>;
1540
+ }
1541
+ /**
1542
+ * Configuration for sitemap generation
1543
+ */
1544
+ interface SitemapConfig {
1545
+ /** Base URL of the website (e.g., 'https://example.com') */
1546
+ baseUrl: string;
1547
+ /** Array of sitemap entries */
1548
+ entries: SitemapEntry[];
1549
+ /** Pretty print the XML output (default: false) */
1550
+ prettyPrint?: boolean;
1551
+ }
1552
+ /**
1553
+ * Generate XML sitemap from entries
1554
+ *
1555
+ * Creates a valid sitemap.xml following the sitemaps.org protocol with
1556
+ * support for multi-language pages using hreflang annotations.
1557
+ *
1558
+ * @param config - Sitemap configuration
1559
+ * @returns XML string for sitemap.xml
1560
+ *
1561
+ * @example Basic sitemap
1562
+ * ```tsx
1563
+ * const sitemap = generateSitemap({
1564
+ * baseUrl: 'https://example.com',
1565
+ * entries: [
1566
+ * { url: 'https://example.com', priority: 1.0, changeFrequency: 'weekly' },
1567
+ * { url: 'https://example.com/about', priority: 0.8 },
1568
+ * { url: 'https://example.com/products', priority: 0.9, changeFrequency: 'daily' }
1569
+ * ]
1570
+ * });
1571
+ * ```
1572
+ *
1573
+ * @example Multi-language sitemap
1574
+ * ```tsx
1575
+ * const sitemap = generateSitemap({
1576
+ * baseUrl: 'https://example.com',
1577
+ * entries: [
1578
+ * {
1579
+ * url: 'https://example.com/en/about',
1580
+ * alternates: [
1581
+ * { hreflang: 'en', href: 'https://example.com/en/about' },
1582
+ * { hreflang: 'fr', href: 'https://example.com/fr/about' },
1583
+ * { hreflang: 'x-default', href: 'https://example.com/en/about' }
1584
+ * ]
1585
+ * }
1586
+ * ]
1587
+ * });
1588
+ * ```
1589
+ */
1590
+ declare function generateSitemap(config: SitemapConfig): string;
1591
+ /**
1592
+ * Create sitemap entries for multi-language pages
1593
+ *
1594
+ * Helper to generate sitemap entries with proper hreflang annotations
1595
+ * for pages that exist in multiple languages.
1596
+ *
1597
+ * @param baseUrl - Base URL of the website
1598
+ * @param path - Page path without locale prefix (e.g., '/about')
1599
+ * @param locales - Array of locale codes (e.g., ['en', 'fr', 'es'])
1600
+ * @param defaultLocale - Default locale for x-default (optional)
1601
+ * @param options - Additional sitemap entry options
1602
+ * @returns Array of sitemap entries, one per locale
1603
+ *
1604
+ * @example
1605
+ * ```tsx
1606
+ * const entries = createMultiLanguageEntries(
1607
+ * 'https://example.com',
1608
+ * '/about',
1609
+ * ['en', 'fr', 'es'],
1610
+ * 'en',
1611
+ * { priority: 0.8, changeFrequency: 'monthly' }
1612
+ * );
1613
+ * // Creates entries for:
1614
+ * // - /en/about (with alternates to fr, es, x-default)
1615
+ * // - /fr/about (with alternates to en, es, x-default)
1616
+ * // - /es/about (with alternates to en, fr, x-default)
1617
+ * ```
1618
+ */
1619
+ declare function createMultiLanguageEntries(baseUrl: string, path: string, locales: string[], defaultLocale?: string, options?: Partial<Omit<SitemapEntry, 'url' | 'alternates'>>): SitemapEntry[];
1620
+ /**
1621
+ * Create a single-language sitemap entry
1622
+ *
1623
+ * @param baseUrl - Base URL of the website
1624
+ * @param path - Page path (e.g., '/about')
1625
+ * @param options - Sitemap entry options
1626
+ * @returns Sitemap entry
1627
+ *
1628
+ * @example
1629
+ * ```tsx
1630
+ * const entry = createSitemapEntry(
1631
+ * 'https://example.com',
1632
+ * '/about',
1633
+ * { priority: 0.8, changeFrequency: 'monthly' }
1634
+ * );
1635
+ * ```
1636
+ */
1637
+ declare function createSitemapEntry(baseUrl: string, path: string, options?: Partial<Omit<SitemapEntry, 'url'>>): SitemapEntry;
1638
+ /**
1639
+ * Validate sitemap entry
1640
+ *
1641
+ * Checks for common issues in sitemap entries.
1642
+ *
1643
+ * @param entry - Sitemap entry to validate
1644
+ * @returns Array of error messages (empty if valid)
1645
+ */
1646
+ declare function validateSitemapEntry(entry: SitemapEntry): string[];
1647
+ /**
1648
+ * Validate entire sitemap configuration
1649
+ *
1650
+ * @param config - Sitemap configuration to validate
1651
+ * @returns Object with isValid flag and array of errors
1652
+ */
1653
+ declare function validateSitemap(config: SitemapConfig): {
1654
+ isValid: boolean;
1655
+ errors: Array<{
1656
+ entry?: SitemapEntry;
1657
+ messages: string[];
1658
+ }>;
1659
+ };
1660
+
1661
+ interface TrackedLinkProps {
1662
+ href: string;
1663
+ children: React.ReactNode;
1664
+ className?: string;
1665
+ trackingType?: 'cta' | 'navigation' | 'outbound' | 'auto';
1666
+ ctaLocation?: string;
1667
+ ctaType?: 'signup' | 'trial' | 'contact' | 'download' | 'other';
1668
+ navLocation?: 'header' | 'footer' | 'content' | 'mobile';
1669
+ onClick?: () => void;
1670
+ [key: string]: unknown;
1671
+ }
1672
+ /**
1673
+ * Link component with built-in analytics tracking
1674
+ * Automatically determines tracking type if set to 'auto'
1675
+ */
1676
+ declare function TrackedLink({ href, children, className, trackingType, ctaLocation, ctaType, navLocation, onClick, ...props }: TrackedLinkProps): react_jsx_runtime.JSX.Element;
1677
+
1678
+ interface Feature {
1679
+ id: string;
1680
+ icon?: ReactNode;
1681
+ name: string;
1682
+ description: string;
1683
+ benefits?: string[];
1684
+ useCases?: string[];
1685
+ learnMoreHref?: string;
1686
+ }
1687
+ interface FeatureCategory {
1688
+ id: string;
1689
+ name: string;
1690
+ description: string;
1691
+ features: Feature[];
1692
+ }
1693
+ interface FeaturesGridProps {
1694
+ categories: FeatureCategory[];
1695
+ className?: string;
1696
+ locale?: 'fr' | 'en';
1697
+ }
1698
+ declare function FeaturesGrid({ categories, className, locale }: FeaturesGridProps): react_jsx_runtime.JSX.Element;
1699
+
1700
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
1701
+ /**
1702
+ * Visual variant of the button
1703
+ * - outlined: Rounded with border (primary brand style)
1704
+ * - filled: Solid background with shadow
1705
+ * - text: Text-only button without border
1706
+ * - ghost: Transparent background, visible on hover
1707
+ * - link: Styled like a link, but button semantics
1708
+ * - destructive: Red variant for delete/remove actions
1709
+ */
1710
+ variant?: 'outlined' | 'filled' | 'text' | 'ghost' | 'link' | 'destructive';
1711
+ /**
1712
+ * Size of the button
1713
+ */
1714
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
1715
+ /**
1716
+ * Full width button
1717
+ */
1718
+ fullWidth?: boolean;
1719
+ /**
1720
+ * Loading state - shows spinner and disables button
1721
+ */
1722
+ loading?: boolean;
1723
+ /**
1724
+ * Custom text to show during loading
1725
+ */
1726
+ loadingText?: string;
1727
+ /**
1728
+ * Success state - shows checkmark animation
1729
+ */
1730
+ success?: boolean;
1731
+ /**
1732
+ * Custom text to show during success
1733
+ */
1734
+ successText?: string;
1735
+ /**
1736
+ * Duration to show success state before reverting (ms)
1737
+ */
1738
+ successDuration?: number;
1739
+ /**
1740
+ * Icon element to display
1741
+ */
1742
+ icon?: ReactNode;
1743
+ /**
1744
+ * Position of the icon
1745
+ */
1746
+ iconPosition?: 'left' | 'right';
1747
+ /**
1748
+ * Icon-only button (no text)
1749
+ */
1750
+ iconOnly?: boolean;
1751
+ /**
1752
+ * Tooltip text to show when button is disabled
1753
+ */
1754
+ disabledTooltip?: string;
1755
+ /**
1756
+ * Enable ripple effect on click
1757
+ */
1758
+ ripple?: boolean;
1759
+ /**
1760
+ * Analytics event name to track on click
1761
+ * Automatically tracks button clicks with this event name
1762
+ */
1763
+ trackingEvent?: string;
1764
+ /**
1765
+ * Additional properties to send with tracking event
1766
+ * Merged with automatic button properties (variant, text, href)
1767
+ */
1768
+ trackingProps?: Record<string, unknown>;
1769
+ /**
1770
+ * Link href (for navigation buttons)
1771
+ */
1772
+ href?: string;
1773
+ }
1774
+
1775
+ interface CardProps extends HTMLAttributes<HTMLDivElement> {
1776
+ /**
1777
+ * Padding variant
1778
+ */
1779
+ padding?: 'none' | 'sm' | 'md' | 'lg';
1780
+ /**
1781
+ * Whether to show a border
1782
+ */
1783
+ bordered?: boolean;
1784
+ /**
1785
+ * Whether to show a shadow
1786
+ */
1787
+ shadow?: boolean;
1788
+ }
1789
+
1790
+ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
1791
+ /**
1792
+ * Label text for the input
1793
+ */
1794
+ label?: string;
1795
+ /**
1796
+ * Error message to display
1797
+ */
1798
+ error?: string;
1799
+ /**
1800
+ * Helper text to display below input
1801
+ */
1802
+ helperText?: string;
1803
+ /**
1804
+ * Full width input
1805
+ */
1806
+ fullWidth?: boolean;
1807
+ }
1808
+
1809
+ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
1810
+ /**
1811
+ * Label text for the textarea
1812
+ */
1813
+ label?: string;
1814
+ /**
1815
+ * Error message to display
1816
+ */
1817
+ error?: string;
1818
+ /**
1819
+ * Helper text to display below textarea
1820
+ */
1821
+ helperText?: string;
1822
+ /**
1823
+ * Full width textarea
1824
+ */
1825
+ fullWidth?: boolean;
1826
+ }
1827
+
1828
+ interface BreadcrumbItem {
1829
+ label: string;
1830
+ href?: string;
1831
+ }
1832
+ interface BreadcrumbProps {
1833
+ items: BreadcrumbItem[];
1834
+ className?: string;
1835
+ }
1836
+
1837
+ 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';
1838
+ interface CustomBadge {
1839
+ type: 'custom';
1840
+ image: string;
1841
+ alt: string;
1842
+ tooltip?: string;
1843
+ }
1844
+ type Badge = BadgeType | CustomBadge;
1845
+
1846
+ interface HeroAnimations {
1847
+ /** Animation type for headline */
1848
+ headline?: 'fadeInUp' | 'fadeIn' | 'slideInLeft' | 'none';
1849
+ /** Animation type for CTA buttons */
1850
+ cta?: 'fadeInUp' | 'fadeIn' | 'none';
1851
+ /** Stagger delay between elements (seconds) */
1852
+ stagger?: number;
1853
+ /** Show scroll indicator */
1854
+ scrollIndicator?: boolean;
1855
+ }
1856
+ interface HeroSectionProps {
1857
+ locale: Locale;
1858
+ content: HeroContent;
1859
+ /** Animation configuration */
1860
+ animations?: HeroAnimations;
1861
+ /** Show sticky CTA after scrolling past hero */
1862
+ stickyCtaAfterScroll?: boolean;
1863
+ /** Trust badges to display */
1864
+ trustBadges?: Badge[];
1865
+ /** Background effect variant */
1866
+ backgroundEffect?: 'none' | 'particles' | 'gradient-shift' | 'mesh';
1867
+ }
1868
+
1869
+ interface OfficeHours {
1870
+ monday?: {
1871
+ open: string;
1872
+ close: string;
1873
+ };
1874
+ tuesday?: {
1875
+ open: string;
1876
+ close: string;
1877
+ };
1878
+ wednesday?: {
1879
+ open: string;
1880
+ close: string;
1881
+ };
1882
+ thursday?: {
1883
+ open: string;
1884
+ close: string;
1885
+ };
1886
+ friday?: {
1887
+ open: string;
1888
+ close: string;
1889
+ };
1890
+ saturday?: {
1891
+ open: string;
1892
+ close: string;
1893
+ };
1894
+ sunday?: {
1895
+ open: string;
1896
+ close: string;
1897
+ };
1898
+ }
1899
+ interface Location {
1900
+ name: LocalizedString | string;
1901
+ address: string;
1902
+ phone?: string;
1903
+ email?: string;
1904
+ hours?: OfficeHours;
1905
+ coordinates?: {
1906
+ lat: number;
1907
+ lng: number;
1908
+ };
1909
+ }
1910
+ interface MapConfig {
1911
+ provider?: 'google' | 'static' | 'link';
1912
+ apiKey?: string;
1913
+ zoom?: number;
1914
+ }
1915
+ interface SpamProtection {
1916
+ honeypot?: boolean;
1917
+ recaptcha?: string;
1918
+ }
1919
+ interface FormIntegration {
1920
+ type: 'sendgrid' | 'mailgun' | 'webhook' | 'custom';
1921
+ config: Record<string, any>;
1922
+ }
1923
+ interface ContactFormConfig {
1924
+ enabled?: boolean;
1925
+ fields?: Array<'name' | 'email' | 'phone' | 'subject' | 'message' | 'attachment'>;
1926
+ requiredFields?: Array<'name' | 'email' | 'phone' | 'subject' | 'message'>;
1927
+ onSubmit?: (data: ContactFormData) => Promise<void>;
1928
+ spamProtection?: SpamProtection;
1929
+ integration?: FormIntegration;
1930
+ }
1931
+ interface ContactSectionProps {
1932
+ locale: Locale;
1933
+ title?: LocalizedString | string;
1934
+ description?: LocalizedString | string;
1935
+ form?: ContactFormConfig;
1936
+ locations?: Location[];
1937
+ defaultLocation?: number;
1938
+ map?: MapConfig;
1939
+ showMap?: boolean;
1940
+ showInfo?: boolean;
1941
+ timezone?: string;
1942
+ showStatus?: boolean;
1943
+ className?: string;
1944
+ }
1945
+ interface ContactFormData {
1946
+ name: string;
1947
+ email: string;
1948
+ phone?: string;
1949
+ subject?: string;
1950
+ message: string;
1951
+ attachment?: File;
1952
+ _honeypot?: string;
1953
+ }
1954
+
1955
+ interface AboutSectionProps {
1956
+ locale: Locale;
1957
+ content: AboutContent;
1958
+ }
1959
+
1960
+ interface ServicesSectionProps {
1961
+ locale: Locale;
1962
+ content: ServicesContent;
1963
+ }
1964
+
1965
+ interface TestimonialContent {
1966
+ quote: {
1967
+ [locale: string]: string;
1968
+ };
1969
+ author?: {
1970
+ [locale: string]: string;
1971
+ };
1972
+ role?: {
1973
+ [locale: string]: string;
1974
+ };
1975
+ company?: {
1976
+ [locale: string]: string;
1977
+ };
1978
+ }
1979
+ interface TestimonialSectionProps {
1980
+ locale: Locale;
1981
+ content: TestimonialContent;
1982
+ }
1983
+
1984
+ interface ServicePageLayoutProps {
1985
+ locale: Locale;
1986
+ title: string;
1987
+ description: string;
1988
+ children?: ReactNode;
1989
+ breadcrumbItems: BreadcrumbItem[];
1990
+ showCTA?: boolean;
1991
+ }
1992
+
1993
+ interface HeaderProps {
1994
+ locale: Locale;
1995
+ config: HeaderConfig;
1996
+ }
1997
+
1998
+ interface FooterProps {
1999
+ locale: Locale;
2000
+ config: FooterConfig;
2001
+ }
2002
+
2003
+ interface LanguageSwitcherProps {
2004
+ currentLocale: string;
2005
+ className?: string;
2006
+ customSlugTranslations?: SlugTranslations;
2007
+ }
2008
+
2009
+ interface SkipLinkProps {
2010
+ /** Target element ID to skip to (e.g., "main-content") */
2011
+ href: string;
2012
+ /** Link text */
2013
+ children: ReactNode;
2014
+ /** Additional CSS classes */
2015
+ className?: string;
2016
+ }
2017
+
2018
+ type AnnouncementPriority = 'polite' | 'assertive';
2019
+ interface A11yAnnouncerProps {
2020
+ /** Announcement message */
2021
+ message?: string;
2022
+ /** Priority level - 'polite' waits for pause, 'assertive' interrupts */
2023
+ priority?: AnnouncementPriority;
2024
+ /** Clear message after this many milliseconds */
2025
+ clearAfter?: number;
2026
+ }
2027
+
2028
+ type IconName = string;
2029
+ interface IconProps extends Omit<LucideProps, 'ref'> {
2030
+ /** Icon name from Lucide React */
2031
+ name: IconName;
2032
+ /** Icon size in pixels @default 24 */
2033
+ size?: number;
2034
+ /** Additional CSS classes */
2035
+ className?: string;
2036
+ }
2037
+
2038
+ interface CodeBlockProps {
2039
+ /** Code to display */
2040
+ code: string;
2041
+ /** Language for syntax highlighting @default 'tsx' */
2042
+ language?: string;
2043
+ /** Show line numbers @default false */
2044
+ showLineNumbers?: boolean;
2045
+ /** Show copy button @default true */
2046
+ showCopy?: boolean;
2047
+ /** Additional CSS classes */
2048
+ className?: string;
2049
+ }
2050
+
2051
+ interface LazySectionProps {
2052
+ /** Component to lazy load */
2053
+ component: () => Promise<{
2054
+ default: ComponentType<any>;
2055
+ }>;
2056
+ /** Props to pass to the lazy component */
2057
+ componentProps?: Record<string, any>;
2058
+ /** Custom loading component */
2059
+ fallback?: ReactNode;
2060
+ /** Load when in viewport @default true */
2061
+ loadOnView?: boolean;
2062
+ /** Viewport intersection threshold @default 0.1 */
2063
+ threshold?: number;
2064
+ /** Additional CSS classes */
2065
+ className?: string;
2066
+ }
2067
+
2068
+ interface FormFieldProps {
2069
+ /** Field label text */
2070
+ label?: string;
2071
+ /** Field name (matches form schema) */
2072
+ name: string;
2073
+ /** Error object from React Hook Form */
2074
+ error?: FieldError;
2075
+ /** Optional hint text shown below input */
2076
+ hint?: string;
2077
+ /** Whether field is required */
2078
+ required?: boolean;
2079
+ /** Input element to render */
2080
+ children: ReactNode;
2081
+ /** Additional CSS classes */
2082
+ className?: string;
2083
+ }
2084
+
2085
+ type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
2086
+ interface ModalProps {
2087
+ /** Whether modal is open */
2088
+ open: boolean;
2089
+ /** Callback when open state changes */
2090
+ onOpenChange: (open: boolean) => void;
2091
+ /** Modal title */
2092
+ title?: string;
2093
+ /** Modal description */
2094
+ description?: string;
2095
+ /** Modal size @default 'md' */
2096
+ size?: ModalSize;
2097
+ /** Modal content */
2098
+ children: ReactNode;
2099
+ /** Whether clicking backdrop closes modal @default true */
2100
+ closeOnBackdrop?: boolean;
2101
+ /** Whether ESC key closes modal @default true */
2102
+ closeOnEscape?: boolean;
2103
+ }
2104
+
2105
+ interface Tab {
2106
+ /** Unique tab identifier */
2107
+ value: string;
2108
+ /** Tab label (bilingual) */
2109
+ label: LocalizedString | string;
2110
+ /** Tab content */
2111
+ content: ReactNode;
2112
+ /** Disabled state */
2113
+ disabled?: boolean;
2114
+ }
2115
+ interface TabsProps {
2116
+ /** Current locale */
2117
+ locale?: 'en' | 'fr';
2118
+ /** Array of tabs */
2119
+ tabs: Tab[];
2120
+ /** Default active tab value */
2121
+ defaultValue?: string;
2122
+ /** Controlled active tab value */
2123
+ value?: string;
2124
+ /** Callback when tab changes */
2125
+ onValueChange?: (value: string) => void;
2126
+ /** Sync active tab with URL query param @default false */
2127
+ syncWithUrl?: boolean;
2128
+ /** URL query param name @default 'tab' */
2129
+ urlParam?: string;
2130
+ /** Tab variant @default 'underline' */
2131
+ variant?: 'underline' | 'pills' | 'bordered';
2132
+ /** Tab orientation @default 'horizontal' */
2133
+ orientation?: 'horizontal' | 'vertical';
2134
+ /** Additional CSS classes */
2135
+ className?: string;
2136
+ }
2137
+
2138
+ interface SelectOption {
2139
+ value: string;
2140
+ label: string;
2141
+ disabled?: boolean;
2142
+ }
2143
+ interface SelectOptionGroup {
2144
+ label: string;
2145
+ options: SelectOption[];
2146
+ }
2147
+ interface SelectProps {
2148
+ /** Options to display */
2149
+ options: SelectOption[] | SelectOptionGroup[];
2150
+ /** Selected value */
2151
+ value?: string;
2152
+ /** Callback when value changes */
2153
+ onValueChange?: (value: string) => void;
2154
+ /** Placeholder text */
2155
+ placeholder?: string;
2156
+ /** Whether select is disabled */
2157
+ disabled?: boolean;
2158
+ /** Additional CSS classes */
2159
+ className?: string;
2160
+ }
2161
+
2162
+ interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'size'> {
2163
+ /** Checkbox label */
2164
+ label?: string;
2165
+ /** Description text below label */
2166
+ description?: string;
2167
+ /** Error message */
2168
+ error?: string;
2169
+ /** Size variant @default 'md' */
2170
+ size?: 'sm' | 'md' | 'lg';
2171
+ }
2172
+
2173
+ interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'size'> {
2174
+ /** Radio label */
2175
+ label?: string;
2176
+ /** Description text below label */
2177
+ description?: string;
2178
+ /** Error message */
2179
+ error?: string;
2180
+ /** Size variant @default 'md' */
2181
+ size?: 'sm' | 'md' | 'lg';
2182
+ }
2183
+
2184
+ export { type A11yAnnouncerProps, type ABTestEvent, AboutContent, type AboutSectionProps, type AggregateRating, type AnalyticsEvent, type AnnouncementPriority, type Answer, type Article, type BreadcrumbItem, type BreadcrumbList, type BreadcrumbProps, type ButtonProps, type CTAClickEvent, type CTAType, type CardProps, type ChangeFrequency, type CheckboxProps, type CodeBlockProps, type ContactFormConfig, type ContactFormData, type ContactPoint, type ContactSectionProps, type ConversionEvent, type ConversionType, type EventCategory, type FAQPage, type Feature, type FeatureAction, type FeatureCategory, type FeatureEvent, FeaturesGrid, FooterConfig, type FooterProps, type FormAction, type FormEvent, type FormFieldProps, HeaderConfig, type HeaderProps, type HeroAnimations, HeroContent, type HeroSectionProps, type I18nConfig, type IconName, type IconProps, type InputProps, LOCALE_COOKIE_NAME, type LanguagePreference, type LanguageSwitcherProps, type LazySectionProps, type ListItem, type Locale, type LocaleCookieConfig, type LocalePrefix, LocalizedString, type Location, type MetadataOptions, type ModalProps, type NavigationEvent, type NavigationLocation, type Offer, type Organization, type PageViewEvent, type Person, type Policy, type PolicyMetadata, type PostalAddress, type PricingAction, type PricingEvent, type Product, type Question, type RadioProps, type Rating, type Review, type ScrollDepth, type ScrollDepthEvent, type SearchAction, type SelectProps, type ServicePageLayoutProps, ServicesContent, type ServicesSectionProps, type SitemapConfig, type SitemapEntry, type SkipLinkProps, type SlugTranslations, type TabsProps, type TestimonialSectionProps, type TextareaProps, ThemeConfig, type Thing, TrackedLink, type ValidLocale, type VideoAction, type VideoEvent, type WebSite, cn, createArticle, createBreadcrumbList, createFAQPage, createI18nMiddleware, createMultiLanguageEntries, createOrganization, createProduct, createSitemapEntry, createWebSite, creditCardSchema, dateString, defaultLocale, defaultSlugTranslations, emailSchema, fileSchema, formErrorMessages, formatCurrency, formatDate, formatDateRange, formatFileSize, formatList, formatLocaleDisplay, formatNumber, formatRelativeTime, generateArticleMetadata, generateDesignTokens, generateMetadata, generateSitemap, generateThemeCSS, getAllPolicies, getAlternateLocales, getDefaultLocale, getErrorMessage, getFontConfig, getFontVariables, getI18nConfig, getLocaleAutonym, getLocaleCookieConfig, getLocaleFromCookie, getLocaleLabel, getLocaleLabels, getLocaleName, getLocaleNames, getLocalePrefix, getLocales, getLocalizedString, getNavigationString, getPolicyLocales, getPolicySlugs, getRelativeTime, getRtlLocales, getTextDirection, imageSchema, isI18nConfigInitialized, isLocaleDetectionEnabled, isRtlLocale, isSupportedLocale, loadPolicy, locales, matchLocale, mustBeTrue, normalizeLocale, numericString, optionalString, passwordSchema, phoneSchema, postalCodeSchema, replaceVariables, requiredString, serializeStructuredData, setI18nConfig, setLocaleCookie, trackABTestEvent, trackCTAClick, trackConversion, trackError, trackEvent, trackFeatureEngagement, trackFormEvent, trackNavigation, trackOutboundLink, trackPageView, trackPricingEvent, trackResourceDownload, trackScrollDepth, trackSearch, trackVideoEvent, translateSlug, urlSchema, validateLocale, validateSitemap, validateSitemapEntry };