@shohojdhara/atomix 0.5.0 → 0.5.2

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 (168) hide show
  1. package/atomix.config.ts +12 -0
  2. package/build-tools/webpack-loader.js +5 -4
  3. package/dist/atomix.css +230 -83
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +1 -1
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/build-tools/webpack-loader.js +5 -4
  8. package/dist/charts.d.ts +24 -23
  9. package/dist/charts.js +271 -369
  10. package/dist/charts.js.map +1 -1
  11. package/dist/config.d.ts +624 -0
  12. package/dist/config.js +59 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/core.d.ts +3 -2
  15. package/dist/core.js +342 -382
  16. package/dist/core.js.map +1 -1
  17. package/dist/forms.d.ts +4 -6
  18. package/dist/forms.js +233 -334
  19. package/dist/forms.js.map +1 -1
  20. package/dist/heavy.d.ts +11 -2
  21. package/dist/heavy.js +406 -445
  22. package/dist/heavy.js.map +1 -1
  23. package/dist/index.d.ts +109 -65
  24. package/dist/index.esm.js +654 -748
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/index.js +621 -717
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.min.js +1 -1
  29. package/dist/index.min.js.map +1 -1
  30. package/dist/layout.js +59 -60
  31. package/dist/layout.js.map +1 -1
  32. package/dist/theme.js +4 -4
  33. package/dist/theme.js.map +1 -1
  34. package/package.json +24 -9
  35. package/scripts/atomix-cli.js +15 -1
  36. package/scripts/cli/__tests__/complexity-utils.test.js +24 -0
  37. package/scripts/cli/__tests__/detector.test.js +50 -0
  38. package/scripts/cli/__tests__/template-engine.test.js +23 -0
  39. package/scripts/cli/__tests__/test-setup.js +1 -133
  40. package/scripts/cli/commands/doctor.js +15 -3
  41. package/scripts/cli/commands/generate.js +113 -51
  42. package/scripts/cli/internal/ai-engine.js +30 -10
  43. package/scripts/cli/internal/complexity-utils.js +60 -0
  44. package/scripts/cli/internal/component-validator.js +49 -16
  45. package/scripts/cli/internal/generator.js +89 -36
  46. package/scripts/cli/internal/hook-generator.js +5 -2
  47. package/scripts/cli/internal/itcss-generator.js +16 -12
  48. package/scripts/cli/templates/next-templates.js +81 -30
  49. package/scripts/cli/templates/storybook-templates.js +12 -2
  50. package/scripts/cli/utils/detector.js +45 -7
  51. package/scripts/cli/utils/diagnostics.js +78 -0
  52. package/scripts/cli/utils/telemetry.js +13 -0
  53. package/src/components/Accordion/Accordion.stories.tsx +4 -0
  54. package/src/components/AtomixGlass/AtomixGlass.tsx +188 -128
  55. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +63 -91
  56. package/src/components/AtomixGlass/PerformanceDashboard.tsx +153 -201
  57. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +9 -6
  58. package/src/components/AtomixGlass/glass-utils.ts +51 -1
  59. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +52 -46
  60. package/src/components/AtomixGlass/stories/Examples.stories.tsx +573 -236
  61. package/src/components/AtomixGlass/stories/Playground.stories.tsx +88 -41
  62. package/src/components/AtomixGlass/stories/argTypes.ts +19 -19
  63. package/src/components/AtomixGlass/stories/shared-components.tsx +7 -12
  64. package/src/components/AtomixGlass/stories/types.ts +3 -3
  65. package/src/components/Button/Button.tsx +114 -57
  66. package/src/components/Callout/Callout.tsx +4 -4
  67. package/src/components/Chart/ChartRenderer.tsx +1 -1
  68. package/src/components/Chart/DonutChart.tsx +11 -8
  69. package/src/components/EdgePanel/EdgePanel.tsx +119 -115
  70. package/src/components/Form/Select.tsx +4 -4
  71. package/src/components/List/List.tsx +4 -4
  72. package/src/components/Navigation/SideMenu/SideMenu.tsx +6 -6
  73. package/src/components/PhotoViewer/PhotoViewerImage.tsx +1 -1
  74. package/src/components/ProductReview/ProductReview.tsx +4 -2
  75. package/src/components/Rating/Rating.tsx +4 -2
  76. package/src/components/SectionIntro/SectionIntro.tsx +4 -2
  77. package/src/components/Steps/Steps.tsx +1 -1
  78. package/src/components/Tabs/Tabs.tsx +5 -5
  79. package/src/components/Testimonial/Testimonial.tsx +4 -2
  80. package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
  81. package/src/layouts/CssGrid/CssGrid.stories.tsx +464 -0
  82. package/src/layouts/CssGrid/CssGrid.tsx +215 -0
  83. package/src/layouts/CssGrid/index.ts +8 -0
  84. package/src/layouts/CssGrid/scripts/CssGrid.js +284 -0
  85. package/src/layouts/CssGrid/scripts/index.js +43 -0
  86. package/src/layouts/Grid/scripts/Container.js +139 -0
  87. package/src/layouts/Grid/scripts/Grid.js +184 -0
  88. package/src/layouts/Grid/scripts/GridCol.js +273 -0
  89. package/src/layouts/Grid/scripts/Row.js +154 -0
  90. package/src/layouts/Grid/scripts/index.js +48 -0
  91. package/src/layouts/MasonryGrid/MasonryGrid.tsx +71 -59
  92. package/src/lib/composables/atomix-glass/useGlassSize.ts +1 -1
  93. package/src/lib/composables/useAccordion.ts +5 -5
  94. package/src/lib/composables/useAtomixGlass.ts +111 -74
  95. package/src/lib/composables/useAtomixGlassStyles.ts +0 -2
  96. package/src/lib/composables/useBarChart.ts +2 -2
  97. package/src/lib/composables/useChart.ts +3 -2
  98. package/src/lib/composables/useChartToolbar.ts +48 -66
  99. package/src/lib/composables/useDataTable.ts +1 -1
  100. package/src/lib/composables/useDatePicker.ts +2 -2
  101. package/src/lib/composables/useEdgePanel.ts +45 -54
  102. package/src/lib/composables/useHeroBackgroundSlider.ts +5 -5
  103. package/src/lib/composables/usePhotoViewer.ts +2 -3
  104. package/src/lib/composables/usePieChart.ts +1 -1
  105. package/src/lib/composables/usePopover.ts +151 -139
  106. package/src/lib/composables/useSideMenu.ts +28 -41
  107. package/src/lib/composables/useSlider.ts +2 -6
  108. package/src/lib/composables/useTooltip.ts +2 -2
  109. package/src/lib/config/index.ts +39 -0
  110. package/src/lib/constants/components.ts +1 -0
  111. package/src/lib/theme/devtools/Comparator.tsx +1 -1
  112. package/src/lib/theme/devtools/Inspector.tsx +1 -1
  113. package/src/lib/theme/devtools/LiveEditor.tsx +1 -1
  114. package/src/lib/theme/runtime/ThemeProvider.tsx +1 -1
  115. package/src/lib/types/components.ts +1 -0
  116. package/src/styles/01-settings/_index.scss +1 -0
  117. package/src/styles/01-settings/_settings.atomix-glass.scss +174 -0
  118. package/src/styles/01-settings/_settings.masonry-grid.scss +42 -6
  119. package/src/styles/02-tools/_tools.glass.scss +6 -0
  120. package/src/styles/05-objects/_objects.masonry-grid.scss +162 -24
  121. package/src/styles/06-components/_components.atomix-glass.scss +160 -99
  122. package/scripts/cli/__tests__/README.md +0 -81
  123. package/scripts/cli/__tests__/basic.test.js +0 -116
  124. package/scripts/cli/__tests__/clean.test.js +0 -278
  125. package/scripts/cli/__tests__/component-generator.test.js +0 -332
  126. package/scripts/cli/__tests__/component-validator.test.js +0 -433
  127. package/scripts/cli/__tests__/generator.test.js +0 -613
  128. package/scripts/cli/__tests__/glass-motion.test.js +0 -256
  129. package/scripts/cli/__tests__/integration.test.js +0 -938
  130. package/scripts/cli/__tests__/migrate.test.js +0 -74
  131. package/scripts/cli/__tests__/security.test.js +0 -206
  132. package/scripts/cli/__tests__/theme-bridge.test.js +0 -507
  133. package/scripts/cli/__tests__/token-manager.test.js +0 -251
  134. package/scripts/cli/__tests__/token-provider.test.js +0 -361
  135. package/scripts/cli/__tests__/utils.test.js +0 -165
  136. package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +0 -95
  137. package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +0 -212
  138. package/src/components/AtomixGlass/stories/Customization.stories.tsx +0 -131
  139. package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +0 -348
  140. package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +0 -410
  141. package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +0 -436
  142. package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +0 -264
  143. package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +0 -247
  144. package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +0 -418
  145. package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +0 -402
  146. package/src/components/AtomixGlass/stories/Modes.stories.tsx +0 -1082
  147. package/src/components/AtomixGlass/stories/Overview.stories.tsx +0 -497
  148. package/src/components/AtomixGlass/stories/Performance.stories.tsx +0 -103
  149. package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +0 -335
  150. package/src/components/AtomixGlass/stories/Shaders.stories.tsx +0 -395
  151. package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +0 -441
  152. package/src/components/TypedButton/TypedButton.stories.tsx +0 -59
  153. package/src/components/TypedButton/TypedButton.tsx +0 -39
  154. package/src/components/TypedButton/index.ts +0 -2
  155. package/src/lib/composables/useBreadcrumb.ts +0 -81
  156. package/src/lib/composables/useChartInteractions.ts +0 -123
  157. package/src/lib/composables/useChartPerformance.ts +0 -347
  158. package/src/lib/composables/useDropdown.ts +0 -338
  159. package/src/lib/composables/useModal.ts +0 -110
  160. package/src/lib/composables/useTypedButton.ts +0 -66
  161. package/src/lib/hooks/usePerformanceMonitor.ts +0 -148
  162. package/src/lib/utils/displacement-generator.ts +0 -92
  163. package/src/lib/utils/memoryMonitor.ts +0 -191
  164. package/src/styles/01-settings/_settings.testtypecheck.scss +0 -53
  165. package/src/styles/01-settings/_settings.typedbutton.scss +0 -53
  166. package/src/styles/06-components/_components.testbutton.scss +0 -212
  167. package/src/styles/06-components/_components.testtypecheck.scss +0 -212
  168. package/src/styles/06-components/_components.typedbutton.scss +0 -212
