@abstraks-dev/ui-library 1.0.1

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 (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +708 -0
  3. package/dist/__tests__/Anchor.test.js +145 -0
  4. package/dist/__tests__/ArrowRight.test.js +91 -0
  5. package/dist/__tests__/Avatar.test.js +123 -0
  6. package/dist/__tests__/Button.test.js +82 -0
  7. package/dist/__tests__/Card.test.js +198 -0
  8. package/dist/__tests__/CheckCircle.test.js +98 -0
  9. package/dist/__tests__/Checkbox.test.js +161 -0
  10. package/dist/__tests__/ChevronDown.test.js +73 -0
  11. package/dist/__tests__/Close.test.js +98 -0
  12. package/dist/__tests__/EditSquare.test.js +99 -0
  13. package/dist/__tests__/Error.test.js +74 -0
  14. package/dist/__tests__/Footer.test.js +66 -0
  15. package/dist/__tests__/Heading.test.js +227 -0
  16. package/dist/__tests__/Hero.test.js +74 -0
  17. package/dist/__tests__/Label.test.js +123 -0
  18. package/dist/__tests__/Loader.test.js +115 -0
  19. package/dist/__tests__/MenuHover.test.js +137 -0
  20. package/dist/__tests__/Paragraph.test.js +93 -0
  21. package/dist/__tests__/PlusCircle.test.js +99 -0
  22. package/dist/__tests__/Radio.test.js +153 -0
  23. package/dist/__tests__/Select.test.js +187 -0
  24. package/dist/__tests__/Tabs.test.js +162 -0
  25. package/dist/__tests__/TextArea.test.js +127 -0
  26. package/dist/__tests__/TextInput.test.js +181 -0
  27. package/dist/__tests__/Toggle.test.js +120 -0
  28. package/dist/__tests__/TrashX.test.js +99 -0
  29. package/dist/__tests__/useHeadingAccessibility.test.js +144 -0
  30. package/dist/components/Anchor.js +131 -0
  31. package/dist/components/Animation.js +129 -0
  32. package/dist/components/AnimationGroup.js +207 -0
  33. package/dist/components/AnimationToggle.js +216 -0
  34. package/dist/components/Avatar.js +153 -0
  35. package/dist/components/Button.js +218 -0
  36. package/dist/components/Card.js +222 -0
  37. package/dist/components/Checkbox.js +305 -0
  38. package/dist/components/Crud.js +564 -0
  39. package/dist/components/DragAndDrop.js +337 -0
  40. package/dist/components/Error.js +206 -0
  41. package/dist/components/Footer.js +99 -0
  42. package/dist/components/Form.js +412 -0
  43. package/dist/components/Header.js +372 -0
  44. package/dist/components/Heading.js +134 -0
  45. package/dist/components/Hero.js +181 -0
  46. package/dist/components/Label.js +256 -0
  47. package/dist/components/Loader.js +302 -0
  48. package/dist/components/MenuHover.js +114 -0
  49. package/dist/components/Paragraph.js +128 -0
  50. package/dist/components/Prompt.js +61 -0
  51. package/dist/components/Radio.js +254 -0
  52. package/dist/components/Select.js +422 -0
  53. package/dist/components/SideMenu.js +313 -0
  54. package/dist/components/Tabs.js +297 -0
  55. package/dist/components/TextArea.js +370 -0
  56. package/dist/components/TextInput.js +286 -0
  57. package/dist/components/Toggle.js +186 -0
  58. package/dist/components/crudFiles/CrudEditBase.js +150 -0
  59. package/dist/components/crudFiles/CrudViewBase.js +39 -0
  60. package/dist/components/crudFiles/crudDevelopment.js +118 -0
  61. package/dist/components/crudFiles/crudEditHandlers.js +50 -0
  62. package/dist/constants/animation.js +30 -0
  63. package/dist/icons/ArrowIcon.js +32 -0
  64. package/dist/icons/ArrowRight.js +33 -0
  65. package/dist/icons/CheckCircle.js +33 -0
  66. package/dist/icons/ChevronDown.js +28 -0
  67. package/dist/icons/Close.js +33 -0
  68. package/dist/icons/EditSquare.js +33 -0
  69. package/dist/icons/Ellipses.js +34 -0
  70. package/dist/icons/Hamburger.js +39 -0
  71. package/dist/icons/LoadingSpinner.js +42 -0
  72. package/dist/icons/PlusCircle.js +33 -0
  73. package/dist/icons/SaveIcon.js +32 -0
  74. package/dist/icons/TrashX.js +33 -0
  75. package/dist/icons/__tests__/CheckCircle.test.js +9 -0
  76. package/dist/icons/__tests__/ChevronDown.test.js +9 -0
  77. package/dist/icons/__tests__/Close.test.js +9 -0
  78. package/dist/icons/__tests__/EditSquare.test.js +9 -0
  79. package/dist/icons/__tests__/PlusCircle.test.js +9 -0
  80. package/dist/icons/__tests__/TrashX.test.js +9 -0
  81. package/dist/icons/index.js +89 -0
  82. package/dist/index.js +332 -0
  83. package/dist/setupTests.js +3 -0
  84. package/dist/styles/_variables.scss +286 -0
  85. package/dist/styles/anchor.scss +40 -0
  86. package/dist/styles/animation-accessibility.scss +96 -0
  87. package/dist/styles/animation-toggle.scss +233 -0
  88. package/dist/styles/animation.scss +3781 -0
  89. package/dist/styles/avatar.scss +285 -0
  90. package/dist/styles/button.scss +430 -0
  91. package/dist/styles/card.scss +210 -0
  92. package/dist/styles/checkbox.scss +160 -0
  93. package/dist/styles/crud.scss +474 -0
  94. package/dist/styles/dragAndDrop.scss +312 -0
  95. package/dist/styles/error.scss +232 -0
  96. package/dist/styles/footer.scss +58 -0
  97. package/dist/styles/form.scss +420 -0
  98. package/dist/styles/grid.scss +29 -0
  99. package/dist/styles/header.scss +276 -0
  100. package/dist/styles/heading.scss +118 -0
  101. package/dist/styles/hero.scss +185 -0
  102. package/dist/styles/htmlElements.scss +20 -0
  103. package/dist/styles/image.scss +9 -0
  104. package/dist/styles/label.scss +340 -0
  105. package/dist/styles/list-item.scss +5 -0
  106. package/dist/styles/loader.scss +354 -0
  107. package/dist/styles/logo.scss +19 -0
  108. package/dist/styles/main.css +9056 -0
  109. package/dist/styles/main.css.map +1 -0
  110. package/dist/styles/main.scss +0 -0
  111. package/dist/styles/menu-hover.scss +30 -0
  112. package/dist/styles/paragraph.scss +88 -0
  113. package/dist/styles/prompt.scss +51 -0
  114. package/dist/styles/radio.scss +202 -0
  115. package/dist/styles/select.scss +363 -0
  116. package/dist/styles/side-menu.scss +334 -0
  117. package/dist/styles/tabs.scss +540 -0
  118. package/dist/styles/text-area.scss +388 -0
  119. package/dist/styles/text-input.scss +171 -0
  120. package/dist/styles/toggle.scss +0 -0
  121. package/dist/styles/unordered-list.scss +8 -0
  122. package/dist/utils/ScrollHandler.js +30 -0
  123. package/dist/utils/accessibility.js +128 -0
  124. package/dist/utils/heroUtils.js +316 -0
  125. package/dist/utils/index.js +104 -0
  126. package/dist/utils/inputValidation.js +29 -0
  127. package/dist/utils/keyboardNavigation.js +536 -0
  128. package/dist/utils/labelUtils.js +708 -0
  129. package/dist/utils/loaderUtils.js +387 -0
  130. package/dist/utils/menuUtils.js +575 -0
  131. package/dist/utils/useHeadingAccessibility.js +298 -0
  132. package/dist/utils/useRadioGroup.js +260 -0
  133. package/dist/utils/useSelectAccessibility.js +426 -0
  134. package/dist/utils/useTabsAccessibility.js +278 -0
  135. package/dist/utils/useTextAreaAccessibility.js +255 -0
  136. package/dist/utils/useTextInputAccessibility.js +295 -0
  137. package/dist/utils/useTypographyAccessibility.js +168 -0
  138. package/dist/utils/useWindowSize.js +32 -0
  139. package/dist/utils/utils/ScrollHandler.js +26 -0
  140. package/dist/utils/utils/accessibility.js +133 -0
  141. package/dist/utils/utils/heroUtils.js +348 -0
  142. package/dist/utils/utils/index.js +9 -0
  143. package/dist/utils/utils/inputValidation.js +22 -0
  144. package/dist/utils/utils/keyboardNavigation.js +664 -0
  145. package/dist/utils/utils/labelUtils.js +772 -0
  146. package/dist/utils/utils/loaderUtils.js +436 -0
  147. package/dist/utils/utils/menuUtils.js +651 -0
  148. package/dist/utils/utils/useHeadingAccessibility.js +334 -0
  149. package/dist/utils/utils/useRadioGroup.js +311 -0
  150. package/dist/utils/utils/useSelectAccessibility.js +498 -0
  151. package/dist/utils/utils/useTabsAccessibility.js +316 -0
  152. package/dist/utils/utils/useTextAreaAccessibility.js +303 -0
  153. package/dist/utils/utils/useTextInputAccessibility.js +338 -0
  154. package/dist/utils/utils/useTypographyAccessibility.js +180 -0
  155. package/dist/utils/utils/useWindowSize.js +26 -0
  156. package/dist/utils/utils/validation.js +131 -0
  157. package/dist/utils/validation.js +139 -0
  158. package/package.json +90 -0
@@ -0,0 +1,387 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.variantGuide = exports.useLoadingState = exports.useLoaderAnnouncements = exports.sizeGuide = exports.loadingMessages = exports.loaderTestingUtils = exports.loaderPerformanceUtils = exports.default = void 0;
7
+ var _react = require("react");
8
+ /**
9
+ * Loader Component Utilities
10
+ * Provides helper functions and hooks for Loader component functionality
11
+ */
12
+
13
+ /**
14
+ * Hook for managing loading states with automatic timeout
15
+ * @param {Object} options - Configuration options
16
+ * @param {boolean} options.initialLoading - Initial loading state
17
+ * @param {number} options.minLoadTime - Minimum loading time in ms
18
+ * @param {number} options.maxLoadTime - Maximum loading time before timeout
19
+ * @param {Function} options.onTimeout - Callback when loading times out
20
+ * @returns {Object} Loading state and handlers
21
+ */
22
+ const useLoadingState = ({
23
+ initialLoading = false,
24
+ minLoadTime = 300,
25
+ maxLoadTime = 30000,
26
+ onTimeout = null
27
+ } = {}) => {
28
+ const [isLoading, setIsLoading] = (0, _react.useState)(initialLoading);
29
+ const [loadingProgress, setLoadingProgress] = (0, _react.useState)(0);
30
+ const [hasTimedOut, setHasTimedOut] = (0, _react.useState)(false);
31
+ const [loadingMessage, setLoadingMessage] = (0, _react.useState)('Loading...');
32
+ const startTimeRef = (0, _react.useRef)(null);
33
+ const timeoutRef = (0, _react.useRef)(null);
34
+ const progressIntervalRef = (0, _react.useRef)(null);
35
+ const startLoading = (0, _react.useCallback)((message = 'Loading...') => {
36
+ setIsLoading(true);
37
+ setHasTimedOut(false);
38
+ setLoadingProgress(0);
39
+ setLoadingMessage(message);
40
+ startTimeRef.current = Date.now();
41
+
42
+ // Set up timeout
43
+ if (maxLoadTime > 0) {
44
+ timeoutRef.current = setTimeout(() => {
45
+ setHasTimedOut(true);
46
+ setLoadingMessage('Loading is taking longer than expected...');
47
+ if (onTimeout) onTimeout();
48
+ }, maxLoadTime);
49
+ }
50
+
51
+ // Set up progress simulation
52
+ progressIntervalRef.current = setInterval(() => {
53
+ setLoadingProgress(prev => {
54
+ const newProgress = Math.min(prev + Math.random() * 10, 90);
55
+ return newProgress;
56
+ });
57
+ }, 200);
58
+ }, [maxLoadTime, onTimeout]);
59
+ const stopLoading = (0, _react.useCallback)(() => {
60
+ const loadTime = startTimeRef.current ? Date.now() - startTimeRef.current : 0;
61
+
62
+ // Ensure minimum load time for UX
63
+ const remainingTime = Math.max(0, minLoadTime - loadTime);
64
+ setTimeout(() => {
65
+ setIsLoading(false);
66
+ setLoadingProgress(100);
67
+ setHasTimedOut(false);
68
+
69
+ // Clean up timers
70
+ if (timeoutRef.current) {
71
+ clearTimeout(timeoutRef.current);
72
+ timeoutRef.current = null;
73
+ }
74
+ if (progressIntervalRef.current) {
75
+ clearInterval(progressIntervalRef.current);
76
+ progressIntervalRef.current = null;
77
+ }
78
+ }, remainingTime);
79
+ }, [minLoadTime]);
80
+ const updateMessage = (0, _react.useCallback)(message => {
81
+ setLoadingMessage(message);
82
+ }, []);
83
+
84
+ // Cleanup on unmount
85
+ (0, _react.useEffect)(() => {
86
+ return () => {
87
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
88
+ if (progressIntervalRef.current) clearInterval(progressIntervalRef.current);
89
+ };
90
+ }, []);
91
+ return {
92
+ isLoading,
93
+ loadingProgress,
94
+ hasTimedOut,
95
+ loadingMessage,
96
+ startLoading,
97
+ stopLoading,
98
+ updateMessage
99
+ };
100
+ };
101
+
102
+ /**
103
+ * Hook for managing loader accessibility announcements
104
+ * @param {Object} options - Configuration options
105
+ * @returns {Object} Accessibility utilities
106
+ */
107
+ exports.useLoadingState = useLoadingState;
108
+ const useLoaderAnnouncements = ({
109
+ politeAnnouncements = true,
110
+ announceProgress = false
111
+ } = {}) => {
112
+ const [announcement, setAnnouncement] = (0, _react.useState)('');
113
+ const liveRegionRef = (0, _react.useRef)(null);
114
+ const announce = (0, _react.useCallback)((message, priority = 'polite') => {
115
+ setAnnouncement(message);
116
+
117
+ // Create live region if needed
118
+ if (!liveRegionRef.current) {
119
+ const region = document.createElement('div');
120
+ region.setAttribute('aria-live', priority);
121
+ region.setAttribute('aria-atomic', 'true');
122
+ region.className = 'sr-only';
123
+ region.style.cssText = `
124
+ position: absolute !important;
125
+ width: 1px !important;
126
+ height: 1px !important;
127
+ padding: 0 !important;
128
+ margin: -1px !important;
129
+ overflow: hidden !important;
130
+ clip: rect(0, 0, 0, 0) !important;
131
+ white-space: nowrap !important;
132
+ border: 0 !important;
133
+ `;
134
+ document.body.appendChild(region);
135
+ liveRegionRef.current = region;
136
+ }
137
+
138
+ // Announce message
139
+ liveRegionRef.current.textContent = message;
140
+
141
+ // Clear after announcement
142
+ setTimeout(() => {
143
+ if (liveRegionRef.current) {
144
+ liveRegionRef.current.textContent = '';
145
+ }
146
+ }, 1000);
147
+ }, []);
148
+ const announceLoadingStart = (0, _react.useCallback)((message = 'Loading started') => {
149
+ if (politeAnnouncements) {
150
+ announce(message, 'polite');
151
+ }
152
+ }, [announce, politeAnnouncements]);
153
+ const announceLoadingComplete = (0, _react.useCallback)((message = 'Loading complete') => {
154
+ if (politeAnnouncements) {
155
+ announce(message, 'polite');
156
+ }
157
+ }, [announce, politeAnnouncements]);
158
+ const announceProgressUpdate = (0, _react.useCallback)((progress, message) => {
159
+ if (announceProgress && progress % 25 === 0) {
160
+ announce(`${message} ${progress}% complete`, 'polite');
161
+ }
162
+ }, [announce, announceProgress]);
163
+
164
+ // Cleanup
165
+ (0, _react.useEffect)(() => {
166
+ return () => {
167
+ if (liveRegionRef.current && document.body.contains(liveRegionRef.current)) {
168
+ document.body.removeChild(liveRegionRef.current);
169
+ }
170
+ };
171
+ }, []);
172
+ return {
173
+ announcement,
174
+ announce,
175
+ announceLoadingStart,
176
+ announceLoadingComplete,
177
+ announceProgressUpdate
178
+ };
179
+ };
180
+
181
+ /**
182
+ * Common loading messages for different contexts
183
+ */
184
+ exports.useLoaderAnnouncements = useLoaderAnnouncements;
185
+ const loadingMessages = exports.loadingMessages = {
186
+ general: 'Loading...',
187
+ saving: 'Saving your changes...',
188
+ loading: 'Loading content...',
189
+ processing: 'Processing your request...',
190
+ uploading: 'Uploading file...',
191
+ downloading: 'Downloading...',
192
+ authenticating: 'Signing you in...',
193
+ searching: 'Searching...',
194
+ deleting: 'Deleting item...',
195
+ creating: 'Creating new item...',
196
+ updating: 'Updating information...',
197
+ connecting: 'Connecting...',
198
+ syncing: 'Syncing data...',
199
+ importing: 'Importing data...',
200
+ exporting: 'Exporting data...'
201
+ };
202
+
203
+ /**
204
+ * Size recommendations based on container/context
205
+ */
206
+ const sizeGuide = exports.sizeGuide = {
207
+ button: 'sm',
208
+ card: 'md',
209
+ modal: 'md',
210
+ page: 'lg',
211
+ fullscreen: 'xl',
212
+ inline: 'sm',
213
+ sidebar: 'md',
214
+ dashboard: 'lg'
215
+ };
216
+
217
+ /**
218
+ * Variant recommendations based on context
219
+ */
220
+ const variantGuide = exports.variantGuide = {
221
+ data: 'svg',
222
+ // Data loading
223
+ file: 'pulse',
224
+ // File operations
225
+ search: 'dots',
226
+ // Search operations
227
+ save: 'spinner',
228
+ // Save operations
229
+ general: 'svg',
230
+ // General loading
231
+ processing: 'pulse',
232
+ // Heavy processing
233
+ quick: 'dots' // Quick operations
234
+ };
235
+
236
+ /**
237
+ * Accessibility testing utilities for loaders
238
+ */
239
+ const loaderTestingUtils = exports.loaderTestingUtils = {
240
+ /**
241
+ * Validates loader accessibility attributes
242
+ */
243
+ validateLoaderAccessibility() {
244
+ const loaders = document.querySelectorAll('[role="status"]');
245
+ const results = [];
246
+ loaders.forEach(loader => {
247
+ const hasAriaLabel = !!loader.getAttribute('aria-label');
248
+ const hasAriaLive = !!loader.getAttribute('aria-live');
249
+ const hasAriaBusy = loader.getAttribute('aria-busy') === 'true';
250
+ const hasScreenReaderText = !!loader.querySelector('.sr-only');
251
+ results.push({
252
+ element: loader.className,
253
+ hasRole: loader.getAttribute('role') === 'status',
254
+ hasAriaLabel,
255
+ hasAriaLive,
256
+ hasAriaBusy,
257
+ hasScreenReaderText,
258
+ ariaLabel: loader.getAttribute('aria-label'),
259
+ isAccessible: hasAriaLabel && hasAriaLive && hasScreenReaderText
260
+ });
261
+ });
262
+ return results;
263
+ },
264
+ /**
265
+ * Tests animation respect for reduced motion
266
+ */
267
+ validateMotionPreferences() {
268
+ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
269
+ const animatedElements = document.querySelectorAll('.loader__svg, .loader__spinner, .loader__dots, .loader__pulse');
270
+ const results = [];
271
+ animatedElements.forEach(element => {
272
+ const computedStyle = window.getComputedStyle(element);
273
+ const hasAnimation = computedStyle.animationName !== 'none';
274
+ const animationDuration = computedStyle.animationDuration;
275
+ results.push({
276
+ element: element.className,
277
+ prefersReducedMotion,
278
+ hasAnimation,
279
+ animationDuration,
280
+ respectsPreference: prefersReducedMotion ? animationDuration === '0s' : true
281
+ });
282
+ });
283
+ return results;
284
+ },
285
+ /**
286
+ * Tests loader focus management
287
+ */
288
+ validateFocusManagement() {
289
+ const loaders = document.querySelectorAll('[role="status"]');
290
+ const results = [];
291
+ loaders.forEach(loader => {
292
+ const isFocusable = loader.tabIndex >= 0;
293
+ const hasProperFocusStyle = !!window.getComputedStyle(loader, ':focus').outline;
294
+ results.push({
295
+ element: loader.className,
296
+ isFocusable,
297
+ hasProperFocusStyle,
298
+ tabIndex: loader.tabIndex,
299
+ isAccessible: !isFocusable // Loaders shouldn't be focusable
300
+ });
301
+ });
302
+ return results;
303
+ },
304
+ /**
305
+ * Tests high contrast compatibility
306
+ */
307
+ validateHighContrast() {
308
+ const loaders = document.querySelectorAll('.loader');
309
+ const results = [];
310
+ loaders.forEach(loader => {
311
+ const style = window.getComputedStyle(loader);
312
+ const spinnerElements = loader.querySelectorAll('.loader__svg, .loader__spinner, .loader__dots, .loader__pulse');
313
+ let hasContrastStyles = false;
314
+ spinnerElements.forEach(spinner => {
315
+ const spinnerStyle = window.getComputedStyle(spinner);
316
+ // Check if element has contrast-friendly styling
317
+ hasContrastStyles = spinnerStyle.border !== 'none' || spinnerStyle.outline !== 'none';
318
+ });
319
+ results.push({
320
+ element: loader.className,
321
+ hasContrastStyles,
322
+ backgroundColor: style.backgroundColor,
323
+ color: style.color,
324
+ isHighContrastReady: hasContrastStyles
325
+ });
326
+ });
327
+ return results;
328
+ },
329
+ /**
330
+ * Comprehensive loader audit
331
+ */
332
+ auditLoader() {
333
+ return {
334
+ accessibility: this.validateLoaderAccessibility(),
335
+ motionPreferences: this.validateMotionPreferences(),
336
+ focusManagement: this.validateFocusManagement(),
337
+ highContrast: this.validateHighContrast(),
338
+ timestamp: new Date().toISOString()
339
+ };
340
+ }
341
+ };
342
+
343
+ /**
344
+ * Performance utilities for loaders
345
+ */
346
+ const loaderPerformanceUtils = exports.loaderPerformanceUtils = {
347
+ /**
348
+ * Measures loader render performance
349
+ */
350
+ measureRenderTime: callback => {
351
+ const start = performance.now();
352
+ callback();
353
+ const end = performance.now();
354
+ return end - start;
355
+ },
356
+ /**
357
+ * Monitors loader animation performance
358
+ */
359
+ monitorAnimationPerformance: element => {
360
+ let frameCount = 0;
361
+ let lastTime = performance.now();
362
+ const monitor = () => {
363
+ frameCount++;
364
+ const currentTime = performance.now();
365
+ const deltaTime = currentTime - lastTime;
366
+ if (deltaTime >= 1000) {
367
+ const fps = Math.round(frameCount * 1000 / deltaTime);
368
+ console.log(`Loader animation FPS: ${fps}`);
369
+ frameCount = 0;
370
+ lastTime = currentTime;
371
+ }
372
+ if (element && element.offsetParent) {
373
+ requestAnimationFrame(monitor);
374
+ }
375
+ };
376
+ requestAnimationFrame(monitor);
377
+ }
378
+ };
379
+ var _default = exports.default = {
380
+ useLoadingState,
381
+ useLoaderAnnouncements,
382
+ loadingMessages,
383
+ sizeGuide,
384
+ variantGuide,
385
+ loaderTestingUtils,
386
+ loaderPerformanceUtils
387
+ };