@shohojdhara/atomix 0.2.9 → 0.3.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 (102) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/atomix.css +309 -105
  3. package/dist/atomix.min.css +3 -5
  4. package/dist/index.d.ts +807 -51
  5. package/dist/index.esm.js +16367 -16405
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +16277 -16330
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.js +1 -1
  10. package/dist/index.min.js.map +1 -1
  11. package/dist/themes/applemix.css +309 -105
  12. package/dist/themes/applemix.min.css +5 -7
  13. package/dist/themes/boomdevs.css +202 -10
  14. package/dist/themes/boomdevs.min.css +3 -5
  15. package/dist/themes/esrar.css +309 -105
  16. package/dist/themes/esrar.min.css +4 -6
  17. package/dist/themes/flashtrade.css +310 -105
  18. package/dist/themes/flashtrade.min.css +5 -7
  19. package/dist/themes/mashroom.css +300 -96
  20. package/dist/themes/mashroom.min.css +4 -6
  21. package/dist/themes/shaj-default.css +300 -96
  22. package/dist/themes/shaj-default.min.css +4 -6
  23. package/package.json +1 -1
  24. package/src/components/AtomixGlass/AtomixGlass.test.tsx +21 -32
  25. package/src/components/AtomixGlass/AtomixGlass.tsx +55 -42
  26. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +205 -57
  27. package/src/components/AtomixGlass/GlassFilter.tsx +22 -8
  28. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +221 -0
  29. package/src/components/AtomixGlass/atomixGLass.old.tsx +0 -3
  30. package/src/components/AtomixGlass/shader-utils.ts +8 -0
  31. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +319 -100
  32. package/src/components/AtomixGlass/stories/Examples.stories.tsx +601 -105
  33. package/src/components/AtomixGlass/stories/Modes.stories.tsx +30 -12
  34. package/src/components/AtomixGlass/stories/Playground.stories.tsx +173 -38
  35. package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +18 -18
  36. package/src/components/AtomixGlass/stories/shared-components.tsx +27 -5
  37. package/src/components/Breadcrumb/Breadcrumb.tsx +8 -3
  38. package/src/components/Button/Button.tsx +62 -17
  39. package/src/components/Callout/Callout.test.tsx +8 -14
  40. package/src/components/Card/Card.tsx +103 -1
  41. package/src/components/Card/index.ts +3 -2
  42. package/src/components/Footer/Footer.stories.tsx +1 -2
  43. package/src/components/Footer/Footer.tsx +0 -5
  44. package/src/components/Footer/FooterLink.tsx +3 -2
  45. package/src/components/Footer/FooterSection.tsx +0 -7
  46. package/src/components/Icon/index.ts +1 -1
  47. package/src/components/Modal/Modal.stories.tsx +29 -38
  48. package/src/components/Modal/Modal.tsx +4 -4
  49. package/src/components/Navigation/Nav/NavItem.tsx +8 -3
  50. package/src/components/Navigation/SideMenu/SideMenu.tsx +49 -41
  51. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +63 -19
  52. package/src/components/Popover/Popover.tsx +1 -1
  53. package/src/components/VideoPlayer/VideoPlayer.stories.tsx +977 -400
  54. package/src/components/VideoPlayer/VideoPlayer.tsx +1 -6
  55. package/src/lib/composables/shared-mouse-tracker.ts +133 -0
  56. package/src/lib/composables/useAtomixGlass.ts +303 -115
  57. package/src/lib/theme/ThemeManager.integration.test.ts +124 -0
  58. package/src/lib/theme/ThemeManager.stories.tsx +13 -13
  59. package/src/lib/theme/ThemeManager.test.ts +4 -0
  60. package/src/lib/theme/ThemeManager.ts +203 -59
  61. package/src/lib/theme/ThemeProvider.tsx +183 -33
  62. package/src/lib/theme/composeTheme.ts +375 -0
  63. package/src/lib/theme/createTheme.test.ts +475 -0
  64. package/src/lib/theme/createTheme.ts +510 -0
  65. package/src/lib/theme/generateCSSVariables.ts +713 -0
  66. package/src/lib/theme/index.ts +67 -0
  67. package/src/lib/theme/themeUtils.ts +333 -0
  68. package/src/lib/theme/types.ts +337 -8
  69. package/src/lib/theme/useTheme.test.tsx +2 -1
  70. package/src/lib/theme/useTheme.ts +6 -22
  71. package/src/lib/types/components.ts +152 -57
  72. package/src/styles/01-settings/_index.scss +2 -2
  73. package/src/styles/01-settings/_settings.badge.scss +2 -2
  74. package/src/styles/01-settings/_settings.border-radius.scss +1 -1
  75. package/src/styles/01-settings/{_settings.maps.scss → _settings.design-tokens.scss} +163 -49
  76. package/src/styles/01-settings/_settings.modal.scss +1 -1
  77. package/src/styles/01-settings/_settings.spacing.scss +14 -13
  78. package/src/styles/03-generic/_generic.root.scss +131 -50
  79. package/src/styles/05-objects/_objects.block.scss +1 -1
  80. package/src/styles/06-components/_components.atomix-glass.scss +20 -22
  81. package/src/styles/06-components/_components.badge.scss +2 -2
  82. package/src/styles/06-components/_components.button.scss +1 -1
  83. package/src/styles/06-components/_components.callout.scss +1 -1
  84. package/src/styles/06-components/_components.card.scss +74 -2
  85. package/src/styles/06-components/_components.chart.scss +1 -1
  86. package/src/styles/06-components/_components.dropdown.scss +6 -0
  87. package/src/styles/06-components/_components.footer.scss +1 -1
  88. package/src/styles/06-components/_components.list-group.scss +1 -1
  89. package/src/styles/06-components/_components.list.scss +1 -1
  90. package/src/styles/06-components/_components.menu.scss +1 -1
  91. package/src/styles/06-components/_components.messages.scss +1 -1
  92. package/src/styles/06-components/_components.modal.scss +7 -2
  93. package/src/styles/06-components/_components.navbar.scss +1 -1
  94. package/src/styles/06-components/_components.popover.scss +10 -0
  95. package/src/styles/06-components/_components.product-review.scss +1 -1
  96. package/src/styles/06-components/_components.progress.scss +1 -1
  97. package/src/styles/06-components/_components.rating.scss +1 -1
  98. package/src/styles/06-components/_components.spinner.scss +1 -1
  99. package/src/styles/99-utilities/_utilities.background.scss +1 -1
  100. package/src/styles/99-utilities/_utilities.border.scss +1 -1
  101. package/src/styles/99-utilities/_utilities.link.scss +1 -1
  102. package/src/styles/99-utilities/_utilities.text.scss +1 -1
