@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.
@@ -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
@@ -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>, margin: {} | [{}, boolean] | (() => SxProps<Theme>), renderer: (data: 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 }, margin, renderer) {
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: (theme) => MUGlobal.adjustWithTheme(itemHeight, margin, theme.spacing),
67
- ...calculateMargin()
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: { paddingTop: 0 } }, children)));
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: ((index: number) => number) | number;
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
  */
@@ -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 = typeof itemSize === 'function'
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: itemSize, ...rest }));
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: ((index: number) => number) | number;
26
+ itemSize: ScrollerListExItemSize;
27
27
  /**
28
28
  * Methods
29
29
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.4.36",
3
+ "version": "1.4.40",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -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: (theme) =>
91
- MUGlobal.adjustWithTheme(itemHeight, margin, theme.spacing),
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 sx={{ paddingTop: 0 }}>{children}</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: ((index: number) => number) | number;
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
- typeof itemSize === 'function'
207
- ? itemSize(itemProps.index)
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={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 { ScrollerListExInnerItemRendererProps } from '../ScrollerListEx';
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: ((index: number) => number) | number;
38
+ itemSize: ScrollerListExItemSize;
36
39
 
37
40
  /**
38
41
  * Methods