@stacksjs/components 0.2.93 → 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 (187) hide show
  1. package/dist/index.js +4 -4
  2. package/package.json +5 -6
  3. package/src/components/CodeBlock.stx +0 -54
  4. package/src/components/Footer.stx +0 -66
  5. package/src/components/Hero.stx +0 -25
  6. package/src/components/Installation.stx +0 -37
  7. package/src/components/index.ts +0 -4
  8. package/src/composables/index.ts +0 -4
  9. package/src/composables/useCopyCode.ts +0 -73
  10. package/src/composables/useDarkMode.ts +0 -100
  11. package/src/composables/useSEO.ts +0 -230
  12. package/src/composables/utilities/index.ts +0 -7
  13. package/src/composables/utilities/useClickOutside.ts +0 -72
  14. package/src/composables/utilities/useFocusTrap.ts +0 -159
  15. package/src/composables/utilities/useKeyboard.ts +0 -124
  16. package/src/composables/utilities/useLocalStorage.ts +0 -132
  17. package/src/composables/utilities/useMediaQuery.ts +0 -118
  18. package/src/index.ts +0 -99
  19. package/src/stx.d.ts +0 -4
  20. package/src/ui/accordion/Accordion.stx +0 -146
  21. package/src/ui/accordion/AccordionItem.stx +0 -37
  22. package/src/ui/accordion/index.ts +0 -47
  23. package/src/ui/audio/Audio.stx +0 -50
  24. package/src/ui/audio/README.md +0 -41
  25. package/src/ui/audio/index.ts +0 -13
  26. package/src/ui/auth/Login.stx +0 -161
  27. package/src/ui/auth/README.md +0 -142
  28. package/src/ui/auth/Signup.stx +0 -159
  29. package/src/ui/auth/TwoFactorChallenge.stx +0 -111
  30. package/src/ui/auth/index.ts +0 -32
  31. package/src/ui/avatar/Avatar.stx +0 -77
  32. package/src/ui/avatar/index.ts +0 -12
  33. package/src/ui/badge/Badge.stx +0 -62
  34. package/src/ui/badge/index.ts +0 -10
  35. package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
  36. package/src/ui/breadcrumb/index.ts +0 -15
  37. package/src/ui/button/Button.stx +0 -74
  38. package/src/ui/button/README.md +0 -80
  39. package/src/ui/button/index.ts +0 -85
  40. package/src/ui/calendar/Calendar.stx +0 -189
  41. package/src/ui/calendar/README.md +0 -254
  42. package/src/ui/calendar/index.ts +0 -14
  43. package/src/ui/card/Card.stx +0 -68
  44. package/src/ui/card/index.ts +0 -13
  45. package/src/ui/checkbox/Checkbox.stx +0 -86
  46. package/src/ui/checkbox/index.ts +0 -16
  47. package/src/ui/combobox/Combobox.stx +0 -96
  48. package/src/ui/combobox/ComboboxButton.stx +0 -25
  49. package/src/ui/combobox/ComboboxInput.stx +0 -32
  50. package/src/ui/combobox/ComboboxOption.stx +0 -49
  51. package/src/ui/combobox/ComboboxOptions.stx +0 -16
  52. package/src/ui/combobox/README.md +0 -150
  53. package/src/ui/combobox/index.ts +0 -40
  54. package/src/ui/command-palette/CommandPalette.stx +0 -81
  55. package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
  56. package/src/ui/command-palette/README.md +0 -42
  57. package/src/ui/command-palette/index.ts +0 -15
  58. package/src/ui/dialog/Dialog.stx +0 -41
  59. package/src/ui/dialog/DialogBackdrop.stx +0 -9
  60. package/src/ui/dialog/DialogDescription.stx +0 -11
  61. package/src/ui/dialog/DialogPanel.stx +0 -16
  62. package/src/ui/dialog/DialogTitle.stx +0 -11
  63. package/src/ui/dialog/README.md +0 -121
  64. package/src/ui/dialog/index.ts +0 -32
  65. package/src/ui/drawer/Drawer.stx +0 -120
  66. package/src/ui/drawer/README.md +0 -90
  67. package/src/ui/drawer/index.ts +0 -9
  68. package/src/ui/dropdown/Dropdown.stx +0 -82
  69. package/src/ui/dropdown/DropdownButton.stx +0 -29
  70. package/src/ui/dropdown/DropdownItem.stx +0 -35
  71. package/src/ui/dropdown/DropdownItems.stx +0 -18
  72. package/src/ui/dropdown/README.md +0 -114
  73. package/src/ui/dropdown/index.ts +0 -29
  74. package/src/ui/form/Form.stx +0 -95
  75. package/src/ui/form/index.ts +0 -67
  76. package/src/ui/heatmap/Heatmap.stx +0 -294
  77. package/src/ui/image/Image.stx +0 -165
  78. package/src/ui/image/README.md +0 -164
  79. package/src/ui/image/index.ts +0 -22
  80. package/src/ui/input/EmailInput.stx +0 -30
  81. package/src/ui/input/NumberInput.stx +0 -126
  82. package/src/ui/input/PasswordInput.stx +0 -143
  83. package/src/ui/input/SearchInput.stx +0 -44
  84. package/src/ui/input/TextInput.stx +0 -132
  85. package/src/ui/input/index.ts +0 -180
  86. package/src/ui/listbox/Listbox.stx +0 -101
  87. package/src/ui/listbox/ListboxButton.stx +0 -28
  88. package/src/ui/listbox/ListboxLabel.stx +0 -11
  89. package/src/ui/listbox/ListboxOption.stx +0 -49
  90. package/src/ui/listbox/ListboxOptions.stx +0 -16
  91. package/src/ui/listbox/README.md +0 -135
  92. package/src/ui/listbox/index.ts +0 -39
  93. package/src/ui/navigator/Navigator.stx +0 -113
  94. package/src/ui/navigator/README.md +0 -352
  95. package/src/ui/navigator/index.ts +0 -20
  96. package/src/ui/notification/Notification.stx +0 -117
  97. package/src/ui/notification/README.md +0 -114
  98. package/src/ui/notification/index.ts +0 -12
  99. package/src/ui/pagination/Pagination.stx +0 -150
  100. package/src/ui/pagination/index.ts +0 -11
  101. package/src/ui/payment/Checkout.stx +0 -31
  102. package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
  103. package/src/ui/payment/PaymentMethods.stx +0 -104
  104. package/src/ui/payment/README.md +0 -345
  105. package/src/ui/payment/SubscriptionCheckout.stx +0 -323
  106. package/src/ui/payment/index.ts +0 -59
  107. package/src/ui/popover/Popover.stx +0 -60
  108. package/src/ui/popover/PopoverButton.stx +0 -29
  109. package/src/ui/popover/PopoverPanel.stx +0 -23
  110. package/src/ui/popover/README.md +0 -91
  111. package/src/ui/popover/index.ts +0 -22
  112. package/src/ui/portal/Portal.stx +0 -57
  113. package/src/ui/portal/index.ts +0 -6
  114. package/src/ui/progress/Progress.stx +0 -131
  115. package/src/ui/progress/index.ts +0 -12
  116. package/src/ui/radio/Radio.stx +0 -77
  117. package/src/ui/radio/index.ts +0 -15
  118. package/src/ui/radio-group/README.md +0 -139
  119. package/src/ui/radio-group/RadioGroup.stx +0 -60
  120. package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
  121. package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
  122. package/src/ui/radio-group/RadioGroupOption.stx +0 -58
  123. package/src/ui/radio-group/index.ts +0 -30
  124. package/src/ui/select/README.md +0 -180
  125. package/src/ui/select/Select.stx +0 -82
  126. package/src/ui/select/index.ts +0 -21
  127. package/src/ui/sidebar/Sidebar.stx +0 -476
  128. package/src/ui/sidebar/SidebarFooter.stx +0 -71
  129. package/src/ui/sidebar/SidebarHeader.stx +0 -103
  130. package/src/ui/sidebar/SidebarItem.stx +0 -86
  131. package/src/ui/sidebar/SidebarSection.stx +0 -83
  132. package/src/ui/sidebar/index.ts +0 -153
  133. package/src/ui/sidebar/themes.ts +0 -240
  134. package/src/ui/skeleton/Skeleton.stx +0 -48
  135. package/src/ui/skeleton/index.ts +0 -11
  136. package/src/ui/spinner/Spinner.stx +0 -109
  137. package/src/ui/spinner/index.ts +0 -9
  138. package/src/ui/stepper/README.md +0 -36
  139. package/src/ui/stepper/Stepper.stx +0 -17
  140. package/src/ui/stepper/StepperStep.stx +0 -57
  141. package/src/ui/stepper/index.ts +0 -19
  142. package/src/ui/storage/README.md +0 -193
  143. package/src/ui/storage/index.ts +0 -347
  144. package/src/ui/switch/README.md +0 -114
  145. package/src/ui/switch/Switch.stx +0 -72
  146. package/src/ui/switch/index.ts +0 -10
  147. package/src/ui/table/README.md +0 -39
  148. package/src/ui/table/Table.stx +0 -14
  149. package/src/ui/table/TableBody.stx +0 -10
  150. package/src/ui/table/TableCell.stx +0 -10
  151. package/src/ui/table/TableHead.stx +0 -10
  152. package/src/ui/table/TableHeader.stx +0 -20
  153. package/src/ui/table/TableRow.stx +0 -11
  154. package/src/ui/table/index.ts +0 -35
  155. package/src/ui/tabs/TabPanel.stx +0 -25
  156. package/src/ui/tabs/Tabs.stx +0 -202
  157. package/src/ui/tabs/index.ts +0 -50
  158. package/src/ui/teleport/Teleport.stx +0 -65
  159. package/src/ui/teleport/index.ts +0 -7
  160. package/src/ui/textarea/Textarea.stx +0 -108
  161. package/src/ui/textarea/index.ts +0 -20
  162. package/src/ui/tooltip/Tooltip.stx +0 -71
  163. package/src/ui/tooltip/index.ts +0 -10
  164. package/src/ui/transition/README.md +0 -30
  165. package/src/ui/transition/Transition.stx +0 -102
  166. package/src/ui/transition/index.ts +0 -25
  167. package/src/ui/video/README.md +0 -47
  168. package/src/ui/video/Video.stx +0 -45
  169. package/src/ui/video/index.ts +0 -16
  170. package/src/ui/virtual-list/VirtualList.stx +0 -67
  171. package/src/ui/virtual-list/index.ts +0 -10
  172. package/src/ui/virtual-table/VirtualTable.stx +0 -103
  173. package/src/ui/virtual-table/index.ts +0 -21
  174. package/src/utils/PROP_VALIDATION.md +0 -458
  175. package/src/utils/THEME_SYSTEM.md +0 -702
  176. package/src/utils/accessibility.ts +0 -841
  177. package/src/utils/animation/easing.ts +0 -368
  178. package/src/utils/animation/helpers.ts +0 -223
  179. package/src/utils/animation/index.ts +0 -5
  180. package/src/utils/animation/keyframes.ts +0 -230
  181. package/src/utils/error-handling.ts +0 -475
  182. package/src/utils/highlighter.ts +0 -93
  183. package/src/utils/i18n.ts +0 -634
  184. package/src/utils/keep-alive.ts +0 -819
  185. package/src/utils/lazy-loading.ts +0 -530
  186. package/src/utils/prop-validation.ts +0 -478
  187. package/src/utils/theme.ts +0 -626
