@shohojdhara/atomix 0.5.5 → 0.5.7

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 (74) hide show
  1. package/README.md +43 -21
  2. package/dist/atomix.css +1016 -1681
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +5 -5
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/core.d.ts +102 -9
  7. package/dist/core.js +89 -79
  8. package/dist/core.js.map +1 -1
  9. package/dist/forms.js +1 -7
  10. package/dist/forms.js.map +1 -1
  11. package/dist/heavy.js +7 -3
  12. package/dist/heavy.js.map +1 -1
  13. package/dist/index.d.ts +181 -55
  14. package/dist/index.esm.js +112 -99
  15. package/dist/index.esm.js.map +1 -1
  16. package/dist/index.js +112 -99
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.min.js +1 -1
  19. package/dist/index.min.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/Accordion/Accordion.tsx +40 -25
  22. package/src/components/Breadcrumb/Breadcrumb.tsx +23 -14
  23. package/src/components/Button/Button.tsx +4 -5
  24. package/src/components/Callout/Callout.tsx +98 -96
  25. package/src/components/Card/Card.tsx +117 -103
  26. package/src/components/Card/index.ts +7 -5
  27. package/src/components/Dropdown/Dropdown.tsx +27 -8
  28. package/src/components/EdgePanel/EdgePanel.tsx +7 -2
  29. package/src/components/Modal/Modal.tsx +27 -8
  30. package/src/components/Spinner/Spinner.tsx +60 -43
  31. package/src/components/Tabs/Tabs.tsx +163 -149
  32. package/src/lib/composables/useInput.ts +11 -9
  33. package/src/lib/types/components.ts +84 -0
  34. package/src/styles/01-settings/_settings.background.scss +2 -1
  35. package/src/styles/02-tools/_tools.background.scss +100 -294
  36. package/src/styles/06-components/_components.avatar-group.scss +1 -3
  37. package/src/styles/06-components/_components.avatar.scss +1 -1
  38. package/src/styles/06-components/_components.badge.scss +2 -2
  39. package/src/styles/06-components/_components.button.scss +3 -3
  40. package/src/styles/06-components/_components.callout.scss +5 -5
  41. package/src/styles/06-components/_components.card.scss +4 -7
  42. package/src/styles/06-components/_components.checkbox.scss +1 -1
  43. package/src/styles/06-components/_components.data-table.scss +1 -1
  44. package/src/styles/06-components/_components.datepicker.scss +1 -1
  45. package/src/styles/06-components/_components.dropdown.scss +3 -3
  46. package/src/styles/06-components/_components.edge-panel.scss +5 -9
  47. package/src/styles/06-components/_components.footer.scss +12 -13
  48. package/src/styles/06-components/_components.hero.scss +2 -2
  49. package/src/styles/06-components/_components.input.scss +3 -3
  50. package/src/styles/06-components/_components.list.scss +1 -1
  51. package/src/styles/06-components/_components.menu.scss +2 -2
  52. package/src/styles/06-components/_components.messages.scss +16 -18
  53. package/src/styles/06-components/_components.modal.scss +6 -6
  54. package/src/styles/06-components/_components.nav.scss +0 -3
  55. package/src/styles/06-components/_components.navbar.scss +3 -3
  56. package/src/styles/06-components/_components.pagination.scss +3 -3
  57. package/src/styles/06-components/_components.photoviewer.scss +3 -3
  58. package/src/styles/06-components/_components.popover.scss +3 -3
  59. package/src/styles/06-components/_components.product-review.scss +2 -2
  60. package/src/styles/06-components/_components.progress.scss +2 -2
  61. package/src/styles/06-components/_components.river.scss +1 -1
  62. package/src/styles/06-components/_components.sectionintro.scss +1 -1
  63. package/src/styles/06-components/_components.select.scss +5 -6
  64. package/src/styles/06-components/_components.side-menu.scss +6 -6
  65. package/src/styles/06-components/_components.skeleton.scss +8 -8
  66. package/src/styles/06-components/_components.slider.scss +6 -6
  67. package/src/styles/06-components/_components.steps.scss +2 -2
  68. package/src/styles/06-components/_components.tabs.scss +2 -2
  69. package/src/styles/06-components/_components.todo.scss +1 -1
  70. package/src/styles/06-components/_components.toggle.scss +3 -5
  71. package/src/styles/06-components/_components.tooltip.scss +2 -4
  72. package/src/styles/06-components/_components.upload.scss +1 -2
  73. package/src/styles/06-components/_components.video-player.scss +2 -2
  74. package/src/styles/99-utilities/_utilities.link.scss +4 -5