@@ -3,6 +3,7 @@ import { useButton } from '../../lib/composables/useButton';
3
3
  import { ButtonProps } from '../../lib/types/components';
4
4
  import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
5
5
  import { Spinner } from '../Spinner/Spinner';
6
+ import { Icon, type PhosphorIconsType } from '../Icon/Icon';
6
7
  import { BUTTON } from '../../lib/constants/components';
7
8
 
8
9
  export type ButtonAsProp = {
@@ -13,7 +14,7 @@ export type ButtonAsProp = {
13
14
  };
14
15
 
15
16
  export const Button = React.memo(
16
- forwardRef<HTMLButtonElement, ButtonProps & ButtonAsProp>(
17
+ forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps & ButtonAsProp>(
17
18
  (
18
19
  {
19
20
  label,
@@ -25,6 +26,8 @@ export const Button = React.memo(
25
26
  loading = false,
26
27
  loadingText,
27
28
  icon,
29
+ iconName,
30
+ iconSize = 'sm',
28
31
  iconPosition = 'start',
29
32
  iconOnly = false,
30
33
  rounded = false,
@@ -35,6 +38,8 @@ export const Button = React.memo(
35
38
  type = 'button',
36
39
  className = '',
37
40
  as: Component = 'button',
41
+ href,
42
+ target,
38
43
  glass,
39
44
  onHover,
40
45
  onFocus,
@@ -51,6 +56,18 @@ export const Button = React.memo(
51
56
  ) => {
52
57
  const isDisabled = disabled || loading;
53
58
 
59
+ // Determine if we should render as a link
60
+ const shouldRenderAsLink = Boolean(href && !isDisabled);
61
+
62
+ // Resolve icon element - support both icon (ReactNode) and iconName (string)
63
+ const iconElement = useMemo(() => {
64
+ if (loading) return null;
65
+ if (iconName) {
66
+ return <Icon name={iconName as PhosphorIconsType} size={iconSize} />;
67
+ }
68
+ return icon;
69
+ }, [icon, iconName, iconSize, loading]);
70
+
54
71
  const { generateButtonClass, handleClick } = useButton({
55
72
  variant,
56
73
  size,
@@ -85,21 +102,21 @@ export const Button = React.memo(
85
102
 
86
103
  // Handle click with loading check
87
104
  const handleClickEvent = useCallback(
88
- (event: React.MouseEvent<HTMLButtonElement>) => {
105
+ (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
89
106
  if (isDisabled) {
90
107
  event.preventDefault();
91
108
  return;
92
109
  }
93
- onClick?.(event);
110
+ onClick?.(event as React.MouseEvent<HTMLButtonElement>);
94
111
  },
95
112
  [isDisabled, onClick]
96
113
  );
97
114
 
98
115
  // Handle hover
99
116
  const handleMouseEnter = useCallback(
100
- (event: React.MouseEvent<HTMLButtonElement>) => {
117
+ (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
101
118
  if (!isDisabled) {
102
- onHover?.(event);
119
+ onHover?.(event as React.MouseEvent<HTMLButtonElement>);
103
120
  }
104
121
  },
105
122
  [isDisabled, onHover]
@@ -107,9 +124,9 @@ export const Button = React.memo(
107
124
 
108
125
  // Handle focus
109
126
  const handleFocusEvent = useCallback(
110
- (event: React.FocusEvent<HTMLButtonElement>) => {
127
+ (event: React.FocusEvent<HTMLButtonElement | HTMLAnchorElement>) => {
111
128
  if (!isDisabled) {
112
- onFocus?.(event);
129
+ onFocus?.(event as React.FocusEvent<HTMLButtonElement>);
113
130
  }
114
131
  },
115
132
  [isDisabled, onFocus]
@@ -117,9 +134,9 @@ export const Button = React.memo(
117
134
 
118
135
  // Handle blur
119
136
  const handleBlurEvent = useCallback(
120
- (event: React.FocusEvent<HTMLButtonElement>) => {
137
+ (event: React.FocusEvent<HTMLButtonElement | HTMLAnchorElement>) => {
121
138
  if (!isDisabled) {
122
- onBlur?.(event);
139
+ onBlur?.(event as React.FocusEvent<HTMLButtonElement>);
123
140
  }
124
141
  },
125
142
  [isDisabled, onBlur]
@@ -141,9 +158,9 @@ export const Button = React.memo(
141
158
 
142
159
  // Button content with icon positioning
143
160
  const buttonContent = useMemo(() => {
144
- const iconElement = icon && !loading && (
161
+ const iconSpan = iconElement && (
145
162
  <span className={BUTTON.ICON_CLASS} aria-hidden="true">
146
- {icon}
163
+ {iconElement}
147
164
  </span>
148
165
  );
149
166
 
@@ -169,7 +186,7 @@ export const Button = React.memo(
169
186
  <>
170
187
  {labelElement}
171
188
  {spinnerElement}
172
- {iconElement}
189
+ {iconSpan}
173
190
  </>
174
191
  );
175
192
  }
@@ -177,23 +194,23 @@ export const Button = React.memo(
177
194
  return (
178
195
  <>
179
196
  {spinnerElement}
180
- {iconElement}
197
+ {iconSpan}
181
198
  {labelElement}
182
199
  </>
183
200
  );
184
- }, [icon, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant]);
201
+ }, [iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant]);
185
202
 
186
203
  // Button props
187
204
  const buttonProps = useMemo(
188
205
  () => ({
189
206
  ref,
190
207
  className: buttonClass,
191
- type: Component === 'button' ? type : undefined,
208
+ type: Component === 'button' && !shouldRenderAsLink ? type : undefined,
192
209
  onClick: handleClickEvent,
193
210
  onMouseEnter: onHover ? handleMouseEnter : undefined,
194
211
  onFocus: onFocus ? handleFocusEvent : undefined,
195
212
  onBlur: onBlur ? handleBlurEvent : undefined,
196
- disabled: isDisabled && Component === 'button',
213
+ disabled: isDisabled && Component === 'button' && !shouldRenderAsLink,
197
214
  'aria-disabled': isDisabled,
198
215
  'aria-busy': loading,
199
216
  'aria-label': ariaLabel || (iconOnly ? label || children : undefined),
@@ -228,8 +245,36 @@ export const Button = React.memo(
228
245
  ]
229
246
  );
230
247
 
248
+ // Render as anchor if href is provided
249
+ if (shouldRenderAsLink) {
250
+ const { ref: _, ...buttonPropsWithoutRef } = buttonProps;
251
+ const anchorButtonProps = {
252
+ ...buttonPropsWithoutRef,
253
+ type: undefined,
254
+ disabled: undefined,
255
+ };
256
+ const anchorElement = (
257
+ <a {...anchorButtonProps} ref={ref as React.Ref<HTMLAnchorElement>} href={href} target={target} rel={target === '_blank' ? 'noopener noreferrer' : undefined}>
258
+ {buttonContent}
259
+ </a>
260
+ );
261
+
262
+ if (glass) {
263
+ const defaultGlassProps = {
264
+ displacementScale: 20,
265
+ blurAmount: 0,
266
+ saturation: 200,
267
+ elasticity: 0,
268
+ };
269
+ const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
270
+ return <AtomixGlass {...glassProps}>{anchorElement}</AtomixGlass>;
271
+ }
272
+
273
+ return anchorElement;
274
+ }
275
+
276
+ // Default button rendering
231
277
  if (glass) {
232
- // Default glass settings for buttons
233
278
  const defaultGlassProps = {
234
279
  displacementScale: 20,
235
280
  blurAmount: 0,
@@ -151,13 +151,9 @@ describe('Callout Component', () => {
151
151
  const glassProps = JSON.parse(glassElement.getAttribute('data-glass-props') || '{}');
152
152
 
153
153
  expect(glassProps).toMatchObject({
154
- displacementScale: 40,
155
- blurAmount: 0,
156
- saturation: 160,
157
- aberrationIntensity: 1,
154
+ displacementScale: 30,
158
155
  cornerRadius: 8,
159
- overLight: false,
160
- mode: 'standard',
156
+ elasticity: 0,
161
157
  });
162
158
  });
163
159
 
@@ -184,10 +180,8 @@ describe('Callout Component', () => {
184
180
  blurAmount: 2,
185
181
  saturation: 180,
186
182
  cornerRadius: 12,
187
- // Default values that weren't overridden
188
- aberrationIntensity: 1,
189
- overLight: false,
190
- mode: 'standard',
183
+ // Default values from Callout
184
+ elasticity: 0,
191
185
  });
192
186
  });
193
187
 
@@ -196,7 +190,7 @@ describe('Callout Component', () => {
196
190
  const TestIcon = () => <div data-testid="test-icon">Icon</div>;
197
191
  const actions = <button data-testid="action-button">Action</button>;
198
192
 
199
- render(
193
+ const { container } = render(
200
194
  <Callout
201
195
  title="Glass Test"
202
196
  variant="success"
@@ -223,9 +217,9 @@ describe('Callout Component', () => {
223
217
  // Check that glass wrapper is present
224
218
  expect(screen.getByTestId('atomix-glass')).toBeInTheDocument();
225
219
 
226
- // Check that all classes are applied
227
- const calloutElement = screen.getByTestId('atomix-glass').firstChild;
228
- expect(calloutElement).toHaveClass(
220
+ // Check that all classes are applied to the outer wrapper
221
+ const outerCallout = container.querySelector('.c-callout');
222
+ expect(outerCallout).toHaveClass(
229
223
  'c-callout',
230
224
  'c-callout--success',
231
225
  'c-callout--oneline',
@@ -12,6 +12,8 @@ export const Card = React.memo(
12
12
  variant = '',
13
13
  appearance = 'filled',
14
14
  elevation = 'none',
15
+ hoverable = false,
16
+ hoverElevation = 'md',
15
17
  // Layout
16
18
  row = false,
17
19
  flat = false,
@@ -77,6 +79,9 @@ export const Card = React.memo(
77
79
  elevation === 'md' ? CARD.CLASSES.ELEVATION_MD : '',
78
80
  elevation === 'lg' ? CARD.CLASSES.ELEVATION_LG : '',
79
81
  elevation === 'xl' ? CARD.CLASSES.ELEVATION_XL : '',
82
+ // Hoverable modifier
83
+ hoverable ? 'c-card--hoverable' : '',
84
+ hoverable && hoverElevation ? `c-card--hover-elevation-${hoverElevation}` : '',
80
85
  // Layout modifiers
81
86
  row ? CARD.CLASSES.ROW : '',
82
87
  flat ? CARD.CLASSES.FLAT : '',
@@ -91,7 +96,7 @@ export const Card = React.memo(
91
96
  ]
92
97
  .filter(Boolean)
93
98
  .join(' '),
94
- [size, variant, appearance, elevation, row, flat, active, disabled, loading, selected, interactive, isClickable, glass, className]
99
+ [size, variant, appearance, elevation, hoverable, hoverElevation, row, flat, active, disabled, loading, selected, interactive, isClickable, glass, className]
95
100
  );
96
101
 
97
102
  // Determine ARIA role
@@ -267,6 +272,103 @@ export const Card = React.memo(
267
272
 
268
273
  Card.displayName = 'Card';
269
274
 
275
+ // Card subcomponents for structured content
276
+ export interface CardHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
277
+ /**
278
+ * Header title
279
+ */
280
+ title?: React.ReactNode;
281
+ /**
282
+ * Header subtitle
283
+ */
284
+ subtitle?: React.ReactNode;
285
+ /**
286
+ * Action element (e.g., button) to display in header
287
+ */
288
+ action?: React.ReactNode;
289
+ /**
290
+ * Icon to display in header
291
+ */
292
+ icon?: React.ReactNode;
293
+ }
294
+
295
+ export const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
296
+ ({ title, subtitle, action, icon, children, className = '', ...props }, ref) => {
297
+ const headerClasses = `${CARD.SELECTORS.HEADER.substring(1)} ${className}`.trim();
298
+
299
+ return (
300
+ <div ref={ref} className={headerClasses} {...props}>
301
+ {icon && <div className={CARD.SELECTORS.ICON.substring(1)}>{icon}</div>}
302
+ {(title || subtitle) && (
303
+ <div>
304
+ {title && <h3 className={CARD.SELECTORS.TITLE.substring(1)}>{title}</h3>}
305
+ {subtitle && <p className={CARD.SELECTORS.TEXT.substring(1)}>{subtitle}</p>}
306
+ </div>
307
+ )}
308
+ {action && <div className={CARD.SELECTORS.ACTIONS.substring(1)}>{action}</div>}
309
+ {children}
310
+ </div>
311
+ );
312
+ }
313
+ );
314
+
315
+ CardHeader.displayName = 'CardHeader';
316
+
317
+ export interface CardBodyProps extends React.HTMLAttributes<HTMLDivElement> {
318
+ /**
319
+ * Make body scrollable
320
+ */
321
+ scrollable?: boolean;
322
+ /**
323
+ * Maximum height for scrollable body
324
+ */
325
+ maxHeight?: string | number;
326
+ }
327
+
328
+ export const CardBody = forwardRef<HTMLDivElement, CardBodyProps>(
329
+ ({ scrollable = false, maxHeight, children, className = '', style, ...props }, ref) => {
330
+ const bodyClasses = `${CARD.SELECTORS.BODY.substring(1)} ${scrollable ? 'c-card__body--scrollable' : ''} ${className}`.trim();
331
+ const bodyStyle: React.CSSProperties = {
332
+ ...style,
333
+ ...(scrollable && maxHeight ? { maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight, overflowY: 'auto' } : {}),
334
+ };
335
+
336
+ return (
337
+ <div ref={ref} className={bodyClasses} style={bodyStyle} {...props}>
338
+ {children}
339
+ </div>
340
+ );
341
+ }
342
+ );
343
+
344
+ CardBody.displayName = 'CardBody';
345
+
346
+ export interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {
347
+ /**
348
+ * Footer alignment
349
+ */
350
+ align?: 'start' | 'center' | 'end' | 'between';
351
+ }
352
+
353
+ export const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
354
+ ({ align, children, className = '', style, ...props }, ref) => {
355
+ const footerClasses = `${CARD.SELECTORS.FOOTER.substring(1)} ${align ? `c-card__footer--align-${align}` : ''} ${className}`.trim();
356
+
357
+ return (
358
+ <div ref={ref} className={footerClasses} style={style} {...props}>
359
+ {children}
360
+ </div>
361
+ );
362
+ }
363
+ );
364
+
365
+ CardFooter.displayName = 'CardFooter';
366
+
367
+ // Attach subcomponents to Card
368
+ (Card as any).Header = CardHeader;
369
+ (Card as any).Body = CardBody;
370
+ (Card as any).Footer = CardFooter;
371
+
270
372
  export type { CardProps };
271
373
 
272
374
  export default Card;
@@ -5,8 +5,9 @@
5
5
  * Types and hooks are defined in the lib directory.
6
6
  */
7
7
 
8
- // Export the main Card component
9
- export { default as Card } from './Card';
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';
10
11
 
11
12
  // Export the ElevationCard variant
12
13
  export { default as ElevationCard } from './ElevationCard';
@@ -143,7 +143,6 @@ export const WithNewsletter: Story = {
143
143
  newsletterDescription:
144
144
  'Get the latest updates, articles, and resources delivered to your inbox.',
145
145
  onNewsletterSubmit: (email: string) => {
146
- console.log('Newsletter signup:', email);
147
146
  alert(`Thank you for subscribing with ${email}!`);
148
147
  },
149
148
  },
@@ -156,7 +155,7 @@ export const WithBackToTop: Story = {
156
155
  showBackToTop: true,
157
156
  backToTopText: 'Back to Top',
158
157
  onBackToTop: () => {
159
- console.log('Back to top clicked');
158
+ // Back to top functionality
160
159
  },
161
160
  },
162
161
  render: Default.render,
@@ -205,11 +205,6 @@ export const Footer = forwardRef<HTMLElement, FooterProps>(
205
205
  {React.Children.map(children, child => {
206
206
  // Check if the child is a valid React element
207
207
  if (React.isValidElement(child)) {
208
- console.log(
209
- 'Footer - passing showNewsletter:',
210
- showNewsletter,
211
- typeof showNewsletter
212
- );
213
208
  // Clone the element and pass the showNewsletter prop
214
209
  return React.cloneElement(child, { showNewsletter } as any);
215
210
  }
@@ -48,12 +48,13 @@ export const FooterLink = forwardRef<HTMLAnchorElement, FooterLinkProps>(
48
48
  };
49
49
 
50
50
  if (LinkComponent) {
51
+ const Component = LinkComponent as React.ComponentType<any>;
51
52
  return (
52
- <LinkComponent ref={ref} to={href} {...linkProps}>
53
+ <Component ref={ref} to={href} {...linkProps}>
53
54
  {icon && <span className="c-footer__link-icon">{icon}</span>}
54
55
  <span className="c-footer__link-text">{children}</span>
55
56
  {external && <span className="c-footer__link-external">↗</span>}
56
- </LinkComponent>
57
+ </Component>
57
58
  );
58
59
  }
59
60
 
@@ -33,13 +33,6 @@ export const FooterSection = forwardRef<
33
33
  ) => {
34
34
  const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed);
35
35
 
36
- console.log(
37
- 'FooterSection render - showNewsletter:',
38
- showNewsletter,
39
- 'Type:',
40
- typeof showNewsletter
41
- );
42
-
43
36
  const handleToggle = () => {
44
37
  if (collapsible) {
45
38
  setIsCollapsed(!isCollapsed);
@@ -1,2 +1,2 @@
1
- export { Icon, type IconProps, type IconSize, type IconWeight } from './Icon';
1
+ export { Icon, type IconProps, type IconSize, type IconWeight, type PhosphorIconsType } from './Icon';
2
2
  export { default } from './Icon';
@@ -317,6 +317,7 @@ export const GlassModal: Story = {
317
317
  appearance. The glass effect creates a modern, elegant look that works well over
318
318
  colorful backgrounds.
319
319
  </p>
320
+ <img src="https://picsum.photos/800/410" alt="desert" style={{ maxWidth: '100%' }} />
320
321
  <p>
321
322
  The glass effect includes displacement, blur, and chromatic aberration for a premium
322
323
  feel.
@@ -329,9 +330,14 @@ export const GlassModal: Story = {
329
330
  Story => (
330
331
  <div
331
332
  style={{
332
- background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
333
- minHeight: '100vh',
334
- padding: '2rem',
333
+ background: 'url(https://picsum.photos/1920/1080)',
334
+ height: '100vh',
335
+ width: '100vw',
336
+ backgroundSize: 'cover',
337
+ backgroundPosition: 'center',
338
+ display: 'flex',
339
+ alignItems: 'center',
340
+ justifyContent: 'center',
335
341
  }}
336
342
  >
337
343
  <Story />
@@ -375,23 +381,10 @@ export const GlassModalCustom: Story = {
375
381
  }
376
382
  footer={
377
383
  <>
378
- <div
379
- className="c-btn c-btn--outline-secondary"
380
- onClick={() => setIsOpen(false)}
381
- style={{
382
- cursor: 'pointer',
383
- padding: '8px 16px',
384
- display: 'inline-block',
385
- marginRight: '8px',
386
- }}
387
- >
384
+ <div className="c-btn c-btn--outline-secondary" onClick={() => setIsOpen(false)}>
388
385
  Cancel
389
386
  </div>
390
- <div
391
- className="c-btn c-btn--primary"
392
- onClick={() => setIsOpen(false)}
393
- style={{ cursor: 'pointer', padding: '8px 16px', display: 'inline-block' }}
394
- >
387
+ <div className="c-btn c-btn--primary" onClick={() => setIsOpen(false)}>
395
388
  Confirm
396
389
  </div>
397
390
  </>
@@ -402,6 +395,7 @@ export const GlassModalCustom: Story = {
402
395
  aberration. The polar mode creates a different visual effect compared to the standard
403
396
  shader mode.
404
397
  </p>
398
+ <img src="https://picsum.photos/800/410" alt="desert" style={{ maxWidth: '100%' }} />
405
399
  </Modal>
406
400
  </>
407
401
  );
@@ -410,12 +404,14 @@ export const GlassModalCustom: Story = {
410
404
  Story => (
411
405
  <div
412
406
  style={{
413
- background:
414
- 'url(https://images.unsplash.com/photo-1744872665943-fd335d371059?q=80&w=3024&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D)',
407
+ background: 'url(https://picsum.photos/1920/1080)',
415
408
  height: '100vh',
416
409
  width: '100vw',
417
410
  backgroundSize: 'cover',
418
411
  backgroundPosition: 'center',
412
+ display: 'flex',
413
+ alignItems: 'center',
414
+ justifyContent: 'center',
419
415
  }}
420
416
  >
421
417
  <Story />
@@ -489,23 +485,10 @@ export const GlassModalSizes: Story = {
489
485
  glass={true}
490
486
  footer={
491
487
  <>
492
- <div
493
- className="c-btn c-btn--outline-secondary"
494
- onClick={() => setIsOpen(false)}
495
- style={{
496
- cursor: 'pointer',
497
- padding: '8px 16px',
498
- display: 'inline-block',
499
- marginRight: '8px',
500
- }}
501
- >
488
+ <div className="c-btn c-btn--outline-secondary" onClick={() => setIsOpen(false)}>
502
489
  Cancel
503
490
  </div>
504
- <div
505
- className="c-btn c-btn--primary"
506
- onClick={() => setIsOpen(false)}
507
- style={{ cursor: 'pointer', padding: '8px 16px', display: 'inline-block' }}
508
- >
491
+ <div className="c-btn c-btn--primary" onClick={() => setIsOpen(false)}>
509
492
  Confirm
510
493
  </div>
511
494
  </>
@@ -515,6 +498,9 @@ export const GlassModalSizes: Story = {
515
498
  <p>
516
499
  The glass effect adapts to different modal sizes while maintaining its visual appeal.
517
500
  </p>
501
+ <p>
502
+ The glass effect enhances the modal's appearance, making it visually appealing and easier to read.
503
+ </p>
518
504
  </Modal>
519
505
  </div>
520
506
  );
@@ -523,9 +509,14 @@ export const GlassModalSizes: Story = {
523
509
  Story => (
524
510
  <div
525
511
  style={{
526
- background: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
527
- minHeight: '100vh',
528
- padding: '2rem',
512
+ background: 'url(https://picsum.photos/1920/1080)',
513
+ height: '100vh',
514
+ width: '100vw',
515
+ backgroundSize: 'cover',
516
+ backgroundPosition: 'center',
517
+ display: 'flex',
518
+ alignItems: 'center',
519
+ justifyContent: 'center',
529
520
  }}
530
521
  >
531
522
  <Story />
@@ -197,11 +197,11 @@ export const Modal: React.FC<ModalProps> = ({
197
197
  ? // Default glass settings for modals
198
198
  (() => {
199
199
  const defaultGlassProps = {
200
- displacementScale: 100,
201
- blurAmount: 2,
202
- aberrationIntensity: 1,
203
- cornerRadius: 12,
200
+ displacementScale: document.querySelector('.c-modal---glass .c-modal__content')?.clientHeight,
201
+ blurAmount: 2.2,
202
+ elasticity: 0,
204
203
  mode: 'shader' as const,
204
+ shaderMode: 'premiumGlass'
205
205
  };
206
206
 
207
207
  const glassProps =
@@ -148,9 +148,14 @@ export const NavItem = forwardRef<HTMLLIElement, NavItemProps>(
148
148
  return (
149
149
  <li ref={ref} className={navItemClass} role="menuitem" aria-haspopup={dropdown || megaMenu}>
150
150
  {LinkComponent ? (
151
- <LinkComponent {...linkProps}>
152
- {dropdown || megaMenu ? childContent[0] : children}
153
- </LinkComponent>
151
+ (() => {
152
+ const Component = LinkComponent as React.ComponentType<any>;
153
+ return (
154
+ <Component {...linkProps}>
155
+ {dropdown || megaMenu ? childContent[0] : children}
156
+ </Component>
157
+ );
158
+ })()
154
159
  ) : (
155
160
  <a {...linkProps}>{dropdown || megaMenu ? childContent[0] : children}</a>
156
161
  )}