@@ -1,230 +0,0 @@
1
- /**
2
- * Keyframe animation utilities using Web Animations API
3
- *
4
- * @example
5
- * ```ts
6
- * import { animate, KeyframeAnimations } from '@stacksjs/components'
7
- *
8
- * // Use predefined animation
9
- * animate(element, 'fadeIn', { duration: 500 })
10
- *
11
- * // Custom keyframes
12
- * createKeyframeAnimation(element, [
13
- * { offset: 0, opacity: 0, transform: 'scale(0.5)' },
14
- * { offset: 1, opacity: 1, transform: 'scale(1)' }
15
- * ], { duration: 300 })
16
- * ```
17
- */
18
-
19
- /**
20
- * Single keyframe definition
21
- */
22
- export interface Keyframe {
23
- /** Keyframe position (0 to 1) */
24
- offset: number
25
- /** CSS properties to animate */
26
- [property: string]: any
27
- }
28
-
29
- /**
30
- * Animation configuration options
31
- */
32
- export interface AnimationOptions {
33
- /** Animation duration in milliseconds */
34
- duration?: number
35
- /** Easing function, CSS easing string */
36
- easing?: string
37
- /** Delay before animation starts in milliseconds */
38
- delay?: number
39
- /** Number of iterations (Infinity for infinite) */
40
- iterations?: number
41
- /** Animation direction */
42
- direction?: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse'
43
- /** Fill mode */
44
- fill?: 'none' | 'forwards' | 'backwards' | 'both'
45
- }
46
-
47
- /**
48
- * Create a keyframe animation using Web Animations API
49
- *
50
- * @param element - Target HTML element
51
- * @param keyframes - Array of keyframe definitions
52
- * @param options - Animation options
53
- * @returns Animation instance or null if not supported
54
- */
55
- export function createKeyframeAnimation(
56
- element: HTMLElement,
57
- keyframes: readonly Keyframe[] | Keyframe[],
58
- options: AnimationOptions = {},
59
- ): Animation | null {
60
- if (typeof element.animate !== 'function') {
61
- console.warn('Web Animations API not supported')
62
- return null
63
- }
64
-
65
- const {
66
- duration = 1000,
67
- easing = 'ease',
68
- delay = 0,
69
- iterations = 1,
70
- direction = 'normal',
71
- fill = 'both',
72
- } = options
73
-
74
- return element.animate([...keyframes], {
75
- duration,
76
- easing,
77
- delay,
78
- iterations,
79
- direction,
80
- fill,
81
- })
82
- }
83
-
84
- /**
85
- * Predefined keyframe animation presets
86
- *
87
- * Available animations:
88
- * - fadeIn/fadeOut
89
- * - slideInUp/Down/Left/Right, slideOutUp/Down/Left/Right
90
- * - zoomIn/Out
91
- * - rotate, bounce, pulse, shake, swing
92
- * - flip, rubberBand, heartbeat
93
- */
94
- export const KeyframeAnimations = {
95
- fadeIn: [
96
- { offset: 0, opacity: 0 },
97
- { offset: 1, opacity: 1 },
98
- ],
99
- fadeOut: [
100
- { offset: 0, opacity: 1 },
101
- { offset: 1, opacity: 0 },
102
- ],
103
- slideInUp: [
104
- { offset: 0, transform: 'translateY(100%)', opacity: 0 },
105
- { offset: 1, transform: 'translateY(0)', opacity: 1 },
106
- ],
107
- slideInDown: [
108
- { offset: 0, transform: 'translateY(-100%)', opacity: 0 },
109
- { offset: 1, transform: 'translateY(0)', opacity: 1 },
110
- ],
111
- slideInLeft: [
112
- { offset: 0, transform: 'translateX(-100%)', opacity: 0 },
113
- { offset: 1, transform: 'translateX(0)', opacity: 1 },
114
- ],
115
- slideInRight: [
116
- { offset: 0, transform: 'translateX(100%)', opacity: 0 },
117
- { offset: 1, transform: 'translateX(0)', opacity: 1 },
118
- ],
119
- slideOutUp: [
120
- { offset: 0, transform: 'translateY(0)', opacity: 1 },
121
- { offset: 1, transform: 'translateY(-100%)', opacity: 0 },
122
- ],
123
- slideOutDown: [
124
- { offset: 0, transform: 'translateY(0)', opacity: 1 },
125
- { offset: 1, transform: 'translateY(100%)', opacity: 0 },
126
- ],
127
- slideOutLeft: [
128
- { offset: 0, transform: 'translateX(0)', opacity: 1 },
129
- { offset: 1, transform: 'translateX(-100%)', opacity: 0 },
130
- ],
131
- slideOutRight: [
132
- { offset: 0, transform: 'translateX(0)', opacity: 1 },
133
- { offset: 1, transform: 'translateX(100%)', opacity: 0 },
134
- ],
135
- zoomIn: [
136
- { offset: 0, transform: 'scale(0)', opacity: 0 },
137
- { offset: 0.5, opacity: 1 },
138
- { offset: 1, transform: 'scale(1)' },
139
- ],
140
- zoomOut: [
141
- { offset: 0, transform: 'scale(1)', opacity: 1 },
142
- { offset: 0.5, opacity: 1 },
143
- { offset: 1, transform: 'scale(0)', opacity: 0 },
144
- ],
145
- rotate: [
146
- { offset: 0, transform: 'rotate(0deg)' },
147
- { offset: 1, transform: 'rotate(360deg)' },
148
- ],
149
- bounce: [
150
- { offset: 0, transform: 'translateY(0)' },
151
- { offset: 0.2, transform: 'translateY(0)' },
152
- { offset: 0.4, transform: 'translateY(-30px)' },
153
- { offset: 0.43, transform: 'translateY(-30px)' },
154
- { offset: 0.53, transform: 'translateY(0)' },
155
- { offset: 0.7, transform: 'translateY(-15px)' },
156
- { offset: 0.8, transform: 'translateY(0)' },
157
- { offset: 0.9, transform: 'translateY(-4px)' },
158
- { offset: 1, transform: 'translateY(0)' },
159
- ],
160
- pulse: [
161
- { offset: 0, transform: 'scale(1)' },
162
- { offset: 0.5, transform: 'scale(1.05)' },
163
- { offset: 1, transform: 'scale(1)' },
164
- ],
165
- shake: [
166
- { offset: 0, transform: 'translateX(0)' },
167
- { offset: 0.1, transform: 'translateX(-10px)' },
168
- { offset: 0.2, transform: 'translateX(10px)' },
169
- { offset: 0.3, transform: 'translateX(-10px)' },
170
- { offset: 0.4, transform: 'translateX(10px)' },
171
- { offset: 0.5, transform: 'translateX(-10px)' },
172
- { offset: 0.6, transform: 'translateX(10px)' },
173
- { offset: 0.7, transform: 'translateX(-10px)' },
174
- { offset: 0.8, transform: 'translateX(10px)' },
175
- { offset: 0.9, transform: 'translateX(-10px)' },
176
- { offset: 1, transform: 'translateX(0)' },
177
- ],
178
- swing: [
179
- { offset: 0, transform: 'rotate(0deg)' },
180
- { offset: 0.2, transform: 'rotate(15deg)' },
181
- { offset: 0.4, transform: 'rotate(-10deg)' },
182
- { offset: 0.6, transform: 'rotate(5deg)' },
183
- { offset: 0.8, transform: 'rotate(-5deg)' },
184
- { offset: 1, transform: 'rotate(0deg)' },
185
- ],
186
- flip: [
187
- { offset: 0, transform: 'perspective(400px) rotateY(0)', animationTimingFunction: 'ease-out' },
188
- { offset: 0.4, transform: 'perspective(400px) translateZ(150px) rotateY(170deg)', animationTimingFunction: 'ease-out' },
189
- { offset: 0.5, transform: 'perspective(400px) translateZ(150px) rotateY(190deg)', animationTimingFunction: 'ease-in' },
190
- { offset: 0.8, transform: 'perspective(400px) rotateY(360deg)', animationTimingFunction: 'ease-in' },
191
- { offset: 1, transform: 'perspective(400px)', animationTimingFunction: 'ease-in' },
192
- ],
193
- rubberBand: [
194
- { offset: 0, transform: 'scale(1)' },
195
- { offset: 0.3, transform: 'scaleX(1.25) scaleY(0.75)' },
196
- { offset: 0.4, transform: 'scaleX(0.75) scaleY(1.25)' },
197
- { offset: 0.5, transform: 'scaleX(1.15) scaleY(0.85)' },
198
- { offset: 0.65, transform: 'scaleX(0.95) scaleY(1.05)' },
199
- { offset: 0.75, transform: 'scaleX(1.05) scaleY(0.95)' },
200
- { offset: 1, transform: 'scale(1)' },
201
- ],
202
- heartbeat: [
203
- { offset: 0, transform: 'scale(1)' },
204
- { offset: 0.14, transform: 'scale(1.3)' },
205
- { offset: 0.28, transform: 'scale(1)' },
206
- { offset: 0.42, transform: 'scale(1.3)' },
207
- { offset: 0.7, transform: 'scale(1)' },
208
- ],
209
- } as const
210
-
211
- /**
212
- * Type for predefined animation names
213
- */
214
- export type KeyframeAnimationName = keyof typeof KeyframeAnimations
215
-
216
- /**
217
- * Animate an element with a predefined animation
218
- *
219
- * @param element - Target HTML element
220
- * @param animationName - Name of predefined animation
221
- * @param options - Animation options
222
- * @returns Animation instance or null if not supported
223
- */
224
- export function animate(
225
- element: HTMLElement,
226
- animationName: KeyframeAnimationName,
227
- options: AnimationOptions = {},
228
- ): Animation | null {
229
- return createKeyframeAnimation(element, KeyframeAnimations[animationName], options)
230
- }
@@ -1,475 +0,0 @@
1
- /**
2
- * Error handling utilities for @stacksjs/components
3
- *
4
- * Provides clear, actionable error messages with links to documentation
5
- *
6
- * @example
7
- * ```ts
8
- * import { ComponentError, handleError } from '@stacksjs/components'
9
- *
10
- * throw new ComponentError('Button', 'Invalid variant provided', {
11
- * received: 'invalid',
12
- * expected: ['primary', 'secondary', 'outline']
13
- * })
14
- * ```
15
- */
16
- import process from 'node:process'
17
-
18
- /**
19
- * Base URL for documentation
20
- */
21
- const DOCS_BASE_URL = 'https://stacksjs.com/components'
22
-
23
- /**
24
- * Error context information
25
- */
26
- export interface ErrorContext {
27
- /** The component name where the error occurred */
28
- component?: string
29
- /** The prop name that caused the error */
30
- prop?: string
31
- /** The value that was received */
32
- received?: any
33
- /** The expected value(s) */
34
- expected?: any
35
- /** Additional details about the error */
36
- details?: string
37
- /** Link to relevant documentation */
38
- docsUrl?: string
39
- }
40
-
41
- /**
42
- * Custom error class for component errors
43
- */
44
- export class ComponentError extends Error {
45
- component: string
46
- context: ErrorContext
47
-
48
- constructor(component: string, message: string, context: ErrorContext = {}) {
49
- const fullMessage = ComponentError.formatMessage(component, message, context)
50
- super(fullMessage)
51
-
52
- this.name = 'ComponentError'
53
- this.component = component
54
- this.context = { component, ...context }
55
-
56
- // Maintains proper stack trace for where error was thrown (only available on V8)
57
- if (Error.captureStackTrace) {
58
- Error.captureStackTrace(this, ComponentError)
59
- }
60
- }
61
-
62
- /**
63
- * Format error message with context
64
- */
65
- static formatMessage(component: string, message: string, context: ErrorContext): string {
66
- let formatted = `[${component}] ${message}`
67
-
68
- if (context.prop) {
69
- formatted += `\n Prop: "${context.prop}"`
70
- }
71
-
72
- if (context.received !== undefined) {
73
- formatted += `\n Received: ${JSON.stringify(context.received)}`
74
- }
75
-
76
- if (context.expected !== undefined) {
77
- const expected = Array.isArray(context.expected)
78
- ? context.expected.map(v => JSON.stringify(v)).join(', ')
79
- : JSON.stringify(context.expected)
80
- formatted += `\n Expected: ${expected}`
81
- }
82
-
83
- if (context.details) {
84
- formatted += `\n Details: ${context.details}`
85
- }
86
-
87
- if (context.docsUrl) {
88
- formatted += `\n Documentation: ${context.docsUrl}`
89
- }
90
- else if (component) {
91
- formatted += `\n Documentation: ${DOCS_BASE_URL}/${component.toLowerCase()}`
92
- }
93
-
94
- return formatted
95
- }
96
-
97
- /**
98
- * Get error as plain object
99
- */
100
- toJSON(): { name: string, message: string, component: string, context: ErrorContext | undefined, stack: string | undefined } {
101
- return {
102
- name: this.name,
103
- message: this.message,
104
- component: this.component,
105
- context: this.context,
106
- stack: this.stack,
107
- }
108
- }
109
- }
110
-
111
- /**
112
- * Error types for common scenarios
113
- */
114
- export const ErrorTypes = {
115
- /**
116
- * Invalid prop value error
117
- */
118
- invalidProp(component: string, prop: string, received: any, expected: any): ComponentError {
119
- return new ComponentError(
120
- component,
121
- `Invalid prop value for "${prop}"`,
122
- {
123
- prop,
124
- received,
125
- expected,
126
- details: Array.isArray(expected)
127
- ? `The "${prop}" prop must be one of the allowed values`
128
- : `The "${prop}" prop does not match the expected type`,
129
- },
130
- )
131
- },
132
-
133
- /**
134
- * Required prop missing error
135
- */
136
- requiredProp(component: string, prop: string): ComponentError {
137
- return new ComponentError(
138
- component,
139
- `Required prop "${prop}" is missing`,
140
- {
141
- prop,
142
- details: `The "${prop}" prop is required for ${component} to function correctly`,
143
- },
144
- )
145
- },
146
-
147
- /**
148
- * Invalid prop type error
149
- */
150
- invalidType(component: string, prop: string, received: any, expected: string): ComponentError {
151
- return new ComponentError(
152
- component,
153
- `Invalid type for prop "${prop}"`,
154
- {
155
- prop,
156
- received: typeof received,
157
- expected,
158
- details: `Expected "${prop}" to be of type ${expected}, but received ${typeof received}`,
159
- },
160
- )
161
- },
162
-
163
- /**
164
- * Component not found error
165
- */
166
- componentNotFound(componentName: string): ComponentError {
167
- return new ComponentError(
168
- 'ComponentLoader',
169
- `Component "${componentName}" not found`,
170
- {
171
- component: componentName,
172
- details: 'Make sure the component is properly imported and registered',
173
- },
174
- )
175
- },
176
-
177
- /**
178
- * Invalid children error
179
- */
180
- invalidChildren(component: string, received: any, expected: string): ComponentError {
181
- return new ComponentError(
182
- component,
183
- 'Invalid children',
184
- {
185
- received: typeof received,
186
- expected,
187
- details: `${component} expects ${expected} as children`,
188
- },
189
- )
190
- },
191
-
192
- /**
193
- * State update error
194
- */
195
- stateUpdate(component: string, stateName: string, error: Error): ComponentError {
196
- return new ComponentError(
197
- component,
198
- `Failed to update state "${stateName}"`,
199
- {
200
- details: error.message,
201
- },
202
- )
203
- },
204
-
205
- /**
206
- * Event handler error
207
- */
208
- eventHandler(component: string, eventName: string, error: Error): ComponentError {
209
- return new ComponentError(
210
- component,
211
- `Error in "${eventName}" event handler`,
212
- {
213
- details: error.message,
214
- },
215
- )
216
- },
217
-
218
- /**
219
- * Render error
220
- */
221
- render(component: string, error: Error): ComponentError {
222
- return new ComponentError(
223
- component,
224
- 'Failed to render component',
225
- {
226
- details: error.message,
227
- },
228
- )
229
- },
230
- }
231
-
232
- /**
233
- * Global error handler
234
- */
235
- let errorHandler: ((_error: Error) => void) | null = null
236
-
237
- /**
238
- * Set global error handler
239
- *
240
- * @param handler - Error handler function
241
- *
242
- * @example
243
- * ```ts
244
- * setErrorHandler((error) => {
245
- * console.error('Component error:', error)
246
- * // Send to error tracking service
247
- * })
248
- * ```
249
- */
250
- export function setErrorHandler(handler: (error: Error) => void): void {
251
- errorHandler = handler
252
- }
253
-
254
- /**
255
- * Clear the global error handler (useful for testing)
256
- */
257
- export function clearErrorHandler(): void {
258
- errorHandler = null
259
- }
260
-
261
- /**
262
- * Handle an error
263
- *
264
- * @param error - Error to handle
265
- * @param options - Handling options
266
- * @param options.throwError - Whether to re-throw the error after handling
267
- * @param options.logError - Whether to log the error to console
268
- *
269
- * @example
270
- * ```ts
271
- * try {
272
- * // Component code
273
- * }
274
- catch (error) {
275
- * handleError(error, { throwError: false })
276
- * }
277
- * ```
278
- */
279
- export function handleError(
280
- error: Error,
281
- options: {
282
- /** Whether to re-throw the error after handling */
283
- throwError?: boolean
284
- /** Whether to log the error to console */
285
- logError?: boolean
286
- } = {},
287
- ): void {
288
- const { throwError = true, logError = true } = options
289
-
290
- // Log to console in development
291
- if (logError && process.env.NODE_ENV !== 'production') {
292
- console.error('Component Error:', error)
293
-
294
- if (error instanceof ComponentError) {
295
- console.group('Error Details')
296
- // eslint-disable-next-line no-console
297
- console.log('Component:', error.component)
298
- // eslint-disable-next-line no-console
299
- console.log('Context:', error.context)
300
- console.groupEnd()
301
- }
302
- }
303
-
304
- // Call global error handler if set
305
- if (errorHandler) {
306
- try {
307
- errorHandler(error)
308
- }
309
- catch (handlerError) {
310
- console.error('Error in error handler:', handlerError)
311
- }
312
- }
313
-
314
- // Re-throw if requested
315
- if (throwError) {
316
- throw error
317
- }
318
- }
319
-
320
- /**
321
- * Create a wrapped function that catches and handles errors
322
- *
323
- * @param fn - Function to wrap
324
- * @param component - Component name for error context
325
- * @param eventName - Event name for error context
326
- * @returns Wrapped function
327
- *
328
- * @example
329
- * ```ts
330
- * const safeHandler = wrapErrorHandler(
331
- * () => { /* ... * / },
332
- * 'Button',
333
- * 'onClick'
334
- * )
335
- * ```
336
- */
337
- export function wrapErrorHandler<T extends (...args: any[]) => any>(
338
- fn: T,
339
- component: string,
340
- eventName: string,
341
- ): T {
342
- return ((...args: any[]) => {
343
- try {
344
- const result = fn(...args)
345
-
346
- // Handle async functions
347
- if (result instanceof Promise) {
348
- return result.catch((error) => {
349
- const wrappedError = ErrorTypes.eventHandler(component, eventName, error)
350
- handleError(wrappedError, { throwError: false })
351
- throw wrappedError
352
- })
353
- }
354
-
355
- return result
356
- }
357
- catch (error) {
358
- const wrappedError = ErrorTypes.eventHandler(component, eventName, error as Error)
359
- handleError(wrappedError, { throwError: false })
360
- throw wrappedError
361
- }
362
- }) as T
363
- }
364
-
365
- /**
366
- * Assert a condition with a custom error
367
- *
368
- * @param condition - Condition to check
369
- * @param error - Error to throw if condition is false
370
- *
371
- * @example
372
- * ```ts
373
- * assert(
374
- * props.variant !== undefined,
375
- * ErrorTypes.requiredProp('Button', 'variant')
376
- * )
377
- * ```
378
- */
379
- export function assert(condition: any, error: Error): asserts condition {
380
- if (!condition) {
381
- throw error
382
- }
383
- }
384
-
385
- /**
386
- * Warning message handler
387
- */
388
- export function warn(component: string, message: string, context: Partial<ErrorContext> = {}): void {
389
- if (process.env.NODE_ENV === 'production') {
390
- return
391
- }
392
-
393
- const fullMessage = ComponentError.formatMessage(component, message, context as ErrorContext)
394
-
395
- console.warn(`⚠️ ${fullMessage}`)
396
- }
397
-
398
- /**
399
- * Development-only assertion
400
- */
401
- export function devAssert(condition: any, error: Error): asserts condition {
402
- if (process.env.NODE_ENV === 'production') {
403
- return
404
- }
405
-
406
- assert(condition, error)
407
- }
408
-
409
- /**
410
- * Create a debug logger for a component
411
- *
412
- * @param component - Component name
413
- * @returns Debug logger functions
414
- *
415
- * @example
416
- * ```ts
417
- * const debug = createDebugger('Button')
418
- * debug.log('Button rendered')
419
- * debug.error('Invalid prop')
420
- * ```
421
- */
422
- export function createDebugger(component: string): {
423
- log: (...args: any[]) => void
424
- warn: (message: string, context?: Partial<ErrorContext>) => void
425
- error: (message: string, context?: ErrorContext) => void
426
- } {
427
- const isDebug = typeof process !== 'undefined' && process.env.DEBUG === 'true'
428
-
429
- return {
430
- log(...args: any[]): void {
431
- if (isDebug) {
432
- console.log(`[${component}]`, ...args)
433
- }
434
- },
435
- warn(message: string, context?: Partial<ErrorContext>): void {
436
- warn(component, message, context)
437
- },
438
- error(message: string, context?: ErrorContext): void {
439
- const error = new ComponentError(component, message, context)
440
- handleError(error, { throwError: false })
441
- },
442
- }
443
- }
444
-
445
- /**
446
- * Error boundary helper for catching render errors
447
- *
448
- * @param component - Component name
449
- * @param renderFn - Render function
450
- * @param fallback - Fallback content on error
451
- * @returns Rendered content or fallback
452
- *
453
- * @example
454
- * ```ts
455
- * const content = errorBoundary(
456
- * 'MyComponent',
457
- * () => renderComponent(),
458
- * '<div>Error loading component</div>'
459
- * )
460
- * ```
461
- */
462
- export function errorBoundary<T>(
463
- component: string,
464
- renderFn: () => T,
465
- fallback: T,
466
- ): T {
467
- try {
468
- return renderFn()
469
- }
470
- catch (error) {
471
- const wrappedError = ErrorTypes.render(component, error as Error)
472
- handleError(wrappedError, { throwError: false })
473
- return fallback
474
- }
475
- }