@@ -3,7 +3,108 @@ import { CARD } from '../../lib/constants/components';
3
3
  import { CardProps } from '../../lib/types/components';
4
4
  import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
5
5
 
6
- export const Card = React.memo(
6
+ // Card subcomponents for structured content
7
+
8
+ export interface CardHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
9
+ /**
10
+ * Header title
11
+ */
12
+ title?: React.ReactNode;
13
+ /**
14
+ * Header subtitle
15
+ */
16
+ subtitle?: React.ReactNode;
17
+ /**
18
+ * Action element (e.g., button) to display in header
19
+ */
20
+ action?: React.ReactNode;
21
+ /**
22
+ * Icon to display in header
23
+ */
24
+ icon?: React.ReactNode;
25
+ }
26
+
27
+ export const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
28
+ ({ title, subtitle, action, icon, children, className = '', ...props }, ref) => {
29
+ const headerClasses = `${CARD.SELECTORS.HEADER.substring(1)} ${className}`.trim();
30
+
31
+ return (
32
+ <div ref={ref} className={headerClasses} {...props}>
33
+ {icon && <div className={CARD.SELECTORS.ICON.substring(1)}>{icon}</div>}
34
+ {(title || subtitle) && (
35
+ <div>
36
+ {title && <h3 className={CARD.SELECTORS.TITLE.substring(1)}>{title}</h3>}
37
+ {subtitle && <p className={CARD.SELECTORS.TEXT.substring(1)}>{subtitle}</p>}
38
+ </div>
39
+ )}
40
+ {action && <div className={CARD.SELECTORS.ACTIONS.substring(1)}>{action}</div>}
41
+ {children}
42
+ </div>
43
+ );
44
+ }
45
+ );
46
+
47
+ CardHeader.displayName = 'CardHeader';
48
+
49
+ export interface CardBodyProps extends React.HTMLAttributes<HTMLDivElement> {
50
+ /**
51
+ * Make body scrollable
52
+ */
53
+ scrollable?: boolean;
54
+ /**
55
+ * Maximum height for scrollable body
56
+ */
57
+ maxHeight?: string | number;
58
+ }
59
+
60
+ export const CardBody = forwardRef<HTMLDivElement, CardBodyProps>(
61
+ ({ scrollable = false, maxHeight, children, className = '', style, ...props }, ref) => {
62
+ const bodyClasses =
63
+ `${CARD.SELECTORS.BODY.substring(1)} ${scrollable ? 'c-card__body--scrollable' : ''} ${className}`.trim();
64
+ const bodyStyle: React.CSSProperties = {
65
+ ...style,
66
+ ...(scrollable && maxHeight
67
+ ? {
68
+ maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight,
69
+ overflowY: 'auto',
70
+ }
71
+ : {}),
72
+ };
73
+
74
+ return (
75
+ <div ref={ref} className={bodyClasses} style={bodyStyle} {...props}>
76
+ {children}
77
+ </div>
78
+ );
79
+ }
80
+ );
81
+
82
+ CardBody.displayName = 'CardBody';
83
+
84
+ export interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {
85
+ /**
86
+ * Footer alignment
87
+ */
88
+ align?: 'start' | 'center' | 'end' | 'between';
89
+ }
90
+
91
+ export const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
92
+ ({ align, children, className = '', style, ...props }, ref) => {
93
+ const footerClasses =
94
+ `${CARD.SELECTORS.FOOTER.substring(1)} ${align ? `c-card__footer--align-${align}` : ''} ${className}`.trim();
95
+
96
+ return (
97
+ <div ref={ref} className={footerClasses} style={style} {...props}>
98
+ {children}
99
+ </div>
100
+ );
101
+ }
102
+ );
103
+
104
+ CardFooter.displayName = 'CardFooter';
105
+
106
+ // Main Card component implementation
107
+ const CardImpl = React.memo(
7
108
  forwardRef<HTMLDivElement | HTMLAnchorElement, CardProps>(
8
109
  (
9
110
  {
@@ -299,111 +400,24 @@ export const Card = React.memo(
299
400
  )
300
401
  );
301
402
 
302
- Card.displayName = 'Card';
303
-
304
- // Card subcomponents for structured content
305
- export interface CardHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
306
- /**
307
- * Header title
308
- */
309
- title?: React.ReactNode;
310
- /**
311
- * Header subtitle
312
- */
313
- subtitle?: React.ReactNode;
314
- /**
315
- * Action element (e.g., button) to display in header
316
- */
317
- action?: React.ReactNode;
318
- /**
319
- * Icon to display in header
320
- */
321
- icon?: React.ReactNode;
322
- }
323
-
324
- export const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
325
- ({ title, subtitle, action, icon, children, className = '', ...props }, ref) => {
326
- const headerClasses = `${CARD.SELECTORS.HEADER.substring(1)} ${className}`.trim();
327
-
328
- return (
329
- <div ref={ref} className={headerClasses} {...props}>
330
- {icon && <div className={CARD.SELECTORS.ICON.substring(1)}>{icon}</div>}
331
- {(title || subtitle) && (
332
- <div>
333
- {title && <h3 className={CARD.SELECTORS.TITLE.substring(1)}>{title}</h3>}
334
- {subtitle && <p className={CARD.SELECTORS.TEXT.substring(1)}>{subtitle}</p>}
335
- </div>
336
- )}
337
- {action && <div className={CARD.SELECTORS.ACTIONS.substring(1)}>{action}</div>}
338
- {children}
339
- </div>
340
- );
341
- }
342
- );
343
-
344
- CardHeader.displayName = 'CardHeader';
345
-
346
- export interface CardBodyProps extends React.HTMLAttributes<HTMLDivElement> {
347
- /**
348
- * Make body scrollable
349
- */
350
- scrollable?: boolean;
351
- /**
352
- * Maximum height for scrollable body
353
- */
354
- maxHeight?: string | number;
355
- }
356
-
357
- export const CardBody = forwardRef<HTMLDivElement, CardBodyProps>(
358
- ({ scrollable = false, maxHeight, children, className = '', style, ...props }, ref) => {
359
- const bodyClasses =
360
- `${CARD.SELECTORS.BODY.substring(1)} ${scrollable ? 'c-card__body--scrollable' : ''} ${className}`.trim();
361
- const bodyStyle: React.CSSProperties = {
362
- ...style,
363
- ...(scrollable && maxHeight
364
- ? {
365
- maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight,
366
- overflowY: 'auto',
367
- }
368
- : {}),
369
- };
370
-
371
- return (
372
- <div ref={ref} className={bodyClasses} style={bodyStyle} {...props}>
373
- {children}
374
- </div>
375
- );
376
- }
377
- );
378
-
379
- CardBody.displayName = 'CardBody';
380
-
381
- export interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {
382
- /**
383
- * Footer alignment
384
- */
385
- align?: 'start' | 'center' | 'end' | 'between';
386
- }
387
-
388
- export const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
389
- ({ align, children, className = '', style, ...props }, ref) => {
390
- const footerClasses =
391
- `${CARD.SELECTORS.FOOTER.substring(1)} ${align ? `c-card__footer--align-${align}` : ''} ${className}`.trim();
403
+ CardImpl.displayName = 'Card';
392
404
 
393
- return (
394
- <div ref={ref} className={footerClasses} style={style} {...props}>
395
- {children}
396
- </div>
397
- );
398
- }
399
- );
405
+ /**
406
+ * Card component with subcomponents for creating card layouts
407
+ */
408
+ type CardComponent = React.FC<CardProps> & {
409
+ Header: typeof CardHeader;
410
+ Body: typeof CardBody;
411
+ Footer: typeof CardFooter;
412
+ };
400
413
 
