@shohojdhara/atomix 0.3.11 → 0.3.12

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.
@@ -52,6 +52,7 @@ export const Basic: Story = {
52
52
  label: 'Option 1',
53
53
  name: 'option',
54
54
  value: 'option1',
55
+ onChange: () => {},
55
56
  },
56
57
  };
57
58
 
@@ -62,38 +63,98 @@ export const Checked: Story = {
62
63
  name: 'option',
63
64
  value: 'option1',
64
65
  checked: true,
66
+ onChange: () => {},
65
67
  },
66
68
  };
67
69
 
68
70
  // Radio button group
69
71
  export const RadioGroup: Story = {
70
- render: (args: any) => (
71
- <div className="u-d-flex u-flex-column u-gap-2">
72
- <Radio label="Option 1" name="radioGroup" value="option1" checked />
73
- <Radio label="Option 2" name="radioGroup" value="option2" />
74
- <Radio label="Option 3" name="radioGroup" value="option3" />
75
- </div>
76
- ),
72
+ render: (args: any) => {
73
+ const [selectedValue, setSelectedValue] = React.useState('option1');
74
+
75
+ return (
76
+ <div className="u-d-flex u-flex-column u-gap-2">
77
+ <Radio
78
+ label="Option 1"
79
+ name="radioGroup"
80
+ value="option1"
81
+ checked={selectedValue === 'option1'}
82
+ onChange={() => setSelectedValue('option1')}
83
+ />
84
+ <Radio
85
+ label="Option 2"
86
+ name="radioGroup"
87
+ value="option2"
88
+ checked={selectedValue === 'option2'}
89
+ onChange={() => setSelectedValue('option2')}
90
+ />
91
+ <Radio
92
+ label="Option 3"
93
+ name="radioGroup"
94
+ value="option3"
95
+ checked={selectedValue === 'option3'}
96
+ onChange={() => setSelectedValue('option3')}
97
+ />
98
+ </div>
99
+ );
100
+ },
77
101
  };
78
102
 
79
103
  // Radio button states
80
104
  export const States: Story = {
81
- render: (args: any) => (
82
- <div className="u-d-flex u-flex-column u-gap-2">
83
- <Radio label="Default radio" name="states" value="default" />
84
- <Radio label="Checked radio" name="states" value="checked" checked />
85
- <Radio label="Disabled radio" name="states" value="disabled" disabled />
86
- <Radio
87
- label="Disabled and checked radio"
88
- name="states"
89
- value="disabledChecked"
90
- disabled
91
- checked
92
- />
93
- <Radio label="Valid radio" name="states" value="valid" valid checked />
94
- <Radio label="Invalid radio" name="states" value="invalid" invalid />
95
- </div>
96
- ),
105
+ render: (args: any) => {
106
+ const [selectedValue, setSelectedValue] = React.useState('default');
107
+
108
+ return (
109
+ <div className="u-d-flex u-flex-column u-gap-2">
110
+ <Radio
111
+ label="Default radio"
112
+ name="states"
113
+ value="default"
114
+ checked={selectedValue === 'default'}
115
+ onChange={() => setSelectedValue('default')}
116
+ />
117
+ <Radio
118
+ label="Checked radio"
119
+ name="states"
120
+ value="checked"
121
+ checked={selectedValue === 'checked'}
122
+ onChange={() => setSelectedValue('checked')}
123
+ />
124
+ <Radio
125
+ label="Disabled radio"
126
+ name="states"
127
+ value="disabled"
128
+ disabled
129
+ onChange={() => {}}
130
+ />
131
+ <Radio
132
+ label="Disabled and checked radio"
133
+ name="states"
134
+ value="disabledChecked"
135
+ disabled
136
+ checked
137
+ onChange={() => {}}
138
+ />
139
+ <Radio
140
+ label="Valid radio"
141
+ name="states"
142
+ value="valid"
143
+ valid
144
+ checked={selectedValue === 'valid'}
145
+ onChange={() => setSelectedValue('valid')}
146
+ />
147
+ <Radio
148
+ label="Invalid radio"
149
+ name="states"
150
+ value="invalid"
151
+ invalid
152
+ checked={selectedValue === 'invalid'}
153
+ onChange={() => setSelectedValue('invalid')}
154
+ />
155
+ </div>
156
+ );
157
+ },
97
158
  };
98
159
 
99
160
  // Without label
@@ -102,6 +163,7 @@ export const WithoutLabel: Story = {
102
163
  name: 'noLabel',
103
164
  value: 'noLabel',
104
165
  ariaLabel: 'Radio button without visible label',
166
+ onChange: () => {},
105
167
  },
