@stacksjs/components 0.2.92 → 0.2.94

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 (188) hide show
  1. package/dist/{Sidebar-yb115a2w.stx → Sidebar-4hn7vw4n.stx} +18 -0
  2. package/dist/index.js +5 -5
  3. package/package.json +5 -6
  4. package/src/components/CodeBlock.stx +0 -54
  5. package/src/components/Footer.stx +0 -66
  6. package/src/components/Hero.stx +0 -25
  7. package/src/components/Installation.stx +0 -37
  8. package/src/components/index.ts +0 -4
  9. package/src/composables/index.ts +0 -4
  10. package/src/composables/useCopyCode.ts +0 -73
  11. package/src/composables/useDarkMode.ts +0 -100
  12. package/src/composables/useSEO.ts +0 -230
  13. package/src/composables/utilities/index.ts +0 -7
  14. package/src/composables/utilities/useClickOutside.ts +0 -72
  15. package/src/composables/utilities/useFocusTrap.ts +0 -159
  16. package/src/composables/utilities/useKeyboard.ts +0 -124
  17. package/src/composables/utilities/useLocalStorage.ts +0 -132
  18. package/src/composables/utilities/useMediaQuery.ts +0 -118
  19. package/src/index.ts +0 -99
  20. package/src/stx.d.ts +0 -4
  21. package/src/ui/accordion/Accordion.stx +0 -146
  22. package/src/ui/accordion/AccordionItem.stx +0 -37
  23. package/src/ui/accordion/index.ts +0 -47
  24. package/src/ui/audio/Audio.stx +0 -50
  25. package/src/ui/audio/README.md +0 -41
  26. package/src/ui/audio/index.ts +0 -13
  27. package/src/ui/auth/Login.stx +0 -161
  28. package/src/ui/auth/README.md +0 -142
  29. package/src/ui/auth/Signup.stx +0 -159
  30. package/src/ui/auth/TwoFactorChallenge.stx +0 -111
  31. package/src/ui/auth/index.ts +0 -32
  32. package/src/ui/avatar/Avatar.stx +0 -77
  33. package/src/ui/avatar/index.ts +0 -12
  34. package/src/ui/badge/Badge.stx +0 -62
  35. package/src/ui/badge/index.ts +0 -10
  36. package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
  37. package/src/ui/breadcrumb/index.ts +0 -15
  38. package/src/ui/button/Button.stx +0 -74
  39. package/src/ui/button/README.md +0 -80
  40. package/src/ui/button/index.ts +0 -85
  41. package/src/ui/calendar/Calendar.stx +0 -189
  42. package/src/ui/calendar/README.md +0 -254
  43. package/src/ui/calendar/index.ts +0 -14
  44. package/src/ui/card/Card.stx +0 -68
  45. package/src/ui/card/index.ts +0 -13
  46. package/src/ui/checkbox/Checkbox.stx +0 -86
  47. package/src/ui/checkbox/index.ts +0 -16
  48. package/src/ui/combobox/Combobox.stx +0 -96
  49. package/src/ui/combobox/ComboboxButton.stx +0 -25
  50. package/src/ui/combobox/ComboboxInput.stx +0 -32
  51. package/src/ui/combobox/ComboboxOption.stx +0 -49
  52. package/src/ui/combobox/ComboboxOptions.stx +0 -16
  53. package/src/ui/combobox/README.md +0 -150
  54. package/src/ui/combobox/index.ts +0 -40
  55. package/src/ui/command-palette/CommandPalette.stx +0 -81
  56. package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
  57. package/src/ui/command-palette/README.md +0 -42
  58. package/src/ui/command-palette/index.ts +0 -15
  59. package/src/ui/dialog/Dialog.stx +0 -41
  60. package/src/ui/dialog/DialogBackdrop.stx +0 -9
  61. package/src/ui/dialog/DialogDescription.stx +0 -11
  62. package/src/ui/dialog/DialogPanel.stx +0 -16
  63. package/src/ui/dialog/DialogTitle.stx +0 -11
  64. package/src/ui/dialog/README.md +0 -121
  65. package/src/ui/dialog/index.ts +0 -32
  66. package/src/ui/drawer/Drawer.stx +0 -120
  67. package/src/ui/drawer/README.md +0 -90
  68. package/src/ui/drawer/index.ts +0 -9
  69. package/src/ui/dropdown/Dropdown.stx +0 -82
  70. package/src/ui/dropdown/DropdownButton.stx +0 -29
  71. package/src/ui/dropdown/DropdownItem.stx +0 -35
  72. package/src/ui/dropdown/DropdownItems.stx +0 -18
  73. package/src/ui/dropdown/README.md +0 -114
  74. package/src/ui/dropdown/index.ts +0 -29
  75. package/src/ui/form/Form.stx +0 -95
  76. package/src/ui/form/index.ts +0 -67
  77. package/src/ui/heatmap/Heatmap.stx +0 -294
  78. package/src/ui/image/Image.stx +0 -165
  79. package/src/ui/image/README.md +0 -164
  80. package/src/ui/image/index.ts +0 -22
  81. package/src/ui/input/EmailInput.stx +0 -30
  82. package/src/ui/input/NumberInput.stx +0 -126
  83. package/src/ui/input/PasswordInput.stx +0 -143
  84. package/src/ui/input/SearchInput.stx +0 -44
  85. package/src/ui/input/TextInput.stx +0 -132
  86. package/src/ui/input/index.ts +0 -180
  87. package/src/ui/listbox/Listbox.stx +0 -101
  88. package/src/ui/listbox/ListboxButton.stx +0 -28
  89. package/src/ui/listbox/ListboxLabel.stx +0 -11
  90. package/src/ui/listbox/ListboxOption.stx +0 -49
  91. package/src/ui/listbox/ListboxOptions.stx +0 -16
  92. package/src/ui/listbox/README.md +0 -135
  93. package/src/ui/listbox/index.ts +0 -39
  94. package/src/ui/navigator/Navigator.stx +0 -113
  95. package/src/ui/navigator/README.md +0 -352
  96. package/src/ui/navigator/index.ts +0 -20
  97. package/src/ui/notification/Notification.stx +0 -117
  98. package/src/ui/notification/README.md +0 -114
  99. package/src/ui/notification/index.ts +0 -12
  100. package/src/ui/pagination/Pagination.stx +0 -150
  101. package/src/ui/pagination/index.ts +0 -11
  102. package/src/ui/payment/Checkout.stx +0 -31
  103. package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
  104. package/src/ui/payment/PaymentMethods.stx +0 -104
  105. package/src/ui/payment/README.md +0 -345
  106. package/src/ui/payment/SubscriptionCheckout.stx +0 -323
  107. package/src/ui/payment/index.ts +0 -59
  108. package/src/ui/popover/Popover.stx +0 -60
  109. package/src/ui/popover/PopoverButton.stx +0 -29
  110. package/src/ui/popover/PopoverPanel.stx +0 -23
  111. package/src/ui/popover/README.md +0 -91
  112. package/src/ui/popover/index.ts +0 -22
  113. package/src/ui/portal/Portal.stx +0 -57
  114. package/src/ui/portal/index.ts +0 -6
  115. package/src/ui/progress/Progress.stx +0 -131
  116. package/src/ui/progress/index.ts +0 -12
  117. package/src/ui/radio/Radio.stx +0 -77
  118. package/src/ui/radio/index.ts +0 -15
  119. package/src/ui/radio-group/README.md +0 -139
  120. package/src/ui/radio-group/RadioGroup.stx +0 -60
  121. package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
  122. package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
  123. package/src/ui/radio-group/RadioGroupOption.stx +0 -58
  124. package/src/ui/radio-group/index.ts +0 -30
  125. package/src/ui/select/README.md +0 -180
  126. package/src/ui/select/Select.stx +0 -82
  127. package/src/ui/select/index.ts +0 -21
  128. package/src/ui/sidebar/Sidebar.stx +0 -458
  129. package/src/ui/sidebar/SidebarFooter.stx +0 -71
  130. package/src/ui/sidebar/SidebarHeader.stx +0 -103
  131. package/src/ui/sidebar/SidebarItem.stx +0 -86
  132. package/src/ui/sidebar/SidebarSection.stx +0 -83
  133. package/src/ui/sidebar/index.ts +0 -153
  134. package/src/ui/sidebar/themes.ts +0 -240
  135. package/src/ui/skeleton/Skeleton.stx +0 -48
  136. package/src/ui/skeleton/index.ts +0 -11
  137. package/src/ui/spinner/Spinner.stx +0 -109
  138. package/src/ui/spinner/index.ts +0 -9
  139. package/src/ui/stepper/README.md +0 -36
  140. package/src/ui/stepper/Stepper.stx +0 -17
  141. package/src/ui/stepper/StepperStep.stx +0 -57
  142. package/src/ui/stepper/index.ts +0 -19
  143. package/src/ui/storage/README.md +0 -193
  144. package/src/ui/storage/index.ts +0 -347
  145. package/src/ui/switch/README.md +0 -114
  146. package/src/ui/switch/Switch.stx +0 -72
  147. package/src/ui/switch/index.ts +0 -10
  148. package/src/ui/table/README.md +0 -39
  149. package/src/ui/table/Table.stx +0 -14
  150. package/src/ui/table/TableBody.stx +0 -10
  151. package/src/ui/table/TableCell.stx +0 -10
  152. package/src/ui/table/TableHead.stx +0 -10
  153. package/src/ui/table/TableHeader.stx +0 -20
  154. package/src/ui/table/TableRow.stx +0 -11
  155. package/src/ui/table/index.ts +0 -35
  156. package/src/ui/tabs/TabPanel.stx +0 -25
  157. package/src/ui/tabs/Tabs.stx +0 -202
  158. package/src/ui/tabs/index.ts +0 -50
  159. package/src/ui/teleport/Teleport.stx +0 -65
  160. package/src/ui/teleport/index.ts +0 -7
  161. package/src/ui/textarea/Textarea.stx +0 -108
  162. package/src/ui/textarea/index.ts +0 -20
  163. package/src/ui/tooltip/Tooltip.stx +0 -71
  164. package/src/ui/tooltip/index.ts +0 -10
  165. package/src/ui/transition/README.md +0 -30
  166. package/src/ui/transition/Transition.stx +0 -102
  167. package/src/ui/transition/index.ts +0 -25
  168. package/src/ui/video/README.md +0 -47
  169. package/src/ui/video/Video.stx +0 -45
  170. package/src/ui/video/index.ts +0 -16
  171. package/src/ui/virtual-list/VirtualList.stx +0 -67
  172. package/src/ui/virtual-list/index.ts +0 -10
  173. package/src/ui/virtual-table/VirtualTable.stx +0 -103
  174. package/src/ui/virtual-table/index.ts +0 -21
  175. package/src/utils/PROP_VALIDATION.md +0 -458
  176. package/src/utils/THEME_SYSTEM.md +0 -702
  177. package/src/utils/accessibility.ts +0 -841
  178. package/src/utils/animation/easing.ts +0 -368
  179. package/src/utils/animation/helpers.ts +0 -223
  180. package/src/utils/animation/index.ts +0 -5
  181. package/src/utils/animation/keyframes.ts +0 -230
  182. package/src/utils/error-handling.ts +0 -475
  183. package/src/utils/highlighter.ts +0 -93
  184. package/src/utils/i18n.ts +0 -634
  185. package/src/utils/keep-alive.ts +0 -819
  186. package/src/utils/lazy-loading.ts +0 -530
  187. package/src/utils/prop-validation.ts +0 -478
  188. package/src/utils/theme.ts +0 -626
