@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,159 @@
|
|
|
1
|
+
# WCAG 2.1 AA Compliance Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist when building sites with the Simple Site Framework to ensure WCAG 2.1 Level AA compliance.
|
|
4
|
+
|
|
5
|
+
## Perceivable
|
|
6
|
+
|
|
7
|
+
### Text Alternatives (1.1)
|
|
8
|
+
- [ ] All images have alt text
|
|
9
|
+
- [ ] Decorative images use empty alt (`alt=""`)
|
|
10
|
+
- [ ] Icon-only buttons have `aria-label`
|
|
11
|
+
- [ ] Form inputs have associated labels
|
|
12
|
+
|
|
13
|
+
### Time-based Media (1.2)
|
|
14
|
+
- [ ] Videos have captions
|
|
15
|
+
- [ ] Audio content has transcripts
|
|
16
|
+
- [ ] Video-only content has audio description or transcript
|
|
17
|
+
|
|
18
|
+
### Adaptable (1.3)
|
|
19
|
+
- [ ] Use semantic HTML elements (`<button>`, `<nav>`, `<main>`, etc.)
|
|
20
|
+
- [ ] Heading hierarchy is logical (h1 → h2 → h3)
|
|
21
|
+
- [ ] Lists use `<ul>`, `<ol>`, `<li>` elements
|
|
22
|
+
- [ ] Tables have proper headers (`<th>`)
|
|
23
|
+
- [ ] Form labels are programmatically associated
|
|
24
|
+
|
|
25
|
+
### Distinguishable (1.4)
|
|
26
|
+
- [ ] Color is not the only means of conveying information
|
|
27
|
+
- [ ] Text contrast is at least 4.5:1 (3:1 for large text)
|
|
28
|
+
- [ ] UI component contrast is at least 3:1
|
|
29
|
+
- [ ] Text can be resized to 200% without loss of functionality
|
|
30
|
+
- [ ] No background audio that can't be paused
|
|
31
|
+
- [ ] Line height is at least 1.5x font size
|
|
32
|
+
- [ ] Paragraph spacing is at least 2x font size
|
|
33
|
+
|
|
34
|
+
## Operable
|
|
35
|
+
|
|
36
|
+
### Keyboard Accessible (2.1)
|
|
37
|
+
- [ ] All functionality available via keyboard
|
|
38
|
+
- [ ] No keyboard traps
|
|
39
|
+
- [ ] Keyboard shortcuts don't conflict with assistive tech
|
|
40
|
+
- [ ] Tab order is logical
|
|
41
|
+
- [ ] Focus is visible on all interactive elements
|
|
42
|
+
|
|
43
|
+
### Enough Time (2.2)
|
|
44
|
+
- [ ] Time limits can be extended or disabled
|
|
45
|
+
- [ ] Auto-updating content can be paused
|
|
46
|
+
- [ ] Session timeouts are announced in advance
|
|
47
|
+
|
|
48
|
+
### Seizures and Physical Reactions (2.3)
|
|
49
|
+
- [ ] No content flashes more than 3 times per second
|
|
50
|
+
- [ ] Parallax and motion can be disabled via `prefers-reduced-motion`
|
|
51
|
+
|
|
52
|
+
### Navigable (2.4)
|
|
53
|
+
- [ ] Skip link to main content
|
|
54
|
+
- [ ] Page titles are descriptive
|
|
55
|
+
- [ ] Focus order is meaningful
|
|
56
|
+
- [ ] Link text describes destination
|
|
57
|
+
- [ ] Multiple ways to find pages (menu, search, sitemap)
|
|
58
|
+
- [ ] Headings and labels are descriptive
|
|
59
|
+
- [ ] Focus is visible
|
|
60
|
+
|
|
61
|
+
### Input Modalities (2.5)
|
|
62
|
+
- [ ] Touch targets are at least 44x44px
|
|
63
|
+
- [ ] Gestures have keyboard alternatives
|
|
64
|
+
- [ ] Click events don't fire on touch down
|
|
65
|
+
- [ ] Labels match accessible names
|
|
66
|
+
|
|
67
|
+
## Understandable
|
|
68
|
+
|
|
69
|
+
### Readable (3.1)
|
|
70
|
+
- [ ] Page language is declared (`lang="en"`)
|
|
71
|
+
- [ ] Language changes are marked (`lang="fr"`)
|
|
72
|
+
|
|
73
|
+
### Predictable (3.2)
|
|
74
|
+
- [ ] Focus doesn't trigger unexpected context changes
|
|
75
|
+
- [ ] Input doesn't cause unexpected context changes
|
|
76
|
+
- [ ] Navigation is consistent across pages
|
|
77
|
+
- [ ] Components with same functionality have consistent labels
|
|
78
|
+
|
|
79
|
+
### Input Assistance (3.3)
|
|
80
|
+
- [ ] Form errors are clearly identified
|
|
81
|
+
- [ ] Labels or instructions provided for input
|
|
82
|
+
- [ ] Error messages suggest corrections
|
|
83
|
+
- [ ] Errors can be corrected before final submission
|
|
84
|
+
- [ ] Confirmation for legal/financial transactions
|
|
85
|
+
|
|
86
|
+
## Robust
|
|
87
|
+
|
|
88
|
+
### Compatible (4.1)
|
|
89
|
+
- [ ] Valid HTML (no duplicate IDs)
|
|
90
|
+
- [ ] Start and end tags are properly nested
|
|
91
|
+
- [ ] ARIA attributes are valid
|
|
92
|
+
- [ ] Status messages use `role="status"` or `aria-live`
|
|
93
|
+
|
|
94
|
+
## Framework-Specific Checks
|
|
95
|
+
|
|
96
|
+
### Components
|
|
97
|
+
- [ ] Use framework components instead of custom elements
|
|
98
|
+
- [ ] Pass `aria-label` to icon-only buttons
|
|
99
|
+
- [ ] Enable `prefers-reduced-motion` support in animations
|
|
100
|
+
- [ ] Use `Toast` for announcements, not console.log
|
|
101
|
+
- [ ] Use `Modal` component's built-in focus trap
|
|
102
|
+
|
|
103
|
+
### Theme
|
|
104
|
+
- [ ] Color palette meets contrast requirements
|
|
105
|
+
- [ ] Focus ring is visible and high-contrast
|
|
106
|
+
- [ ] Error/success states use more than just color
|
|
107
|
+
|
|
108
|
+
### Forms
|
|
109
|
+
- [ ] Use `FormField` component for consistent labels
|
|
110
|
+
- [ ] Use `error` prop to display validation messages
|
|
111
|
+
- [ ] Mark required fields with `required` prop
|
|
112
|
+
- [ ] Group related inputs with `fieldset` and `legend`
|
|
113
|
+
|
|
114
|
+
## Testing Process
|
|
115
|
+
|
|
116
|
+
1. **Automated Testing**
|
|
117
|
+
- Use Lighthouse audit
|
|
118
|
+
- Run axe DevTools browser extension
|
|
119
|
+
- Integrate axe-core in test suite
|
|
120
|
+
|
|
121
|
+
2. **Manual Testing**
|
|
122
|
+
- Navigate entire site with keyboard only
|
|
123
|
+
- Test with screen reader (NVDA, VoiceOver, JAWS)
|
|
124
|
+
- Zoom to 200% and verify layout
|
|
125
|
+
- Test with high contrast mode
|
|
126
|
+
- Verify with `prefers-reduced-motion` enabled
|
|
127
|
+
|
|
128
|
+
3. **User Testing**
|
|
129
|
+
- Test with users who use assistive technology
|
|
130
|
+
- Get feedback from people with disabilities
|
|
131
|
+
|
|
132
|
+
## Common Issues to Avoid
|
|
133
|
+
|
|
134
|
+
❌ **Don't**
|
|
135
|
+
- Use `div` or `span` as buttons
|
|
136
|
+
- Rely on color alone for status
|
|
137
|
+
- Hide focus indicators
|
|
138
|
+
- Use low-contrast colors
|
|
139
|
+
- Autoplay videos with sound
|
|
140
|
+
- Create keyboard traps
|
|
141
|
+
- Use tiny touch targets
|
|
142
|
+
- Skip heading levels
|
|
143
|
+
|
|
144
|
+
✅ **Do**
|
|
145
|
+
- Use semantic HTML
|
|
146
|
+
- Provide text alternatives
|
|
147
|
+
- Make interactive elements keyboard accessible
|
|
148
|
+
- Ensure sufficient color contrast
|
|
149
|
+
- Support prefers-reduced-motion
|
|
150
|
+
- Test with assistive technology
|
|
151
|
+
- Follow ARIA best practices
|
|
152
|
+
- Keep it simple
|
|
153
|
+
|
|
154
|
+
## Resources
|
|
155
|
+
|
|
156
|
+
- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/)
|
|
157
|
+
- [Framework Component Guides](./components/)
|
|
158
|
+
- [Keyboard Navigation Guide](./keyboard-navigation.md)
|
|
159
|
+
- [Screen Reader Testing](./screen-readers.md)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# API Reference - Component Discovery Index
|
|
2
|
+
|
|
3
|
+
Quick reference for all 35+ framework components with their key capabilities.
|
|
4
|
+
|
|
5
|
+
## Layout Components (6)
|
|
6
|
+
|
|
7
|
+
| Component | Purpose | Key Features |
|
|
8
|
+
|-----------|---------|--------------|
|
|
9
|
+
| `Header` | Site header with navigation | Mobile menu, language switcher, sticky header, logo display |
|
|
10
|
+
| `Footer` | Site footer | Multi-column layout, social links, copyright, newsletter |
|
|
11
|
+
| `LanguageSwitcher` | Language toggle | French/English switching with flags |
|
|
12
|
+
| `PageLayout` | Standard page wrapper | Consistent spacing, responsive containers |
|
|
13
|
+
| `ServicePageLayout` | Service detail pages | Hero, content sections, sidebar CTA |
|
|
14
|
+
| `LazySection` | Lazy-loading wrapper | Intersection observer, loading states, performance optimization |
|
|
15
|
+
|
|
16
|
+
## Section Components (15)
|
|
17
|
+
|
|
18
|
+
| Component | Purpose | Key Features |
|
|
19
|
+
|-----------|---------|--------------|
|
|
20
|
+
| `HeroSection` | Above-fold hero banner | **Animations** (fadeInUp, slideInLeft), **sticky CTA**, **video backgrounds**, **parallax**, **trust badges**, scroll indicator |
|
|
21
|
+
| `AboutSection` | Company/service overview | Rich content, timeline, team grid, image gallery |
|
|
22
|
+
| `ServicesSection` | Service offerings grid | Hover effects, filtering, card layouts |
|
|
23
|
+
| `FeaturesGrid` | Feature showcase | Icons, descriptions, grid/list layouts |
|
|
24
|
+
| `TestimonialsSection` | Customer testimonials | Ratings, rotation, avatar display |
|
|
25
|
+
| `FAQSection` | Frequently asked questions | **Searchable**, **expandable accordion**, categories |
|
|
26
|
+
| `TeamSection` | Team member profiles | Bios, photos, social links, grid layout |
|
|
27
|
+
| `ContactSection` | Contact form and info | **Full form validation**, **multiple locations**, **maps**, **office hours**, file uploads, spam protection |
|
|
28
|
+
| `CTASection` | Call-to-action prompts | Banner, split, card variants |
|
|
29
|
+
| `WhyChooseUsSection` | Differentiators | Icon + text grid, visual emphasis |
|
|
30
|
+
| `SecurePortalSection` | Secure portal CTA | Login link, security badges |
|
|
31
|
+
| `PersonalTaxesSection` | Service-specific CTA | Tax service promotion |
|
|
32
|
+
| `RecruitingSection` | Recruitment CTA | Job listings link, company culture |
|
|
33
|
+
| `PricingSection` | Pricing tables | Feature comparison, highlights, CTAs |
|
|
34
|
+
| `StatsSection` | Statistics showcase | Counter animations, grid layout |
|
|
35
|
+
| `LogosSection` | Client/partner logos | Responsive grid, grayscale/color variants |
|
|
36
|
+
| `TimelineSection` | Company/process timeline | Vertical timeline with milestones |
|
|
37
|
+
| `ProcessSection` | Step-by-step process | Numbered steps, visual flow |
|
|
38
|
+
|
|
39
|
+
## UI Components (14)
|
|
40
|
+
|
|
41
|
+
| Component | Purpose | Key Features |
|
|
42
|
+
|-----------|---------|--------------|
|
|
43
|
+
| `Button` | Action buttons | **6 variants** (outlined, filled, text, ghost, link, destructive), **5 sizes**, **loading/success states**, **icons**, **ripple effect**, **tooltips** |
|
|
44
|
+
| `Card` | Content containers | Variants, hover effects, flexible layout |
|
|
45
|
+
| `Badge` | Status/category indicators | Color variants, sizes |
|
|
46
|
+
| `Icon` | Type-safe icons | **1000+ Lucide icons**, autocomplete, presets |
|
|
47
|
+
| `Input` | Text input fields | Validation states, labels, errors |
|
|
48
|
+
| `Textarea` | Multi-line text input | Auto-resize, character count |
|
|
49
|
+
| `Select` | Dropdown selection | Radix UI powered, keyboard navigation |
|
|
50
|
+
| `Checkbox` | Boolean input | Indeterminate state, labels |
|
|
51
|
+
| `Radio` | Single choice input | Radio groups, labels |
|
|
52
|
+
| `FormField` | Form field wrapper | Label, error display, required indicator |
|
|
53
|
+
| `Breadcrumb` | Breadcrumb navigation | Auto-generated from route, custom items |
|
|
54
|
+
| `Tabs` | Tab navigation | Radix UI powered, keyboard accessible |
|
|
55
|
+
| `Accordion` | Collapsible content | Radix UI powered, single/multiple open |
|
|
56
|
+
| `Dialog` | Modal dialogs | Radix UI powered, focus trap, backdrop |
|
|
57
|
+
| `Tooltip` | Hover tooltips | Radix UI powered, positioning |
|
|
58
|
+
| `Toast` | Toast notifications | Success, error, info variants |
|
|
59
|
+
|
|
60
|
+
## Development Tools (4)
|
|
61
|
+
|
|
62
|
+
| Component | Purpose | Key Features |
|
|
63
|
+
|-----------|---------|--------------|
|
|
64
|
+
| `StyleGuide` | Interactive brand reference | **All colors**, **typography**, **components**, **spacing**, perfect for design reviews |
|
|
65
|
+
| `CodeBlock` | Syntax-highlighted code | **Copy button**, line numbers, 100+ languages |
|
|
66
|
+
| `ComponentDemo` | Live component previews | Code + preview, interactive examples |
|
|
67
|
+
| `HeadScripts` | Document head injection | Meta tags, structured data, scripts |
|
|
68
|
+
| `BodyEndScripts` | Body end injection | Analytics, chat widgets, deferred scripts |
|
|
69
|
+
|
|
70
|
+
## Key Type Exports
|
|
71
|
+
|
|
72
|
+
### Component Props
|
|
73
|
+
- `ButtonProps` - Enhanced button configuration (loading, success, icons, ripple)
|
|
74
|
+
- `HeroSectionProps` - Hero configuration including animations
|
|
75
|
+
- `ContactSectionProps` - Contact form and location configuration
|
|
76
|
+
- `IconProps` - Icon component props with type-safe names
|
|
77
|
+
|
|
78
|
+
### Configuration Types
|
|
79
|
+
- `ThemeConfig` - Complete theme configuration
|
|
80
|
+
- `SiteContent` - Site content structure
|
|
81
|
+
- `NavigationConfig` - Header/footer navigation
|
|
82
|
+
- `LocalizedString` - Bilingual text (`{ fr: string, en: string }`)
|
|
83
|
+
|
|
84
|
+
### Feature-Specific Types
|
|
85
|
+
- `HeroAnimations` - Animation configuration for hero section
|
|
86
|
+
```typescript
|
|
87
|
+
{
|
|
88
|
+
headline?: 'fadeInUp' | 'fadeIn' | 'slideInLeft' | 'none'
|
|
89
|
+
cta?: 'fadeInUp' | 'fadeIn' | 'none'
|
|
90
|
+
stagger?: number
|
|
91
|
+
scrollIndicator?: boolean
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- `ContactFormConfig` - Form field and validation configuration
|
|
96
|
+
```typescript
|
|
97
|
+
{
|
|
98
|
+
enabled?: boolean
|
|
99
|
+
fields?: Array<'name' | 'email' | 'phone' | 'subject' | 'message' | 'attachment'>
|
|
100
|
+
requiredFields?: Array<'name' | 'email' | 'phone' | 'subject' | 'message'>
|
|
101
|
+
onSubmit?: (data: ContactFormData) => Promise<void>
|
|
102
|
+
spamProtection?: SpamProtection
|
|
103
|
+
integration?: FormIntegration
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- `Badge` - Trust badge/logo configuration
|
|
108
|
+
- `Location` - Office location with maps and hours
|
|
109
|
+
- `FormIntegration` - Third-party form integrations (email services, CRMs)
|
|
110
|
+
|
|
111
|
+
## Utility Functions
|
|
112
|
+
|
|
113
|
+
| Function | Purpose | Example |
|
|
114
|
+
|----------|---------|---------|
|
|
115
|
+
| `getLocalizedString(str, locale)` | Get text for current locale | `getLocalizedString(content.title, 'fr')` |
|
|
116
|
+
| `cn(...classes)` | Merge Tailwind classes | `cn('px-4', 'py-2', className)` |
|
|
117
|
+
| `generateThemeCSS(theme)` | Generate CSS variables | Used internally by framework |
|
|
118
|
+
|
|
119
|
+
## Import Patterns
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// Components
|
|
123
|
+
import { HeroSection, Button, Icon } from '@zoyth/simple-site-framework'
|
|
124
|
+
|
|
125
|
+
// Types
|
|
126
|
+
import type { HeroAnimations, ContactFormConfig } from '@zoyth/simple-site-framework'
|
|
127
|
+
|
|
128
|
+
// Utilities
|
|
129
|
+
import { getLocalizedString, cn } from '@zoyth/simple-site-framework'
|
|
130
|
+
|
|
131
|
+
// Icon presets
|
|
132
|
+
import { Icons } from '@zoyth/simple-site-framework'
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Most Commonly Used Components
|
|
136
|
+
|
|
137
|
+
For a typical professional services site:
|
|
138
|
+
|
|
139
|
+
1. **HeroSection** - with animations and sticky CTA
|
|
140
|
+
2. **ServicesSection** - showcase offerings
|
|
141
|
+
3. **ContactSection** - with working form
|
|
142
|
+
4. **AboutSection** - company story
|
|
143
|
+
5. **TestimonialsSection** - social proof
|
|
144
|
+
6. **FAQSection** - answer common questions
|
|
145
|
+
7. **Button** - CTAs throughout
|
|
146
|
+
8. **Icon** - visual elements
|
|
147
|
+
|
|
148
|
+
## Advanced Features to Explore
|
|
149
|
+
|
|
150
|
+
- **Button loading/success states** - Automatic state management for forms
|
|
151
|
+
- **Hero sticky CTA** - CTA button that appears on scroll
|
|
152
|
+
- **Hero animations** - Coordinated entrance animations
|
|
153
|
+
- **Contact multi-location** - Support multiple offices with maps
|
|
154
|
+
- **Icon type safety** - Autocomplete for 1000+ icons
|
|
155
|
+
- **LazySection** - Performance optimization for below-fold content
|
|
156
|
+
- **StyleGuide** - Interactive brand reference for stakeholders
|
|
157
|
+
|
|
158
|
+
## Next Steps
|
|
159
|
+
|
|
160
|
+
- See **[Full API Reference](./components/)** for detailed prop documentation (coming soon - issue #46)
|
|
161
|
+
- See **[Examples](../examples/)** for usage patterns (coming soon - issue #46)
|
|
162
|
+
- See **[Recipes](../recipes/)** for common patterns (coming soon - issue #46)
|
|
163
|
+
- See **[README.md](../../README.md)** for quick start guide
|
|
164
|
+
- See **[QUICKSTART.md](../../QUICKSTART.md)** for step-by-step tutorial
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# Accessibility Components & Hooks
|
|
2
|
+
|
|
3
|
+
Comprehensive accessibility utilities for building WCAG 2.1 AA compliant applications.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
### SkipLink
|
|
8
|
+
|
|
9
|
+
Allows keyboard users to skip repetitive navigation and jump directly to main content.
|
|
10
|
+
|
|
11
|
+
#### Import
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { SkipLink } from '@zoyth/simple-site-framework'
|
|
15
|
+
import type { SkipLinkProps } from '@zoyth/simple-site-framework'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
#### Props
|
|
19
|
+
|
|
20
|
+
| Prop | Type | Required | Description |
|
|
21
|
+
|------|------|----------|-------------|
|
|
22
|
+
| `href` | `string` | ✅ | Target element ID (e.g., "#main-content") |
|
|
23
|
+
| `children` | `ReactNode` | ✅ | Link text |
|
|
24
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
25
|
+
|
|
26
|
+
#### Usage
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
// In your layout, before header
|
|
30
|
+
<SkipLink href="#main-content">
|
|
31
|
+
Skip to main content
|
|
32
|
+
</SkipLink>
|
|
33
|
+
|
|
34
|
+
// In your main content area
|
|
35
|
+
<main id="main-content" tabIndex={-1}>
|
|
36
|
+
{/* Your content */}
|
|
37
|
+
</main>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The link is hidden by default and appears only when focused with Tab key.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### A11yAnnouncer
|
|
45
|
+
|
|
46
|
+
Screen reader announcement component for dynamic content changes.
|
|
47
|
+
|
|
48
|
+
#### Import
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { A11yAnnouncer, GlobalA11yAnnouncer } from '@zoyth/simple-site-framework'
|
|
52
|
+
import type { A11yAnnouncerProps, AnnouncementPriority } from '@zoyth/simple-site-framework'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
#### Props
|
|
56
|
+
|
|
57
|
+
| Prop | Type | Default | Description |
|
|
58
|
+
|------|------|---------|-------------|
|
|
59
|
+
| `message` | `string` | - | Message to announce |
|
|
60
|
+
| `priority` | `'polite' \| 'assertive'` | `'polite'` | Announcement priority |
|
|
61
|
+
| `clearAfter` | `number` | `3000` | Clear message after ms |
|
|
62
|
+
|
|
63
|
+
#### Priority Levels
|
|
64
|
+
|
|
65
|
+
- **polite**: Waits for user to pause before announcing (default)
|
|
66
|
+
- **assertive**: Interrupts screen reader immediately (use sparingly)
|
|
67
|
+
|
|
68
|
+
#### Local Announcer
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
const [message, setMessage] = useState('')
|
|
72
|
+
|
|
73
|
+
// Trigger announcement
|
|
74
|
+
<button onClick={() => setMessage('Item added to cart')}>
|
|
75
|
+
Add to Cart
|
|
76
|
+
</button>
|
|
77
|
+
|
|
78
|
+
// Announcer component
|
|
79
|
+
<A11yAnnouncer message={message} priority="polite" />
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Global Announcer
|
|
83
|
+
|
|
84
|
+
Place once in your root layout for app-wide announcements:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// app/layout.tsx
|
|
88
|
+
import { GlobalA11yAnnouncer } from '@zoyth/simple-site-framework'
|
|
89
|
+
|
|
90
|
+
export default function RootLayout({ children }) {
|
|
91
|
+
return (
|
|
92
|
+
<html>
|
|
93
|
+
<body>
|
|
94
|
+
<GlobalA11yAnnouncer />
|
|
95
|
+
{children}
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Then announce from anywhere:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { announce } from '@zoyth/simple-site-framework'
|
|
106
|
+
|
|
107
|
+
// Polite announcement
|
|
108
|
+
announce('Form submitted successfully', 'polite')
|
|
109
|
+
|
|
110
|
+
// Assertive announcement (errors, urgent)
|
|
111
|
+
announce('Error: Please fix the form errors', 'assertive')
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Hooks
|
|
115
|
+
|
|
116
|
+
### useA11y
|
|
117
|
+
|
|
118
|
+
Convenience hook for accessibility utilities.
|
|
119
|
+
|
|
120
|
+
#### Import
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { useA11y } from '@zoyth/simple-site-framework'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### Usage
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
function MyComponent() {
|
|
130
|
+
const { announce } = useA11y()
|
|
131
|
+
|
|
132
|
+
const handleSubmit = async () => {
|
|
133
|
+
await submitForm()
|
|
134
|
+
announce('Form submitted successfully!', 'polite')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return <button onClick={handleSubmit}>Submit</button>
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Requires `<GlobalA11yAnnouncer />` in your layout.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### useFocusTrap
|
|
146
|
+
|
|
147
|
+
Trap keyboard focus within a container (for modals, dialogs).
|
|
148
|
+
|
|
149
|
+
#### Import
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { useFocusTrap } from '@zoyth/simple-site-framework'
|
|
153
|
+
import type { UseFocusTrapOptions } from '@zoyth/simple-site-framework'
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Options
|
|
157
|
+
|
|
158
|
+
| Option | Type | Default | Description |
|
|
159
|
+
|--------|------|---------|-------------|
|
|
160
|
+
| `enabled` | `boolean` | `true` | Whether focus trap is active |
|
|
161
|
+
| `initialFocus` | `HTMLElement \| null` | - | Element to focus on activation |
|
|
162
|
+
| `allowTabEscape` | `boolean` | `false` | Allow Tab to escape the trap |
|
|
163
|
+
|
|
164
|
+
#### Usage
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
function Modal({ isOpen, onClose }) {
|
|
168
|
+
const modalRef = useRef<HTMLDivElement>(null)
|
|
169
|
+
|
|
170
|
+
useFocusTrap(modalRef, { enabled: isOpen })
|
|
171
|
+
|
|
172
|
+
if (!isOpen) return null
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<div ref={modalRef} role="dialog">
|
|
176
|
+
<h2>Modal Title</h2>
|
|
177
|
+
<button onClick={onClose}>Close</button>
|
|
178
|
+
<input type="text" />
|
|
179
|
+
</div>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Focus automatically moves to first focusable element and cycles within the modal.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### useFocusReturn
|
|
189
|
+
|
|
190
|
+
Return focus to previous element when component unmounts.
|
|
191
|
+
|
|
192
|
+
#### Import
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import { useFocusReturn } from '@zoyth/simple-site-framework'
|
|
196
|
+
import type { UseFocusReturnOptions } from '@zoyth/simple-site-framework'
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### Options
|
|
200
|
+
|
|
201
|
+
| Option | Type | Default | Description |
|
|
202
|
+
|--------|------|---------|-------------|
|
|
203
|
+
| `enabled` | `boolean` | `true` | Whether to return focus |
|
|
204
|
+
| `returnTo` | `HTMLElement \| null` | - | Custom element to focus |
|
|
205
|
+
|
|
206
|
+
#### Usage
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
function Modal({ isOpen, onClose }) {
|
|
210
|
+
useFocusReturn({ enabled: isOpen })
|
|
211
|
+
|
|
212
|
+
if (!isOpen) return null
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<div role="dialog">
|
|
216
|
+
<h2>Modal Title</h2>
|
|
217
|
+
<button onClick={onClose}>Close</button>
|
|
218
|
+
</div>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Focus returns to the element that triggered the modal when it closes.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### useModalFocus
|
|
228
|
+
|
|
229
|
+
Combined hook for complete modal focus management (trap + return).
|
|
230
|
+
|
|
231
|
+
#### Import
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { useModalFocus } from '@zoyth/simple-site-framework'
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### Usage
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
function Modal({ isOpen, onClose }) {
|
|
241
|
+
const modalRef = useRef<HTMLDivElement>(null)
|
|
242
|
+
|
|
243
|
+
useModalFocus(modalRef, { enabled: isOpen })
|
|
244
|
+
|
|
245
|
+
if (!isOpen) return null
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<div ref={modalRef} role="dialog">
|
|
249
|
+
<h2>Modal Title</h2>
|
|
250
|
+
<button onClick={onClose}>Close</button>
|
|
251
|
+
<input type="text" />
|
|
252
|
+
</div>
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Handles both focus trapping and focus return automatically.
|
|
258
|
+
|
|
259
|
+
## Complete Modal Example
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
import { useRef } from 'react'
|
|
263
|
+
import { useModalFocus, useA11y } from '@zoyth/simple-site-framework'
|
|
264
|
+
|
|
265
|
+
function DeleteConfirmModal({ isOpen, onClose, onConfirm }) {
|
|
266
|
+
const modalRef = useRef<HTMLDivElement>(null)
|
|
267
|
+
const { announce } = useA11y()
|
|
268
|
+
|
|
269
|
+
useModalFocus(modalRef, { enabled: isOpen })
|
|
270
|
+
|
|
271
|
+
const handleConfirm = () => {
|
|
272
|
+
onConfirm()
|
|
273
|
+
announce('Item deleted', 'polite')
|
|
274
|
+
onClose()
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!isOpen) return null
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<div
|
|
281
|
+
ref={modalRef}
|
|
282
|
+
role="dialog"
|
|
283
|
+
aria-labelledby="modal-title"
|
|
284
|
+
aria-modal="true"
|
|
285
|
+
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
|
286
|
+
>
|
|
287
|
+
<div className="bg-white p-6 rounded-lg max-w-md">
|
|
288
|
+
<h2 id="modal-title" className="text-xl font-bold mb-4">
|
|
289
|
+
Confirm Delete
|
|
290
|
+
</h2>
|
|
291
|
+
<p className="mb-6">
|
|
292
|
+
Are you sure you want to delete this item? This action cannot be undone.
|
|
293
|
+
</p>
|
|
294
|
+
<div className="flex gap-4">
|
|
295
|
+
<button
|
|
296
|
+
onClick={handleConfirm}
|
|
297
|
+
className="px-4 py-2 bg-red-600 text-white rounded"
|
|
298
|
+
>
|
|
299
|
+
Delete
|
|
300
|
+
</button>
|
|
301
|
+
<button
|
|
302
|
+
onClick={onClose}
|
|
303
|
+
className="px-4 py-2 bg-gray-200 rounded"
|
|
304
|
+
>
|
|
305
|
+
Cancel
|
|
306
|
+
</button>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
)
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Best Practices
|
|
315
|
+
|
|
316
|
+
### SkipLink
|
|
317
|
+
- Place before all other content (first element in body)
|
|
318
|
+
- Use clear, concise text ("Skip to main content")
|
|
319
|
+
- Target main content area with `id` attribute
|
|
320
|
+
- Make target focusable with `tabIndex={-1}`
|
|
321
|
+
|
|
322
|
+
### Announcements
|
|
323
|
+
- Use `'polite'` for most announcements
|
|
324
|
+
- Use `'assertive'` only for errors or urgent information
|
|
325
|
+
- Keep messages concise and clear
|
|
326
|
+
- Don't announce every tiny change
|
|
327
|
+
- Clear messages after a few seconds
|
|
328
|
+
|
|
329
|
+
### Focus Management
|
|
330
|
+
- Always trap focus in modals/dialogs
|
|
331
|
+
- Return focus when closing modals
|
|
332
|
+
- Focus first interactive element by default
|
|
333
|
+
- Provide visual focus indicators
|
|
334
|
+
- Test with keyboard only
|
|
335
|
+
|
|
336
|
+
### Testing
|
|
337
|
+
- Test with keyboard navigation (Tab, Shift+Tab)
|
|
338
|
+
- Test with screen readers (NVDA, VoiceOver, JAWS)
|
|
339
|
+
- Verify announcements are read correctly
|
|
340
|
+
- Ensure focus trap doesn't break navigation
|
|
341
|
+
- Check focus return works as expected
|
|
342
|
+
|
|
343
|
+
## Accessibility Checklist
|
|
344
|
+
|
|
345
|
+
When using these components:
|
|
346
|
+
|
|
347
|
+
- [ ] SkipLink is first element in document
|
|
348
|
+
- [ ] Main content has unique `id` attribute
|
|
349
|
+
- [ ] GlobalA11yAnnouncer in root layout
|
|
350
|
+
- [ ] Modals use focus trap
|
|
351
|
+
- [ ] Modals return focus on close
|
|
352
|
+
- [ ] Announcements use appropriate priority
|
|
353
|
+
- [ ] All interactive elements are keyboard accessible
|
|
354
|
+
- [ ] Focus indicators are visible
|
|
355
|
+
- [ ] Tested with keyboard only
|
|
356
|
+
- [ ] Tested with screen reader
|