@linagora/twake-mui 14.0.0 → 14.1.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 +7 -0
- package/dist/components/LoadMore/LoadMore.stories.d.ts +7 -0
- package/dist/components/LoadMore/LoadMore.stories.js +43 -0
- package/dist/components/LoadMore/index.d.ts +9 -0
- package/dist/components/LoadMore/index.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# @linagora/twake-mui [14.1.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@14.0.0...@linagora/twake-mui@14.1.0) (2026-10-15)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **twake-mui:** Migrate LoadMore from cozy-ui ([3b505ec](https://github.com/linagora/twake-ui/commit/3b505ec16434d371d7a730cc314df06e6013b724))
|
|
7
|
+
|
|
1
8
|
# @linagora/twake-mui [14.0.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@13.2.1...@linagora/twake-mui@14.0.0) (2026-10-15)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import LoadMore from './index';
|
|
3
|
+
declare const meta: Meta<typeof LoadMore>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof meta>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Screenshot: Story;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Box, Stack, Typography } from '@mui/material';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import LoadMore from './index';
|
|
4
|
+
const sleep = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));
|
|
5
|
+
const InfiniteList = ({ fetchMore: onFetchMore, ...props }) => {
|
|
6
|
+
const [elements, setElements] = useState([1, 2]);
|
|
7
|
+
const fetchMore = async () => {
|
|
8
|
+
onFetchMore?.();
|
|
9
|
+
await sleep(1000);
|
|
10
|
+
setElements(previous => [...previous, previous.length + 1]);
|
|
11
|
+
};
|
|
12
|
+
return (React.createElement(Box, { sx: { height: 300, overflow: 'auto' } },
|
|
13
|
+
React.createElement(Typography, null, "Scroll down to load more."),
|
|
14
|
+
elements.map(element => (React.createElement(Box, { key: element, sx: { bgcolor: 'grey.500', height: 160, mb: 1 } }))),
|
|
15
|
+
elements.length < 25 && React.createElement(LoadMore, { fetchMore: fetchMore, ...props })));
|
|
16
|
+
};
|
|
17
|
+
const Section = ({ title, children }) => (React.createElement("section", null,
|
|
18
|
+
React.createElement("h3", null, title),
|
|
19
|
+
children));
|
|
20
|
+
const meta = {
|
|
21
|
+
title: 'LoadMore',
|
|
22
|
+
component: LoadMore,
|
|
23
|
+
tags: ['autodocs'],
|
|
24
|
+
argTypes: {
|
|
25
|
+
label: { control: 'text' },
|
|
26
|
+
fetchMore: { action: 'fetchMore' }
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export default meta;
|
|
30
|
+
export const Default = {
|
|
31
|
+
args: {
|
|
32
|
+
label: 'Load more'
|
|
33
|
+
},
|
|
34
|
+
render: args => React.createElement(InfiniteList, { ...args })
|
|
35
|
+
};
|
|
36
|
+
export const Screenshot = {
|
|
37
|
+
tags: ['argos'],
|
|
38
|
+
render: () => (React.createElement(Stack, { spacing: 4 },
|
|
39
|
+
React.createElement(Section, { title: "Button" },
|
|
40
|
+
React.createElement(LoadMore, { label: "Load more", fetchMore: () => { } })),
|
|
41
|
+
React.createElement(Section, { title: "Loading" },
|
|
42
|
+
React.createElement(LoadMore, { label: "Load more", fetchMore: () => new Promise(() => { }) }))))
|
|
43
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ButtonProps } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export interface LoadMoreProps extends Omit<ButtonProps, 'children' | 'onClick' | 'loading'> {
|
|
4
|
+
/** Called when the next batch of data needs to be loaded. Can return a promise. */
|
|
5
|
+
fetchMore: () => unknown;
|
|
6
|
+
label: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
declare const LoadMore: React.FC<LoadMoreProps>;
|
|
9
|
+
export default LoadMore;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Button, CircularProgress } from '@mui/material';
|
|
2
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
const LoadMore = ({ fetchMore, label, ...props }) => {
|
|
4
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
5
|
+
const elementRef = useRef(null);
|
|
6
|
+
const startFetchMore = useCallback(async () => {
|
|
7
|
+
if (isLoading)
|
|
8
|
+
return;
|
|
9
|
+
setIsLoading(true);
|
|
10
|
+
await fetchMore();
|
|
11
|
+
setIsLoading(false);
|
|
12
|
+
}, [isLoading, fetchMore]);
|
|
13
|
+
const handleClick = () => {
|
|
14
|
+
void startFetchMore();
|
|
15
|
+
};
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const element = elementRef.current;
|
|
18
|
+
if (!element)
|
|
19
|
+
return;
|
|
20
|
+
const observer = new IntersectionObserver((entries) => {
|
|
21
|
+
if (entries.some(entry => entry.isIntersecting))
|
|
22
|
+
void startFetchMore();
|
|
23
|
+
});
|
|
24
|
+
observer.observe(element);
|
|
25
|
+
return () => observer.disconnect();
|
|
26
|
+
}, [startFetchMore]);
|
|
27
|
+
return (React.createElement("span", { ref: elementRef },
|
|
28
|
+
React.createElement(Button, { variant: "text", onClick: handleClick, ...props }, isLoading ? React.createElement(CircularProgress, { size: 16 }) : label)));
|
|
29
|
+
};
|
|
30
|
+
export default LoadMore;
|
package/dist/index.d.ts
CHANGED
|
@@ -52,6 +52,7 @@ export { default as ListItemText } from './components/ListItemText';
|
|
|
52
52
|
export { default as ListItemSkeleton } from './components/ListItemSkeleton';
|
|
53
53
|
export { default as ListSkeleton } from './components/ListSkeleton';
|
|
54
54
|
export { default as ListSubheader } from './components/ListSubheader';
|
|
55
|
+
export { default as LoadMore } from './components/LoadMore';
|
|
55
56
|
export { default as Markdown } from './components/Markdown';
|
|
56
57
|
export { default as MidEllipsis } from './components/MidEllipsis';
|
|
57
58
|
export { default as PointerAlert } from './components/PointerAlert';
|
|
@@ -130,6 +131,7 @@ export type { ListItemTextProps } from './components/ListItemText';
|
|
|
130
131
|
export type { ListItemSkeletonProps } from './components/ListItemSkeleton';
|
|
131
132
|
export type { ListSkeletonProps } from './components/ListSkeleton';
|
|
132
133
|
export type { ListSubheaderProps } from './components/ListSubheader';
|
|
134
|
+
export type { LoadMoreProps } from './components/LoadMore';
|
|
133
135
|
export type { MarkdownProps } from './components/Markdown';
|
|
134
136
|
export type { MidEllipsisProps } from './components/MidEllipsis';
|
|
135
137
|
export type { TabsProps } from './components/Tabs';
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,7 @@ export { default as ListItemText } from './components/ListItemText';
|
|
|
55
55
|
export { default as ListItemSkeleton } from './components/ListItemSkeleton';
|
|
56
56
|
export { default as ListSkeleton } from './components/ListSkeleton';
|
|
57
57
|
export { default as ListSubheader } from './components/ListSubheader';
|
|
58
|
+
export { default as LoadMore } from './components/LoadMore';
|
|
58
59
|
export { default as Markdown } from './components/Markdown';
|
|
59
60
|
export { default as MidEllipsis } from './components/MidEllipsis';
|
|
60
61
|
export { default as PointerAlert } from './components/PointerAlert';
|