@etsoo/react 1.4.36 → 1.4.40
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 +15 -0
- package/lib/mu/MUGlobal.js +28 -0
- package/lib/mu/MobileListItemRenderer.d.ts +1 -2
- package/lib/mu/MobileListItemRenderer.js +6 -42
- package/lib/mu/ResponsibleContainer.d.ts +2 -2
- package/lib/mu/ScrollerListEx.d.ts +20 -1
- package/lib/mu/ScrollerListEx.js +73 -6
- package/lib/mu/pages/ResponsivePageProps.d.ts +2 -2
- package/package.json +1 -1
- package/src/mu/MUGlobal.ts +32 -0
- package/src/mu/MobileListItemRenderer.tsx +11 -52
- package/src/mu/ResponsibleContainer.tsx +3 -2
- package/src/mu/ScrollerListEx.tsx +125 -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,20 @@ export declare class MUGlobal {
|
|
|
62
63
|
* @returns Updated object
|
|
63
64
|
*/
|
|
64
65
|
static adjustWithTheme(size: number, adjust: {}, updateFunc: (value: number) => string): {};
|
|
66
|
+
/**
|
|
67
|
+
* Break points defined
|
|
68
|
+
*/
|
|
69
|
+
static breakpoints: readonly ["xs", "sm", "md", "lg", "xl"];
|
|
70
|
+
/**
|
|
71
|
+
* Get multple medias theme space
|
|
72
|
+
* Responsive values and Breakpoints as an object
|
|
73
|
+
* xs = theme.breakpoints.up('xs')
|
|
74
|
+
* https://mui.com/system/basics/
|
|
75
|
+
* @param spaces Spaces
|
|
76
|
+
* @param theme Theme
|
|
77
|
+
* @returns Result
|
|
78
|
+
*/
|
|
79
|
+
static getSpace(spaces: {}, theme: Theme): number;
|
|
65
80
|
/**
|
|
66
81
|
* Update object number properties with theme
|
|
67
82
|
* @param input Input object
|
package/lib/mu/MUGlobal.js
CHANGED
|
@@ -70,6 +70,30 @@ export class MUGlobal {
|
|
|
70
70
|
});
|
|
71
71
|
return newObj;
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Get multple medias theme space
|
|
75
|
+
* Responsive values and Breakpoints as an object
|
|
76
|
+
* xs = theme.breakpoints.up('xs')
|
|
77
|
+
* https://mui.com/system/basics/
|
|
78
|
+
* @param spaces Spaces
|
|
79
|
+
* @param theme Theme
|
|
80
|
+
* @returns Result
|
|
81
|
+
*/
|
|
82
|
+
static getSpace(spaces, theme) {
|
|
83
|
+
const start = this.breakpoints.length - 1;
|
|
84
|
+
for (let i = start; i >= 0; i--) {
|
|
85
|
+
const key = this.breakpoints[i];
|
|
86
|
+
const value = Reflect.get(spaces, key);
|
|
87
|
+
if (typeof value === 'number') {
|
|
88
|
+
const mediaRaw = theme.breakpoints.up(key);
|
|
89
|
+
const mediaQuery = mediaRaw.substring(mediaRaw.indexOf('('));
|
|
90
|
+
if (window.matchMedia(mediaQuery).matches) {
|
|
91
|
+
return parseInt(theme.spacing(value), 10);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
73
97
|
/**
|
|
74
98
|
* Update object number properties with theme
|
|
75
99
|
* @param input Input object
|
|
@@ -118,3 +142,7 @@ MUGlobal.textFieldVariant = 'filled';
|
|
|
118
142
|
* Page default paddings
|
|
119
143
|
*/
|
|
120
144
|
MUGlobal.pagePaddings = { xs: 2, sm: 3 };
|
|
145
|
+
/**
|
|
146
|
+
* Break points defined
|
|
147
|
+
*/
|
|
148
|
+
MUGlobal.breakpoints = ['xs', 'sm', 'md', 'lg', 'xl'];
|
|
@@ -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,52 +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
|
-
// Half
|
|
29
|
-
//const halfMargin = MUGlobal.half(margin);
|
|
30
|
-
//const nMargin = MUGlobal.reverse(margin);
|
|
31
|
-
const calculateMargin = () => {
|
|
32
|
-
if (typeof margin === 'function')
|
|
33
|
-
return margin();
|
|
34
|
-
if (Array.isArray(margin)) {
|
|
35
|
-
const marginValue = margin[0];
|
|
36
|
-
const isNarrow = margin[1];
|
|
37
|
-
const nMargin = MUGlobal.reverse(marginValue);
|
|
38
|
-
const half = MUGlobal.half(marginValue);
|
|
39
|
-
if (isNarrow) {
|
|
40
|
-
const nHalf = MUGlobal.reverse(half);
|
|
41
|
-
return {
|
|
42
|
-
marginLeft: nHalf,
|
|
43
|
-
marginRight: nHalf,
|
|
44
|
-
marginTop: half,
|
|
45
|
-
marginBottom: half
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
return {
|
|
50
|
-
marginLeft: nMargin,
|
|
51
|
-
marginRight: nMargin,
|
|
52
|
-
marginTop: half,
|
|
53
|
-
marginBottom: half
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
const half = MUGlobal.half(margin);
|
|
58
|
-
return {
|
|
59
|
-
marginLeft: margin,
|
|
60
|
-
marginRight: margin,
|
|
61
|
-
marginTop: half,
|
|
62
|
-
marginBottom: half
|
|
63
|
-
};
|
|
64
|
-
};
|
|
65
27
|
return (React.createElement(Card, { sx: {
|
|
66
|
-
height:
|
|
67
|
-
...
|
|
28
|
+
height: itemHeight,
|
|
29
|
+
...margins
|
|
68
30
|
} },
|
|
69
31
|
React.createElement(CardHeader, { sx: { paddingBottom: 0.5 }, action: Array.isArray(actions) ? (React.createElement(MoreFab, { iconButton: true, size: "small", anchorOrigin: {
|
|
70
32
|
vertical: 'bottom',
|
|
@@ -98,5 +60,7 @@ export function MobileListItemRenderer({ data, itemHeight }, margin, renderer) {
|
|
|
98
60
|
}
|
|
99
61
|
}
|
|
100
62
|
} })) : (actions), title: title, titleTypographyProps: { variant: 'body2' }, subheader: subheader, subheaderTypographyProps: { variant: 'caption' } }),
|
|
101
|
-
React.createElement(CardContent, { sx: {
|
|
63
|
+
React.createElement(CardContent, { sx: {
|
|
64
|
+
paddingTop: 0
|
|
65
|
+
} }, children)));
|
|
102
66
|
}
|
|
@@ -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)
|
|
@@ -82,17 +113,53 @@ export function ScrollerListEx(props) {
|
|
|
82
113
|
};
|
|
83
114
|
// Destruct
|
|
84
115
|
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;
|
|
116
|
+
const [itemHeight, space, margins] = calculateItemSize(itemProps.index);
|
|
88
117
|
return defaultItemRenderer({
|
|
89
118
|
itemHeight,
|
|
90
119
|
innerItemRenderer,
|
|
91
120
|
onMouseDown,
|
|
121
|
+
space,
|
|
122
|
+
margins,
|
|
92
123
|
selected: isSelected(itemProps.data),
|
|
93
124
|
...itemProps
|
|
94
125
|
});
|
|
95
126
|
}, onSelectChange, selectedColor = '#edf4fb', ...rest } = props;
|
|
127
|
+
// Theme
|
|
128
|
+
const theme = useTheme();
|
|
129
|
+
// Cache calculation
|
|
130
|
+
const itemSizeResult = React.useMemo(() => {
|
|
131
|
+
if (typeof itemSize === 'function')
|
|
132
|
+
return undefined;
|
|
133
|
+
const [size, spaces, isNarrow] = itemSize;
|
|
134
|
+
if (typeof spaces === 'number')
|
|
135
|
+
return [
|
|
136
|
+
size,
|
|
137
|
+
spaces,
|
|
138
|
+
defaultMargin(MUGlobal.pagePaddings, undefined)
|
|
139
|
+
];
|
|
140
|
+
return [
|
|
141
|
+
size,
|
|
142
|
+
MUGlobal.getSpace(spaces, theme),
|
|
143
|
+
defaultMargin(spaces, isNarrow)
|
|
144
|
+
];
|
|
145
|
+
}, [itemSize]);
|
|
146
|
+
// Calculate size
|
|
147
|
+
const calculateItemSize = (index) => {
|
|
148
|
+
// Callback function
|
|
149
|
+
if (typeof itemSize === 'function') {
|
|
150
|
+
const result = itemSize(index);
|
|
151
|
+
if (result.length == 2)
|
|
152
|
+
return [...result, defaultMargin(MUGlobal.pagePaddings)];
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
// Calculation
|
|
156
|
+
return itemSizeResult;
|
|
157
|
+
};
|
|
158
|
+
// Local item size
|
|
159
|
+
const itemSizeLocal = (index) => {
|
|
160
|
+
const [size, space] = calculateItemSize(index);
|
|
161
|
+
return size + space;
|
|
162
|
+
};
|
|
96
163
|
// Layout
|
|
97
|
-
return (React.createElement(ScrollerList, { className: Utils.mergeClasses('ScrollerListEx-Body', className, createGridStyle(alternatingColors, selectedColor)), itemKey: itemKey, itemRenderer: itemRenderer, itemSize:
|
|
164
|
+
return (React.createElement(ScrollerList, { className: Utils.mergeClasses('ScrollerListEx-Body', className, createGridStyle(alternatingColors, selectedColor)), itemKey: itemKey, itemRenderer: itemRenderer, itemSize: itemSizeLocal, ...rest }));
|
|
98
165
|
}
|
|
@@ -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,37 @@ export class MUGlobal {
|
|
|
125
126
|
return newObj;
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Break points defined
|
|
131
|
+
*/
|
|
132
|
+
static breakpoints = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get multple medias theme space
|
|
136
|
+
* Responsive values and Breakpoints as an object
|
|
137
|
+
* xs = theme.breakpoints.up('xs')
|
|
138
|
+
* https://mui.com/system/basics/
|
|
139
|
+
* @param spaces Spaces
|
|
140
|
+
* @param theme Theme
|
|
141
|
+
* @returns Result
|
|
142
|
+
*/
|
|
143
|
+
static getSpace(spaces: {}, theme: Theme) {
|
|
144
|
+
const start = this.breakpoints.length - 1;
|
|
145
|
+
for (let i = start; i >= 0; i--) {
|
|
146
|
+
const key = this.breakpoints[i];
|
|
147
|
+
const value = Reflect.get(spaces, key);
|
|
148
|
+
if (typeof value === 'number') {
|
|
149
|
+
const mediaRaw = theme.breakpoints.up(key as Breakpoint);
|
|
150
|
+
const mediaQuery = mediaRaw.substring(mediaRaw.indexOf('('));
|
|
151
|
+
if (window.matchMedia(mediaQuery).matches) {
|
|
152
|
+
return parseInt(theme.spacing(value), 10);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
128
160
|
/**
|
|
129
161
|
* Update object number properties with theme
|
|
130
162
|
* @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,49 +38,11 @@ export function MobileListItemRenderer<T>(
|
|
|
47
38
|
// Elements
|
|
48
39
|
const [title, subheader, actions, children] = renderer(data);
|
|
49
40
|
|
|
50
|
-
// Half
|
|
51
|
-
//const halfMargin = MUGlobal.half(margin);
|
|
52
|
-
//const nMargin = MUGlobal.reverse(margin);
|
|
53
|
-
const calculateMargin = () => {
|
|
54
|
-
if (typeof margin === 'function') return margin();
|
|
55
|
-
if (Array.isArray(margin)) {
|
|
56
|
-
const marginValue = margin[0];
|
|
57
|
-
const isNarrow = margin[1];
|
|
58
|
-
const nMargin = MUGlobal.reverse(marginValue);
|
|
59
|
-
const half = MUGlobal.half(marginValue);
|
|
60
|
-
if (isNarrow) {
|
|
61
|
-
const nHalf = MUGlobal.reverse(half);
|
|
62
|
-
return {
|
|
63
|
-
marginLeft: nHalf,
|
|
64
|
-
marginRight: nHalf,
|
|
65
|
-
marginTop: half,
|
|
66
|
-
marginBottom: half
|
|
67
|
-
};
|
|
68
|
-
} else {
|
|
69
|
-
return {
|
|
70
|
-
marginLeft: nMargin,
|
|
71
|
-
marginRight: nMargin,
|
|
72
|
-
marginTop: half,
|
|
73
|
-
marginBottom: half
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const half = MUGlobal.half(margin);
|
|
79
|
-
return {
|
|
80
|
-
marginLeft: margin,
|
|
81
|
-
marginRight: margin,
|
|
82
|
-
marginTop: half,
|
|
83
|
-
marginBottom: half
|
|
84
|
-
};
|
|
85
|
-
};
|
|
86
|
-
|
|
87
41
|
return (
|
|
88
42
|
<Card
|
|
89
43
|
sx={{
|
|
90
|
-
height:
|
|
91
|
-
|
|
92
|
-
...calculateMargin()
|
|
44
|
+
height: itemHeight,
|
|
45
|
+
...margins
|
|
93
46
|
}}
|
|
94
47
|
>
|
|
95
48
|
<CardHeader
|
|
@@ -145,7 +98,13 @@ export function MobileListItemRenderer<T>(
|
|
|
145
98
|
subheader={subheader}
|
|
146
99
|
subheaderTypographyProps={{ variant: 'caption' }}
|
|
147
100
|
/>
|
|
148
|
-
<CardContent
|
|
101
|
+
<CardContent
|
|
102
|
+
sx={{
|
|
103
|
+
paddingTop: 0
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
{children}
|
|
107
|
+
</CardContent>
|
|
149
108
|
</Card>
|
|
150
109
|
);
|
|
151
110
|
}
|
|
@@ -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}`;
|
|
@@ -202,14 +275,15 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
|
|
|
202
275
|
itemKey = (index: number, data: T) =>
|
|
203
276
|
DataTypes.getIdValue(data, idField) ?? index,
|
|
204
277
|
itemRenderer = (itemProps) => {
|
|
205
|
-
const itemHeight =
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
: itemSize;
|
|
278
|
+
const [itemHeight, space, margins] = calculateItemSize(
|
|
279
|
+
itemProps.index
|
|
280
|
+
);
|
|
209
281
|
return defaultItemRenderer({
|
|
210
282
|
itemHeight,
|
|
211
283
|
innerItemRenderer,
|
|
212
284
|
onMouseDown,
|
|
285
|
+
space,
|
|
286
|
+
margins,
|
|
213
287
|
selected: isSelected(itemProps.data),
|
|
214
288
|
...itemProps
|
|
215
289
|
});
|
|
@@ -219,6 +293,49 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
|
|
|
219
293
|
...rest
|
|
220
294
|
} = props;
|
|
221
295
|
|
|
296
|
+
// Theme
|
|
297
|
+
const theme = useTheme();
|
|
298
|
+
|
|
299
|
+
// Cache calculation
|
|
300
|
+
const itemSizeResult = React.useMemo(():
|
|
301
|
+
| [number, number, {}]
|
|
302
|
+
| undefined => {
|
|
303
|
+
if (typeof itemSize === 'function') return undefined;
|
|
304
|
+
const [size, spaces, isNarrow] = itemSize;
|
|
305
|
+
if (typeof spaces === 'number')
|
|
306
|
+
return [
|
|
307
|
+
size,
|
|
308
|
+
spaces,
|
|
309
|
+
defaultMargin(MUGlobal.pagePaddings, undefined)
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
return [
|
|
313
|
+
size,
|
|
314
|
+
MUGlobal.getSpace(spaces, theme),
|
|
315
|
+
defaultMargin(spaces, isNarrow)
|
|
316
|
+
];
|
|
317
|
+
}, [itemSize]);
|
|
318
|
+
|
|
319
|
+
// Calculate size
|
|
320
|
+
const calculateItemSize = (index: number): [number, number, {}] => {
|
|
321
|
+
// Callback function
|
|
322
|
+
if (typeof itemSize === 'function') {
|
|
323
|
+
const result = itemSize(index);
|
|
324
|
+
if (result.length == 2)
|
|
325
|
+
return [...result, defaultMargin(MUGlobal.pagePaddings)];
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Calculation
|
|
330
|
+
return itemSizeResult!;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// Local item size
|
|
334
|
+
const itemSizeLocal = (index: number) => {
|
|
335
|
+
const [size, space] = calculateItemSize(index);
|
|
336
|
+
return size + space;
|
|
337
|
+
};
|
|
338
|
+
|
|
222
339
|
// Layout
|
|
223
340
|
return (
|
|
224
341
|
<ScrollerList<T>
|
|
@@ -229,7 +346,7 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
|
|
|
229
346
|
)}
|
|
230
347
|
itemKey={itemKey}
|
|
231
348
|
itemRenderer={itemRenderer}
|
|
232
|
-
itemSize={
|
|
349
|
+
itemSize={itemSizeLocal}
|
|
233
350
|
{...rest}
|
|
234
351
|
/>
|
|
235
352
|
);
|
|
@@ -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
|