106
168
  };
107
169
 
@@ -112,6 +174,7 @@ export const Glass: Story = {
112
174
  name: 'glass',
113
175
  value: 'glass',
114
176
  glass: true,
177
+ onChange: () => {},
115
178
  },
116
179
  render: (args: any) => (
117
180
  <div
@@ -143,6 +206,7 @@ export const GlassCustom: Story = {
143
206
  aberrationIntensity: 0.8,
144
207
  cornerRadius: 12,
145
208
  } as any,
209
+ onChange: () => {},
146
210
  },
147
211
  render: (args: any) => (
148
212
  <div
@@ -166,91 +230,159 @@ export const GlassCustom: Story = {
166
230
 
167
231
  // Glass radio group
168
232
  export const GlassGroup: Story = {
169
- render: () => (
170
- <div
171
- style={{
172
- background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
173
- padding: '2rem',
174
- borderRadius: '12px',
175
- minHeight: '300px',
176
- display: 'flex',
177
- alignItems: 'center',
178
- justifyContent: 'center',
179
- }}
180
- >
181
- <div>
182
- <h3
183
- style={{
184
- color: 'white',
185
- marginBottom: '2rem',
186
- textAlign: 'center',
187
- textShadow: '0 2px 4px rgba(0,0,0,0.5)',
188
- }}
189
- >
190
- Glass Radio Group
191
- </h3>
192
- <div className="u-d-flex u-flex-column u-gap-2">
193
- <Radio label="Glass Option 1" name="glassGroup" value="option1" checked glass />
194
- <Radio label="Glass Option 2" name="glassGroup" value="option2" glass />
195
- <Radio label="Glass Option 3" name="glassGroup" value="option3" glass />
233
+ render: () => {
234
+ const [selectedValue, setSelectedValue] = React.useState('option1');
235
+
236
+ return (
237
+ <div
238
+ style={{
239
+ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
240
+ padding: '2rem',
241
+ borderRadius: '12px',
242
+ minHeight: '300px',
243
+ display: 'flex',
244
+ alignItems: 'center',
245
+ justifyContent: 'center',
246
+ }}
247
+ >
248
+ <div>
249
+ <h3
250
+ style={{
251
+ color: 'white',
252
+ marginBottom: '2rem',
253
+ textAlign: 'center',
254
+ textShadow: '0 2px 4px rgba(0,0,0,0.5)',
255
+ }}
256
+ >
257
+ Glass Radio Group
258
+ </h3>
259
+ <div className="u-d-flex u-flex-column u-gap-2">
260
+ <Radio
261
+ label="Glass Option 1"
262
+ name="glassGroup"
263
+ value="option1"
264
+ checked={selectedValue === 'option1'}
265
+ onChange={() => setSelectedValue('option1')}
266
+ glass
267
+ />
268
+ <Radio
269
+ label="Glass Option 2"
270
+ name="glassGroup"
271
+ value="option2"
272
+ checked={selectedValue === 'option2'}
273
+ onChange={() => setSelectedValue('option2')}
274
+ glass
275
+ />
276
+ <Radio
277
+ label="Glass Option 3"
278
+ name="glassGroup"
279
+ value="option3"
280
+ checked={selectedValue === 'option3'}
281
+ onChange={() => setSelectedValue('option3')}
282
+ glass
283
+ />
284
+ </div>
196
285
  </div>
197
286
  </div>
198
- </div>
199
- ),
287
+ );
288
+ },
200
289
  };
201
290
 
202
291
  // Glass states
203
292
  export const GlassStates: Story = {
204
- render: () => (
205
- <div
206
- style={{
207
- background: 'linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #feca57)',
208
- backgroundSize: '400% 400%',
209
- animation: 'gradient 15s ease infinite',
210
- padding: '2rem',
211
- borderRadius: '12px',
212
- minHeight: '500px',
213
- display: 'flex',
214
- alignItems: 'center',
215
- justifyContent: 'center',
216
- }}
217
- >
218
- <style>
219
- {`
220
- @keyframes gradient {
221
- 0% { background-position: 0% 50%; }
222
- 50% { background-position: 100% 50%; }
223
- 100% { background-position: 0% 50%; }
224
- }
225
- `}
226
- </style>
227
- <div>
228
- <h3
229
- style={{
230
- color: 'white',
231
- marginBottom: '2rem',
232
- textAlign: 'center',
233
- textShadow: '0 2px 4px rgba(0,0,0,0.5)',
234
- }}
235
- >
236
- Glass Radio States
237
- </h3>
238
- <div className="u-d-flex u-flex-column u-gap-2">
239
- <Radio label="Glass Default" name="glassStates" value="default" glass />
240
- <Radio label="Glass Checked" name="glassStates" value="checked" checked glass />
241
- <Radio label="Glass Disabled" name="glassStates" value="disabled" disabled glass />
242
- <Radio
243
- label="Glass Disabled and Checked"
244
- name="glassStates"
245
- value="disabledChecked"
246
- disabled
247
- checked
248
- glass
249
- />
250
- <Radio label="Glass Valid" name="glassStates" value="valid" valid checked glass />
251
- <Radio label="Glass Invalid" name="glassStates" value="invalid" invalid glass />
293
+ render: () => {
294
+ const [selectedValue, setSelectedValue] = React.useState('default');
295
+
296
+ return (
297
+ <div
298
+ style={{
299
+ background: 'linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #feca57)',
300
+ backgroundSize: '400% 400%',
301
+ animation: 'gradient 15s ease infinite',
302
+ padding: '2rem',
303
+ borderRadius: '12px',
304
+ minHeight: '500px',
305
+ display: 'flex',
306
+ alignItems: 'center',
307
+ justifyContent: 'center',
308
+ }}
309
+ >
310
+ <style>
311
+ {`
312
+ @keyframes gradient {
313
+ 0% { background-position: 0% 50%; }
314
+ 50% { background-position: 100% 50%; }
315
+ 100% { background-position: 0% 50%; }
316
+ }
317
+ `}
318
+ </style>
319
+ <div>
320
+ <h3
321
+ style={{
322
+ color: 'white',
323
+ marginBottom: '2rem',
324
+ textAlign: 'center',
325
+ textShadow: '0 2px 4px rgba(0,0,0,0.5)',
326
+ }}
327
+ >
328
+ Glass Radio States
329
+ </h3>
330
+ <div className="u-d-flex u-flex-column u-gap-2">
331
+ <Radio
332
+ label="Glass Default"
333
+ name="glassStates"
334
+ value="default"
335
+ checked={selectedValue === 'default'}
336
+ onChange={() => setSelectedValue('default')}
337
+ glass
338
+ />
339
+ <Radio
340
+ label="Glass Checked"
341
+ name="glassStates"
342
+ value="checked"
343
+ checked={selectedValue === 'checked'}
344
+ onChange={() => setSelectedValue('checked')}
345
+ glass
346
+ />
347
+ <Radio
348
+ label="Glass Disabled"
349
+ name="glassStates"
350
+ value="disabled"
351
+ disabled
352
+ checked={selectedValue === 'disabled'}
353
+ onChange={() => setSelectedValue('disabled')}
354
+ glass
355
+ />
356
+ <Radio
357
+ label="Glass Disabled and Checked"
358
+ name="glassStates"
359
+ value="disabledChecked"
360
+ disabled
361
+ checked={selectedValue === 'disabledChecked'}
362
+ onChange={() => setSelectedValue('disabledChecked')}
363
+ glass
364
+ />
365
+ <Radio
366
+ label="Glass Valid"
367
+ name="glassStates"
368
+ value="valid"
369
+ valid
370
+ checked={selectedValue === 'valid'}
371
+ onChange={() => setSelectedValue('valid')}
372
+ glass
373
+ />
374
+ <Radio
375
+ label="Glass Invalid"
376
+ name="glassStates"
377
+ value="invalid"
378
+ invalid
379
+ checked={selectedValue === 'invalid'}
380
+ onChange={() => setSelectedValue('invalid')}
381
+ glass
382
+ />
383
+ </div>
252
384
  </div>
253
385
  </div>
254
- </div>
255
- ),
256
- };
386
+ );
387
+ },
388
+ };
@@ -23,7 +23,7 @@ export const NavDropdown: React.FC<NavDropdownProps> = forwardRef<HTMLLIElement,
23
23
  });