@@ -1,478 +0,0 @@
1
- import process from 'node:process'
2
-
3
- /**
4
- * Runtime prop validation utilities for component development
5
- *
6
- * Provides development-only warnings for invalid prop values with clear,
7
- * actionable error messages.
8
- *
9
- * @example
10
- * ```ts
11
- * import { validateProps, PropTypes } from '@stacksjs/components'
12
- *
13
- * // Define prop schema
14
- * const schema = {
15
- * size: PropTypes.oneOf(['sm', 'md', 'lg']),
16
- * count: PropTypes.number.required,
17
- * onClick: PropTypes.func,
18
- * user: PropTypes.shape({
19
- * name: PropTypes.string.required,
20
- * age: PropTypes.number
21
- * })
22
- * }
23
- *
24
- * // Validate props
25
- * validateProps('Button', props, schema)
26
- * ```
27
- */
28
-
29
- /**
30
- * Environment check - only validate in development
31
- */
32
- const isDevelopment = process.env.NODE_ENV !== 'production'
33
-
34
- /**
35
- * Prop validator function type
36
- */
37
- export interface PropValidator<_T = any> {
38
- /** Validator function */
39
- validate: (value: any, propName: string, componentName: string) => boolean
40
- /** Error message generator */
41
- message: (value: any, propName: string, componentName: string) => string
42
- /** Whether this prop is required */
43
- isRequired?: boolean
44
- }
45
-
46
- /**
47
- * Base validator class
48
- */
49
- class Validator<T = any> implements PropValidator<T> {
50
- constructor(
51
- public validate: (value: any, propName: string, componentName: string) => boolean,
52
- public message: (value: any, propName: string, componentName: string) => string,
53
- public isRequired = false,
54
- ) {}
55
-
56
- /**
57
- * Mark this validator as required
58
- */
59
- get required(): Validator<T> {
60
- return new Validator(this.validate, this.message, true)
61
- }
62
- }
63
-
64
- /**
65
- * PropTypes - collection of common validators
66
- */
67
- export const PropTypes: {
68
- string: Validator<string>
69
- number: Validator<number>
70
- boolean: Validator<boolean>
71
- func: Validator<(...args: any[]) => any>
72
- object: Validator<object>
73
- array: Validator<any[]>
74
- any: Validator<any>
75
- email: Validator<string>
76
- url: Validator<string>
77
- oneOf: <T>(validValues: T[]) => Validator<T>
78
- oneOfType: (validators: Validator[]) => Validator
79
- arrayOf: (validator: Validator) => Validator
80
- shape: (shape: Record<string, Validator>) => Validator
81
- instanceOf: <T>(expectedClass: new (...args: any[]) => T) => Validator<T>
82
- custom: (validatorFn: (value: any, propName: string, componentName: string) => boolean, errorMessage: string | ((value: any, propName: string, componentName: string) => string)) => Validator
83
- min: (min: number) => Validator<number>
84
- max: (max: number) => Validator<number>
85
- range: (min: number, max: number) => Validator<number>
86
- pattern: (pattern: RegExp) => Validator<string>
87
- } = {
88
- /**
89
- * String type validator
90
- */
91
- string: new Validator<string>(
92
- value => typeof value === 'string',
93
- (value, propName, componentName) =>
94
- `Invalid prop \`${propName}\` of type \`${typeof value}\` supplied to \`${componentName}\`, expected \`string\`.`,
95
- ),
96
-
97
- /**
98
- * Number type validator
99
- */
100
- number: new Validator<number>(
101
- value => typeof value === 'number' && !Number.isNaN(value),
102
- (value, propName, componentName) =>
103
- `Invalid prop \`${propName}\` of type \`${typeof value}\` supplied to \`${componentName}\`, expected \`number\`.`,
104
- ),
105
-
106
- /**
107
- * Boolean type validator
108
- */
109
- boolean: new Validator<boolean>(
110
- value => typeof value === 'boolean',
111
- (value, propName, componentName) =>
112
- `Invalid prop \`${propName}\` of type \`${typeof value}\` supplied to \`${componentName}\`, expected \`boolean\`.`,
113
- ),
114
-
115
- /**
116
- * Function type validator
117
- */
118
- func: new Validator<(...args: any[]) => any>(
119
- value => typeof value === 'function',
120
- (value, propName, componentName) =>
121
- `Invalid prop \`${propName}\` of type \`${typeof value}\` supplied to \`${componentName}\`, expected \`function\`.`,
122
- ),
123
-
124
- /**
125
- * Object type validator
126
- */
127
- object: new Validator<object>(
128
- value => typeof value === 'object' && value !== null && !Array.isArray(value),
129
- (value, propName, componentName) =>
130
- `Invalid prop \`${propName}\` of type \`${typeof value}\` supplied to \`${componentName}\`, expected \`object\`.`,
131
- ),
132
-
133
- /**
134
- * Array type validator
135
- */
136
- array: new Validator<any[]>(
137
- value => Array.isArray(value),
138
- (value, propName, componentName) =>
139
- `Invalid prop \`${propName}\` of type \`${typeof value}\` supplied to \`${componentName}\`, expected \`array\`.`,
140
- ),
141
-
142
- /**
143
- * Any type validator (always passes)
144
- */
145
- any: new Validator<any>(
146
- () => true,
147
- () => '',
148
- ),
149
-
150
- /**
151
- * OneOf validator - value must be one of specified options
152
- *
153
- * @param validValues - Array of valid values
154
- */
155
- oneOf<T>(validValues: T[]): Validator<T> {
156
- return new Validator(
157
- value => validValues.includes(value),
158
- (value, propName, componentName) =>
159
- `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected one of [${validValues.map(v => JSON.stringify(v)).join(', ')}].`,
160
- )
161
- },
162
-
163
- /**
164
- * OneOfType validator - value must match one of specified types
165
- *
166
- * @param validators - Array of validators
167
- */
168
- oneOfType(validators: Validator[]): Validator {
169
- return new Validator(
170
- (value, propName, componentName) =>
171
- validators.some(v => v.validate(value, propName, componentName)),
172
- (_value, propName, componentName) =>
173
- `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected one of the specified types.`,
174
- )
175
- },
176
-
177
- /**
178
- * ArrayOf validator - all array elements must match type
179
- *
180
- * @param validator - Validator for array elements
181
- */
182
- arrayOf(validator: Validator): Validator {
183
- return new Validator(
184
- (value, propName, componentName) => {
185
- if (!Array.isArray(value))
186
- return false
187
- return value.every((item, index) => validator.validate(item, `${propName}[${index}]`, componentName))
188
- },
189
- (_value, propName, componentName) =>
190
- `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected array of specified type.`,
191
- )
192
- },
193
-
194
- /**
195
- * Shape validator - object must match specified shape
196
- *
197
- * @param shape - Object shape definition
198
- */
199
- shape(shape: Record<string, Validator>): Validator {
200
- return new Validator(
201
- (value, propName, componentName) => {
202
- if (typeof value !== 'object' || value === null || Array.isArray(value))
203
- return false
204
-
205
- // Check all required fields
206
- for (const [key, validator] of Object.entries(shape)) {
207
- if (validator.isRequired && !(key in value))
208
- return false
209
-
210
- if (key in value && !validator.validate(value[key], `${propName}.${key}`, componentName))
211
- return false
212
- }
213
-
214
- return true
215
- },
216
- (_value, propName, componentName) =>
217
- `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected object matching specified shape.`,
218
- )
219
- },
220
-
221
- /**
222
- * InstanceOf validator - value must be instance of class
223
- *
224
- * @param expectedClass - Expected class constructor
225
- */
226
- instanceOf<T>(expectedClass: new (...args: any[]) => T): Validator<T> {
227
- return new Validator(
228
- value => value instanceof expectedClass,
229
- (_value, propName, componentName) =>
230
- `Invalid prop \`${propName}\` supplied to \`${componentName}\`, expected instance of \`${expectedClass.name}\`.`,
231
- )
232
- },
233
-
234
- /**
235
- * Custom validator
236
- *
237
- * @param validatorFn - Custom validation function
238
- * @param errorMessage - Error message or message generator
239
- */
240
- custom(
241
- validatorFn: (value: any, propName: string, componentName: string) => boolean,
242
- errorMessage: string | ((_value: any, _propName: string, _componentName: string) => string),
243
- ): Validator {
244
- const messageGenerator = typeof errorMessage === 'string'
245
- ? () => errorMessage
246
- : errorMessage
247
-
248
- return new Validator(validatorFn, messageGenerator)
249
- },
250
-
251
- /**
252
- * Min validator for numbers
253
- *
254
- * @param min - Minimum value (inclusive)
255
- */
256
- min(min: number): Validator<number> {
257
- return new Validator(
258
- value => typeof value === 'number' && value >= min,
259
- (value, propName, componentName) =>
260
- `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected value >= ${min}.`,
261
- )
262
- },
263
-
264
- /**
265
- * Max validator for numbers
266
- *
267
- * @param max - Maximum value (inclusive)
268
- */
269
- max(max: number): Validator<number> {
270
- return new Validator(
271
- value => typeof value === 'number' && value <= max,
272
- (value, propName, componentName) =>
273
- `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected value <= ${max}.`,
274
- )
275
- },
276
-
277
- /**
278
- * Range validator for numbers
279
- *
280
- * @param min - Minimum value (inclusive)
281
- * @param max - Maximum value (inclusive)
282
- */
283
- range(min: number, max: number): Validator<number> {
284
- return new Validator(
285
- value => typeof value === 'number' && value >= min && value <= max,
286
- (value, propName, componentName) =>
287
- `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected value between ${min} and ${max}.`,
288
- )
289
- },
290
-
291
- /**
292
- * Pattern validator for strings
293
- *
294
- * @param pattern - Regular expression pattern
295
- */
296
- pattern(pattern: RegExp): Validator<string> {
297
- return new Validator(
298
- value => typeof value === 'string' && pattern.test(value),
299
- (value, propName, componentName) =>
300
- `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected value matching pattern ${pattern}.`,
301
- )
302
- },
303
-
304
- /**
305
- * Email validator
306
- */
307
- email: new Validator<string>(
308
- value => typeof value === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
309
- (value, propName, componentName) =>
310
- `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected valid email address.`,
311
- ),
312
-
313
- /**
314
- * URL validator
315
- */
316
- url: new Validator<string>(
317
- (value) => {
318
- if (typeof value !== 'string')
319
- return false
320
- try {
321
- const _url = new URL(value)
322
- return true
323
- }
324
- catch {
325
- return false
326
- }
327
- },
328
- (value, propName, componentName) =>
329
- `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected valid URL.`,
330
- ),
331
- }
332
-
333
- /**
334
- * Prop schema definition
335
- */
336
- export type PropSchema = Record<string, Validator>
337
-
338
- /**
339
- * Validation result
340
- */
341
- export interface ValidationResult {
342
- /** Whether validation passed */
343
- valid: boolean
344
- /** Array of error messages */
345
- errors: string[]
346
- }
347
-
348
- /**
349
- * Validate props against schema
350
- *
351
- * @param componentName - Name of component being validated
352
- * @param props - Props object to validate
353
- * @param schema - Prop schema definition
354
- * @param options - Validation options
355
- * @param options.throwOnError - Whether to throw on validation failure
356
- * @param options.logWarnings - Whether to log warnings to console
357
- * @returns Validation result
358
- */
359
- export function validateProps(
360
- componentName: string,
361
- props: Record<string, any>,
362
- schema: PropSchema,
363
- options: {
364
- /** Whether to throw on validation failure (default: false) */
365
- throwOnError?: boolean
366
- /** Whether to log warnings to console (default: true in dev) */
367
- logWarnings?: boolean
368
- } = {},
369
- ): ValidationResult {
370
- const { throwOnError = false, logWarnings = isDevelopment } = options
371
- const errors: string[] = []
372
-
373
- // Skip validation in production
374
- if (!isDevelopment) {
375
- return { valid: true, errors: [] }
376
- }
377
-
378
- // Check each prop in schema
379
- for (const [propName, validator] of Object.entries(schema)) {
380
- const propValue = props[propName]
381
- const isUndefined = propValue === undefined
382
-
383
- // Check required props
384
- if (validator.isRequired && isUndefined) {
385
- const error = `Required prop \`${propName}\` was not specified in \`${componentName}\`.`
386
- errors.push(error)
387
- continue
388
- }
389
-
390
- // Skip validation if prop is undefined and not required
391
- if (isUndefined)
392
- continue
393
-
394
- // Run validator
395
- if (!validator.validate(propValue, propName, componentName)) {
396
- const error = validator.message(propValue, propName, componentName)
397
- errors.push(error)
398
- }
399
- }
400
-
401
- // Handle errors
402
- if (errors.length > 0) {
403
- if (logWarnings) {
404
- console.group(`⚠️ Prop validation failed for \`${componentName}\``)
405
- errors.forEach(error => console.warn(error))
406
- console.groupEnd()
407
- }
408
-
409
- if (throwOnError) {
410
- throw new Error(`Prop validation failed for \`${componentName}\`:\n${errors.join('\n')}`)
411
- }
412
- }
413
-
414
- return {
415
- valid: errors.length === 0,
416
- errors,
417
- }
418
- }
419
-
420
- /**
421
- * Create a prop validator function for a component
422
- *
423
- * @param componentName - Name of component
424
- * @param schema - Prop schema definition
425
- * @returns Validator function
426
- *
427
- * @example
428
- * ```ts
429
- * const validateButtonProps = createPropValidator('Button', {
430
- * size: PropTypes.oneOf(['sm', 'md', 'lg']),
431
- * disabled: PropTypes.boolean,
432
- * onClick: PropTypes.func.required
433
- * })
434
- *
435
- * // In component
436
- * validateButtonProps(props)
437
- * ```
438
- */
439
- export function createPropValidator(
440
- componentName: string,
441
- schema: PropSchema,
442
- options?: { throwOnError?: boolean, logWarnings?: boolean },
443
- ): (props: Record<string, any>) => ValidationResult {
444
- return (props: Record<string, any>) => validateProps(componentName, props, schema, options)
445
- }
446
-
447
- /**
448
- * Assert that a value matches a validator
449
- *
450
- * @param value - Value to validate
451
- * @param validator - Validator to use
452
- * @param name - Name for error messages
453
- * @throws Error if validation fails
454
- */
455
- export function assertProp<T>(value: any, validator: Validator<T>, name = 'value'): asserts value is T {
456
- if (!isDevelopment)
457
- return
458
-
459
- if (!validator.validate(value, name, 'assertion')) {
460
- throw new Error(validator.message(value, name, 'assertion'))
461
- }
462
- }
463
-
464
- /**
465
- * Warn if prop doesn't match validator (non-throwing)
466
- *
467
- * @param value - Value to validate
468
- * @param validator - Validator to use
469
- * @param name - Name for warning messages
470
- */
471
- export function warnProp(value: any, validator: Validator, name = 'value'): void {
472
- if (!isDevelopment)
473
- return
474
-
475
- if (!validator.validate(value, name, 'warning')) {
476
- console.warn(validator.message(value, name, 'warning'))
477
- }
478
- }