Skip to content

Commit 16e12b8

Browse files
Add load more functionality (#737)
* feat(components): add LoadMore component for dynamic list expansion Introduce LoadMore component to allow users to load additional items into a list. This component includes a "Show More" button and an optional count indicator. It supports a loading state and automatically hides the button when all items are loaded. This addition enhances user experience by providing a seamless way to view more content without navigating away from the current page. * refactor(stories): update LoadMore stories to use StoryObj for improved type safety and readability fix(stories): correct story names to follow consistent naming convention * style(types.ts): add semicolons to type definitions for consistency and readability * refactor(LoadMore.tsx, LoadMoreList.tsx): convert components from arrow functions to named functions for improved readability and consistency fix(LoadMoreList.tsx): change key in list items from index to item value to ensure unique keys and prevent potential rendering issues * style(loadMore): remove redundant comments for cleaner code Remove unnecessary comments in LoadMoreList.tsx and LoadMore.stories.tsx to improve code readability and maintainability. * feat(loadMore): add "Show Less" button functionality to LoadMore component Add a "Show Less" button to allow users to reduce the number of displayed items. This enhances user control over the list view, especially when dealing with large datasets. Update stories to reflect the new feature and rename "WithoutCount" to "WithCount" for clarity. * feat(loadMore): add "Show Less" button functionality to allow users to reduce items docs(loadMore): update documentation to include "Show Less" button usage style(PaginationAmount): adjust spacing in pagination result display for consistency * Update src/components/loadMore/LoadMore.stories.tsx Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/components/loadMore/LoadMore.stories.tsx Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore(package.json): bump version from 10.4.6 to 10.4.8 to prepare for new release * test(ExtendedPagination.spec.tsx): remove space in result range display to ensure consistency in text rendering * style(pagination): add space after dash in pagination display Ensure consistent spacing in pagination text for better readability. * chore(package.json): bump version from 10.4.8 to 10.5.0 to reflect new features or improvements * test(ExtendedPagination.spec.tsx): fix spacing in expected text for consistency in test assertions --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent a8cf952 commit 16e12b8

File tree

8 files changed

+478
-1
lines changed

8 files changed

+478
-1
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@nordcloud/gnui",
33
"description": "Nordcloud Design System - a collection of reusable React components used in Nordcloud's SaaS products",
4-
"version": "10.4.6",
4+
"version": "10.5.0",
55
"license": "MIT",
66
"repository": {
77
"type": "git",

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export * from "./input";
1616
export * from "./list";
1717
export * from "./listLoader";
1818
export * from "./loader";
19+
export * from "./loadMore";
1920
export * from "./message";
2021
export * from "./modal";
2122
export * from "./select";
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import { Meta, Story, Canvas, ArgsTable } from "@storybook/addon-docs";
2+
import { LoadMore } from "./LoadMore";
3+
import { LoadMoreList } from "./LoadMoreList";
4+
5+
<Meta title="Components/LoadMore" component={LoadMore} />
6+
7+
# Load More
8+
9+
The `LoadMore` component provides a "Show More" button that allows users to load additional items into an existing list. It can optionally display a count indicator showing the number of loaded items.
10+
11+
## Features
12+
13+
- "Show More" button to load additional items when clicked
14+
- Optional count indicator showing current items and total (e.g., "1-5 of 15")
15+
- "Show Less" button appears when all items are loaded (if onLoadLess prop is provided)
16+
- Supports a loading state to disable the button during data fetching
17+
- Automatically hides the "Show More" button when all items are loaded
18+
- Option to hide the count indicator with centered button layout
19+
20+
## Basic Usage
21+
22+
```jsx
23+
import { LoadMore } from "@gnui/core";
24+
25+
// Inside your component
26+
const MyList = () => {
27+
const [items, setItems] = useState([
28+
/* initial items */
29+
]);
30+
const [isLoading, setIsLoading] = useState(false);
31+
32+
const handleLoadMore = () => {
33+
setIsLoading(true);
34+
// Fetch more items, then:
35+
setItems([...items, ...newItems]);
36+
setIsLoading(false);
37+
};
38+
39+
const handleLoadLess = () => {
40+
// Reduce items to initial batch size
41+
setItems(items.slice(0, batchSize));
42+
};
43+
44+
return (
45+
<div>
46+
<ul>
47+
{items.map((item) => (
48+
<li key={item.id}>{item.name}</li>
49+
))}
50+
</ul>
51+
52+
<LoadMore
53+
currentCount={items.length}
54+
total={totalItems}
55+
onLoadMore={handleLoadMore}
56+
onLoadLess={handleLoadLess}
57+
isLoading={isLoading}
58+
/>
59+
</div>
60+
);
61+
};
62+
```
63+
64+
## Examples
65+
66+
### Basic Example (without count)
67+
68+
Shows only the centered "Show More" button:
69+
70+
<Canvas>
71+
<Story id="components-loadmore--basic" />
72+
</Canvas>
73+
74+
### With Count
75+
76+
Shows both the count indicator and "Show More" button:
77+
78+
<Canvas>
79+
<Story id="components-loadmore--with-count" />
80+
</Canvas>
81+
82+
### Mid-List Example
83+
84+
Shows the state when some items are loaded:
85+
86+
<Canvas>
87+
<Story id="components-loadmore--mid-list" />
88+
</Canvas>
89+
90+
### End of List Example
91+
92+
Shows how the button is hidden when all items are loaded:
93+
94+
<Canvas>
95+
<Story id="components-loadmore--end-of-list" />
96+
</Canvas>
97+
98+
### Loading State
99+
100+
Shows the button in a loading state:
101+
102+
<Canvas>
103+
<Story id="components-loadmore--loading" />
104+
</Canvas>
105+
106+
### Working Example with List
107+
108+
A complete example showing the component in use with a list:
109+
110+
<Canvas>
111+
<Story id="components-loadmore--with-list" />
112+
</Canvas>
113+
114+
### With Show Less
115+
116+
Shows how the "Show Less" button appears when all items are loaded and onLoadLess is provided:
117+
118+
<Canvas>
119+
<Story id="components-loadmore--with-show-less" />
120+
</Canvas>
121+
122+
## Props
123+
124+
<ArgsTable of={LoadMore} />
125+
126+
## Accessibility
127+
128+
The component follows accessibility best practices:
129+
130+
- The "Show More" button is properly labeled for screen readers
131+
- The button is disabled during loading states to prevent multiple clicks
132+
- The count indicator (when shown) provides context about the loaded items
133+
134+
## Usage Guidelines
135+
136+
1. **Basic (Without Count)**
137+
138+
```jsx
139+
<LoadMore hideCount currentCount={5} total={15} onLoadMore={handleLoadMore} />
140+
```
141+
142+
2. **With Count**
143+
144+
```jsx
145+
<LoadMore currentCount={5} total={15} onLoadMore={handleLoadMore} />
146+
```
147+
148+
3. **With Show Less**
149+
150+
```jsx
151+
<LoadMore currentCount={15} total={15} onLoadMore={handleLoadMore} onLoadLess={handleLoadLess} />
152+
```
153+
154+
4. **With Loading State**
155+
```jsx
156+
<LoadMore currentCount={5} total={15} onLoadMore={handleLoadMore} isLoading={true} />
157+
```
158+
159+
## Design Considerations
160+
161+
- The count indicator uses the same styling as other pagination components for consistency
162+
- When `hideCount` is true, the button is automatically centered
163+
- The button uses the link color and underline hover effect for a lightweight appearance
164+
- Loading state is visually indicated while maintaining the button's position
165+
- "Show Less" button appears in place of "Show More" when all items are loaded and onLoadLess is provided
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import * as React from "react";
2+
import { Meta, StoryObj } from "@storybook/react";
3+
import { LoadMore } from "./LoadMore";
4+
import { LoadMoreList } from "./LoadMoreList";
5+
6+
const meta: Meta<typeof LoadMore> = {
7+
title: "Components/LoadMore",
8+
component: LoadMore,
9+
parameters: {
10+
docs: {
11+
description: {
12+
component:
13+
'A component that shows a "Show More" button to load additional items, optionally with a count indicator.',
14+
},
15+
},
16+
},
17+
};
18+
19+
export default meta;
20+
21+
type Story = StoryObj<typeof LoadMore>;
22+
23+
export const Basic: Story = {
24+
render: () => (
25+
<LoadMore
26+
hideCount
27+
currentCount={5}
28+
total={15}
29+
onLoadMore={() => console.log("Load more clicked")}
30+
/>
31+
),
32+
name: "basic",
33+
};
34+
35+
export const WithCount: Story = {
36+
render: () => (
37+
<LoadMore
38+
currentCount={5}
39+
total={15}
40+
onLoadMore={() => console.log("Load more clicked")}
41+
/>
42+
),
43+
name: "with-count",
44+
};
45+
46+
export const MidList: Story = {
47+
render: () => (
48+
<LoadMore
49+
currentCount={10}
50+
total={15}
51+
onLoadMore={() => console.log("Load more clicked")}
52+
/>
53+
),
54+
name: "mid-list",
55+
};
56+
57+
export const EndOfList: Story = {
58+
render: () => (
59+
<LoadMore
60+
currentCount={15}
61+
total={15}
62+
onLoadMore={() => console.log("Load more clicked")}
63+
/>
64+
),
65+
name: "end-of-list",
66+
};
67+
68+
export const Loading: Story = {
69+
render: () => (
70+
<LoadMore
71+
isLoading
72+
currentCount={5}
73+
total={15}
74+
onLoadMore={() => console.log("Load more clicked")}
75+
/>
76+
),
77+
name: "loading",
78+
};
79+
80+
export const WithList: Story = {
81+
render: () => <LoadMoreList />,
82+
name: "with-list",
83+
};
84+
85+
export const WithShowLess: Story = {
86+
render: () => (
87+
<LoadMoreList
88+
totalItems={15}
89+
batchSize={5}
90+
initialItems={Array.from(
91+
{ length: 15 },
92+
(_, index) => `Item ${index + 1}`
93+
)}
94+
/>
95+
),
96+
name: "with-show-less",
97+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import * as React from "react";
2+
import styled from "styled-components";
3+
import theme from "../../theme";
4+
import { Button } from "../button";
5+
import { PaginationAmount, StyledPaginationBox } from "../paginationHelpers";
6+
import { LoadMoreProps } from "./types";
7+
8+
const Container = styled(StyledPaginationBox)<{ hideCount?: boolean }>`
9+
justify-content: ${({ hideCount }) =>
10+
hideCount ? "center" : "space-between"};
11+
padding: ${theme.spacing.spacing02} ${theme.spacing.spacing03};
12+
height: 36px;
13+
`;
14+
15+
/**
16+
* LoadMore displays a "Show More" button to load additional items when clicked,
17+
* optionally with a count of loaded items.
18+
*/
19+
export function LoadMore({
20+
currentCount,
21+
total,
22+
onLoadMore,
23+
onLoadLess,
24+
isLoading = false,
25+
hideCount = false,
26+
className,
27+
}: LoadMoreProps) {
28+
const hasMoreItems = currentCount < total;
29+
const showLessButton = onLoadLess && currentCount === total && total > 0;
30+
31+
return (
32+
<Container className={className} small={false} hideCount={hideCount}>
33+
{!hideCount && (
34+
<PaginationAmount from={0} size={currentCount} count={total} />
35+
)}
36+
37+
{hasMoreItems && (
38+
<Button
39+
severity="medium"
40+
size="sm"
41+
initialState={isLoading ? "loading" : undefined}
42+
aria-label="Show more items"
43+
disabled={isLoading}
44+
onClick={onLoadMore}
45+
>
46+
{isLoading ? "Loading..." : "Show more"}
47+
</Button>
48+
)}
49+
50+
{showLessButton && (
51+
<Button
52+
severity="medium"
53+
size="sm"
54+
aria-label="Show less items"
55+
initialState={isLoading ? "loading" : undefined}
56+
disabled={isLoading}
57+
onClick={onLoadLess}
58+
>
59+
{isLoading ? "Loading..." : "Show less"}
60+
</Button>
61+
)}
62+
</Container>
63+
);
64+
}

0 commit comments

Comments
 (0)