24
24
 
25
25
  const [isActive, setIsActive] = useState(false);
26
- const dropdownRef = useRef<HTMLDivElement>(null);
26
+ const dropdownRef = useRef<HTMLElement>(null);
27
27
 
28
28
  const dropdownMenuClass = generateDropdownMenuClass({
29
29
  alignment,
@@ -82,11 +82,15 @@ export const NavDropdown: React.FC<NavDropdownProps> = forwardRef<HTMLLIElement,
82
82
  </>
83
83
  );
84
84
 
85
- // Create the dropdown/mega menu content
85
+ const MenuTag = megaMenu ? 'div' : 'ul';
86
86
  const menuContent = (
87
- <div className={dropdownMenuClass} ref={dropdownRef} aria-hidden={!isActive}>
87
+ <MenuTag
88
+ className={dropdownMenuClass}
89
+ ref={dropdownRef as any}
90
+ aria-hidden={!isActive}
91
+ >
88
92
  {children}
89
- </div>
93
+ </MenuTag>
90
94
  );
91
95
 
92
96
  return (
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useRef, forwardRef, createContext, useContext } from 'react';
1
+ import React, { useState, useEffect, useRef, forwardRef } from 'react';
2
2
  import { SideMenuProps } from '../../../lib/types/components';
3
3
  import { useSideMenu } from '../../../lib/composables/useSideMenu';
4
4
  import { Icon } from '../../Icon';
@@ -7,25 +7,7 @@ import useForkRef from '../../../lib/utils/useForkRef';
7
7
  import SideMenuList from './SideMenuList';
8
8
  import SideMenuItem from './SideMenuItem';
9
9
 
10
- // Context for passing LinkComponent to SideMenuItem children
11
- const SideMenuContext = createContext<{
12
- LinkComponent?: React.ComponentType<{
13
- href?: string;
14
- to?: string;
15
- children: React.ReactNode;
16
- className?: string;
17
- onClick?: (event: React.MouseEvent) => void;
18
- target?: string;
19
- rel?: string;
20
- 'aria-disabled'?: boolean;
21
- 'aria-current'?: string;
22
- tabIndex?: number;
23
- ref?: React.Ref<HTMLAnchorElement>;
24
- }>;
25
- }>({});
26
-
27
- // Hook to use SideMenu context
28
- export const useSideMenuContext = () => useContext(SideMenuContext);
10
+
29
11
 
30
12
  /**
31
13
  * SideMenu component provides a collapsible navigation menu with title and menu items.
@@ -235,7 +217,6 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
235
217
  id={id ? `${id}-content` : undefined}
236
218
  aria-hidden={shouldShowToggler ? !isOpenState : false}
237
219
  >
238
- <SideMenuContext.Provider value={{ LinkComponent }}>
239
220
  <div ref={innerRef} className="c-side-menu__inner">
240
221
  {children}
241
222
  {menuItems?.map((item, index) => {
@@ -321,7 +302,6 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
321
302
  );
322
303
  })}
323
304
  </div>
324
- </SideMenuContext.Provider>
325
305
  </div>
326
306
  </>
327
307
  );
@@ -1,7 +1,6 @@
1
1
  import React, { forwardRef } from 'react';
2
2
  import { SideMenuItemProps } from '../../../lib/types/components';
3
3
  import { useSideMenuItem } from '../../../lib/composables/useSideMenu';
4
- import { useSideMenuContext } from './SideMenu';
5
4
 
6
5
  /**
7
6
  * SideMenuItem component represents a single navigation item in a side menu.
@@ -17,7 +16,13 @@ import { useSideMenuContext } from './SideMenu';
17
16
  * Click me
18
17
  * </SideMenuItem>
19
18
  *
20
- * // With icon
19
+ * // With icon and custom link component
20
+ * import Link from 'next/link';
21
+ * <SideMenuItem href="/settings" icon={<Icon name="Settings" />} LinkComponent={Link}>
22
+ * Settings
23
+ * </SideMenuItem>
24
+ *
25
+ * // With icon and custom link component
21
26
  * <SideMenuItem href="/settings" icon={<Icon name="Settings" />}>
22
27
  * Settings
23
28
  * </SideMenuItem>
@@ -44,9 +49,6 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
44
49
  },
45
50
  ref
46
51
  ) => {
47
- const { LinkComponent: LinkComponentFromContext } = useSideMenuContext();
48
- // Use LinkComponent from props first, then fall back to context
49
- const LinkComponent = LinkComponentProp ?? LinkComponentFromContext;
50
52
 
51
53
  const { generateSideMenuItemClass, handleClick } = useSideMenuItem({
52
54
  active,
@@ -58,12 +60,8 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
58
60
 
59
61
  // Render as link if href is provided
60
62
  if (href) {
61
- // When using a custom LinkComponent (e.g., Next.js Link, React Router Link)
62
- if (LinkComponent) {
63
- const Component = LinkComponent;
64
-
65
- // Build link props - support both 'href' (Next.js) and 'to' (React Router)
66
- // The Link component will use whichever prop it needs
63
+ if (LinkComponentProp) {
64
+ const LinkComp = LinkComponentProp as React.ComponentType<any>;
67
65
  const linkProps: {
68
66
  ref?: React.Ref<HTMLAnchorElement>;
69
67
  className?: string;
@@ -88,16 +86,14 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
88
86
  target: target,
89
87
  rel: rel,
90
88
  tabIndex: disabled ? -1 : 0,
91
- // Support both Next.js (href) and React Router (to) Link components
92
- // Pass both props - the Link component will use whichever it needs
93
89
  ...(disabled ? {} : { href, to: href }),
94
90
  };
95
91
 
96
92
  return (
97
- <Component {...linkProps}>
93
+ <LinkComp {...linkProps}>
98
94
  {icon && <span className="c-side-menu__link-icon">{icon}</span>}
99
95
  <span className="c-side-menu__link-text">{children}</span>
100
- </Component>
96
+ </LinkComp>
101
97
  );
102
98
  }
103
99
 
@@ -1418,19 +1418,7 @@ export interface SideMenuProps extends BaseComponentProps {
1418
1418
  * <SideMenu LinkComponent={Link} />
1419
1419
  * ```
1420
1420
  */
1421
- LinkComponent?: React.ComponentType<{
1422
- href?: string;
1423
- to?: string;
1424
- children: React.ReactNode;
1425
- className?: string;
1426
- onClick?: (event: React.MouseEvent) => void;
1427
- target?: string;
1428
- rel?: string;
1429
- 'aria-disabled'?: boolean;
1430
- 'aria-current'?: string;
1431
- tabIndex?: number;
1432
- ref?: React.Ref<HTMLAnchorElement>;
1433
- }>;
1421
+ LinkComponent?: React.ElementType;
1434
1422
 
1435
1423
  /**
1436
1424
  * Menu items
@@ -1524,19 +1512,7 @@ export interface SideMenuItemProps extends BaseComponentProps {
1524
1512
  * <SideMenuItem href="/about" LinkComponent={Link}>About</SideMenuItem>
1525
1513
  * ```
1526
1514
  */
1527
- LinkComponent?: React.ComponentType<{
1528
- href?: string;
1529
- to?: string;
1530
- children: React.ReactNode;
1531
- className?: string;
1532
- onClick?: (event: React.MouseEvent) => void;
1533
- target?: string;
1534
- rel?: string;
1535
- 'aria-disabled'?: boolean;
1536
- 'aria-current'?: string;
1537
- tabIndex?: number;
1538
- ref?: React.Ref<HTMLAnchorElement>;
1539
- }>;
1515
+ LinkComponent?: React.ElementType;
1540
1516
  }