401
- CardFooter.displayName = 'CardFooter';
414
+ // Create compound component with proper typing
415
+ const CardWithSubcomponents = CardImpl as unknown as CardComponent;
416
+ CardWithSubcomponents.Header = CardHeader;
417
+ CardWithSubcomponents.Body = CardBody;
418
+ CardWithSubcomponents.Footer = CardFooter;
402
419
 
403
- // Attach subcomponents to Card
404
- (Card as any).Header = CardHeader;
405
- (Card as any).Body = CardBody;
406
- (Card as any).Footer = CardFooter;
420
+ export const Card = CardWithSubcomponents;
407
421
 
408
422
  export type { CardProps };
409
423
 
@@ -6,11 +6,13 @@
6
6
  */
7
7
 
8
8
  // Export the main Card component with subcomponents
9
- export { default as Card, CardHeader, CardBody, CardFooter } from './Card';
10
- export type { CardHeaderProps, CardBodyProps, CardFooterProps } from './Card';
9
+ export { Card, CardHeader, CardBody, CardFooter } from './Card';
10
+ export type { CardProps, CardHeaderProps, CardBodyProps, CardFooterProps } from './Card';
11
+
12
+ // Export the ElevationCard component
13
+ export { default as ElevationCard, type ElevationCardProps } from './ElevationCard';
14
+
11
15
 