@@ -1,338 +0,0 @@
1
- import { useState, useRef, useEffect, useCallback } from 'react';
2
- import { DROPDOWN } from '../constants/components';
3
- import type { DropdownPlacement, DropdownTrigger } from '../types/components';
4
-
5
- interface UseDropdownProps {
6
- placement?: DropdownPlacement;
7
- trigger?: DropdownTrigger;
8
- offset?: number;
9
- defaultOpen?: boolean;
10
- isOpen?: boolean;
11
- onOpenChange?: (isOpen: boolean) => void;
12
- closeOnClickOutside?: boolean;
13
- closeOnEscape?: boolean;
14
- id?: string;
15
- }
16
-
17
- interface UseDropdownReturn {
18
- isOpen: boolean;
19
- setIsOpen: (isOpen: boolean) => void;
20
- triggerRef: React.RefObject<HTMLElement | null>;
21
- menuRef: React.RefObject<HTMLElement | null>;
22
- dropdownId: string;
23
- currentPlacement: DropdownPlacement;
24
- updatePosition: () => void;
25
- }
26
-
27
- /**
28
- * Hook for managing dropdown state and position
29
- */
30
- export const useDropdown = ({
31
- placement = DROPDOWN.DEFAULTS.PLACEMENT as DropdownPlacement,
32
- trigger = DROPDOWN.DEFAULTS.TRIGGER as DropdownTrigger,
33
- offset = DROPDOWN.DEFAULTS.OFFSET,
34
- defaultOpen = false,
35
- isOpen: controlledIsOpen,
36
- onOpenChange,
37
- closeOnClickOutside = true,
38
- closeOnEscape = true,
39
- id,
40
- }: UseDropdownProps): UseDropdownReturn => {
41
- // Generate unique ID for the dropdown menu
42
- const uniqueId = useRef(`dropdown-${id || Math.random().toString(36).substring(2, 9)}`);
43
-
44
- // Setup controlled vs uncontrolled state
45
- const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState(defaultOpen);
46
-
47
- // Use either controlled or uncontrolled state
48
- const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : uncontrolledIsOpen;
49
-
50
- // Callback to update open state with notification to parent
51
- const setIsOpen = useCallback(
52
- (nextIsOpen: boolean) => {
53
- if (controlledIsOpen === undefined) {
54
- setUncontrolledIsOpen(nextIsOpen);
55
- }
56
-
57
- if (onOpenChange) {
58
- onOpenChange(nextIsOpen);
59
- }
60
- },
61
- [controlledIsOpen, onOpenChange]
62
- );
63
-
64
- // Refs for trigger and dropdown menu elements
65
- const triggerRef = useRef<HTMLElement>(null);
66
- const menuRef = useRef<HTMLElement>(null);
67
-
68
- // Current placement state
69
- const [currentPlacement, setCurrentPlacement] = useState(placement);
70
-
71
- // Handle click outside
72
- useEffect(() => {
73
- if (!isOpen || !closeOnClickOutside) return undefined;
74
-
75
- const handleClickOutside = (event: MouseEvent) => {
76
- if (
77
- menuRef.current &&
78
- triggerRef.current &&
79
- !menuRef.current.contains(event.target as Node) &&
80
- !triggerRef.current.contains(event.target as Node)
81
- ) {
82
- setIsOpen(false);
83
- }
84
- };
85
-
86
- document.addEventListener('mousedown', handleClickOutside);
87
-
88
- return () => {
89
- document.removeEventListener('mousedown', handleClickOutside);
90
- };
91
- }, [isOpen, closeOnClickOutside, setIsOpen]);
92
-
93
- // Handle escape key
94
- useEffect(() => {
95
- if (!isOpen || !closeOnEscape) return undefined;
96
-
97
- const handleEscapeKey = (event: KeyboardEvent) => {
98
- if (event.key === 'Escape') {
99
- setIsOpen(false);
100
- }
101
- };
102
-
103
- document.addEventListener('keydown', handleEscapeKey);
104
-
105
- return () => {
106
- document.removeEventListener('keydown', handleEscapeKey);
107
- };
108
- }, [isOpen, closeOnEscape, setIsOpen]);
109
-
110
- // Handle arrow key navigation
111
- useEffect(() => {
112
- if (!isOpen || !menuRef.current) return undefined;
113
-
114
- const handleKeyDown = (event: KeyboardEvent) => {
115
- const menu = menuRef.current;
116
- if (!menu) return;
117
-
118
- const items = Array.from(
119
- menu.querySelectorAll<HTMLElement>('[role="menuitem"]:not([disabled])')
120
- );
121
- if (items.length === 0) return;
122
-
123
- const currentIndex = items.indexOf(document.activeElement as HTMLElement);
124
-
125
- switch (event.key) {
126
- case 'ArrowDown':
127
- event.preventDefault();
128
- const nextIndex = (currentIndex + 1) % items.length;
129
- const nextItem = items[nextIndex];
130
- if (nextItem) nextItem.focus();
131
- break;
132
- case 'ArrowUp':
133
- event.preventDefault();
134
- const prevIndex = (currentIndex - 1 + items.length) % items.length;
135
- const prevItem = items[prevIndex];
136
- if (prevItem) prevItem.focus();
137
- break;
138
- case 'Home':
139
- event.preventDefault();
140
- const firstItem = items[0];
141
- if (firstItem) firstItem.focus();
142
- break;
143
- case 'End':
144
- event.preventDefault();
145
- const lastItem = items[items.length - 1];
146
- if (lastItem) lastItem.focus();
147
- break;
148
- case 'Tab':
149
- // Close dropdown on tab
150
- setIsOpen(false);
151
- break;
152
- default:
153
- break;
154
- }
155
- };
156
-
157
- document.addEventListener('keydown', handleKeyDown);
158
-
159
- return () => {
160
- document.removeEventListener('keydown', handleKeyDown);
161
- };
162
- }, [isOpen, setIsOpen]);
163
-
164
- // Focus management when dropdown opens
165
- useEffect(() => {
166
- if (isOpen && menuRef.current) {
167
- const firstItem = menuRef.current.querySelector<HTMLElement>(
168
- '[role="menuitem"]:not([disabled])'
169
- );
170
- if (firstItem) {
171
- setTimeout(() => firstItem.focus(), 0);
172
- }
173
- }
174
- }, [isOpen]);
175
-
176
- // Helper function to get the flipped placement if needed
177
- const getFlippedPlacement = useCallback(
178
- (
179
- placement: DropdownPlacement,
180
- triggerRect: DOMRect,
181
- menuRect: DOMRect,
182
- offset: number
183
- ): DropdownPlacement => {
184
- const viewportWidth = window.innerWidth;
185
- const viewportHeight = window.innerHeight;
186
-
187
- // Start with the requested placement
188
- let newPlacement = placement;
189
-
190
- // Flip vertical placement if needed
191
- if (
192
- placement.startsWith('bottom') &&
193
- triggerRect.bottom + menuRect.height + offset > viewportHeight
194
- ) {
195
- newPlacement = placement.replace('bottom', 'top') as DropdownPlacement;
196
- } else if (placement.startsWith('top') && triggerRect.top - menuRect.height - offset < 0) {
197
- newPlacement = placement.replace('top', 'bottom') as DropdownPlacement;
198
- }
199
-
200
- // Flip horizontal placement if needed
201
- if (placement.startsWith('left') && triggerRect.left - menuRect.width - offset < 0) {
202
- newPlacement = placement.replace('left', 'right') as DropdownPlacement;
203
- } else if (
204
- placement.startsWith('right') &&
205
- triggerRect.right + menuRect.width + offset > viewportWidth
206
- ) {
207
- newPlacement = placement.replace('right', 'left') as DropdownPlacement;
208
- }
209
-
210
- // Adjust alignment for top/bottom placements
211
- if (newPlacement.startsWith('top') || newPlacement.startsWith('bottom')) {
212
- if (newPlacement.endsWith('start') && triggerRect.left + menuRect.width > viewportWidth) {
213
- newPlacement = newPlacement.replace('start', 'end') as DropdownPlacement;
214
- } else if (newPlacement.endsWith('end') && triggerRect.right - menuRect.width < 0) {
215
- newPlacement = newPlacement.replace('end', 'start') as DropdownPlacement;
216
- }
217
- }
218
-
219
- return newPlacement;
220
- },
221
- []
222
- );
223
-
224
- // Helper function to calculate position based on placement
225
- const calculatePosition = useCallback(
226
- (
227
- placement: DropdownPlacement,
228
- triggerRect: DOMRect,
229
- menuRect: DOMRect,
230
- offset: number
231
- ): { top: number; left: number } => {
232
- let top = 0;
233
- let left = 0;
234
-
235
- // Vertical positioning
236
- if (placement.startsWith('bottom')) {
237
- top = triggerRect.height + offset;
238
- } else if (placement.startsWith('top')) {
239
- top = -menuRect.height - offset;
240
- } else if (placement.startsWith('left') || placement.startsWith('right')) {
241
- top = triggerRect.height / 2 - menuRect.height / 2;
242
- }
243
-
244
- // Horizontal positioning
245
- if (placement.startsWith('left')) {
246
- left = -menuRect.width - offset;
247
- } else if (placement.startsWith('right')) {
248
- left = triggerRect.width + offset;
249
- } else if (placement.endsWith('start')) {
250
- left = 0;
251
- } else if (placement.endsWith('end')) {
252
- left = triggerRect.width - menuRect.width;
253
- } else {
254
- left = triggerRect.width / 2 - menuRect.width / 2;
255
- }
256
-
257
- return { top, left };
258
- },
259
- []
260
- );
261
-
262
- // Calculate and update dropdown position
263
- const updatePosition = useCallback(() => {
264
- if (!isOpen || !triggerRef.current || !menuRef.current) return;
265
-
266
- const triggerRect = triggerRef.current.getBoundingClientRect();
267
- const menuRect = menuRef.current.getBoundingClientRect();
268
-
269
- // Get the optimal placement
270
- const newPlacement = getFlippedPlacement(placement, triggerRect, menuRect, offset);
271
-
272
- // Calculate position based on the new placement
273
- const { top, left } = calculatePosition(newPlacement, triggerRect, menuRect, offset);
274
-
275
- // Apply position
276
- menuRef.current.style.position = 'absolute';
277
- menuRef.current.style.top = `${top}px`;
278
- menuRef.current.style.left = `${left}px`;
279
-
280
- // Update placement state if it changed
281
- if (newPlacement !== currentPlacement) {
282
- setCurrentPlacement(newPlacement);
283
- }
284
- }, [isOpen, offset, placement, currentPlacement, getFlippedPlacement, calculatePosition]);
285
-
286
- // Update position when menu is opened
287
- useEffect(() => {
288
- if (!isOpen) return undefined;
289
-
290
- // Initial position update
291
- updatePosition();
292
-
293
- // Use ResizeObserver to detect size changes in the menu
294
- let resizeObserver: ResizeObserver | null = null;
295
- if (menuRef.current && typeof ResizeObserver !== 'undefined') {
296
- resizeObserver = new ResizeObserver(() => {
297
- requestAnimationFrame(updatePosition);
298
- });
299
- resizeObserver.observe(menuRef.current);
300
- }
301
-
302
- // Update position on resize/scroll
303
- const handleResize = () => {
304
- requestAnimationFrame(updatePosition);
305
- };
306
-
307
- const handleScroll = () => {
308
- requestAnimationFrame(updatePosition);
309
- };
310
-
311
- window.addEventListener('resize', handleResize);
312
- window.addEventListener('scroll', handleScroll, { passive: true });
313
-
314
- // Fallback for browsers without ResizeObserver or for dynamic content changes
315
- // Use a less frequent interval (500ms instead of 200ms)
316
- const intervalId = window.setInterval(updatePosition, 500);
317
-
318
- return () => {
319
- if (resizeObserver && menuRef.current) {
320
- resizeObserver.unobserve(menuRef.current);
321
- resizeObserver.disconnect();
322
- }
323
- window.removeEventListener('resize', handleResize);
324
- window.removeEventListener('scroll', handleScroll);
325
- window.clearInterval(intervalId);
326
- };
327
- }, [isOpen, updatePosition]);
328
-
329
- return {
330
- isOpen,
331
- setIsOpen,
332
- triggerRef,
333
- menuRef,
334
- dropdownId: uniqueId.current,
335
- currentPlacement,
336
- updatePosition,
337
- };
338
- };
@@ -1,110 +0,0 @@
1
- import { useState, useCallback, useEffect } from 'react';
2
-
3
- export interface UseModalProps {
4
- /**
5
- * Whether the modal is open
6
- */
7
- isOpen?: boolean;
8
-
9
- /**
10
- * Callback when modal state changes
11
- */
12
- onOpenChange?: (isOpen: boolean) => void;
13
-
14
- /**
15
- * Callback when modal opens
16
- */
17
- onOpen?: () => void;
18
-
19
- /**
20
- * Callback when modal closes
21
- */
22
- onClose?: () => void;
23
- }
24
-
25
- export interface UseModalReturn {
26
- /**
27
- * Current open state
28
- */
29
- isOpen: boolean;
30
-
31
- /**
32
- * Function to open the modal
33
- */
34
- open: () => void;
35
-
36
- /**
37
- * Function to close the modal
38
- */
39
- close: () => void;
40
-
41
- /**
42
- * Function to toggle the modal
43
- */
44
- toggle: () => void;
45
- }
46
-
47
- /**
48
- * Hook for managing modal state
49
- */
50
- export function useModal({
51
- isOpen: isOpenProp,
52
- onOpenChange,
53
- onOpen,
54
- onClose,
55
- }: UseModalProps = {}): UseModalReturn {
56
- // For uncontrolled usage
57
- const [isOpenState, setIsOpenState] = useState(false);
58
-
59
- // Determine if we're in controlled or uncontrolled mode
60
- const isControlled = isOpenProp !== undefined;
61
- const isOpen = isControlled ? !!isOpenProp : isOpenState;
62
-
63
- // Update internal state when prop changes (for controlled mode)
64
- useEffect(() => {
65
- if (isControlled) {
66
- setIsOpenState(!!isOpenProp);
67
- }
68
- }, [isOpenProp, isControlled]);
69
-
70
- const updateOpen = useCallback(
71
- (nextIsOpen: boolean) => {
72
- // For uncontrolled mode, update internal state
73
- if (!isControlled) {
74
- setIsOpenState(nextIsOpen);
75
- }
76
-
77
- // Call the change handler in either mode
78
- if (onOpenChange) {
79
- onOpenChange(nextIsOpen);
80
- }
81
-
82
- // Call the specific handler
83
- if (nextIsOpen && onOpen) {
84
- onOpen();
85
- } else if (!nextIsOpen && onClose) {
86
- onClose();
87
- }
88
- },
89
- [isControlled, onOpenChange, onOpen, onClose]
90
- );
91
-
92
- const open = useCallback(() => {
93
- updateOpen(true);
94
- }, [updateOpen]);
95
-
96
- const close = useCallback(() => {
97
- updateOpen(false);
98
- }, [updateOpen]);
99
-
100
- const toggle = useCallback(() => {
101
- updateOpen(!isOpen);
102
- }, [isOpen, updateOpen]);
103
-
104
- return {
105
- isOpen,
106
- open,
107
- close,
108
- toggle,
109
- };
110
- }
@@ -1,66 +0,0 @@
1
- import { TypedButtonProps } from '../types/components';
2
- import { TYPEDBUTTON } from '../constants/components';
3
-
4
- /**
5
- * TypedButton state and functionality
6
- * @param initialProps - Initial typedbutton properties
7
- * @returns TypedButton state and methods
8
- */
9
- export function useTypedButton(initialProps?: Partial<TypedButtonProps>) {
10
- // Default typedbutton properties
11
- const defaultProps: Partial<TypedButtonProps> = {
12
- variant: 'primary',
13
- size: 'md',
14
- disabled: false,
15
- ...initialProps,
16
- };
17
-
18
- /**
19
- * Generate typedbutton class based on properties
20
- * @param props - TypedButton properties
21
- * @returns Class string
22
- */
23
- const generateClassNames = (props: Partial<TypedButtonProps> = {}): string => {
24
- const {
25
- variant = defaultProps.variant,
26
- size = defaultProps.size,
27
- disabled = defaultProps.disabled,
28
- glass = defaultProps.glass,
29
- className = '',
30
- } = props;
31
-
32
- const sizeClass = size === 'md' ? '' : `c-typedbutton--${size}`;
33
- const disabledClass = disabled ? 'c-typedbutton--disabled' : '';
34
- const glassClass = glass ? 'c-typedbutton--glass' : '';
35
-
36
- return [
37
- TYPEDBUTTON.BASE_CLASS,
38
- `c-typedbutton--${variant}`,
39
- sizeClass,
40
- disabledClass,
41
- glassClass,
42
- className,
43
- ]
44
- .filter(Boolean)
45
- .join(' ');
46
- };
47
-
48
- /**
49
- * Handle typedbutton click with disabled check
50
- * @param handler - Click handler function
51
- * @returns Function that respects disabled state
52
- */
53
- const handleClick = (handler?: (event: React.MouseEvent<HTMLDivElement>) => void) => {
54
- return (event: React.MouseEvent<HTMLDivElement>) => {
55
- if (!defaultProps.disabled && handler) {
56
- handler(event);
57
- }
58
- };
59
- };
60
-
61
- return {
62
- defaultProps,
63
- generateClassNames,
64
- handleClick,
65
- };
66
- }
@@ -1,148 +0,0 @@
1
- /**
2
- * Performance Monitoring Hook
3
- *
4
- * Tracks component render times and re-render counts
5
- * for performance analysis and optimization
6
- */
7
-
8
- import { useEffect, useRef } from 'react';
9
-
10
- export interface PerformanceMetrics {
11
- /**
12
- * Component name
13
- */
14
- componentName: string;
15
- /**
16
- * Number of renders
17
- */
18
- renderCount: number;
19
- /**
20
- * Average render time in milliseconds
21
- */
22
- averageRenderTime: number;
23
- /**
24
- * Total render time in milliseconds
25
- */
26
- totalRenderTime: number;
27
- /**
28
- * Maximum render time in milliseconds
29
- */
30
- maxRenderTime: number;
31
- /**
32
- * Minimum render time in milliseconds
33
- */
34
- minRenderTime: number;
35
- }
36
-
37
- /**
38
- * Options for performance monitoring
39
- */
40
- export interface UsePerformanceMonitorOptions {
41
- /**
42
- * Component name to track
43
- */
44
- componentName: string;
45
- /**
46
- * Whether to log metrics to console (development only)
47
- */
48
- logToConsole?: boolean;
49
- /**
50
- * Threshold in milliseconds to warn about slow renders
51
- */
52
- warnThreshold?: number;
53
- /**
54
- * Callback to report metrics (e.g., to analytics)
55
- */
56
- onMetrics?: (metrics: PerformanceMetrics) => void;
57
- }
58
-
59
- /**
60
- * Hook to monitor component performance
61
- *
62
- * @param options - Performance monitoring options
63
- * @returns Performance metrics
64
- *
65
- * @example
66
- * ```tsx
67
- * function MyComponent() {
68
- * usePerformanceMonitor({
69
- * componentName: 'MyComponent',
70
- * warnThreshold: 16, // Warn if render takes > 16ms (1 frame)
71
- * });
72
- *
73
- * return <div>Content</div>;
74
- * }
75
- * ```
76
- */
77
- export function usePerformanceMonitor(options: UsePerformanceMonitorOptions) {
78
- const {
79
- componentName,
80
- logToConsole = typeof process === 'undefined' || process.env?.NODE_ENV === 'development',
81
- warnThreshold = 16,
82
- onMetrics,
83
- } = options;
84
-
85
- const metricsRef = useRef<PerformanceMetrics>({
86
- componentName,
87
- renderCount: 0,
88
- averageRenderTime: 0,
89
- totalRenderTime: 0,
90
- maxRenderTime: 0,
91
- minRenderTime: Infinity,
92
- });
93
-
94
- const renderStartRef = useRef<number>(0);
95
-
96
- useEffect(() => {
97
- // Start timing the render
98
- renderStartRef.current = performance.now();
99
- });
100
-
101
- useEffect(() => {
102
- // Calculate render time
103
- const renderTime = performance.now() - renderStartRef.current;
104
- const metrics = metricsRef.current;
105
-
106
- // Update metrics
107
- metrics.renderCount += 1;
108
- metrics.totalRenderTime += renderTime;
109
- metrics.averageRenderTime = metrics.totalRenderTime / metrics.renderCount;
110
- metrics.maxRenderTime = Math.max(metrics.maxRenderTime, renderTime);
111
- metrics.minRenderTime = Math.min(metrics.minRenderTime, renderTime);
112
-
113
- // Warn if render is slow
114
- if (renderTime > warnThreshold && logToConsole) {
115
- console.warn(
116
- `[Performance] ${componentName} render took ${renderTime.toFixed(2)}ms ` +
117
- `(threshold: ${warnThreshold}ms)`
118
- );
119
- }
120
-
121
- // Log metrics in development
122
- if (logToConsole && metrics.renderCount % 10 === 0) {
123
- console.log(`[Performance] ${componentName} metrics:`, {
124
- renderCount: metrics.renderCount,
125
- averageRenderTime: metrics.averageRenderTime.toFixed(2) + 'ms',
126
- maxRenderTime: metrics.maxRenderTime.toFixed(2) + 'ms',
127
- minRenderTime: metrics.minRenderTime.toFixed(2) + 'ms',
128
- });
129
- }
130
-
131
- // Report metrics via callback
132
- if (onMetrics) {
133
- onMetrics({ ...metrics });
134
- }
135
- });
136
-
137
- return metricsRef.current;
138
- }
139
-
140
- /**
141
- * Get all performance metrics for all monitored components
142
- * (useful for debugging and analytics)
143
- */
144
- export function getPerformanceMetrics(): PerformanceMetrics[] {
145
- // This would need to be implemented with a global store
146
- // For now, this is a placeholder
147
- return [];
148
- }