1541
1517
 
1542
1518
  /**
@@ -416,7 +416,7 @@
416
416
  }
417
417
 
418
418
  // Remove borders for glass variant on all positions
419
- &.c-edge-panel--start .c-edge-panel__glass-wrapper {
419
+ &.c-edge-panel--start .c-edge-panel__glass-content {
420
420
  animation: slideInStart 0.3s ease forwards;
421
421
 
422
422
  &.is-animating-out {
@@ -424,7 +424,7 @@
424
424
  }
425
425
  }
426
426
 
427
- &.c-edge-panel--end .c-edge-panel__glass-wrapper {
427
+ &.c-edge-panel--end .c-edge-panel__glass-content {
428
428
  animation: slideInEnd 0.3s ease forwards;
429
429
 
430
430
  &.is-animating-out {
@@ -432,11 +432,11 @@
432
432
  }
433
433
  }
434
434
 
435
- &.c-edge-panel--top .c-edge-panel__glass-wrapper {
435
+ &.c-edge-panel--top .c-edge-panel__glass-content{
436
436
  animation: slideInTop 0.3s ease forwards;
437
437
  }
438
438
 
439
- &.c-edge-panel--bottom .c-edge-panel__glass-wrapper {
439
+ &.c-edge-panel--bottom .c-edge-panel__glass-content {
440
440
  animation: slideInBottom 0.3s ease forwards;
441
441
  }
442
442
 
@@ -92,6 +92,9 @@
92
92
  visibility: hidden;
93
93
  opacity: 0;
94
94
  white-space: nowrap;
95
+ list-style: none;
96
+ padding: 0;
97
+ margin: 0;
95
98
  @include transition.basic-transition();
96
99
 
97
100
  &--center {