12
- // Export the ElevationCard variant
13
- export { default as ElevationCard } from './ElevationCard';
14
16
 
15
17
  // Default export for the main Card component
16
- export { default } from './Card';
18
+ export { default } from './Card';
@@ -8,6 +8,7 @@ import React, {
8
8
  memo,
9
9
  forwardRef,
10
10
  ReactNode,
11
+ ComponentType,
11
12
  } from 'react';
12
13
  import { DROPDOWN } from '../../lib/constants/components';
13
14
  import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
@@ -27,6 +28,18 @@ export type DropdownContextType = {
27
28
  trigger: string;
28
29
  };
29
30
 
31
+ // Type definitions for compound component handling
32
+ type ExtendedComponentType<P = {}> = ComponentType<P> & {
33
+ displayName?: string;
34
+ }
35
+
36
+ interface DropdownTriggerProps extends React.HTMLAttributes<HTMLDivElement> {
37
+ onClick?: (e: React.MouseEvent) => void;
38
+ onKeyDown?: (e: React.KeyboardEvent) => void;
39
+ }
40
+
41
+ interface DropdownMenuProps extends React.HTMLAttributes<HTMLUListElement> {}
42
+
30
43
  // Create context for dropdown state management
31
44
  const DropdownContext = createContext<DropdownContextType>({
32
45
  isOpen: false,
@@ -140,7 +153,9 @@ export const DropdownItem: React.FC<DropdownItemProps> = memo(
140
153
  <li>
141
154
  {linkComponent ? (
142
155
  (() => {
143
- const Component = linkComponent as React.ComponentType<any>;
156
+ const Component = linkComponent as React.ComponentType<
157
+ React.AnchorHTMLAttributes<HTMLAnchorElement>
158
+ >;
144
159
  return (
145
160
  <Component {...linkProps}>
146
161
  {icon && <span className="c-dropdown__menu-item-icon">{icon}</span>}
@@ -402,7 +417,9 @@ export const Dropdown: DropdownComponent = memo(function DropdownBase({
402
417
  const hasCompoundComponents = React.Children.toArray(children).some(
403
418
  child =>
404
419
  React.isValidElement(child) &&
405
- ['DropdownTrigger', 'DropdownMenu'].includes((child.type as any).displayName)
420
+ ['DropdownTrigger', 'DropdownMenu'].includes(
421
+ (child.type as React.ComponentType & { displayName?: string }).displayName || ''
422
+ )
406
423
  );
407
424
 
408
425
  let triggerContent: ReactNode;
@@ -412,23 +429,25 @@ export const Dropdown: DropdownComponent = memo(function DropdownBase({
412
429
  // Find Trigger and Menu in children
413
430
  React.Children.forEach(children, child => {
414
431
  if (React.isValidElement(child)) {
415
- if ((child.type as any).displayName === 'DropdownTrigger') {
416
- triggerContent = React.cloneElement(child, {
432
+ const component = child.type as ExtendedComponentType;
433
+ if (component.displayName === 'DropdownTrigger') {
434
+ const triggerProps: DropdownTriggerProps = {
417
435
  ref: toggleRef,
418
436
  onClick: (e: React.MouseEvent) => {
419
437
  handleToggleClick(e);
420
- (child.props as any).onClick?.(e);
438
+ (child.props as DropdownTriggerProps).onClick?.(e);
421
439
  },
422
440
  onKeyDown: (e: React.KeyboardEvent) => {
423
441
  handleToggleKeyDown(e);
424
- (child.props as any).onKeyDown?.(e);
442
+ (child.props as DropdownTriggerProps).onKeyDown?.(e);
425
443
  },
426
444
  'aria-haspopup': 'menu',
427
445
  'aria-expanded': isOpen,
428
446
  'aria-controls': dropdownId,
429
447
  tabIndex: 0,
430
- } as any);
431
- } else if ((child.type as any).displayName === 'DropdownMenu') {
448
+ };
449
+ triggerContent = React.cloneElement(child, triggerProps);
450
+ } else if (component.displayName === 'DropdownMenu') {
432
451
  menuContentNode = child;
433
452
  }
434
453
  }
@@ -1,10 +1,15 @@
1
- import React, { useRef, useEffect, memo, forwardRef } from 'react';
1
+ import React, { useRef, useEffect, memo, forwardRef, ComponentType } from 'react';
2
2
  import { EdgePanelProps } from '../../lib/types/components';
3
3
  import { useEdgePanel } from '../../lib/composables/useEdgePanel';
4
4
  import { EDGE_PANEL } from '../../lib/constants/components';
5
5
  import { Icon } from '../Icon/Icon';
6
6
  import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
7
7
 
8
+ // Type-safe type alias for compound component detection
9
+ type ExtendedComponentType<P = {}> = ComponentType<P> & {
10
+ displayName?: string;
11
+ }
12
+
8
13
  // Subcomponents
9
14
  export const EdgePanelHeader = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
10
15
  ({ children, className = '', ...props }, ref) => (
@@ -146,7 +151,7 @@ const EdgePanelComponentBase = ({
146
151
  child =>
147
152
  React.isValidElement(child) &&
148
153
  ['EdgePanelHeader', 'EdgePanelBody', 'EdgePanelFooter'].includes(
149
- (child.type as any).displayName
154
+ (child.type as ExtendedComponentType).displayName || ''
150
155
  )
151
156
  );
152
157
 
@@ -1,6 +1,21 @@
1
- import React, { useEffect, useRef, useState, useCallback, memo, forwardRef, ReactNode, useId } from 'react';
1
+ import React, {
2
+ useEffect,
3
+ useRef,
4
+ useState,
5
+ useCallback,
6
+ memo,
7
+ forwardRef,
8
+ ReactNode,
9
+ useId,
10
+ ComponentType,
11
+ } from 'react';
2
12
  import { ModalProps } from '../../lib/types/components';
3
13
  import { MODAL } from '../../lib/constants/components';
14
+
15
+ // Define ExtendedComponentType as a type alias instead of an interface to avoid TS2312 error
16
+ type ExtendedComponentType<P = {}> = ComponentType<P> & {
17
+ displayName?: string;
18
+ }
4
19
  import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
5
20
  import { useFocusTrap } from '../../lib/composables/useFocusTrap';
6
21
 
@@ -225,9 +240,12 @@ const ModalImpl = memo(
225
240
  .join(' ');
226
241
 
227
242
  // Check for compound components usage
228
- const hasCompoundComponents = React.Children.toArray(children).some((child) =>
229
- React.isValidElement(child) &&
230
- ['ModalHeader', 'ModalBody', 'ModalFooter'].includes((child.type as any).displayName)
243
+ const hasCompoundComponents = React.Children.toArray(children).some(
244
+ child =>
245
+ React.isValidElement(child) &&
246
+ ['ModalHeader', 'ModalBody', 'ModalFooter'].includes(
247
+ (child.type as ExtendedComponentType).displayName || ''
248
+ )
231
249
  );
232
250
 
233
251
  const modalContent = (
@@ -236,12 +254,13 @@ const ModalImpl = memo(
236
254
  React.Children.map(children, child => {
237
255
  if (
238
256
  React.isValidElement(child) &&
239
- (child.type as any).displayName === 'ModalHeader'
257
+ (child.type as ExtendedComponentType).displayName === 'ModalHeader'
240
258
  ) {
241
- return React.cloneElement(child, {
242
- onClose: (child.props as any).onClose || close,
259
+ return React.cloneElement(child as React.ReactElement<ModalHeaderProps>, {
260
+ ...(child.props as ModalHeaderProps),
261
+ onClose: (child.props as ModalHeaderProps).onClose || close,
243
262
  id: titleId,
244
- } as any);
263
+ });
245
264
  }
246
265
  return child;
247
266
  })
@@ -1,52 +1,69 @@
1
- import React, { memo } from 'react';
1
+ import React, { memo, forwardRef } from 'react';
2
2
  import { SpinnerProps } from '../../lib/types/components';
3
3
  import { useSpinner } from '../../lib/composables/useSpinner';
4
4
  import { SPINNER } from '../../lib/constants/components';
5
5
  import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
6
6
 
7
- export const Spinner: React.FC<SpinnerProps> = memo(
8
- ({
9
- size = 'md',
10
- variant = 'primary',
11
- fullscreen = false,
12
- className = '',
13
- style,
14
- glass,
15
- 'aria-label': ariaLabel,
16
- role = 'status',
17
- }) => {
18
- const { generateSpinnerClass } = useSpinner({
19
- size,
20
- variant,
21
- fullscreen,
22
- });
23
-
24
- const spinnerClass = generateSpinnerClass({
25
- size,
26
- variant,
27
- fullscreen,
28
- className: `${className} ${glass ? 'c-spinner--glass' : ''}`.trim(),
29
- });
30
-
31
- const spinnerContent = (
32
- <div className={spinnerClass} style={style} role={role} aria-label={ariaLabel || 'Loading'}>
33
- <span className={SPINNER.VISUALLY_HIDDEN}>{ariaLabel || 'Loading...'}</span>
34
- </div>
35
- );
36
-
37
- if (glass) {
38
- const defaultGlassProps = {
39
- displacementScale: 20,
40
- blurAmount: 1,
41
- borderRadius: 999,
42
- mode: 'shader' as const,
43
- };
44
- const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
45
- return <AtomixGlass {...glassProps}>{spinnerContent}</AtomixGlass>;
46
- }
7
+ export const Spinner = memo(
8
+ forwardRef<HTMLDivElement, SpinnerProps>(
9
+ (
10
+ {
11
+ size = 'md',
12
+ variant = 'primary',
13
+ fullscreen = false,
14
+ className = '',
15
+ style,
16
+ glass,
17
+ 'aria-label': ariaLabel,
18
+ role = 'status',
19
+ 'aria-live': ariaLive = 'polite',
20
+ 'aria-describe': ariaDescribe,
21
+ ...rest
22
+ },
23
+ ref
24
+ ) => {
25
+ const { generateSpinnerClass } = useSpinner({
26
+ size,
27
+ variant,
28
+ fullscreen,
29
+ });
30
+
31
+ const spinnerClass = generateSpinnerClass({
32
+ size,
33
+ variant,
34
+ fullscreen,
35
+ className: `${className} ${glass ? 'c-spinner--glass' : ''}`.trim(),
36
+ });
37
+
38
+ const spinnerContent = (
39
+ <div
40
+ ref={ref}
41
+ className={spinnerClass}
42
+ style={style}
43
+ role={role}
44
+ aria-label={ariaLabel || 'Loading'}
45
+ aria-live={ariaLive}
46
+ aria-describe={ariaDescribe}
47
+ {...rest}
48
+ >
49
+ <span className={SPINNER.VISUALLY_HIDDEN}>{ariaLabel || 'Loading content...'}</span>
50
+ </div>
51
+ );
47
52
 
48
- return spinnerContent;
49
- }
53
+ if (glass) {
54
+ const defaultGlassProps = {
55
+ displacementScale: 20,
56
+ blurAmount: 1,
57
+ borderRadius: 999,
58
+ mode: 'shader' as const,
59
+ };
60
+ const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
61
+ return <AtomixGlass {...glassProps}>{spinnerContent}</AtomixGlass>;
62
+ }
63
+
64
+ return spinnerContent;
65
+ }
66
+ )
50
67
  );
51
68
 
52
69
  export type { SpinnerProps };