@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,393 @@
1
+ # Recipe: Forms with Validation
2
+
3
+ Complete guide to building accessible forms with validation using React Hook Form and Zod.
4
+
5
+ ## Overview
6
+
7
+ This recipe shows how to:
8
+ - Create forms with React Hook Form
9
+ - Validate with Zod schemas
10
+ - Display error messages accessibly
11
+ - Handle loading and success states
12
+ - Announce form submission results
13
+
14
+ ## Prerequisites
15
+
16
+ ```bash
17
+ npm install react-hook-form @hookform/resolvers zod
18
+ ```
19
+
20
+ ## Basic Contact Form
21
+
22
+ ### 1. Define Zod Schema
23
+
24
+ ```typescript
25
+ import { z } from 'zod'
26
+
27
+ const contactSchema = z.object({
28
+ name: z.string().min(2, 'Name must be at least 2 characters'),
29
+ email: z.string().email('Invalid email address'),
30
+ message: z.string().min(10, 'Message must be at least 10 characters'),
31
+ })
32
+
33
+ type ContactFormData = z.infer<typeof contactSchema>
34
+ ```
35
+
36
+ ### 2. Create Form Component
37
+
38
+ ```tsx
39
+ import { useForm } from 'react-hook-form'
40
+ import { zodResolver } from '@hookform/resolvers/zod'
41
+ import { Button, FormField, useA11y } from '@zoyth/simple-site-framework'
42
+ import { useState } from 'react'
43
+
44
+ function ContactForm() {
45
+ const { announce } = useA11y()
46
+ const [isSubmitting, setIsSubmitting] = useState(false)
47
+ const [isSuccess, setIsSuccess] = useState(false)
48
+
49
+ const {
50
+ register,
51
+ handleSubmit,
52
+ formState: { errors },
53
+ reset,
54
+ } = useForm<ContactFormData>({
55
+ resolver: zodResolver(contactSchema),
56
+ })
57
+
58
+ const onSubmit = async (data: ContactFormData) => {
59
+ setIsSubmitting(true)
60
+
61
+ try {
62
+ await fetch('/api/contact', {
63
+ method: 'POST',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ body: JSON.stringify(data),
66
+ })
67
+
68
+ setIsSuccess(true)
69
+ announce('Message sent successfully!', 'polite')
70
+ reset()
71
+
72
+ setTimeout(() => setIsSuccess(false), 3000)
73
+ } catch (error) {
74
+ announce('Error sending message. Please try again.', 'assertive')
75
+ } finally {
76
+ setIsSubmitting(false)
77
+ }
78
+ }
79
+
80
+ return (
81
+ <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
82
+ <FormField
83
+ name="name"
84
+ label="Name"
85
+ error={errors.name}
86
+ required
87
+ >
88
+ <input
89
+ {...register('name')}
90
+ type="text"
91
+ className="w-full px-4 py-2 border rounded"
92
+ aria-invalid={errors.name ? 'true' : 'false'}
93
+ />
94
+ </FormField>
95
+
96
+ <FormField
97
+ name="email"
98
+ label="Email"
99
+ error={errors.email}
100
+ required
101
+ >
102
+ <input
103
+ {...register('email')}
104
+ type="email"
105
+ className="w-full px-4 py-2 border rounded"
106
+ aria-invalid={errors.email ? 'true' : 'false'}
107
+ />
108
+ </FormField>
109
+
110
+ <FormField
111
+ name="message"
112
+ label="Message"
113
+ error={errors.message}
114
+ required
115
+ >
116
+ <textarea
117
+ {...register('message')}
118
+ rows={4}
119
+ className="w-full px-4 py-2 border rounded"
120
+ aria-invalid={errors.message ? 'true' : 'false'}
121
+ />
122
+ </FormField>
123
+
124
+ <Button
125
+ type="submit"
126
+ variant="filled"
127
+ size="lg"
128
+ loading={isSubmitting}
129
+ loadingText="Sending..."
130
+ success={isSuccess}
131
+ successText="Sent!"
132
+ disabled={isSubmitting}
133
+ >
134
+ Send Message
135
+ </Button>
136
+ </form>
137
+ )
138
+ }
139
+ ```
140
+
141
+ ## Advanced: Multi-Step Form
142
+
143
+ ```tsx
144
+ import { useState } from 'react'
145
+ import { useForm } from 'react-hook-form'
146
+ import { zodResolver } from '@hookform/resolvers/zod'
147
+ import { z } from 'zod'
148
+ import { Button, FormField } from '@zoyth/simple-site-framework'
149
+
150
+ // Step schemas
151
+ const step1Schema = z.object({
152
+ name: z.string().min(2),
153
+ email: z.string().email(),
154
+ })
155
+
156
+ const step2Schema = z.object({
157
+ company: z.string().min(2),
158
+ role: z.string().min(2),
159
+ })
160
+
161
+ const step3Schema = z.object({
162
+ message: z.string().min(10),
163
+ })
164
+
165
+ // Combined schema
166
+ const fullSchema = step1Schema.merge(step2Schema).merge(step3Schema)
167
+ type FormData = z.infer<typeof fullSchema>
168
+
169
+ function MultiStepForm() {
170
+ const [step, setStep] = useState(1)
171
+
172
+ const {
173
+ register,
174
+ handleSubmit,
175
+ formState: { errors },
176
+ trigger,
177
+ } = useForm<FormData>({
178
+ resolver: zodResolver(fullSchema),
179
+ mode: 'onChange',
180
+ })
181
+
182
+ const nextStep = async () => {
183
+ let isValid = false
184
+
185
+ if (step === 1) {
186
+ isValid = await trigger(['name', 'email'])
187
+ } else if (step === 2) {
188
+ isValid = await trigger(['company', 'role'])
189
+ }
190
+
191
+ if (isValid) {
192
+ setStep(step + 1)
193
+ }
194
+ }
195
+
196
+ const onSubmit = async (data: FormData) => {
197
+ console.log('Form submitted:', data)
198
+ // Handle submission
199
+ }
200
+
201
+ return (
202
+ <form onSubmit={handleSubmit(onSubmit)}>
203
+ {/* Progress indicator */}
204
+ <div className="mb-8">
205
+ <div className="flex justify-between mb-2">
206
+ {[1, 2, 3].map((s) => (
207
+ <div
208
+ key={s}
209
+ className={`w-1/3 h-2 ${
210
+ s <= step ? 'bg-primary' : 'bg-gray-200'
211
+ }`}
212
+ />
213
+ ))}
214
+ </div>
215
+ <p className="text-sm text-gray-600">
216
+ Step {step} of 3
217
+ </p>
218
+ </div>
219
+
220
+ {/* Step 1: Personal Info */}
221
+ {step === 1 && (
222
+ <div className="space-y-6">
223
+ <FormField name="name" label="Name" error={errors.name} required>
224
+ <input {...register('name')} type="text" />
225
+ </FormField>
226
+
227
+ <FormField name="email" label="Email" error={errors.email} required>
228
+ <input {...register('email')} type="email" />
229
+ </FormField>
230
+
231
+ <Button onClick={nextStep} variant="filled">
232
+ Next
233
+ </Button>
234
+ </div>
235
+ )}
236
+
237
+ {/* Step 2: Company Info */}
238
+ {step === 2 && (
239
+ <div className="space-y-6">
240
+ <FormField name="company" label="Company" error={errors.company} required>
241
+ <input {...register('company')} type="text" />
242
+ </FormField>
243
+
244
+ <FormField name="role" label="Role" error={errors.role} required>
245
+ <input {...register('role')} type="text" />
246
+ </FormField>
247
+
248
+ <div className="flex gap-4">
249
+ <Button onClick={() => setStep(1)} variant="outlined">
250
+ Back
251
+ </Button>
252
+ <Button onClick={nextStep} variant="filled">
253
+ Next
254
+ </Button>
255
+ </div>
256
+ </div>
257
+ )}
258
+
259
+ {/* Step 3: Message */}
260
+ {step === 3 && (
261
+ <div className="space-y-6">
262
+ <FormField name="message" label="Message" error={errors.message} required>
263
+ <textarea {...register('message')} rows={4} />
264
+ </FormField>
265
+
266
+ <div className="flex gap-4">
267
+ <Button onClick={() => setStep(2)} variant="outlined">
268
+ Back
269
+ </Button>
270
+ <Button type="submit" variant="filled">
271
+ Submit
272
+ </Button>
273
+ </div>
274
+ </div>
275
+ )}
276
+ </form>
277
+ )
278
+ }
279
+ ```
280
+
281
+ ## Form with File Upload
282
+
283
+ ```tsx
284
+ import { useForm } from 'react-hook-form'
285
+ import { zodResolver } from '@hookform/resolvers/zod'
286
+ import { z } from 'zod'
287
+
288
+ const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB
289
+ const ACCEPTED_FILE_TYPES = ['image/jpeg', 'image/png', 'application/pdf']
290
+
291
+ const formSchema = z.object({
292
+ name: z.string().min(2),
293
+ file: z
294
+ .instanceof(FileList)
295
+ .refine((files) => files.length > 0, 'File is required')
296
+ .refine(
297
+ (files) => files[0]?.size <= MAX_FILE_SIZE,
298
+ 'File size must be less than 5MB'
299
+ )
300
+ .refine(
301
+ (files) => ACCEPTED_FILE_TYPES.includes(files[0]?.type),
302
+ 'Only .jpg, .png, and .pdf files are accepted'
303
+ ),
304
+ })
305
+
306
+ function FileUploadForm() {
307
+ const {
308
+ register,
309
+ handleSubmit,
310
+ formState: { errors },
311
+ } = useForm({
312
+ resolver: zodResolver(formSchema),
313
+ })
314
+
315
+ const onSubmit = async (data) => {
316
+ const formData = new FormData()
317
+ formData.append('name', data.name)
318
+ formData.append('file', data.file[0])
319
+
320
+ await fetch('/api/upload', {
321
+ method: 'POST',
322
+ body: formData,
323
+ })
324
+ }
325
+
326
+ return (
327
+ <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
328
+ <FormField name="name" label="Name" error={errors.name}>
329
+ <input {...register('name')} type="text" />
330
+ </FormField>
331
+
332
+ <FormField
333
+ name="file"
334
+ label="Upload File"
335
+ error={errors.file}
336
+ helpText="Max 5MB. Accepted: JPG, PNG, PDF"
337
+ >
338
+ <input {...register('file')} type="file" accept=".jpg,.png,.pdf" />
339
+ </FormField>
340
+
341
+ <Button type="submit" variant="filled">
342
+ Upload
343
+ </Button>
344
+ </form>
345
+ )
346
+ }
347
+ ```
348
+
349
+ ## Accessibility Checklist
350
+
351
+ - [ ] All fields have associated labels
352
+ - [ ] Required fields marked with `required` prop
353
+ - [ ] Error messages are descriptive and specific
354
+ - [ ] Errors announced to screen readers
355
+ - [ ] Success announced to screen readers
356
+ - [ ] Loading state disables submit button
357
+ - [ ] Form can be completed with keyboard only
358
+ - [ ] Focus indicators are visible
359
+ - [ ] Error fields receive focus
360
+ - [ ] Help text provides clear guidance
361
+
362
+ ## Best Practices
363
+
364
+ 1. **Validation**
365
+ - Validate on client and server
366
+ - Provide instant feedback
367
+ - Show errors after blur, not while typing
368
+ - Clear errors when fixed
369
+
370
+ 2. **Error Messages**
371
+ - Be specific about the problem
372
+ - Suggest how to fix it
373
+ - Use plain language
374
+ - Display near the field
375
+
376
+ 3. **Loading States**
377
+ - Disable submit during submission
378
+ - Show loading indicator
379
+ - Don't lose form data on error
380
+ - Provide feedback on success
381
+
382
+ 4. **Accessibility**
383
+ - Use semantic HTML (`<form>`, `<label>`, `<input>`)
384
+ - Link labels to inputs with `htmlFor`/`id`
385
+ - Use `aria-invalid` on error fields
386
+ - Announce success/error to screen readers
387
+ - Make form keyboard navigable
388
+
389
+ 5. **UX**
390
+ - Auto-focus first field
391
+ - Save progress for long forms
392
+ - Confirm before leaving with unsaved changes
393
+ - Provide clear submission feedback
package/package.json ADDED
@@ -0,0 +1,152 @@
1
+ {
2
+ "name": "@zoyth/simple-site-framework",
3
+ "version": "1.0.0",
4
+ "description": "A configuration-driven framework for building professional service websites",
5
+ "keywords": [
6
+ "framework",
7
+ "nextjs",
8
+ "react",
9
+ "website-builder",
10
+ "professional-services"
11
+ ],
12
+ "homepage": "https://github.com/zoyth/simple-site-framework#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/zoyth/simple-site-framework/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/zoyth/simple-site-framework.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "François Lane",
22
+ "type": "commonjs",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.mjs",
27
+ "require": "./dist/index.js"
28
+ },
29
+ "./components": {
30
+ "types": "./dist/components/index.d.ts",
31
+ "import": "./dist/components/index.mjs",
32
+ "require": "./dist/components/index.js"
33
+ },
34
+ "./config": {
35
+ "types": "./dist/config/index.d.ts",
36
+ "import": "./dist/config/index.mjs",
37
+ "require": "./dist/config/index.js"
38
+ },
39
+ "./lib/i18n": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/lib/i18n/index.mjs",
42
+ "require": "./dist/lib/i18n/index.js"
43
+ },
44
+ "./client": {
45
+ "types": "./dist/client.d.ts",
46
+ "import": "./dist/client.mjs",
47
+ "require": "./dist/client.js"
48
+ }
49
+ },
50
+ "main": "./dist/index.js",
51
+ "types": "./dist/index.d.ts",
52
+ "bin": {
53
+ "create-simple-site": "bin/create-simple-site.js",
54
+ "simple-site": "bin/simple-site.js"
55
+ },
56
+ "directories": {
57
+ "doc": "docs",
58
+ "example": "examples"
59
+ },
60
+ "files": [
61
+ "dist",
62
+ "bin",
63
+ "docs"
64
+ ],
65
+ "scripts": {
66
+ "build": "tsup",
67
+ "dev": "tsup --watch",
68
+ "typecheck": "tsc --noEmit",
69
+ "test": "vitest",
70
+ "test:ui": "vitest --ui",
71
+ "test:coverage": "vitest --coverage",
72
+ "lint": "eslint src/",
73
+ "lint:fix": "eslint src/ --fix",
74
+ "format": "prettier --write \"src/**/*.{ts,tsx}\"",
75
+ "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
76
+ "prepare": "npm run build"
77
+ },
78
+ "dependencies": {
79
+ "clsx": "^2.1.1",
80
+ "rehype-slug": "^6.0.0",
81
+ "tailwind-merge": "^3.4.0"
82
+ },
83
+ "devDependencies": {
84
+ "@eslint/js": "^9.39.2",
85
+ "@hookform/resolvers": "^3.9.1",
86
+ "@radix-ui/react-accordion": "^1.2.2",
87
+ "@radix-ui/react-dialog": "^1.1.4",
88
+ "@radix-ui/react-select": "^2.2.6",
89
+ "@radix-ui/react-tabs": "^1.1.13",
90
+ "@radix-ui/react-tooltip": "^1.2.8",
91
+ "@tailwindcss/typography": "^0.5.16",
92
+ "@testing-library/dom": "^10.4.1",
93
+ "@testing-library/jest-dom": "^6.9.1",
94
+ "@testing-library/react": "^16.3.2",
95
+ "@testing-library/user-event": "^14.6.1",
96
+ "@types/fs-extra": "^11.0.4",
97
+ "@types/inquirer": "^9.0.9",
98
+ "@types/node": "^20.11.5",
99
+ "@types/react": "^18.2.48",
100
+ "@types/react-dom": "^18.2.18",
101
+ "@types/react-syntax-highlighter": "^15.5.13",
102
+ "@typescript-eslint/eslint-plugin": "^8.54.0",
103
+ "@typescript-eslint/parser": "^8.54.0",
104
+ "@vitejs/plugin-react": "^5.1.2",
105
+ "chalk": "^5.6.2",
106
+ "commander": "^14.0.3",
107
+ "eslint": "^9.39.2",
108
+ "eslint-config-prettier": "^10.1.8",
109
+ "eslint-plugin-react": "^7.37.5",
110
+ "eslint-plugin-react-hooks": "^7.0.1",
111
+ "framer-motion": "^11.15.0",
112
+ "fs-extra": "^11.3.3",
113
+ "inquirer": "^13.2.2",
114
+ "jsdom": "^27.4.0",
115
+ "lucide-react": "^0.563.0",
116
+ "next": "^15.0.0",
117
+ "next-mdx-remote": "^5.0.0",
118
+ "ora": "^9.1.0",
119
+ "prettier": "^3.8.1",
120
+ "react": "^19.0.0",
121
+ "react-dom": "^19.0.0",
122
+ "react-hook-form": "^7.54.2",
123
+ "react-syntax-highlighter": "^16.1.0",
124
+ "tsup": "^8.0.1",
125
+ "typescript": "^5.3.3",
126
+ "vitest": "^4.0.18",
127
+ "zod": "^3.24.1"
128
+ },
129
+ "peerDependencies": {
130
+ "@hookform/resolvers": "^3.3.0",
131
+ "@radix-ui/react-accordion": "^1.1.0",
132
+ "@radix-ui/react-dialog": "^1.0.0",
133
+ "@radix-ui/react-select": "^2.0.0",
134
+ "@radix-ui/react-tabs": "^1.1.0",
135
+ "@radix-ui/react-tooltip": "^1.0.0",
136
+ "@tailwindcss/typography": "^0.5.0",
137
+ "framer-motion": "^11.0.0",
138
+ "lucide-react": "^0.300.0",
139
+ "next": "^14.0.0 || ^15.0.0 || ^16.0.0",
140
+ "next-mdx-remote": "^5.0.0",
141
+ "react": "^18.0.0 || ^19.0.0",
142
+ "react-dom": "^18.0.0 || ^19.0.0",
143
+ "react-hook-form": "^7.50.0",
144
+ "tailwindcss": "^3.4.0 || ^4.0.0",
145
+ "zod": "^3.22.0"
146
+ },
147
+ "publishConfig": {
148
+ "access": "public",
149
+ "registry": "https://registry.npmjs.org/"
150
+ },
151
+ "module": "./dist/index.mjs"
152
+ }