@etsoo/react 1.4.38 → 1.4.39
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/lib/mu/MUGlobal.d.ts +8 -0
- package/lib/mu/MUGlobal.js +19 -0
- package/lib/mu/MobileListItemRenderer.d.ts +1 -2
- package/lib/mu/MobileListItemRenderer.js +3 -37
- package/lib/mu/ResponsibleContainer.d.ts +2 -2
- package/lib/mu/ScrollerListEx.d.ts +20 -1
- package/lib/mu/ScrollerListEx.js +67 -6
- package/lib/mu/pages/ResponsivePageProps.d.ts +2 -2
- package/package.json +1 -1
- package/src/mu/MUGlobal.ts +23 -0
- package/src/mu/MobileListItemRenderer.tsx +4 -47
- package/src/mu/ResponsibleContainer.tsx +3 -2
- package/src/mu/ScrollerListEx.tsx +117 -8
- package/src/mu/pages/ResponsivePageProps.ts +5 -2
package/lib/mu/MUGlobal.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Theme } from '@mui/material';
|
|
1
2
|
export declare class MUGlobal {
|
|
2
3
|
/**
|
|
3
4
|
* Search field shrink
|
|
@@ -62,6 +63,13 @@ export declare class MUGlobal {
|
|
|
62
63
|
* @returns Updated object
|
|
63
64
|
*/
|
|
64
65
|
static adjustWithTheme(size: number, adjust: {}, updateFunc: (value: number) => string): {};
|
|
66
|
+
/**
|
|
67
|
+
* Get multple medias theme space
|
|
68
|
+
* @param spaces Spaces
|
|
69
|
+
* @param theme Theme
|
|
70
|
+
* @returns Result
|
|
71
|
+
*/
|
|
72
|
+
static getSpace(spaces: {}, theme: Theme): number;
|
|
65
73
|
/**
|
|
66
74
|
* Update object number properties with theme
|
|
67
75
|
* @param input Input object
|
package/lib/mu/MUGlobal.js
CHANGED
|
@@ -70,6 +70,25 @@ export class MUGlobal {
|
|
|
70
70
|
});
|
|
71
71
|
return newObj;
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Get multple medias theme space
|
|
75
|
+
* @param spaces Spaces
|
|
76
|
+
* @param theme Theme
|
|
77
|
+
* @returns Result
|
|
78
|
+
*/
|
|
79
|
+
static getSpace(spaces, theme) {
|
|
80
|
+
for (const [key, value] of Object.entries(spaces)) {
|
|
81
|
+
if (typeof value === 'number' &&
|
|
82
|
+
theme.breakpoints.keys.findIndex((bk) => bk === key) != -1) {
|
|
83
|
+
const mediaRaw = theme.breakpoints.up(key);
|
|
84
|
+
const mediaQuery = mediaRaw.substring(mediaRaw.indexOf('('));
|
|
85
|
+
if (window.matchMedia(mediaQuery).matches) {
|
|
86
|
+
return parseInt(theme.spacing(value), 10);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
73
92
|
/**
|
|
74
93
|
* Update object number properties with theme
|
|
75
94
|
* @param input Input object
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { SxProps, Theme } from '@mui/material';
|
|
2
1
|
import React from 'react';
|
|
3
2
|
import { ListItemReact } from '../components/ListItemReact';
|
|
4
3
|
import { ScrollerListExInnerItemRendererProps } from './ScrollerListEx';
|
|
@@ -9,7 +8,7 @@ import { ScrollerListExInnerItemRendererProps } from './ScrollerListEx';
|
|
|
9
8
|
* @param renderer Renderer for card content
|
|
10
9
|
* @returns Component
|
|
11
10
|
*/
|
|
12
|
-
export declare function MobileListItemRenderer<T>({ data, itemHeight }: ScrollerListExInnerItemRendererProps<T>,
|
|
11
|
+
export declare function MobileListItemRenderer<T>({ data, itemHeight, margins }: ScrollerListExInnerItemRendererProps<T>, renderer: (data: T) => [
|
|
13
12
|
string,
|
|
14
13
|
string | undefined,
|
|
15
14
|
React.ReactNode | (ListItemReact | boolean)[],
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Card, CardContent, CardHeader, LinearProgress } from '@mui/material';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { MoreFab } from './MoreFab';
|
|
4
|
-
import { MUGlobal } from './MUGlobal';
|
|
5
4
|
function getActions(input) {
|
|
6
5
|
// Actions
|
|
7
6
|
const actions = [];
|
|
@@ -19,48 +18,15 @@ function getActions(input) {
|
|
|
19
18
|
* @param renderer Renderer for card content
|
|
20
19
|
* @returns Component
|
|
21
20
|
*/
|
|
22
|
-
export function MobileListItemRenderer({ data, itemHeight },
|
|
21
|
+
export function MobileListItemRenderer({ data, itemHeight, margins }, renderer) {
|
|
23
22
|
// Loading
|
|
24
23
|
if (data == null)
|
|
25
24
|
return React.createElement(LinearProgress, null);
|
|
26
25
|
// Elements
|
|
27
26
|
const [title, subheader, actions, children] = renderer(data);
|
|
28
|
-
// Calculate margin
|
|
29
|
-
const calculateMargin = () => {
|
|
30
|
-
if (typeof margin === 'function')
|
|
31
|
-
return margin();
|
|
32
|
-
if (Array.isArray(margin)) {
|
|
33
|
-
const marginValue = margin[0];
|
|
34
|
-
const isNarrow = margin[1];
|
|
35
|
-
const half = MUGlobal.half(marginValue);
|
|
36
|
-
if (isNarrow) {
|
|
37
|
-
return {
|
|
38
|
-
marginLeft: 0,
|
|
39
|
-
marginRight: 0,
|
|
40
|
-
marginTop: half,
|
|
41
|
-
marginBottom: half
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
return {
|
|
46
|
-
marginLeft: half,
|
|
47
|
-
marginRight: half,
|
|
48
|
-
marginTop: half,
|
|
49
|
-
marginBottom: half
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const half = MUGlobal.half(margin);
|
|
54
|
-
return {
|
|
55
|
-
marginLeft: margin,
|
|
56
|
-
marginRight: margin,
|
|
57
|
-
marginTop: half,
|
|
58
|
-
marginBottom: half
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
27
|
return (React.createElement(Card, { sx: {
|
|
62
|
-
height:
|
|
63
|
-
...
|
|
28
|
+
height: itemHeight,
|
|
29
|
+
...margins
|
|
64
30
|
} },
|
|
65
31
|
React.createElement(CardHeader, { sx: { paddingBottom: 0.5 }, action: Array.isArray(actions) ? (React.createElement(MoreFab, { iconButton: true, size: "small", anchorOrigin: {
|
|
66
32
|
vertical: 'bottom',
|
|
@@ -6,7 +6,7 @@ import { GridColumn } from '../components/GridColumn';
|
|
|
6
6
|
import { GridJsonData } from '../components/GridLoader';
|
|
7
7
|
import { DataGridExProps } from './DataGridEx';
|
|
8
8
|
import { GridMethodRef } from './GridMethodRef';
|
|
9
|
-
import { ScrollerListExInnerItemRendererProps } from './ScrollerListEx';
|
|
9
|
+
import { ScrollerListExInnerItemRendererProps, ScrollerListExItemSize } from './ScrollerListEx';
|
|
10
10
|
/**
|
|
11
11
|
* ResponsibleContainer props
|
|
12
12
|
*/
|
|
@@ -51,7 +51,7 @@ export interface ResponsibleContainerProps<T extends {}, F extends DataTypes.Bas
|
|
|
51
51
|
/**
|
|
52
52
|
* Item size, a function indicates its a variable size list
|
|
53
53
|
*/
|
|
54
|
-
itemSize:
|
|
54
|
+
itemSize: ScrollerListExItemSize;
|
|
55
55
|
/**
|
|
56
56
|
* Load data callback
|
|
57
57
|
*/
|
|
@@ -13,11 +13,26 @@ export interface ScrollerListExInnerItemRendererProps<T> extends ListChildCompon
|
|
|
13
13
|
* Item height
|
|
14
14
|
*/
|
|
15
15
|
itemHeight: number;
|
|
16
|
+
/**
|
|
17
|
+
* Item space
|
|
18
|
+
*/
|
|
19
|
+
space: number;
|
|
20
|
+
/**
|
|
21
|
+
* Default margins
|
|
22
|
+
*/
|
|
23
|
+
margins: {};
|
|
16
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Extended ScrollerList ItemSize type
|
|
27
|
+
* 1. Callback function
|
|
28
|
+
* 2. Static sets
|
|
29
|
+
* 3. Dynamic calculation
|
|
30
|
+
*/
|
|
31
|
+
export declare type ScrollerListExItemSize = ((index: number) => [number, number] | [number, number, {}]) | [number, number] | [number, {}, boolean?];
|
|
17
32
|
/**
|
|
18
33
|
* Extended ScrollerList Props
|
|
19
34
|
*/
|
|
20
|
-
export interface ScrollerListExProps<T> extends Omit<ScrollerListProps<T>, 'itemRenderer'> {
|
|
35
|
+
export interface ScrollerListExProps<T> extends Omit<ScrollerListProps<T>, 'itemRenderer' | 'itemSize'> {
|
|
21
36
|
/**
|
|
22
37
|
* Alternating colors for odd/even rows
|
|
23
38
|
*/
|
|
@@ -34,6 +49,10 @@ export interface ScrollerListExProps<T> extends Omit<ScrollerListProps<T>, 'item
|
|
|
34
49
|
* Item renderer
|
|
35
50
|
*/
|
|
36
51
|
itemRenderer?: (props: ListChildComponentProps<T>) => React.ReactElement;
|
|
52
|
+
/**
|
|
53
|
+
* Item size, a function indicates its a variable size list
|
|
54
|
+
*/
|
|
55
|
+
itemSize: ScrollerListExItemSize;
|
|
37
56
|
/**
|
|
38
57
|
* On items select change
|
|
39
58
|
*/
|
package/lib/mu/ScrollerListEx.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { css } from '@emotion/css';
|
|
2
2
|
import { DataTypes, Utils } from '@etsoo/shared';
|
|
3
|
+
import { useTheme } from '@mui/material';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { ScrollerList } from '../components/ScrollerList';
|
|
6
|
+
import { MUGlobal } from './MUGlobal';
|
|
5
7
|
// Scroll bar size
|
|
6
8
|
const scrollbarSize = 16;
|
|
7
9
|
// Selected class name
|
|
@@ -36,15 +38,44 @@ const createGridStyle = (alternatingColors, selectedColor) => {
|
|
|
36
38
|
}
|
|
37
39
|
});
|
|
38
40
|
};
|
|
41
|
+
// Default margin
|
|
42
|
+
const defaultMargin = (margin, isNarrow) => {
|
|
43
|
+
const half = MUGlobal.half(margin);
|
|
44
|
+
if (isNarrow == null) {
|
|
45
|
+
const half = MUGlobal.half(margin);
|
|
46
|
+
return {
|
|
47
|
+
marginLeft: margin,
|
|
48
|
+
marginRight: margin,
|
|
49
|
+
marginTop: half,
|
|
50
|
+
marginBottom: half
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (isNarrow) {
|
|
54
|
+
return {
|
|
55
|
+
marginLeft: 0,
|
|
56
|
+
marginRight: 0,
|
|
57
|
+
marginTop: half,
|
|
58
|
+
marginBottom: half
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
marginLeft: half,
|
|
63
|
+
marginRight: half,
|
|
64
|
+
marginTop: half,
|
|
65
|
+
marginBottom: half
|
|
66
|
+
};
|
|
67
|
+
};
|
|
39
68
|
// Default itemRenderer
|
|
40
|
-
function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, selected, style, itemHeight }) {
|
|
69
|
+
function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, selected, style, itemHeight, space, margins }) {
|
|
41
70
|
// Child
|
|
42
71
|
const child = innerItemRenderer({
|
|
43
72
|
index,
|
|
44
73
|
data,
|
|
45
74
|
style,
|
|
46
75
|
selected,
|
|
47
|
-
itemHeight
|
|
76
|
+
itemHeight,
|
|
77
|
+
space,
|
|
78
|
+
margins
|
|
48
79
|
});
|
|
49
80
|
let rowClass = `ScrollerListEx-Row${index % 2}`;
|
|
50
81
|
if (selected)
|
|
@@ -80,19 +111,49 @@ export function ScrollerListEx(props) {
|
|
|
80
111
|
: false;
|
|
81
112
|
return selected;
|
|
82
113
|
};
|
|
114
|
+
// Theme
|
|
115
|
+
const theme = useTheme();
|
|
116
|
+
// Calculate size
|
|
117
|
+
const calculateItemSize = (index) => {
|
|
118
|
+
// Callback function
|
|
119
|
+
if (typeof itemSize === 'function') {
|
|
120
|
+
const result = itemSize(index);
|
|
121
|
+
if (result.length == 2)
|
|
122
|
+
return [...result, defaultMargin(MUGlobal.pagePaddings)];
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
// Calculation
|
|
126
|
+
const [size, spaces, isNarrow] = itemSize;
|
|
127
|
+
if (typeof spaces === 'number')
|
|
128
|
+
return [
|
|
129
|
+
size,
|
|
130
|
+
spaces,
|
|
131
|
+
defaultMargin(MUGlobal.pagePaddings, undefined)
|
|
132
|
+
];
|
|
133
|
+
return [
|
|
134
|
+
size,
|
|
135
|
+
MUGlobal.getSpace(spaces, theme),
|
|
136
|
+
defaultMargin(spaces, isNarrow)
|
|
137
|
+
];
|
|
138
|
+
};
|
|
139
|
+
// Local item size
|
|
140
|
+
const itemSizeLocal = (index) => {
|
|
141
|
+
const [size, space] = calculateItemSize(index);
|
|
142
|
+
return size + space;
|
|
143
|
+
};
|
|
83
144
|
// Destruct
|
|
84
145
|
const { alternatingColors = [undefined, undefined], className, idField = 'id', innerItemRenderer, itemSize, itemKey = (index, data) => { var _a; return (_a = DataTypes.getIdValue(data, idField)) !== null && _a !== void 0 ? _a : index; }, itemRenderer = (itemProps) => {
|
|
85
|
-
const itemHeight
|
|
86
|
-
? itemSize(itemProps.index)
|
|
87
|
-
: itemSize;
|
|
146
|
+
const [itemHeight, space, margins] = calculateItemSize(itemProps.index);
|
|
88
147
|
return defaultItemRenderer({
|
|
89
148
|
itemHeight,
|
|
90
149
|
innerItemRenderer,
|
|
91
150
|
onMouseDown,
|
|
151
|
+
space,
|
|
152
|
+
margins,
|
|
92
153
|
selected: isSelected(itemProps.data),
|
|
93
154
|
...itemProps
|
|
94
155
|
});
|
|
95
156
|
}, onSelectChange, selectedColor = '#edf4fb', ...rest } = props;
|
|
96
157
|
// Layout
|
|
97
|
-
return (React.createElement(ScrollerList, { className: Utils.mergeClasses('ScrollerListEx-Body', className, createGridStyle(alternatingColors, selectedColor)), itemKey: itemKey, itemRenderer: itemRenderer, itemSize:
|
|
158
|
+
return (React.createElement(ScrollerList, { className: Utils.mergeClasses('ScrollerListEx-Body', className, createGridStyle(alternatingColors, selectedColor)), itemKey: itemKey, itemRenderer: itemRenderer, itemSize: itemSizeLocal, ...rest }));
|
|
98
159
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { DataTypes } from '@etsoo/shared';
|
|
3
3
|
import { ListChildComponentProps } from 'react-window';
|
|
4
4
|
import { GridMethodRef } from '../GridMethodRef';
|
|
5
|
-
import { ScrollerListExInnerItemRendererProps } from '../ScrollerListEx';
|
|
5
|
+
import { ScrollerListExInnerItemRendererProps, ScrollerListExItemSize } from '../ScrollerListEx';
|
|
6
6
|
import { DataGridPageProps } from './DataGridPageProps';
|
|
7
7
|
/**
|
|
8
8
|
* Response page props
|
|
@@ -23,7 +23,7 @@ export interface ResponsePageProps<T, F extends DataTypes.BasicTemplate> extends
|
|
|
23
23
|
/**
|
|
24
24
|
* Item size, a function indicates its a variable size list
|
|
25
25
|
*/
|
|
26
|
-
itemSize:
|
|
26
|
+
itemSize: ScrollerListExItemSize;
|
|
27
27
|
/**
|
|
28
28
|
* Methods
|
|
29
29
|
*/
|
package/package.json
CHANGED
package/src/mu/MUGlobal.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NumberUtils } from '@etsoo/shared';
|
|
2
|
+
import { Breakpoint, Theme } from '@mui/material';
|
|
2
3
|
|
|
3
4
|
export class MUGlobal {
|
|
4
5
|
/**
|
|
@@ -125,6 +126,28 @@ export class MUGlobal {
|
|
|
125
126
|
return newObj;
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Get multple medias theme space
|
|
131
|
+
* @param spaces Spaces
|
|
132
|
+
* @param theme Theme
|
|
133
|
+
* @returns Result
|
|
134
|
+
*/
|
|
135
|
+
static getSpace(spaces: {}, theme: Theme) {
|
|
136
|
+
for (const [key, value] of Object.entries(spaces)) {
|
|
137
|
+
if (
|
|
138
|
+
typeof value === 'number' &&
|
|
139
|
+
theme.breakpoints.keys.findIndex((bk) => bk === key) != -1
|
|
140
|
+
) {
|
|
141
|
+
const mediaRaw = theme.breakpoints.up(key as Breakpoint);
|
|
142
|
+
const mediaQuery = mediaRaw.substring(mediaRaw.indexOf('('));
|
|
143
|
+
if (window.matchMedia(mediaQuery).matches) {
|
|
144
|
+
return parseInt(theme.spacing(value), 10);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
128
151
|
/**
|
|
129
152
|
* Update object number properties with theme
|
|
130
153
|
* @param input Input object
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Card,
|
|
3
|
-
CardContent,
|
|
4
|
-
CardHeader,
|
|
5
|
-
LinearProgress,
|
|
6
|
-
SxProps,
|
|
7
|
-
Theme
|
|
8
|
-
} from '@mui/material';
|
|
1
|
+
import { Card, CardContent, CardHeader, LinearProgress } from '@mui/material';
|
|
9
2
|
import React from 'react';
|
|
10
3
|
import { ListItemReact } from '../components/ListItemReact';
|
|
11
4
|
import { MoreFab } from './MoreFab';
|
|
12
|
-
import { MUGlobal } from './MUGlobal';
|
|
13
5
|
import { ScrollerListExInnerItemRendererProps } from './ScrollerListEx';
|
|
14
6
|
|
|
15
7
|
function getActions(input: (ListItemReact | boolean)[]): ListItemReact[] {
|
|
@@ -30,8 +22,7 @@ function getActions(input: (ListItemReact | boolean)[]): ListItemReact[] {
|
|
|
30
22
|
* @returns Component
|
|
31
23
|
*/
|
|
32
24
|
export function MobileListItemRenderer<T>(
|
|
33
|
-
{ data, itemHeight }: ScrollerListExInnerItemRendererProps<T>,
|
|
34
|
-
margin: {} | [{}, boolean] | (() => SxProps<Theme>),
|
|
25
|
+
{ data, itemHeight, margins }: ScrollerListExInnerItemRendererProps<T>,
|
|
35
26
|
renderer: (
|
|
36
27
|
data: T
|
|
37
28
|
) => [
|
|
@@ -47,45 +38,11 @@ export function MobileListItemRenderer<T>(
|
|
|
47
38
|
// Elements
|
|
48
39
|
const [title, subheader, actions, children] = renderer(data);
|
|
49
40
|
|
|
50
|
-
// Calculate margin
|
|
51
|
-
const calculateMargin = () => {
|
|
52
|
-
if (typeof margin === 'function') return margin();
|
|
53
|
-
if (Array.isArray(margin)) {
|
|
54
|
-
const marginValue = margin[0];
|
|
55
|
-
const isNarrow = margin[1];
|
|
56
|
-
const half = MUGlobal.half(marginValue);
|
|
57
|
-
if (isNarrow) {
|
|
58
|
-
return {
|
|
59
|
-
marginLeft: 0,
|
|
60
|
-
marginRight: 0,
|
|
61
|
-
marginTop: half,
|
|
62
|
-
marginBottom: half
|
|
63
|
-
};
|
|
64
|
-
} else {
|
|
65
|
-
return {
|
|
66
|
-
marginLeft: half,
|
|
67
|
-
marginRight: half,
|
|
68
|
-
marginTop: half,
|
|
69
|
-
marginBottom: half
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const half = MUGlobal.half(margin);
|
|
75
|
-
return {
|
|
76
|
-
marginLeft: margin,
|
|
77
|
-
marginRight: margin,
|
|
78
|
-
marginTop: half,
|
|
79
|
-
marginBottom: half
|
|
80
|
-
};
|
|
81
|
-
};
|
|
82
|
-
|
|
83
41
|
return (
|
|
84
42
|
<Card
|
|
85
43
|
sx={{
|
|
86
|
-
height:
|
|
87
|
-
|
|
88
|
-
...calculateMargin()
|
|
44
|
+
height: itemHeight,
|
|
45
|
+
...margins
|
|
89
46
|
}}
|
|
90
47
|
>
|
|
91
48
|
<CardHeader
|
|
@@ -21,7 +21,8 @@ import { MUGlobal } from './MUGlobal';
|
|
|
21
21
|
import { PullToRefreshUI } from './PullToRefreshUI';
|
|
22
22
|
import {
|
|
23
23
|
ScrollerListEx,
|
|
24
|
-
ScrollerListExInnerItemRendererProps
|
|
24
|
+
ScrollerListExInnerItemRendererProps,
|
|
25
|
+
ScrollerListExItemSize
|
|
25
26
|
} from './ScrollerListEx';
|
|
26
27
|
import { SearchBar } from './SearchBar';
|
|
27
28
|
|
|
@@ -91,7 +92,7 @@ export interface ResponsibleContainerProps<
|
|
|
91
92
|
/**
|
|
92
93
|
* Item size, a function indicates its a variable size list
|
|
93
94
|
*/
|
|
94
|
-
itemSize:
|
|
95
|
+
itemSize: ScrollerListExItemSize;
|
|
95
96
|
|
|
96
97
|
/**
|
|
97
98
|
* Load data callback
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { css } from '@emotion/css';
|
|
2
2
|
import { DataTypes, Utils } from '@etsoo/shared';
|
|
3
|
+
import { useTheme } from '@mui/material';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { ListChildComponentProps } from 'react-window';
|
|
5
6
|
import { ScrollerList, ScrollerListProps } from '../components/ScrollerList';
|
|
7
|
+
import { MUGlobal } from './MUGlobal';
|
|
6
8
|
|
|
7
9
|
// Scroll bar size
|
|
8
10
|
const scrollbarSize = 16;
|
|
@@ -44,6 +46,37 @@ const createGridStyle = (
|
|
|
44
46
|
});
|
|
45
47
|
};
|
|
46
48
|
|
|
49
|
+
// Default margin
|
|
50
|
+
const defaultMargin = (margin: {}, isNarrow?: boolean) => {
|
|
51
|
+
const half = MUGlobal.half(margin);
|
|
52
|
+
|
|
53
|
+
if (isNarrow == null) {
|
|
54
|
+
const half = MUGlobal.half(margin);
|
|
55
|
+
return {
|
|
56
|
+
marginLeft: margin,
|
|
57
|
+
marginRight: margin,
|
|
58
|
+
marginTop: half,
|
|
59
|
+
marginBottom: half
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (isNarrow) {
|
|
64
|
+
return {
|
|
65
|
+
marginLeft: 0,
|
|
66
|
+
marginRight: 0,
|
|
67
|
+
marginTop: half,
|
|
68
|
+
marginBottom: half
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
marginLeft: half,
|
|
74
|
+
marginRight: half,
|
|
75
|
+
marginTop: half,
|
|
76
|
+
marginBottom: half
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
47
80
|
/**
|
|
48
81
|
* Extended ScrollerList inner item renderer props
|
|
49
82
|
*/
|
|
@@ -58,13 +91,34 @@ export interface ScrollerListExInnerItemRendererProps<T>
|
|
|
58
91
|
* Item height
|
|
59
92
|
*/
|
|
60
93
|
itemHeight: number;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Item space
|
|
97
|
+
*/
|
|
98
|
+
space: number;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Default margins
|
|
102
|
+
*/
|
|
103
|
+
margins: {};
|
|
61
104
|
}
|
|
62
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Extended ScrollerList ItemSize type
|
|
108
|
+
* 1. Callback function
|
|
109
|
+
* 2. Static sets
|
|
110
|
+
* 3. Dynamic calculation
|
|
111
|
+
*/
|
|
112
|
+
export type ScrollerListExItemSize =
|
|
113
|
+
| ((index: number) => [number, number] | [number, number, {}])
|
|
114
|
+
| [number, number]
|
|
115
|
+
| [number, {}, boolean?];
|
|
116
|
+
|
|
63
117
|
/**
|
|
64
118
|
* Extended ScrollerList Props
|
|
65
119
|
*/
|
|
66
120
|
export interface ScrollerListExProps<T>
|
|
67
|
-
extends Omit<ScrollerListProps<T>, 'itemRenderer'> {
|
|
121
|
+
extends Omit<ScrollerListProps<T>, 'itemRenderer' | 'itemSize'> {
|
|
68
122
|
/**
|
|
69
123
|
* Alternating colors for odd/even rows
|
|
70
124
|
*/
|
|
@@ -87,6 +141,11 @@ export interface ScrollerListExProps<T>
|
|
|
87
141
|
*/
|
|
88
142
|
itemRenderer?: (props: ListChildComponentProps<T>) => React.ReactElement;
|
|
89
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Item size, a function indicates its a variable size list
|
|
146
|
+
*/
|
|
147
|
+
itemSize: ScrollerListExItemSize;
|
|
148
|
+
|
|
90
149
|
/**
|
|
91
150
|
* On items select change
|
|
92
151
|
*/
|
|
@@ -116,6 +175,16 @@ interface defaultItemRendererProps<T> extends ListChildComponentProps<T> {
|
|
|
116
175
|
*/
|
|
117
176
|
itemHeight: number;
|
|
118
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Item space
|
|
180
|
+
*/
|
|
181
|
+
space: number;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Default margins
|
|
185
|
+
*/
|
|
186
|
+
margins: {};
|
|
187
|
+
|
|
119
188
|
/**
|
|
120
189
|
* Item selected
|
|
121
190
|
*/
|
|
@@ -130,7 +199,9 @@ function defaultItemRenderer<T>({
|
|
|
130
199
|
onMouseDown,
|
|
131
200
|
selected,
|
|
132
201
|
style,
|
|
133
|
-
itemHeight
|
|
202
|
+
itemHeight,
|
|
203
|
+
space,
|
|
204
|
+
margins
|
|
134
205
|
}: defaultItemRendererProps<T>) {
|
|
135
206
|
// Child
|
|
136
207
|
const child = innerItemRenderer({
|
|
@@ -138,7 +209,9 @@ function defaultItemRenderer<T>({
|
|
|
138
209
|
data,
|
|
139
210
|
style,
|
|
140
211
|
selected,
|
|
141
|
-
itemHeight
|
|
212
|
+
itemHeight,
|
|
213
|
+
space,
|
|
214
|
+
margins
|
|
142
215
|
});
|
|
143
216
|
|
|
144
217
|
let rowClass = `ScrollerListEx-Row${index % 2}`;
|
|
@@ -192,6 +265,41 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
|
|
|
192
265
|
return selected;
|
|
193
266
|
};
|
|
194
267
|
|
|
268
|
+
// Theme
|
|
269
|
+
const theme = useTheme();
|
|
270
|
+
|
|
271
|
+
// Calculate size
|
|
272
|
+
const calculateItemSize = (index: number): [number, number, {}] => {
|
|
273
|
+
// Callback function
|
|
274
|
+
if (typeof itemSize === 'function') {
|
|
275
|
+
const result = itemSize(index);
|
|
276
|
+
if (result.length == 2)
|
|
277
|
+
return [...result, defaultMargin(MUGlobal.pagePaddings)];
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Calculation
|
|
282
|
+
const [size, spaces, isNarrow] = itemSize;
|
|
283
|
+
if (typeof spaces === 'number')
|
|
284
|
+
return [
|
|
285
|
+
size,
|
|
286
|
+
spaces,
|
|
287
|
+
defaultMargin(MUGlobal.pagePaddings, undefined)
|
|
288
|
+
];
|
|
289
|
+
|
|
290
|
+
return [
|
|
291
|
+
size,
|
|
292
|
+
MUGlobal.getSpace(spaces, theme),
|
|
293
|
+
defaultMargin(spaces, isNarrow)
|
|
294
|
+
];
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Local item size
|
|
298
|
+
const itemSizeLocal = (index: number) => {
|
|
299
|
+
const [size, space] = calculateItemSize(index);
|
|
300
|
+
return size + space;
|
|
301
|
+
};
|
|
302
|
+
|
|
195
303
|
// Destruct
|
|
196
304
|
const {
|
|
197
305
|
alternatingColors = [undefined, undefined],
|
|
@@ -202,14 +310,15 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
|
|
|
202
310
|
itemKey = (index: number, data: T) =>
|
|
203
311
|
DataTypes.getIdValue(data, idField) ?? index,
|
|
204
312
|
itemRenderer = (itemProps) => {
|
|
205
|
-
const itemHeight =
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
: itemSize;
|
|
313
|
+
const [itemHeight, space, margins] = calculateItemSize(
|
|
314
|
+
itemProps.index
|
|
315
|
+
);
|
|
209
316
|
return defaultItemRenderer({
|
|
210
317
|
itemHeight,
|
|
211
318
|
innerItemRenderer,
|
|
212
319
|
onMouseDown,
|
|
320
|
+
space,
|
|
321
|
+
margins,
|
|
213
322
|
selected: isSelected(itemProps.data),
|
|
214
323
|
...itemProps
|
|
215
324
|
});
|
|
@@ -229,7 +338,7 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
|
|
|
229
338
|
)}
|
|
230
339
|
itemKey={itemKey}
|
|
231
340
|
itemRenderer={itemRenderer}
|
|
232
|
-
itemSize={
|
|
341
|
+
itemSize={itemSizeLocal}
|
|
233
342
|
{...rest}
|
|
234
343
|
/>
|
|
235
344
|
);
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { DataTypes } from '@etsoo/shared';
|
|
2
2
|
import { ListChildComponentProps } from 'react-window';
|
|
3
3
|
import { GridMethodRef } from '../GridMethodRef';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
ScrollerListExInnerItemRendererProps,
|
|
6
|
+
ScrollerListExItemSize
|
|
7
|
+
} from '../ScrollerListEx';
|
|
5
8
|
import { DataGridPageProps } from './DataGridPageProps';
|
|
6
9
|
|
|
7
10
|
/**
|
|
@@ -32,7 +35,7 @@ export interface ResponsePageProps<T, F extends DataTypes.BasicTemplate>
|
|
|
32
35
|
/**
|
|
33
36
|
* Item size, a function indicates its a variable size list
|
|
34
37
|
*/
|
|
35
|
-
itemSize:
|
|
38
|
+
itemSize: ScrollerListExItemSize;
|
|
36
39
|
|
|
37
40
|
/**
|
|
38
41
|
* Methods
|