@shohojdhara/atomix 0.3.15 → 0.4.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.
- package/build-tools/index.d.ts +31 -30
- package/build-tools/package.json +4 -21
- package/dist/atomix.css +20234 -2027
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +76 -2
- package/dist/atomix.min.css.map +1 -1
- package/dist/build-tools/index.d.ts +31 -30
- package/dist/build-tools/package.json +4 -21
- package/dist/charts.js +4 -5
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +87 -10
- package/dist/core.js +673 -480
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +15 -3
- package/dist/forms.js +530 -97
- package/dist/forms.js.map +1 -1
- package/dist/heavy.js +5 -6
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +644 -277
- package/dist/index.esm.js +1948 -1347
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +3333 -2728
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/layout.js.map +1 -1
- package/dist/theme.d.ts +9 -9
- package/dist/theme.js.map +1 -1
- package/package.json +2 -2
- package/scripts/atomix-cli.js +10 -1
- package/scripts/cli/__tests__/utils.test.js +6 -2
- package/scripts/cli/migration-tools.js +2 -2
- package/scripts/cli/theme-bridge.js +7 -9
- package/scripts/cli/utils.js +2 -1
- package/src/components/Accordion/Accordion.stories.tsx +72 -23
- package/src/components/Accordion/Accordion.test.tsx +70 -50
- package/src/components/Accordion/Accordion.tsx +219 -96
- package/src/components/Accordion/AccordionCompound.test.tsx +70 -0
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +1 -1
- package/src/components/AtomixGlass/GlassFilter.tsx +9 -16
- package/src/components/AtomixGlass/glass-utils.ts +4 -3
- package/src/components/AtomixGlass/shader-utils.ts +128 -52
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +1 -1
- package/src/components/AtomixGlass/stories/Shaders.stories.tsx +1 -1
- package/src/components/Avatar/Avatar.stories.tsx +45 -62
- package/src/components/Avatar/Avatar.tsx +58 -56
- package/src/components/Badge/Badge.stories.tsx +20 -9
- package/src/components/Badge/Badge.test.tsx +41 -41
- package/src/components/Badge/Badge.tsx +64 -62
- package/src/components/Block/Block.stories.tsx +14 -4
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +9 -8
- package/src/components/Breadcrumb/Breadcrumb.tsx +173 -65
- package/src/components/Breadcrumb/BreadcrumbCompound.test.tsx +84 -0
- package/src/components/Button/Button.stories.tsx +13 -22
- package/src/components/Button/Button.test.tsx +97 -81
- package/src/components/Button/Button.tsx +46 -14
- package/src/components/Button/ButtonGroup.stories.tsx +37 -32
- package/src/components/Button/ButtonGroup.tsx +4 -15
- package/src/components/Callout/Callout.stories.tsx +166 -918
- package/src/components/Callout/Callout.tsx +196 -84
- package/src/components/Callout/CalloutCompound.test.tsx +72 -0
- package/src/components/Card/Card.stories.tsx +67 -36
- package/src/components/Card/Card.tsx +30 -14
- package/src/components/Chart/AreaChart.tsx +1 -1
- package/src/components/Chart/CandlestickChart.tsx +23 -16
- package/src/components/Chart/Chart.stories.tsx +4 -9
- package/src/components/Chart/Chart.tsx +40 -44
- package/src/components/Chart/ChartRenderer.tsx +39 -12
- package/src/components/Chart/ChartToolbar.tsx +21 -5
- package/src/components/Chart/DonutChart.tsx +1 -1
- package/src/components/Chart/FunnelChart.tsx +4 -1
- package/src/components/Chart/GaugeChart.tsx +3 -1
- package/src/components/Chart/HeatmapChart.tsx +50 -37
- package/src/components/Chart/LineChart.tsx +3 -2
- package/src/components/Chart/MultiAxisChart.tsx +24 -16
- package/src/components/Chart/RadarChart.tsx +19 -17
- package/src/components/Chart/ScatterChart.tsx +29 -21
- package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +6 -2
- package/src/components/ColorModeToggle/ColorModeToggle.tsx +15 -3
- package/src/components/Countdown/Countdown.stories.tsx +7 -7
- package/src/components/DataTable/DataTable.stories.tsx +43 -38
- package/src/components/DataTable/DataTable.test.tsx +26 -148
- package/src/components/DataTable/DataTable.tsx +485 -456
- package/src/components/DatePicker/DatePicker.stories.tsx +32 -47
- package/src/components/DatePicker/DatePicker.tsx +31 -26
- package/src/components/Dropdown/Dropdown.stories.tsx +2 -5
- package/src/components/Dropdown/Dropdown.tsx +425 -298
- package/src/components/Dropdown/DropdownCompound.test.tsx +64 -0
- package/src/components/EdgePanel/EdgePanel.stories.tsx +6 -19
- package/src/components/EdgePanel/EdgePanel.tsx +163 -113
- package/src/components/EdgePanel/EdgePanelCompound.test.tsx +53 -0
- package/src/components/Footer/Footer.stories.tsx +21 -16
- package/src/components/Footer/Footer.tsx +130 -128
- package/src/components/Footer/FooterLink.tsx +2 -2
- package/src/components/Form/Checkbox.test.tsx +49 -49
- package/src/components/Form/Checkbox.tsx +108 -100
- package/src/components/Form/Form.stories.tsx +2 -10
- package/src/components/Form/Input.stories.tsx +22 -39
- package/src/components/Form/Input.test.tsx +38 -44
- package/src/components/Form/Radio.stories.tsx +6 -12
- package/src/components/Form/Radio.tsx +68 -66
- package/src/components/Form/Select.stories.tsx +23 -0
- package/src/components/Form/Select.test.tsx +99 -0
- package/src/components/Form/Select.tsx +239 -186
- package/src/components/Form/SelectOption.tsx +88 -0
- package/src/components/Form/Textarea.test.tsx +27 -32
- package/src/components/Hero/Hero.stories.tsx +93 -23
- package/src/components/Hero/Hero.test.tsx +142 -0
- package/src/components/Hero/Hero.tsx +343 -58
- package/src/components/Icon/index.ts +7 -1
- package/src/components/List/List.test.tsx +62 -0
- package/src/components/List/List.tsx +32 -25
- package/src/components/List/ListItem.tsx +20 -0
- package/src/components/Modal/Modal.stories.tsx +67 -2
- package/src/components/Modal/Modal.tsx +208 -125
- package/src/components/Modal/ModalCompound.test.tsx +94 -0
- package/src/components/Navigation/Menu/MegaMenu.tsx +70 -70
- package/src/components/Navigation/Nav/NavDropdown.tsx +1 -5
- package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +128 -28
- package/src/components/Navigation/SideMenu/SideMenu.tsx +5 -7
- package/src/components/Navigation/SideMenu/SideMenuItem.tsx +4 -5
- package/src/components/Pagination/Pagination.stories.tsx +7 -4
- package/src/components/Pagination/Pagination.tsx +199 -202
- package/src/components/PhotoViewer/PhotoViewer.tsx +4 -1
- package/src/components/Popover/Popover.stories.tsx +99 -192
- package/src/components/Popover/Popover.tsx +41 -37
- package/src/components/Progress/Progress.stories.tsx +35 -44
- package/src/components/River/River.stories.tsx +2 -1
- package/src/components/SectionIntro/SectionIntro.stories.tsx +71 -71
- package/src/components/Slider/Slider.stories.tsx +12 -4
- package/src/components/Spinner/Spinner.stories.tsx +3 -1
- package/src/components/Spinner/Spinner.test.tsx +23 -23
- package/src/components/Spinner/Spinner.tsx +43 -46
- package/src/components/Steps/Steps.stories.tsx +8 -6
- package/src/components/Steps/Steps.tsx +124 -21
- package/src/components/Steps/StepsCompound.test.tsx +81 -0
- package/src/components/Tabs/Tabs.stories.tsx +12 -9
- package/src/components/Tabs/Tabs.tsx +230 -75
- package/src/components/Tabs/TabsCompound.test.tsx +64 -0
- package/src/components/Toggle/Toggle.stories.tsx +27 -13
- package/src/components/Toggle/Toggle.test.tsx +65 -70
- package/src/components/Toggle/Toggle.tsx +4 -1
- package/src/components/Tooltip/Tooltip.stories.tsx +24 -20
- package/src/components/Tooltip/Tooltip.tsx +104 -106
- package/src/components/Upload/Upload.stories.tsx +129 -127
- package/src/components/Upload/Upload.tsx +287 -283
- package/src/components/VideoPlayer/VideoPlayer.tsx +6 -1
- package/src/components/index.ts +13 -2
- package/src/layouts/Grid/Grid.stories.tsx +9 -3
- package/src/layouts/MasonryGrid/MasonryGrid.tsx +5 -1
- package/src/lib/__tests__/theme-tools.test.ts +32 -6
- package/src/lib/composables/index.ts +0 -4
- package/src/lib/composables/shared-mouse-tracker.ts +13 -14
- package/src/lib/composables/useAtomixGlass.ts +102 -60
- package/src/lib/composables/useChartExport.ts +1 -1
- package/src/lib/composables/useDataTable.ts +29 -17
- package/src/lib/composables/useHero.ts +58 -14
- package/src/lib/composables/useHeroBackgroundSlider.ts +2 -9
- package/src/lib/composables/useInput.ts +10 -8
- package/src/lib/composables/useSideMenu.ts +6 -5
- package/src/lib/composables/useTooltip.ts +1 -2
- package/src/lib/composables/useVideoPlayer.ts +44 -35
- package/src/lib/config/index.ts +154 -154
- package/src/lib/constants/cssVariables.ts +29 -29
- package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +2 -6
- package/src/lib/hooks/index.ts +1 -1
- package/src/lib/hooks/useComponentCustomization.ts +11 -17
- package/src/lib/hooks/usePerformanceMonitor.ts +6 -7
- package/src/lib/patterns/__tests__/slots.test.ts +1 -1
- package/src/lib/patterns/index.ts +1 -1
- package/src/lib/patterns/slots.tsx +8 -13
- package/src/lib/storybook/InteractiveDemo.tsx +13 -18
- package/src/lib/storybook/PreviewContainer.tsx +1 -1
- package/src/lib/storybook/VariantsGrid.tsx +3 -7
- package/src/lib/storybook/index.ts +1 -1
- package/src/lib/theme/adapters/cssVariableMapper.ts +47 -74
- package/src/lib/theme/adapters/index.ts +3 -9
- package/src/lib/theme/adapters/themeAdapter.ts +41 -26
- package/src/lib/theme/config/index.ts +1 -1
- package/src/lib/theme/config/types.ts +2 -2
- package/src/lib/theme/config/validator.ts +10 -5
- package/src/lib/theme/constants/constants.ts +2 -2
- package/src/lib/theme/constants/index.ts +1 -2
- package/src/lib/theme/core/__tests__/createTheme.test.ts +20 -22
- package/src/lib/theme/core/composeTheme.ts +32 -26
- package/src/lib/theme/core/createTheme.ts +1 -1
- package/src/lib/theme/core/createThemeObject.ts +308 -301
- package/src/lib/theme/core/index.ts +3 -3
- package/src/lib/theme/devtools/CLI.ts +105 -111
- package/src/lib/theme/devtools/Comparator.tsx +50 -32
- package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +50 -48
- package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +257 -63
- package/src/lib/theme/devtools/Inspector.tsx +75 -60
- package/src/lib/theme/devtools/LiveEditor.tsx +97 -76
- package/src/lib/theme/devtools/Preview.tsx +150 -106
- package/src/lib/theme/devtools/ThemeValidator.ts +29 -21
- package/src/lib/theme/devtools/index.ts +3 -9
- package/src/lib/theme/devtools/useHistory.ts +23 -21
- package/src/lib/theme/errors/errors.ts +12 -11
- package/src/lib/theme/errors/index.ts +2 -7
- package/src/lib/theme/generators/generateCSS.ts +9 -13
- package/src/lib/theme/generators/generateCSSNested.ts +1 -6
- package/src/lib/theme/generators/generateCSSVariables.ts +673 -630
- package/src/lib/theme/generators/index.ts +1 -4
- package/src/lib/theme/i18n/index.ts +1 -1
- package/src/lib/theme/i18n/rtl.ts +13 -13
- package/src/lib/theme/index.ts +7 -16
- package/src/lib/theme/runtime/ThemeApplicator.ts +4 -4
- package/src/lib/theme/runtime/ThemeContext.tsx +1 -1
- package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +19 -23
- package/src/lib/theme/runtime/ThemeProvider.tsx +230 -239
- package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +1 -1
- package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +24 -29
- package/src/lib/theme/runtime/index.ts +2 -5
- package/src/lib/theme/runtime/useTheme.ts +18 -18
- package/src/lib/theme/runtime/useThemeTokens.ts +22 -22
- package/src/lib/theme/test/testTheme.ts +15 -16
- package/src/lib/theme/tokens/index.ts +2 -7
- package/src/lib/theme/tokens/tokens.ts +25 -24
- package/src/lib/theme/types.ts +428 -411
- package/src/lib/theme/utils/__tests__/themeValidation.test.ts +3 -3
- package/src/lib/theme/utils/componentTheming.ts +18 -18
- package/src/lib/theme/utils/domUtils.ts +277 -289
- package/src/lib/theme/utils/index.ts +1 -2
- package/src/lib/theme/utils/injectCSS.ts +10 -14
- package/src/lib/theme/utils/naming.ts +20 -16
- package/src/lib/theme/utils/themeHelpers.ts +10 -12
- package/src/lib/theme/utils/themeUtils.ts +85 -86
- package/src/lib/theme/utils/themeValidation.ts +82 -33
- package/src/lib/theme-tools.ts +8 -6
- package/src/lib/types/components.ts +180 -73
- package/src/lib/types/partProps.ts +1 -1
- package/src/lib/utils/__tests__/componentUtils.test.ts +57 -2
- package/src/lib/utils/__tests__/csv.test.ts +1 -1
- package/src/lib/utils/__tests__/themeNaming.test.ts +117 -0
- package/src/lib/utils/componentUtils.ts +8 -12
- package/src/lib/utils/csv.ts +3 -1
- package/src/lib/utils/dataTableExport.ts +1 -5
- package/src/lib/utils/fontPreloader.ts +10 -19
- package/src/lib/utils/icons.ts +4 -1
- package/src/lib/utils/index.ts +2 -6
- package/src/lib/utils/memoryMonitor.ts +10 -8
- package/src/lib/utils/themeNaming.ts +3 -3
- package/src/styles/01-settings/_index.scss +0 -1
- package/src/styles/01-settings/_settings.colors.scss +8 -8
- package/src/styles/01-settings/_settings.design-tokens.scss +61 -50
- package/src/styles/01-settings/_settings.navbar.scss +1 -1
- package/src/styles/01-settings/_settings.spacing.scss +3 -4
- package/src/styles/01-settings/_settings.tooltip.scss +1 -1
- package/src/styles/01-settings/_settings.typography.scss +1 -1
- package/src/styles/02-tools/_tools.breakpoints.scss +1 -1
- package/src/styles/02-tools/_tools.button.scss +51 -21
- package/src/styles/02-tools/_tools.utility-api.scss +36 -24
- package/src/styles/03-generic/_generic.root.scss +4 -3
- package/src/styles/06-components/_components.atomix-glass.scss +13 -9
- package/src/styles/06-components/_components.button.scss +16 -4
- package/src/styles/06-components/_components.callout.scss +27 -21
- package/src/styles/06-components/_components.card.scss +5 -14
- package/src/styles/06-components/_components.chart.scss +22 -19
- package/src/styles/06-components/_components.checkbox.scss +3 -1
- package/src/styles/06-components/_components.color-mode-toggle.scss +3 -1
- package/src/styles/06-components/_components.edge-panel.scss +9 -2
- package/src/styles/06-components/_components.footer.scss +1 -1
- package/src/styles/06-components/_components.side-menu.scss +5 -5
- package/src/styles/06-components/_components.toggle.scss +18 -0
- package/src/styles/06-components/_index.scss +1 -1
- package/src/styles/06-components/old.chart.styles.scss +0 -2
- package/src/styles/99-utilities/_utilities.border.scss +69 -27
- package/src/styles/99-utilities/_utilities.display.scss +1 -1
- package/src/styles/99-utilities/_utilities.opacity.scss +10 -0
- package/src/styles/99-utilities/_utilities.position.scss +16 -9
- package/src/styles/99-utilities/_utilities.scss +1 -1
- package/src/styles/99-utilities/_utilities.sizes.scss +47 -18
- package/src/styles/99-utilities/_utilities.spacing.scss +118 -66
- package/src/styles/99-utilities/_utilities.text-gradient.scss +30 -30
- package/src/styles/99-utilities/_utilities.text.scss +67 -47
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
+
import { Dropdown } from './Dropdown';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
describe('Dropdown Component', () => {
|
|
7
|
+
it('renders correctly with legacy props', () => {
|
|
8
|
+
// In legacy mode, `menu` prop content is rendered inside the dropdown wrapper.
|
|
9
|
+
// The dropdown wrapper uses CSS visibility/opacity/display to hide the menu when not open.
|
|
10
|
+
// `toBeVisible` checks if the element is visible to the user.
|
|
11
|
+
// However, if the menu is just visually hidden via CSS classes (e.g. opacity: 0),
|
|
12
|
+
// jest-dom might consider it visible if display is not none and visibility is not hidden.
|
|
13
|
+
// Let's check if the wrapper has `is-open` class.
|
|
14
|
+
|
|
15
|
+
const { container } = render(
|
|
16
|
+
<Dropdown menu={<Dropdown.Item>Item 1</Dropdown.Item>}>
|
|
17
|
+
<button>Trigger</button>
|
|
18
|
+
</Dropdown>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
expect(screen.getByText('Trigger')).toBeInTheDocument();
|
|
22
|
+
|
|
23
|
+
// Check if the menu wrapper exists but does not have 'is-open' class
|
|
24
|
+
const menuWrapper = container.querySelector('.c-dropdown__menu-wrapper');
|
|
25
|
+
expect(menuWrapper).not.toHaveClass('is-open');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('renders correctly with compound components', () => {
|
|
29
|
+
render(
|
|
30
|
+
<Dropdown>
|
|
31
|
+
<Dropdown.Trigger>
|
|
32
|
+
<button>Compound Trigger</button>
|
|
33
|
+
</Dropdown.Trigger>
|
|
34
|
+
<Dropdown.Menu>
|
|
35
|
+
<Dropdown.Item>Item 1</Dropdown.Item>
|
|
36
|
+
</Dropdown.Menu>
|
|
37
|
+
</Dropdown>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(screen.getByText('Compound Trigger')).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('toggles menu in compound mode', () => {
|
|
44
|
+
const { container } = render(
|
|
45
|
+
<Dropdown>
|
|
46
|
+
<Dropdown.Trigger>
|
|
47
|
+
<button>Trigger</button>
|
|
48
|
+
</Dropdown.Trigger>
|
|
49
|
+
<Dropdown.Menu>
|
|
50
|
+
<Dropdown.Item>Item 1</Dropdown.Item>
|
|
51
|
+
</Dropdown.Menu>
|
|
52
|
+
</Dropdown>
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
fireEvent.click(screen.getByText('Trigger'));
|
|
56
|
+
|
|
57
|
+
// Check if open class is applied or aria-expanded
|
|
58
|
+
const trigger = screen.getByText('Trigger').closest('.c-dropdown__toggle');
|
|
59
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
60
|
+
|
|
61
|
+
const menuWrapper = container.querySelector('.c-dropdown__menu-wrapper');
|
|
62
|
+
expect(menuWrapper).toHaveClass('is-open');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -230,18 +230,13 @@ const DemoPanelContent = ({
|
|
|
230
230
|
);
|
|
231
231
|
|
|
232
232
|
export const BasicUsage: Story = {
|
|
233
|
-
render:
|
|
233
|
+
render: args => {
|
|
234
234
|
const [isOpen, setIsOpen] = useState(false);
|
|
235
235
|
|
|
236
236
|
return (
|
|
237
237
|
<>
|
|
238
238
|
<Button onClick={() => setIsOpen(true)}>Open Edge Panel</Button>
|
|
239
|
-
<EdgePanel
|
|
240
|
-
{...args}
|
|
241
|
-
isOpen={isOpen}
|
|
242
|
-
onOpenChange={setIsOpen}
|
|
243
|
-
title="Basic Edge Panel"
|
|
244
|
-
>
|
|
239
|
+
<EdgePanel {...args} isOpen={isOpen} onOpenChange={setIsOpen} title="Basic Edge Panel">
|
|
245
240
|
<DemoPanelContent {...args} />
|
|
246
241
|
</EdgePanel>
|
|
247
242
|
</>
|
|
@@ -271,7 +266,7 @@ export const AllPositions: Story = {
|
|
|
271
266
|
return (
|
|
272
267
|
<>
|
|
273
268
|
<div className="u-flex u-gap-2 u-flex-wrap">
|
|
274
|
-
{(['start', 'end', 'top', 'bottom'] as const).map(
|
|
269
|
+
{(['start', 'end', 'top', 'bottom'] as const).map(pos => (
|
|
275
270
|
<Button
|
|
276
271
|
key={pos}
|
|
277
272
|
variant={position === pos ? 'primary' : 'secondary'}
|
|
@@ -306,18 +301,13 @@ export const AllPositions: Story = {
|
|
|
306
301
|
};
|
|
307
302
|
|
|
308
303
|
export const WithSlideMode: Story = {
|
|
309
|
-
render:
|
|
304
|
+
render: args => {
|
|
310
305
|
const [isOpen, setIsOpen] = useState(false);
|
|
311
306
|
|
|
312
307
|
return (
|
|
313
308
|
<>
|
|
314
309
|
<Button onClick={() => setIsOpen(true)}>Open Slide Mode Panel</Button>
|
|
315
|
-
<EdgePanel
|
|
316
|
-
{...args}
|
|
317
|
-
isOpen={isOpen}
|
|
318
|
-
onOpenChange={setIsOpen}
|
|
319
|
-
title="Slide Mode Panel"
|
|
320
|
-
>
|
|
310
|
+
<EdgePanel {...args} isOpen={isOpen} onOpenChange={setIsOpen} title="Slide Mode Panel">
|
|
321
311
|
<DemoPanelContent {...args} />
|
|
322
312
|
</EdgePanel>
|
|
323
313
|
</>
|
|
@@ -834,10 +824,7 @@ export const GlassShowcase: Story = {
|
|
|
834
824
|
<p className="u-mb-4">
|
|
835
825
|
Enhanced polar distortion creates unique radial patterns from center.
|
|
836
826
|
</p>
|
|
837
|
-
<Card
|
|
838
|
-
title="Radial Distortion"
|
|
839
|
-
text="Creates circular displacement patterns."
|
|
840
|
-
/>
|
|
827
|
+
<Card title="Radial Distortion" text="Creates circular displacement patterns." />
|
|
841
828
|
</div>
|
|
842
829
|
</EdgePanel>
|
|
843
830
|
|
|
@@ -1,10 +1,53 @@
|
|
|
1
|
-
import React, { useRef, useEffect } from 'react';
|
|
1
|
+
import React, { useRef, useEffect, memo, forwardRef } 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
|
+
// Subcomponents
|
|
9
|
+
export const EdgePanelHeader = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
10
|
+
({ children, className = '', ...props }, ref) => (
|
|
11
|
+
<div ref={ref} className={`c-edge-panel__header ${className}`.trim()} {...props}>
|
|
12
|
+
{children}
|
|
13
|
+
</div>
|
|
14
|
+
)
|
|
15
|
+
);
|
|
16
|
+
EdgePanelHeader.displayName = 'EdgePanelHeader';
|
|
17
|
+
|
|
18
|
+
export const EdgePanelBody = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
19
|
+
({ children, className = '', ...props }, ref) => (
|
|
20
|
+
<div ref={ref} className={`c-edge-panel__body ${className}`.trim()} {...props}>
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
EdgePanelBody.displayName = 'EdgePanelBody';
|
|
26
|
+
|
|
27
|
+
export const EdgePanelFooter = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
28
|
+
({ children, className = '', ...props }, ref) => (
|
|
29
|
+
<div ref={ref} className={`c-edge-panel__footer ${className}`.trim()} {...props}>
|
|
30
|
+
{children}
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
);
|
|
34
|
+
EdgePanelFooter.displayName = 'EdgePanelFooter';
|
|
35
|
+
|
|
36
|
+
export const EdgePanelCloseButton = forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
|
|
37
|
+
({ className = '', onClick, ...props }, ref) => (
|
|
38
|
+
<button
|
|
39
|
+
ref={ref}
|
|
40
|
+
className={`c-edge-panel__close c-btn c-btn--icon ${className}`.trim()}
|
|
41
|
+
onClick={onClick}
|
|
42
|
+
aria-label="Close panel"
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<Icon name="X" />
|
|
46
|
+
</button>
|
|
47
|
+
)
|
|
48
|
+
);
|
|
49
|
+
EdgePanelCloseButton.displayName = 'EdgePanelCloseButton';
|
|
50
|
+
|
|
8
51
|
/**
|
|
9
52
|
* EdgePanel - A sliding panel component that appears from any screen edge
|
|
10
53
|
*
|
|
@@ -21,131 +64,138 @@ import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
|
|
|
21
64
|
* <p>Panel content</p>
|
|
22
65
|
* </EdgePanel>
|
|
23
66
|
*
|
|
24
|
-
* //
|
|
25
|
-
* <EdgePanel
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* <p>Panel with glass morphism</p>
|
|
33
|
-
* </EdgePanel>
|
|
34
|
-
*
|
|
35
|
-
* // With custom glass configuration
|
|
36
|
-
* <EdgePanel
|
|
37
|
-
* title="Custom Glass"
|
|
38
|
-
* isOpen={isOpen}
|
|
39
|
-
* onOpenChange={setIsOpen}
|
|
40
|
-
* position="start"
|
|
41
|
-
* glass={{
|
|
42
|
-
* mode: 'shader',
|
|
43
|
-
* shaderVariant: 'liquidGlass',
|
|
44
|
-
* displacementScale: 70,
|
|
45
|
-
* blurAmount: 1.8,
|
|
46
|
-
* saturation: 170,
|
|
47
|
-
* }}
|
|
48
|
-
* >
|
|
49
|
-
* <p>Panel with custom glass effect</p>
|
|
67
|
+
* // Compound Usage
|
|
68
|
+
* <EdgePanel isOpen={isOpen} onOpenChange={setIsOpen}>
|
|
69
|
+
* <EdgePanel.Header>
|
|
70
|
+
* <h4>Title</h4>
|
|
71
|
+
* <EdgePanel.CloseButton onClick={() => setIsOpen(false)} />
|
|
72
|
+
* </EdgePanel.Header>
|
|
73
|
+
* <EdgePanel.Body>Content</EdgePanel.Body>
|
|
74
|
+
* <EdgePanel.Footer>Footer</EdgePanel.Footer>
|
|
50
75
|
* </EdgePanel>
|
|
51
76
|
* ```
|
|
52
77
|
*/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const {
|
|
68
|
-
isOpen: isOpenState,
|
|
69
|
-
containerRef,
|
|
70
|
-
backdropRef,
|
|
71
|
-
generateEdgePanelClass,
|
|
72
|
-
closePanel,
|
|
73
|
-
handleBackdropClick,
|
|
74
|
-
} = useEdgePanel({
|
|
75
|
-
position,
|
|
76
|
-
mode,
|
|
77
|
-
isOpen,
|
|
78
|
+
type EdgePanelComponent = React.FC<EdgePanelProps> & {
|
|
79
|
+
Header: typeof EdgePanelHeader;
|
|
80
|
+
Body: typeof EdgePanelBody;
|
|
81
|
+
Footer: typeof EdgePanelFooter;
|
|
82
|
+
CloseButton: typeof EdgePanelCloseButton;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const EdgePanel: EdgePanelComponent = memo(
|
|
86
|
+
({
|
|
87
|
+
title,
|
|
88
|
+
children,
|
|
89
|
+
position = 'start',
|
|
90
|
+
mode = 'slide',
|
|
91
|
+
isOpen = false,
|
|
78
92
|
onOpenChange,
|
|
79
|
-
backdrop,
|
|
80
|
-
closeOnBackdropClick,
|
|
81
|
-
closeOnEscape,
|
|
93
|
+
backdrop = true,
|
|
94
|
+
closeOnBackdropClick = true,
|
|
95
|
+
closeOnEscape = true,
|
|
96
|
+
className = '',
|
|
97
|
+
style,
|
|
82
98
|
glass,
|
|
83
|
-
})
|
|
99
|
+
}: EdgePanelProps) => {
|
|
100
|
+
const {
|
|
101
|
+
isOpen: isOpenState,
|
|
102
|
+
containerRef,
|
|
103
|
+
backdropRef,
|
|
104
|
+
generateEdgePanelClass,
|
|
105
|
+
closePanel,
|
|
106
|
+
handleBackdropClick,
|
|
107
|
+
} = useEdgePanel({
|
|
108
|
+
position,
|
|
109
|
+
mode,
|
|
110
|
+
isOpen,
|
|
111
|
+
onOpenChange,
|
|
112
|
+
backdrop,
|
|
113
|
+
closeOnBackdropClick,
|
|
114
|
+
closeOnEscape,
|
|
115
|
+
glass,
|
|
116
|
+
});
|
|
84
117
|
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
// Moved useRef outside of conditional rendering to fix hook order issue
|
|
119
|
+
const glassContentRef = useRef<HTMLDivElement>(null);
|
|
87
120
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
const panelClass = generateEdgePanelClass({
|
|
122
|
+
position,
|
|
123
|
+
isOpen,
|
|
124
|
+
className: glass ? `${className} c-edge-panel--glass` : className,
|
|
125
|
+
});
|
|
93
126
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return
|
|
97
|
-
|
|
127
|
+
// If not open and not controlled by parent, don't render
|
|
128
|
+
// Note: useEdgePanel manages internal state if onOpenChange is not provided?
|
|
129
|
+
// Looking at useEdgePanel (implied): it seems to return isOpenState.
|
|
130
|
+
// If we return null here, animations might be cut off.
|
|
131
|
+
// Usually EdgePanel/Drawer should stay mounted but hidden or conditionally mounted.
|
|
132
|
+
// The original code returned null if !isOpenState && isOpen === false.
|
|
133
|
+
// Let's keep that logic.
|
|
134
|
+
if (!isOpenState && isOpen === false) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
98
137
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<div className={panelClass} data-position={position} data-mode={mode} style={style}>
|
|
123
|
-
{backdrop && (
|
|
124
|
-
<div ref={backdropRef} className="c-edge-panel__backdrop" onClick={handleBackdropClick} />
|
|
125
|
-
)}
|
|
126
|
-
<div ref={containerRef} className="c-edge-panel__container">
|
|
127
|
-
{glass ? (
|
|
128
|
-
<AtomixGlass
|
|
129
|
-
{...glassProps}
|
|
138
|
+
const defaultGlassProps = {
|
|
139
|
+
elasticity: 0,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
|
|
143
|
+
|
|
144
|
+
// Check for compound components
|
|
145
|
+
const hasCompoundComponents = React.Children.toArray(children).some((child) =>
|
|
146
|
+
React.isValidElement(child) &&
|
|
147
|
+
['EdgePanelHeader', 'EdgePanelBody', 'EdgePanelFooter'].includes((child.type as any).displayName)
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const panelContent = hasCompoundComponents ? (
|
|
151
|
+
children
|
|
152
|
+
) : (
|
|
153
|
+
<>
|
|
154
|
+
<div className="c-edge-panel__header">
|
|
155
|
+
<h4>{title}</h4>
|
|
156
|
+
<button
|
|
157
|
+
className="c-edge-panel__close c-btn c-btn--icon"
|
|
158
|
+
onClick={() => closePanel()}
|
|
159
|
+
aria-label="Close panel"
|
|
130
160
|
>
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
161
|
+
<Icon name="X" />
|
|
162
|
+
</button>
|
|
163
|
+
</div>
|
|
164
|
+
<div className="c-edge-panel__body">{children}</div>
|
|
165
|
+
</>
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<div className={panelClass} data-position={position} data-mode={mode} style={style}>
|
|
170
|
+
{backdrop && (
|
|
171
|
+
<div ref={backdropRef} className="c-edge-panel__backdrop" onClick={handleBackdropClick} />
|
|
141
172
|
)}
|
|
173
|
+
<div ref={containerRef} className="c-edge-panel__container">
|
|
174
|
+
{glass ? (
|
|
175
|
+
<AtomixGlass {...glassProps}>
|
|
176
|
+
<div
|
|
177
|
+
ref={glassContentRef}
|
|
178
|
+
className="c-edge-panel__glass-content"
|
|
179
|
+
style={{ borderRadius: containerRef.current?.style.borderRadius }}
|
|
180
|
+
>
|
|
181
|
+
{panelContent}
|
|
182
|
+
</div>
|
|
183
|
+
</AtomixGlass>
|
|
184
|
+
) : (
|
|
185
|
+
panelContent
|
|
186
|
+
)}
|
|
187
|
+
</div>
|
|
142
188
|
</div>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
export type { EdgePanelProps };
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
) as unknown as EdgePanelComponent;
|
|
148
192
|
|
|
149
193
|
EdgePanel.displayName = 'EdgePanel';
|
|
194
|
+
EdgePanel.Header = EdgePanelHeader;
|
|
195
|
+
EdgePanel.Body = EdgePanelBody;
|
|
196
|
+
EdgePanel.Footer = EdgePanelFooter;
|
|
197
|
+
EdgePanel.CloseButton = EdgePanelCloseButton;
|
|
198
|
+
|
|
199
|
+
export type { EdgePanelProps };
|
|
150
200
|
|
|
151
201
|
export default EdgePanel;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
+
import { EdgePanel } from './EdgePanel';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
describe('EdgePanel Component', () => {
|
|
7
|
+
it('renders correctly with legacy props', () => {
|
|
8
|
+
render(
|
|
9
|
+
<EdgePanel isOpen={true} title="Legacy Title">
|
|
10
|
+
Legacy Content
|
|
11
|
+
</EdgePanel>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
expect(screen.getByText('Legacy Title')).toBeInTheDocument();
|
|
15
|
+
expect(screen.getByText('Legacy Content')).toBeInTheDocument();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('renders correctly with compound components', () => {
|
|
19
|
+
render(
|
|
20
|
+
<EdgePanel isOpen={true}>
|
|
21
|
+
<EdgePanel.Header>
|
|
22
|
+
<h4>Compound Title</h4>
|
|
23
|
+
</EdgePanel.Header>
|
|
24
|
+
<EdgePanel.Body>
|
|
25
|
+
Compound Content
|
|
26
|
+
</EdgePanel.Body>
|
|
27
|
+
<EdgePanel.Footer>
|
|
28
|
+
Footer
|
|
29
|
+
</EdgePanel.Footer>
|
|
30
|
+
</EdgePanel>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(screen.getByText('Compound Title')).toBeInTheDocument();
|
|
34
|
+
expect(screen.getByText('Compound Content')).toBeInTheDocument();
|
|
35
|
+
expect(screen.getByText('Footer')).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('uses close button in compound mode', () => {
|
|
39
|
+
const onClose = vi.fn();
|
|
40
|
+
render(
|
|
41
|
+
<EdgePanel isOpen={true} onOpenChange={onClose}>
|
|
42
|
+
<EdgePanel.Header>
|
|
43
|
+
<EdgePanel.CloseButton onClick={() => onClose(false)} />
|
|
44
|
+
</EdgePanel.Header>
|
|
45
|
+
<EdgePanel.Body>Content</EdgePanel.Body>
|
|
46
|
+
</EdgePanel>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const closeBtn = screen.getByLabelText('Close panel');
|
|
50
|
+
fireEvent.click(closeBtn);
|
|
51
|
+
expect(onClose).toHaveBeenCalledWith(false);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -97,7 +97,10 @@ Footer provides a comprehensive footer section for websites with multiple layout
|
|
|
97
97
|
options: ['columns', 'centered', 'minimal', 'stacked', 'flexible', 'sidebar', 'wide'],
|
|
98
98
|
description: 'Footer layout variant',
|
|
99
99
|
table: {
|
|
100
|
-
type: {
|
|
100
|
+
type: {
|
|
101
|
+
summary:
|
|
102
|
+
'"columns" | "centered" | "minimal" | "stacked" | "flexible" | "sidebar" | "wide"',
|
|
103
|
+
},
|
|
101
104
|
defaultValue: { summary: 'columns' },
|
|
102
105
|
},
|
|
103
106
|
},
|
|
@@ -289,7 +292,7 @@ export const BasicUsage: Story = {
|
|
|
289
292
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
290
293
|
socialLinks: sampleSocialLinks,
|
|
291
294
|
},
|
|
292
|
-
render:
|
|
295
|
+
render: args => (
|
|
293
296
|
<Footer {...args}>
|
|
294
297
|
<SampleFooterContent />
|
|
295
298
|
</Footer>
|
|
@@ -316,7 +319,7 @@ export const WithNewsletter: Story = {
|
|
|
316
319
|
onNewsletterSubmit: fn(),
|
|
317
320
|
socialLinks: sampleSocialLinks,
|
|
318
321
|
},
|
|
319
|
-
render:
|
|
322
|
+
render: args => (
|
|
320
323
|
<Footer {...args}>
|
|
321
324
|
<SampleFooterContent />
|
|
322
325
|
</Footer>
|
|
@@ -340,7 +343,7 @@ export const WithBackToTop: Story = {
|
|
|
340
343
|
onBackToTop: fn(),
|
|
341
344
|
socialLinks: sampleSocialLinks,
|
|
342
345
|
},
|
|
343
|
-
render:
|
|
346
|
+
render: args => (
|
|
344
347
|
<Footer {...args}>
|
|
345
348
|
<SampleFooterContent />
|
|
346
349
|
</Footer>
|
|
@@ -362,7 +365,7 @@ export const CenteredLayout: Story = {
|
|
|
362
365
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
363
366
|
socialLinks: sampleSocialLinks,
|
|
364
367
|
},
|
|
365
|
-
render:
|
|
368
|
+
render: args => (
|
|
366
369
|
<Footer {...args}>
|
|
367
370
|
<SampleFooterContent />
|
|
368
371
|
</Footer>
|
|
@@ -384,7 +387,7 @@ export const MinimalLayout: Story = {
|
|
|
384
387
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
385
388
|
socialLinks: sampleSocialLinks,
|
|
386
389
|
},
|
|
387
|
-
render:
|
|
390
|
+
render: args => (
|
|
388
391
|
<Footer {...args}>
|
|
389
392
|
<SampleFooterContent />
|
|
390
393
|
</Footer>
|
|
@@ -406,7 +409,7 @@ export const StackedLayout: Story = {
|
|
|
406
409
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
407
410
|
socialLinks: sampleSocialLinks,
|
|
408
411
|
},
|
|
409
|
-
render:
|
|
412
|
+
render: args => (
|
|
410
413
|
<Footer {...args}>
|
|
411
414
|
<SampleFooterContent />
|
|
412
415
|
</Footer>
|
|
@@ -428,7 +431,7 @@ export const FlexibleLayout: Story = {
|
|
|
428
431
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
429
432
|
socialLinks: sampleSocialLinks,
|
|
430
433
|
},
|
|
431
|
-
render:
|
|
434
|
+
render: args => (
|
|
432
435
|
<Footer {...args}>
|
|
433
436
|
<SampleFooterContent />
|
|
434
437
|
</Footer>
|
|
@@ -450,7 +453,7 @@ export const SidebarLayout: Story = {
|
|
|
450
453
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
451
454
|
socialLinks: sampleSocialLinks,
|
|
452
455
|
},
|
|
453
|
-
render:
|
|
456
|
+
render: args => (
|
|
454
457
|
<Footer {...args}>
|
|
455
458
|
<SampleFooterContent />
|
|
456
459
|
</Footer>
|
|
@@ -472,7 +475,7 @@ export const WideLayout: Story = {
|
|
|
472
475
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
473
476
|
socialLinks: sampleSocialLinks,
|
|
474
477
|
},
|
|
475
|
-
render:
|
|
478
|
+
render: args => (
|
|
476
479
|
<Footer {...args}>
|
|
477
480
|
<SampleFooterContent />
|
|
478
481
|
</Footer>
|
|
@@ -494,7 +497,7 @@ export const DarkVariant: Story = {
|
|
|
494
497
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
495
498
|
socialLinks: sampleSocialLinks,
|
|
496
499
|
},
|
|
497
|
-
render:
|
|
500
|
+
render: args => (
|
|
498
501
|
<Footer {...args}>
|
|
499
502
|
<SampleFooterContent />
|
|
500
503
|
</Footer>
|
|
@@ -516,7 +519,7 @@ export const LargeSize: Story = {
|
|
|
516
519
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
517
520
|
socialLinks: sampleSocialLinks,
|
|
518
521
|
},
|
|
519
|
-
render:
|
|
522
|
+
render: args => (
|
|
520
523
|
<Footer {...args}>
|
|
521
524
|
<SampleFooterContent />
|
|
522
525
|
</Footer>
|
|
@@ -538,7 +541,7 @@ export const WithGlassEffect: Story = {
|
|
|
538
541
|
socialLinks: sampleSocialLinks,
|
|
539
542
|
glass: true,
|
|
540
543
|
},
|
|
541
|
-
render:
|
|
544
|
+
render: args => (
|
|
542
545
|
<Footer {...args}>
|
|
543
546
|
<SampleFooterContent />
|
|
544
547
|
</Footer>
|
|
@@ -560,9 +563,11 @@ export const StickyFooter: Story = {
|
|
|
560
563
|
copyright: '© 2024 Atomix. All rights reserved.',
|
|
561
564
|
socialLinks: sampleSocialLinks,
|
|
562
565
|
},
|
|
563
|
-
render:
|
|
566
|
+
render: args => (
|
|
564
567
|
<div style={{ minHeight: '200vh' }}>
|
|
565
|
-
<div
|
|
568
|
+
<div
|
|
569
|
+
style={{ height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
|
|
570
|
+
>
|
|
566
571
|
<p>Scroll down to see the sticky footer</p>
|
|
567
572
|
</div>
|
|
568
573
|
<Footer {...args}>
|
|
@@ -577,4 +582,4 @@ export const StickyFooter: Story = {
|
|
|
577
582
|
},
|
|
578
583
|
},
|
|
579
584
|
},
|
|
580
|
-
};
|
|
585
|
+
};
|