@shohojdhara/atomix 0.3.14 → 0.4.0
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/CHANGELOG.md +20 -0
- package/build-tools/EXAMPLES.md +372 -0
- package/build-tools/README.md +242 -0
- package/build-tools/__tests__/error-handler.test.js +230 -0
- package/build-tools/__tests__/index.test.js +141 -0
- package/build-tools/__tests__/rollup-plugin.test.js +194 -0
- package/build-tools/__tests__/utils.test.js +161 -0
- package/build-tools/__tests__/vite-plugin.test.js +129 -0
- package/build-tools/__tests__/webpack-loader.test.js +190 -0
- package/build-tools/error-handler.js +308 -0
- package/build-tools/index.d.ts +44 -0
- package/build-tools/index.js +88 -0
- package/build-tools/package.json +50 -0
- package/build-tools/rollup-plugin.js +236 -0
- package/build-tools/types.d.ts +163 -0
- package/build-tools/utils.js +203 -0
- package/build-tools/vite-plugin.js +161 -0
- package/build-tools/webpack-loader.js +123 -0
- package/dist/atomix.css +21044 -2618
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +77 -3
- package/dist/atomix.min.css.map +1 -1
- package/dist/build-tools/EXAMPLES.md +372 -0
- package/dist/build-tools/README.md +242 -0
- package/dist/build-tools/__tests__/error-handler.test.js +230 -0
- package/dist/build-tools/__tests__/index.test.js +141 -0
- package/dist/build-tools/__tests__/rollup-plugin.test.js +194 -0
- package/dist/build-tools/__tests__/utils.test.js +161 -0
- package/dist/build-tools/__tests__/vite-plugin.test.js +129 -0
- package/dist/build-tools/__tests__/webpack-loader.test.js +190 -0
- package/dist/build-tools/error-handler.js +308 -0
- package/dist/build-tools/index.d.ts +44 -0
- package/dist/build-tools/index.js +88 -0
- package/dist/build-tools/package.json +50 -0
- package/dist/build-tools/rollup-plugin.js +236 -0
- package/dist/build-tools/types.d.ts +163 -0
- package/dist/build-tools/utils.js +203 -0
- package/dist/build-tools/vite-plugin.js +161 -0
- package/dist/build-tools/webpack-loader.js +123 -0
- package/dist/charts.d.ts +1 -1
- package/dist/charts.js +86 -57
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +136 -112
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +2 -5
- package/dist/forms.js +140 -128
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +1 -1
- package/dist/heavy.js +136 -112
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +152 -78
- package/dist/index.esm.js +346 -340
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +359 -353
- 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 +23 -8
- package/scripts/atomix-cli.js +170 -73
- package/scripts/cli/__tests__/README.md +81 -0
- package/scripts/cli/__tests__/basic.test.js +115 -0
- package/scripts/cli/__tests__/component-generator.test.js +332 -0
- package/scripts/cli/__tests__/integration.test.js +327 -0
- package/scripts/cli/__tests__/test-setup.js +133 -0
- package/scripts/cli/__tests__/token-manager.test.js +251 -0
- package/scripts/cli/__tests__/utils.test.js +161 -0
- package/scripts/cli/component-generator.js +253 -299
- package/scripts/cli/dependency-checker.js +355 -0
- package/scripts/cli/interactive-init.js +46 -5
- package/scripts/cli/template-manager.js +0 -2
- package/scripts/cli/templates/common-templates.js +636 -0
- package/scripts/cli/templates/composable-templates.js +148 -126
- package/scripts/cli/templates/index.js +23 -16
- package/scripts/cli/templates/project-templates.js +151 -23
- package/scripts/cli/templates/react-templates.js +280 -210
- package/scripts/cli/templates/scss-templates.js +90 -91
- package/scripts/cli/templates/testing-templates.js +206 -27
- package/scripts/cli/templates/testing-utils.js +278 -0
- package/scripts/cli/templates/types-templates.js +70 -56
- package/scripts/cli/theme-bridge.js +8 -2
- package/scripts/cli/token-manager.js +318 -206
- package/scripts/cli/utils.js +0 -1
- package/src/components/Accordion/Accordion.stories.tsx +358 -850
- package/src/components/Accordion/Accordion.test.tsx +70 -50
- package/src/components/Accordion/Accordion.tsx +99 -94
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +1 -1
- package/src/components/AtomixGlass/AtomixGlass.tsx +80 -39
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +103 -81
- package/src/components/AtomixGlass/GlassFilter.tsx +9 -16
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +8 -7
- package/src/components/AtomixGlass/glass-utils.ts +6 -5
- package/src/components/AtomixGlass/shader-utils.ts +133 -52
- package/src/components/AtomixGlass/stories/Customization.stories.tsx +131 -0
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +2957 -2853
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -1
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +348 -0
- package/src/components/AtomixGlass/stories/Performance.stories.tsx +103 -0
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -36
- package/src/components/AtomixGlass/stories/{ShaderVariants.stories.tsx → Shaders.stories.tsx} +2 -2
- package/src/components/AtomixGlass/stories/shared-components.tsx +90 -190
- package/src/components/Avatar/Avatar.stories.tsx +195 -0
- package/src/components/Avatar/Avatar.tsx +58 -56
- package/src/components/Badge/Badge.stories.tsx +122 -352
- package/src/components/Badge/Badge.test.tsx +41 -41
- package/src/components/Badge/Badge.tsx +64 -62
- package/src/components/Block/Block.stories.tsx +30 -11
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +142 -23
- package/src/components/Breadcrumb/Breadcrumb.tsx +62 -60
- package/src/components/Button/Button.stories.tsx +454 -1126
- package/src/components/Button/Button.test.tsx +123 -0
- package/src/components/Button/Button.tsx +88 -60
- package/src/components/Button/ButtonGroup.stories.tsx +376 -215
- package/src/components/Button/ButtonGroup.tsx +4 -15
- package/src/components/Callout/Callout.stories.tsx +316 -568
- package/src/components/Card/Card.stories.tsx +292 -81
- 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 +153 -16
- 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 +152 -66
- package/src/components/ColorModeToggle/ColorModeToggle.tsx +15 -3
- package/src/components/Countdown/Countdown.stories.tsx +114 -7
- package/src/components/DataTable/DataTable.stories.tsx +349 -144
- package/src/components/DataTable/DataTable.test.tsx +26 -148
- package/src/components/DataTable/DataTable.tsx +485 -456
- package/src/components/DatePicker/DatePicker.stories.tsx +310 -1066
- package/src/components/DatePicker/DatePicker.tsx +31 -26
- package/src/components/Dropdown/Dropdown.stories.tsx +153 -36
- package/src/components/Dropdown/Dropdown.tsx +313 -299
- package/src/components/EdgePanel/EdgePanel.stories.tsx +221 -25
- package/src/components/EdgePanel/EdgePanel.tsx +1 -3
- package/src/components/Footer/Footer.stories.tsx +396 -327
- package/src/components/Footer/Footer.tsx +130 -128
- package/src/components/Footer/FooterLink.tsx +2 -2
- package/src/components/Form/Checkbox.stories.tsx +140 -6
- package/src/components/Form/Checkbox.test.tsx +63 -0
- package/src/components/Form/Checkbox.tsx +122 -78
- package/src/components/Form/Form.stories.tsx +110 -19
- package/src/components/Form/FormGroup.stories.tsx +127 -4
- 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 +146 -17
- package/src/components/Form/Radio.tsx +68 -66
- package/src/components/Form/Select.stories.tsx +140 -8
- package/src/components/Form/Select.tsx +184 -182
- package/src/components/Form/Textarea.stories.tsx +149 -6
- package/src/components/Form/Textarea.test.tsx +27 -32
- package/src/components/Hero/Hero.stories.tsx +372 -38
- package/src/components/Hero/Hero.tsx +201 -55
- package/src/components/Icon/index.ts +7 -1
- package/src/components/List/List.stories.tsx +141 -3
- package/src/components/List/List.tsx +19 -23
- package/src/components/Modal/Modal.stories.tsx +183 -43
- package/src/components/Modal/Modal.tsx +130 -127
- 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 +354 -97
- package/src/components/Popover/Popover.tsx +41 -37
- package/src/components/Progress/Progress.stories.tsx +160 -7
- package/src/components/River/River.stories.tsx +3 -2
- package/src/components/SectionIntro/SectionIntro.stories.tsx +239 -47
- package/src/components/Slider/Slider.stories.tsx +12 -4
- package/src/components/Spinner/Spinner.stories.tsx +104 -8
- package/src/components/Spinner/Spinner.test.tsx +23 -23
- package/src/components/Spinner/Spinner.tsx +43 -46
- package/src/components/Steps/Steps.stories.tsx +173 -42
- package/src/components/Tabs/Tabs.stories.tsx +141 -12
- package/src/components/Tabs/Tabs.tsx +74 -72
- package/src/components/Testimonial/Testimonial.stories.tsx +120 -3
- package/src/components/Todo/Todo.stories.tsx +198 -9
- package/src/components/Toggle/Toggle.stories.tsx +137 -36
- package/src/components/Toggle/Toggle.test.tsx +65 -70
- package/src/components/Toggle/Toggle.tsx +4 -1
- package/src/components/Tooltip/Tooltip.stories.tsx +194 -100
- package/src/components/Tooltip/Tooltip.tsx +104 -106
- package/src/components/Upload/Upload.stories.tsx +241 -150
- 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/README.md +2 -2
- package/src/lib/__tests__/theme-tools.test.ts +219 -0
- package/src/lib/composables/index.ts +2 -2
- package/src/lib/composables/shared-mouse-tracker.ts +13 -14
- package/src/lib/composables/useAtomixGlass.ts +126 -97
- package/src/lib/composables/useChartExport.ts +3 -8
- package/src/lib/composables/useDataTable.ts +72 -43
- 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/components.ts +9 -32
- 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 +107 -105
- 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 +172 -71
- package/src/lib/types/partProps.ts +1 -1
- package/src/lib/utils/__tests__/csv.test.ts +45 -0
- package/src/lib/utils/componentUtils.ts +8 -12
- package/src/lib/utils/csv.ts +19 -0
- package/src/lib/utils/dataTableExport.ts +2 -15
- 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 +2 -2
- package/src/styles/01-settings/_index.scss +1 -1
- package/src/styles/01-settings/_settings.accordion.scss +28 -7
- package/src/styles/01-settings/_settings.colors.scss +11 -11
- 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 +4 -4
- package/src/styles/02-tools/_tools.button.scss +51 -21
- package/src/styles/02-tools/_tools.utility-api.scss +38 -12
- package/src/styles/03-generic/_generic.root.scss +4 -3
- package/src/styles/06-components/_components.accordion.scss +56 -14
- 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 +25 -17
- 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/_index.scss +2 -0
- 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 +2 -0
- 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 +45 -0
- package/src/styles/99-utilities/_utilities.text.scss +67 -46
- package/themes/dark-complementary/README.md +98 -0
- package/themes/dark-complementary/index.scss +158 -0
- package/themes/default-light/README.md +81 -0
- package/themes/default-light/index.scss +154 -0
- package/themes/high-contrast/README.md +105 -0
- package/themes/high-contrast/index.scss +172 -0
- package/themes/test-theme/README.md +38 -0
- package/themes/test-theme/index.scss +47 -0
- package/scripts/cli/templates-original-backup.js +0 -1655
- package/scripts/cli/templates_backup.js +0 -684
- package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +0 -1438
- package/src/lib/composables/useButton.ts +0 -93
- package/src/lib/composables/useCheckbox.ts +0 -70
|
@@ -33,83 +33,83 @@ export const MegaMenu = forwardRef<HTMLDivElement, MegaMenuProps>(
|
|
|
33
33
|
|
|
34
34
|
MegaMenu.displayName = 'MegaMenu';
|
|
35
35
|
|
|
36
|
-
export const MegaMenuColumn = forwardRef<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
>(({ title, icon, children, width = 'auto', className = '', disabled = false }, ref) => {
|
|
40
|
-
const columnClass = `o-grid__col o-grid__col--${width} ${className}`;
|
|
36
|
+
export const MegaMenuColumn = forwardRef<HTMLDivElement, MegaMenuColumnProps>(
|
|
37
|
+
({ title, icon, children, width = 'auto', className = '', disabled = false }, ref) => {
|
|
38
|
+
const columnClass = `o-grid__col o-grid__col--${width} ${className}`;
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
return (
|
|
41
|
+
<div ref={ref} className={columnClass}>
|
|
42
|
+
{(title || icon) && (
|
|
43
|
+
<div className="c-menu__header">
|
|
44
|
+
{icon &&
|
|
45
|
+
(typeof icon === 'string' ? (
|
|
46
|
+
icon.startsWith('c-icon-') ? (
|
|
47
|
+
<Icon
|
|
48
|
+
name={mapIconName(icon.replace('c-icon-', ''))}
|
|
49
|
+
size="sm"
|
|
50
|
+
className="c-menu__header-icon"
|
|
51
|
+
/>
|
|
52
|
+
) : (
|
|
53
|
+
<i className={`c-menu__header-icon ${icon}`}>
|
|
54
|
+
{typeof icon !== 'string' && icon}
|
|
55
|
+
</i>
|
|
56
|
+
)
|
|
54
57
|
) : (
|
|
55
|
-
<
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
{title && <div className="c-menu__header-title">{title}</div>}
|
|
61
|
-
</div>
|
|
62
|
-
)}
|
|
58
|
+
<span className="c-menu__header-icon">{icon}</span>
|
|
59
|
+
))}
|
|
60
|
+
{title && <div className="c-menu__header-title">{title}</div>}
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
64
|
+
<ul className="c-menu__subitems-list" role="menu">
|
|
65
|
+
{React.Children.map(children, child => {
|
|
66
|
+
if (React.isValidElement(child)) {
|
|
67
|
+
// Pass disabled prop down to all children if column is disabled
|
|
68
|
+
const childProps = child.props as any;
|
|
69
|
+
return (
|
|
70
|
+
<li className="c-menu__subitem" role="menuitem">
|
|
71
|
+
{React.cloneElement(child as React.ReactElement<any>, {
|
|
72
|
+
...childProps,
|
|
73
|
+
disabled: disabled ? true : childProps?.disabled,
|
|
74
|
+
})}
|
|
75
|
+
</li>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
})}
|
|
80
|
+
</ul>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
);
|
|
84
85
|
|
|
85
86
|
MegaMenuColumn.displayName = 'MegaMenuColumn';
|
|
86
87
|
|
|
87
|
-
export const MegaMenuLink = forwardRef<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
88
|
+
export const MegaMenuLink = forwardRef<HTMLAnchorElement, MegaMenuLinkProps>(
|
|
89
|
+
({ href, children, className = '', disabled = false, onClick }, ref) => {
|
|
90
|
+
const handleClick = (e: React.MouseEvent) => {
|
|
91
|
+
if (disabled) {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
96
95
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
if (onClick) {
|
|
97
|
+
onClick();
|
|
98
|
+
}
|
|
99
|
+
};
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
101
|
+
return (
|
|
102
|
+
<a
|
|
103
|
+
ref={ref}
|
|
104
|
+
href={href}
|
|
105
|
+
className={`c-menu__subitem-link ${disabled ? 'is-disabled' : ''} ${className}`}
|
|
106
|
+
onClick={handleClick}
|
|
107
|
+
aria-disabled={disabled}
|
|
108
|
+
>
|
|
109
|
+
{children}
|
|
110
|
+
</a>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
114
|
|
|
115
115
|
MegaMenuLink.displayName = 'MegaMenuLink';
|
|
@@ -84,11 +84,7 @@ export const NavDropdown: React.FC<NavDropdownProps> = forwardRef<HTMLLIElement,
|
|
|
84
84
|
|
|
85
85
|
const MenuTag = megaMenu ? 'div' : 'ul';
|
|
86
86
|
const menuContent = (
|
|
87
|
-
<MenuTag
|
|
88
|
-
className={dropdownMenuClass}
|
|
89
|
-
ref={dropdownRef as any}
|
|
90
|
-
aria-hidden={!isActive}
|
|
91
|
-
>
|
|
87
|
+
<MenuTag className={dropdownMenuClass} ref={dropdownRef as any} aria-hidden={!isActive}>
|
|
92
88
|
{children}
|
|
93
89
|
</MenuTag>
|
|
94
90
|
);
|
|
@@ -456,7 +456,13 @@ export const ComplexNavigation: Story = {
|
|
|
456
456
|
export const ResponsiveDemo: Story = {
|
|
457
457
|
render: args => (
|
|
458
458
|
<div style={{ maxWidth: '300px', margin: '0 auto' }}>
|
|
459
|
-
<p
|
|
459
|
+
<p
|
|
460
|
+
style={{
|
|
461
|
+
marginBottom: '1rem',
|
|
462
|
+
fontSize: '0.875rem',
|
|
463
|
+
color: 'var(--atomix-secondary-text-emphasis, #666)',
|
|
464
|
+
}}
|
|
465
|
+
>
|
|
460
466
|
Resize your browser window to see the responsive behavior. On mobile (less than 768px), the
|
|
461
467
|
menu becomes collapsible.
|
|
462
468
|
</p>
|
|
@@ -548,9 +554,15 @@ export const DesktopCollapsible: Story = {
|
|
|
548
554
|
|
|
549
555
|
return (
|
|
550
556
|
<div style={{ maxWidth: '300px', padding: '2rem', margin: '0 auto' }}>
|
|
551
|
-
<p
|
|
552
|
-
|
|
553
|
-
|
|
557
|
+
<p
|
|
558
|
+
style={{
|
|
559
|
+
marginBottom: '1rem',
|
|
560
|
+
fontSize: '0.875rem',
|
|
561
|
+
color: 'var(--atomix-secondary-text-emphasis, #666)',
|
|
562
|
+
}}
|
|
563
|
+
>
|
|
564
|
+
Desktop vertical collapse - click the toggle button to expand/collapse the menu
|
|
565
|
+
vertically. Each section can also be toggled independently.
|
|
554
566
|
</p>
|
|
555
567
|
<SideMenu
|
|
556
568
|
{...args}
|
|
@@ -564,7 +576,11 @@ export const DesktopCollapsible: Story = {
|
|
|
564
576
|
title: 'Navigation',
|
|
565
577
|
items: [
|
|
566
578
|
{ title: 'Home', href: '/', icon: <Icon name="House" size="sm" />, active: true },
|
|
567
|
-
{
|
|
579
|
+
{
|
|
580
|
+
title: 'Dashboard',
|
|
581
|
+
href: '/dashboard',
|
|
582
|
+
icon: <Icon name="ChartBar" size="sm" />,
|
|
583
|
+
},
|
|
568
584
|
{ title: 'Analytics', href: '/analytics', icon: <Icon name="TrendUp" size="sm" /> },
|
|
569
585
|
{ title: 'Users', href: '/users', icon: <Icon name="Users" size="sm" /> },
|
|
570
586
|
{ title: 'Settings', href: '/settings', icon: <Icon name="Gear" size="sm" /> },
|
|
@@ -573,16 +589,32 @@ export const DesktopCollapsible: Story = {
|
|
|
573
589
|
{
|
|
574
590
|
title: 'Products',
|
|
575
591
|
items: [
|
|
576
|
-
{
|
|
577
|
-
|
|
578
|
-
|
|
592
|
+
{
|
|
593
|
+
title: 'All Products',
|
|
594
|
+
href: '/products',
|
|
595
|
+
icon: <Icon name="Package" size="sm" />,
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
title: 'Categories',
|
|
599
|
+
href: '/products/categories',
|
|
600
|
+
icon: <Icon name="Tag" size="sm" />,
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
title: 'Inventory',
|
|
604
|
+
href: '/products/inventory',
|
|
605
|
+
icon: <Icon name="Warehouse" size="sm" />,
|
|
606
|
+
},
|
|
579
607
|
],
|
|
580
608
|
},
|
|
581
609
|
{
|
|
582
610
|
title: 'Services',
|
|
583
611
|
items: [
|
|
584
612
|
{ title: 'Service List', href: '/services', icon: <Icon name="Gear" size="sm" /> },
|
|
585
|
-
{
|
|
613
|
+
{
|
|
614
|
+
title: 'Service Requests',
|
|
615
|
+
href: '/services/requests',
|
|
616
|
+
icon: <Icon name="Clipboard" size="sm" />,
|
|
617
|
+
},
|
|
586
618
|
],
|
|
587
619
|
},
|
|
588
620
|
{
|
|
@@ -594,7 +626,15 @@ export const DesktopCollapsible: Story = {
|
|
|
594
626
|
},
|
|
595
627
|
]}
|
|
596
628
|
/>
|
|
597
|
-
<div
|
|
629
|
+
<div
|
|
630
|
+
style={{
|
|
631
|
+
marginTop: '1rem',
|
|
632
|
+
padding: '0.75rem',
|
|
633
|
+
backgroundColor: 'var(--atomix-secondary-bg-subtle, rgba(0,0,0,0.05))',
|
|
634
|
+
borderRadius: '6px',
|
|
635
|
+
fontSize: '0.875rem',
|
|
636
|
+
}}
|
|
637
|
+
>
|
|
598
638
|
<strong>Current state:</strong> {isOpen ? 'Expanded' : 'Collapsed'}
|
|
599
639
|
</div>
|
|
600
640
|
</div>
|
|
@@ -621,9 +661,22 @@ export const NestedMenuItems: Story = {
|
|
|
621
661
|
{
|
|
622
662
|
title: 'Dashboard',
|
|
623
663
|
items: [
|
|
624
|
-
{
|
|
625
|
-
|
|
626
|
-
|
|
664
|
+
{
|
|
665
|
+
title: 'Overview',
|
|
666
|
+
href: '/dashboard',
|
|
667
|
+
icon: <Icon name="ChartBar" size="sm" />,
|
|
668
|
+
active: true,
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
title: 'Analytics',
|
|
672
|
+
href: '/dashboard/analytics',
|
|
673
|
+
icon: <Icon name="TrendUp" size="sm" />,
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
title: 'Reports',
|
|
677
|
+
href: '/dashboard/reports',
|
|
678
|
+
icon: <Icon name="FileText" size="sm" />,
|
|
679
|
+
},
|
|
627
680
|
],
|
|
628
681
|
},
|
|
629
682
|
{
|
|
@@ -631,7 +684,11 @@ export const NestedMenuItems: Story = {
|
|
|
631
684
|
items: [
|
|
632
685
|
{ title: 'Users', href: '/users', icon: <Icon name="Users" size="sm" /> },
|
|
633
686
|
{ title: 'Roles', href: '/users/roles', icon: <Icon name="Shield" size="sm" /> },
|
|
634
|
-
{
|
|
687
|
+
{
|
|
688
|
+
title: 'Permissions',
|
|
689
|
+
href: '/users/permissions',
|
|
690
|
+
icon: <Icon name="Lock" size="sm" />,
|
|
691
|
+
},
|
|
635
692
|
],
|
|
636
693
|
},
|
|
637
694
|
{
|
|
@@ -646,8 +703,17 @@ export const NestedMenuItems: Story = {
|
|
|
646
703
|
title: 'Settings',
|
|
647
704
|
items: [
|
|
648
705
|
{ title: 'General', href: '/settings/general', icon: <Icon name="Gear" size="sm" /> },
|
|
649
|
-
{
|
|
650
|
-
|
|
706
|
+
{
|
|
707
|
+
title: 'Notifications',
|
|
708
|
+
href: '/settings/notifications',
|
|
709
|
+
icon: <Icon name="Bell" size="sm" />,
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
title: 'Security',
|
|
713
|
+
href: '/settings/security',
|
|
714
|
+
icon: <Icon name="Lock" size="sm" />,
|
|
715
|
+
disabled: true,
|
|
716
|
+
},
|
|
651
717
|
],
|
|
652
718
|
},
|
|
653
719
|
],
|
|
@@ -684,15 +750,27 @@ export const NestedMenuItemsWithChildren: Story = {
|
|
|
684
750
|
title: 'Products',
|
|
685
751
|
items: [
|
|
686
752
|
{ title: 'All Products', href: '/products', icon: <Icon name="Package" size="sm" /> },
|
|
687
|
-
{
|
|
688
|
-
|
|
753
|
+
{
|
|
754
|
+
title: 'Categories',
|
|
755
|
+
href: '/products/categories',
|
|
756
|
+
icon: <Icon name="Tag" size="sm" />,
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
title: 'Inventory',
|
|
760
|
+
href: '/products/inventory',
|
|
761
|
+
icon: <Icon name="Warehouse" size="sm" />,
|
|
762
|
+
},
|
|
689
763
|
],
|
|
690
764
|
},
|
|
691
765
|
{
|
|
692
766
|
title: 'Services',
|
|
693
767
|
items: [
|
|
694
768
|
{ title: 'Service List', href: '/services', icon: <Icon name="Gear" size="sm" /> },
|
|
695
|
-
{
|
|
769
|
+
{
|
|
770
|
+
title: 'Service Requests',
|
|
771
|
+
href: '/services/requests',
|
|
772
|
+
icon: <Icon name="Clipboard" size="sm" />,
|
|
773
|
+
},
|
|
696
774
|
],
|
|
697
775
|
},
|
|
698
776
|
],
|
|
@@ -728,8 +806,16 @@ export const NestedMenuItemsCustomIcons: Story = {
|
|
|
728
806
|
title: 'Preferences',
|
|
729
807
|
toggleIcon: <Icon name="CaretDown" size="xs" />,
|
|
730
808
|
items: [
|
|
731
|
-
{
|
|
732
|
-
|
|
809
|
+
{
|
|
810
|
+
title: 'Notifications',
|
|
811
|
+
href: '/settings/notifications',
|
|
812
|
+
icon: <Icon name="Bell" size="sm" />,
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
title: 'Appearance',
|
|
816
|
+
href: '/settings/appearance',
|
|
817
|
+
icon: <Icon name="PaintBrush" size="sm" />,
|
|
818
|
+
},
|
|
733
819
|
{ title: 'Language', href: '/settings/language', icon: <Icon name="Globe" size="sm" /> },
|
|
734
820
|
],
|
|
735
821
|
},
|
|
@@ -737,8 +823,16 @@ export const NestedMenuItemsCustomIcons: Story = {
|
|
|
737
823
|
title: 'Billing',
|
|
738
824
|
toggleIcon: <Icon name="CaretDown" size="xs" />,
|
|
739
825
|
items: [
|
|
740
|
-
{
|
|
741
|
-
|
|
826
|
+
{
|
|
827
|
+
title: 'Subscription',
|
|
828
|
+
href: '/settings/billing',
|
|
829
|
+
icon: <Icon name="CreditCard" size="sm" />,
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
title: 'Invoices',
|
|
833
|
+
href: '/settings/invoices',
|
|
834
|
+
icon: <Icon name="Receipt" size="sm" />,
|
|
835
|
+
},
|
|
742
836
|
],
|
|
743
837
|
},
|
|
744
838
|
],
|
|
@@ -763,7 +857,13 @@ export const DesktopCollapsibleStartCollapsed: Story = {
|
|
|
763
857
|
|
|
764
858
|
return (
|
|
765
859
|
<div style={{ maxWidth: '300px', padding: '2rem', margin: '0 auto' }}>
|
|
766
|
-
<p
|
|
860
|
+
<p
|
|
861
|
+
style={{
|
|
862
|
+
marginBottom: '1rem',
|
|
863
|
+
fontSize: '0.875rem',
|
|
864
|
+
color: 'var(--atomix-secondary-text-emphasis, #666)',
|
|
865
|
+
}}
|
|
866
|
+
>
|
|
767
867
|
Sidebar starts collapsed on desktop.
|
|
768
868
|
</p>
|
|
769
869
|
<SideMenu
|
|
@@ -1034,7 +1134,7 @@ export const GlassCustom: Story = {
|
|
|
1034
1134
|
backgroundImage="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?q=80&w=2940&auto=format&fit=crop"
|
|
1035
1135
|
overlay
|
|
1036
1136
|
>
|
|
1037
|
-
<div style={{ position: 'relative', width: '320px'
|
|
1137
|
+
<div style={{ position: 'relative', width: '320px' }}>
|
|
1038
1138
|
<SideMenu
|
|
1039
1139
|
title="Nature Explorer"
|
|
1040
1140
|
glass={{
|
|
@@ -1119,7 +1219,7 @@ export const GlassThemeShowcase: Story = {
|
|
|
1119
1219
|
backgroundImage="https://images.unsplash.com/photo-1505142468610-359e7d316be0?q=80&w=2940&auto=format&fit=crop"
|
|
1120
1220
|
height="70vh"
|
|
1121
1221
|
>
|
|
1122
|
-
<div style={{ position: 'relative', width: '300px'
|
|
1222
|
+
<div style={{ position: 'relative', width: '300px' }}>
|
|
1123
1223
|
<SideMenu title="Ocean Explorer" glass>
|
|
1124
1224
|
<SideMenuList>
|
|
1125
1225
|
<SideMenuItem href="/" icon={<Icon name="House" size="sm" />} active>
|
|
@@ -1153,7 +1253,7 @@ export const GlassThemeShowcase: Story = {
|
|
|
1153
1253
|
backgroundImage="https://images.unsplash.com/photo-1514565131-fce0801e5785?q=80&w=2940&auto=format&fit=crop"
|
|
1154
1254
|
height="70vh"
|
|
1155
1255
|
>
|
|
1156
|
-
<div style={{ position: 'relative', width: '300px'
|
|
1256
|
+
<div style={{ position: 'relative', width: '300px' }}>
|
|
1157
1257
|
<SideMenu glass>
|
|
1158
1258
|
<SideMenuList>
|
|
1159
1259
|
<SideMenuItem href="/dashboard" icon={<Icon name="ChartBar" size="sm" />} active>
|
|
@@ -1187,7 +1287,7 @@ export const GlassThemeShowcase: Story = {
|
|
|
1187
1287
|
backgroundImage="https://images.unsplash.com/photo-1495616811223-4d98c6e9c869?q=80&w=2940&auto=format&fit=crop"
|
|
1188
1288
|
height="70vh"
|
|
1189
1289
|
>
|
|
1190
|
-
<div style={{ position: 'relative', width: '320px'
|
|
1290
|
+
<div style={{ position: 'relative', width: '320px' }}>
|
|
1191
1291
|
<SideMenu
|
|
1192
1292
|
title="Travel Hub"
|
|
1193
1293
|
glass={{
|
|
@@ -7,8 +7,6 @@ import useForkRef from '../../../lib/utils/useForkRef';
|
|
|
7
7
|
import SideMenuList from './SideMenuList';
|
|
8
8
|
import SideMenuItem from './SideMenuItem';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
10
|
/**
|
|
13
11
|
* SideMenu component provides a collapsible navigation menu with title and menu items.
|
|
14
12
|
* Automatically collapses on mobile devices and can be toggled via a header button.
|
|
@@ -99,9 +97,9 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
99
97
|
const currentLength = menuItems?.length ?? 0;
|
|
100
98
|
// Only update if the length actually changed to prevent infinite loops
|
|
101
99
|
if (menuItemsLengthRef.current === currentLength) return;
|
|
102
|
-
|
|
100
|
+
|
|
103
101
|
menuItemsLengthRef.current = currentLength;
|
|
104
|
-
|
|
102
|
+
|
|
105
103
|
setNestedItemStates(prevStates => {
|
|
106
104
|
const newStates: Record<number, boolean> = {};
|
|
107
105
|
menuItems?.forEach((_, index) => {
|
|
@@ -217,8 +215,8 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
217
215
|
id={id ? `${id}-content` : undefined}
|
|
218
216
|
aria-hidden={shouldShowToggler ? !isOpenState : false}
|
|
219
217
|
>
|
|
220
|
-
|
|
221
|
-
|
|
218
|
+
<div ref={innerRef} className="c-side-menu__inner">
|
|
219
|
+
{children}
|
|
222
220
|
{menuItems?.map((item, index) => {
|
|
223
221
|
const isNestedItemOpen = nestedItemStates[index] ?? true;
|
|
224
222
|
const hasItems = item.items && item.items.length > 0;
|
|
@@ -301,7 +299,7 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
301
299
|
</div>
|
|
302
300
|
);
|
|
303
301
|
})}
|
|
304
|
-
|
|
302
|
+
</div>
|
|
305
303
|
</div>
|
|
306
304
|
</>
|
|
307
305
|
);
|
|
@@ -49,7 +49,6 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
|
|
|
49
49
|
},
|
|
50
50
|
ref
|
|
51
51
|
) => {
|
|
52
|
-
|
|
53
52
|
const { generateSideMenuItemClass, handleClick } = useSideMenuItem({
|
|
54
53
|
active,
|
|
55
54
|
disabled,
|
|
@@ -88,15 +87,15 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
|
|
|
88
87
|
tabIndex: disabled ? -1 : 0,
|
|
89
88
|
...(disabled ? {} : { href, to: href }),
|
|
90
89
|
};
|
|
91
|
-
|
|
90
|
+
|
|
92
91
|
return (
|
|
93
|
-
|
|
92
|
+
<LinkComp {...linkProps}>
|
|
94
93
|
{icon && <span className="c-side-menu__link-icon">{icon}</span>}
|
|
95
94
|
<span className="c-side-menu__link-text">{children}</span>
|
|
96
95
|
</LinkComp>
|
|
97
96
|
);
|
|
98
97
|
}
|
|
99
|
-
|
|
98
|
+
|
|
100
99
|
// Regular anchor tag
|
|
101
100
|
const linkProps = {
|
|
102
101
|
ref: ref as React.Ref<HTMLAnchorElement>,
|
|
@@ -109,7 +108,7 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
|
|
|
109
108
|
rel: rel,
|
|
110
109
|
tabIndex: disabled ? -1 : 0,
|
|
111
110
|
};
|
|
112
|
-
|
|
111
|
+
|
|
113
112
|
return (
|
|
114
113
|
<a {...linkProps}>
|
|
115
114
|
{icon && <span className="c-side-menu__link-icon">{icon}</span>}
|
|
@@ -72,7 +72,7 @@ const meta = {
|
|
|
72
72
|
},
|
|
73
73
|
},
|
|
74
74
|
args: {
|
|
75
|
-
onPageChange: () => {
|
|
75
|
+
onPageChange: () => {},
|
|
76
76
|
},
|
|
77
77
|
} satisfies Meta<typeof Pagination>;
|
|
78
78
|
|
|
@@ -105,7 +105,8 @@ export const Default: Story = {
|
|
|
105
105
|
parameters: {
|
|
106
106
|
docs: {
|
|
107
107
|
description: {
|
|
108
|
-
story:
|
|
108
|
+
story:
|
|
109
|
+
'Default pagination with first/last and previous/next navigation buttons using icons.',
|
|
109
110
|
},
|
|
110
111
|
},
|
|
111
112
|
},
|
|
@@ -348,7 +349,8 @@ export const WithSearch: Story = {
|
|
|
348
349
|
parameters: {
|
|
349
350
|
docs: {
|
|
350
351
|
description: {
|
|
351
|
-
story:
|
|
352
|
+
story:
|
|
353
|
+
'Pagination with search functionality to quickly jump to a specific page. Users can type a page number and submit to navigate directly.',
|
|
352
354
|
},
|
|
353
355
|
},
|
|
354
356
|
},
|
|
@@ -369,7 +371,8 @@ export const WithSearchLargeDataset: Story = {
|
|
|
369
371
|
parameters: {
|
|
370
372
|
docs: {
|
|
371
373
|
description: {
|
|
372
|
-
story:
|
|
374
|
+
story:
|
|
375
|
+
'Pagination with search functionality for large datasets. The search feature is especially useful when dealing with many pages.',
|
|
373
376
|
},
|
|
374
377
|
},
|
|
375
378
|
},
|