@etsoo/react 1.4.35 → 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.
@@ -1,3 +1,4 @@
1
+ import { Theme } from '@mui/material';
1
2
  export declare class MUGlobal {
2
3
  /**
3
4
  * Search field shrink
@@ -40,14 +41,20 @@ export declare class MUGlobal {
40
41
  * @returns Updated object
41
42
  */
42
43
  static half(input: {}): {};
44
+ /**
45
+ * Reverse object number properties, like 5 to -5
46
+ * @param input Input object
47
+ * @returns Updated object
48
+ */
49
+ static reverse(input: {}): {};
43
50
  /**
44
51
  * Update object number properties with adjustment
45
52
  * @param input Input object
46
- * @param adjust Adjust value
53
+ * @param adjust Adjust value or new size object
47
54
  * @param field Specific field
48
55
  * @returns Updated object
49
56
  */
50
- static increase(input: {}, adjust: number, field?: string): {};
57
+ static increase(input: {}, adjust: number | {}, field?: string): {};
51
58
  /**
52
59
  * Adjust size with theme update
53
60
  * @param size Base size
@@ -56,6 +63,13 @@ export declare class MUGlobal {
56
63
  * @returns Updated object
57
64
  */
58
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;
59
73
  /**
60
74
  * Update object number properties with theme
61
75
  * @param input Input object
@@ -14,10 +14,24 @@ export class MUGlobal {
14
14
  });
15
15
  return newObj;
16
16
  }
17
+ /**
18
+ * Reverse object number properties, like 5 to -5
19
+ * @param input Input object
20
+ * @returns Updated object
21
+ */
22
+ static reverse(input) {
23
+ const newObj = { ...input };
24
+ Object.entries(newObj).forEach(([key, value]) => {
25
+ if (typeof value === 'number') {
26
+ Reflect.set(newObj, key, -value);
27
+ }
28
+ });
29
+ return newObj;
30
+ }
17
31
  /**
18
32
  * Update object number properties with adjustment
19
33
  * @param input Input object
20
- * @param adjust Adjust value
34
+ * @param adjust Adjust value or new size object
21
35
  * @param field Specific field
22
36
  * @returns Updated object
23
37
  */
@@ -25,8 +39,14 @@ export class MUGlobal {
25
39
  const newObj = { ...input };
26
40
  Object.entries(newObj).forEach(([key, value]) => {
27
41
  if (typeof value === 'number') {
28
- if (field == null || field === key)
29
- Reflect.set(newObj, key, value + adjust);
42
+ if (field == null || field === key) {
43
+ const adjustValue = typeof adjust === 'number'
44
+ ? adjust
45
+ : Reflect.get(adjust, key);
46
+ if (adjustValue == null || typeof adjustValue !== 'number')
47
+ return;
48
+ Reflect.set(newObj, key, value + adjustValue);
49
+ }
30
50
  }
31
51
  });
32
52
  return newObj;
@@ -50,6 +70,25 @@ export class MUGlobal {
50
70
  });
51
71
  return newObj;
52
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
+ }
53
92
  /**
54
93
  * Update object number properties with theme
55
94
  * @param input Input object
@@ -8,7 +8,7 @@ import { ScrollerListExInnerItemRendererProps } from './ScrollerListEx';
8
8
  * @param renderer Renderer for card content
9
9
  * @returns Component
10
10
  */
11
- export declare function MobileListItemRenderer<T>({ data, itemHeight }: ScrollerListExInnerItemRendererProps<T>, margin: {}, renderer: (data: T) => [
11
+ export declare function MobileListItemRenderer<T>({ data, itemHeight, margins }: ScrollerListExInnerItemRendererProps<T>, renderer: (data: T) => [
12
12
  string,
13
13
  string | undefined,
14
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,20 +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
27
  return (React.createElement(Card, { sx: {
31
- height: (theme) => MUGlobal.adjustWithTheme(itemHeight, margin, theme.spacing),
32
- marginLeft: margin,
33
- marginRight: margin,
34
- marginTop: halfMargin,
35
- marginBottom: halfMargin
28
+ height: itemHeight,
29
+ ...margins
36
30
  } },
37
31
  React.createElement(CardHeader, { sx: { paddingBottom: 0.5 }, action: Array.isArray(actions) ? (React.createElement(MoreFab, { iconButton: true, size: "small", anchorOrigin: {
38
32
  vertical: 'bottom',
@@ -66,5 +60,7 @@ export function MobileListItemRenderer({ data, itemHeight }, margin, renderer) {
66
60
  }
67
61
  }
68
62
  } })) : (actions), title: title, titleTypographyProps: { variant: 'body2' }, subheader: subheader, subheaderTypographyProps: { variant: 'caption' } }),
69
- React.createElement(CardContent, { sx: { paddingTop: 0 } }, children)));
63
+ React.createElement(CardContent, { sx: {
64
+ paddingTop: 0
65
+ } }, children)));
70
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)
@@ -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 = typeof itemSize === 'function'
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: itemSize, ...rest }));
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: ((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.35",
3
+ "version": "1.4.39",
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
  /**
@@ -56,19 +57,42 @@ export class MUGlobal {
56
57
  return newObj;
57
58
  }
58
59
 
60
+ /**
61
+ * Reverse object number properties, like 5 to -5
62
+ * @param input Input object
63
+ * @returns Updated object
64
+ */
65
+ static reverse(input: {}) {
66
+ const newObj = { ...input };
67
+ Object.entries(newObj).forEach(([key, value]) => {
68
+ if (typeof value === 'number') {
69
+ Reflect.set(newObj, key, -value);
70
+ }
71
+ });
72
+ return newObj;
73
+ }
74
+
59
75
  /**
60
76
  * Update object number properties with adjustment
61
77
  * @param input Input object
62
- * @param adjust Adjust value
78
+ * @param adjust Adjust value or new size object
63
79
  * @param field Specific field
64
80
  * @returns Updated object
65
81
  */
66
- static increase(input: {}, adjust: number, field?: string) {
82
+ static increase(input: {}, adjust: number | {}, field?: string) {
67
83
  const newObj = { ...input };
68
84
  Object.entries(newObj).forEach(([key, value]) => {
69
85
  if (typeof value === 'number') {
70
- if (field == null || field === key)
71
- Reflect.set(newObj, key, value + adjust);
86
+ if (field == null || field === key) {
87
+ const adjustValue =
88
+ typeof adjust === 'number'
89
+ ? adjust
90
+ : Reflect.get(adjust, key);
91
+ if (adjustValue == null || typeof adjustValue !== 'number')
92
+ return;
93
+
94
+ Reflect.set(newObj, key, value + adjustValue);
95
+ }
72
96
  }
73
97
  });
74
98
  return newObj;
@@ -102,6 +126,28 @@ export class MUGlobal {
102
126
  return newObj;
103
127
  }
104
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
+
105
151
  /**
106
152
  * Update object number properties with theme
107
153
  * @param input Input object
@@ -2,7 +2,6 @@ import { Card, CardContent, CardHeader, LinearProgress } from '@mui/material';
2
2
  import React from 'react';
3
3
  import { ListItemReact } from '../components/ListItemReact';
4
4
  import { MoreFab } from './MoreFab';
5
- import { MUGlobal } from './MUGlobal';
6
5
  import { ScrollerListExInnerItemRendererProps } from './ScrollerListEx';
7
6
 
8
7
  function getActions(input: (ListItemReact | boolean)[]): ListItemReact[] {
@@ -23,8 +22,7 @@ function getActions(input: (ListItemReact | boolean)[]): ListItemReact[] {
23
22
  * @returns Component
24
23
  */
25
24
  export function MobileListItemRenderer<T>(
26
- { data, itemHeight }: ScrollerListExInnerItemRendererProps<T>,
27
- margin: {},
25
+ { data, itemHeight, margins }: ScrollerListExInnerItemRendererProps<T>,
28
26
  renderer: (
29
27
  data: T
30
28
  ) => [
@@ -40,18 +38,11 @@ export function MobileListItemRenderer<T>(
40
38
  // Elements
41
39
  const [title, subheader, actions, children] = renderer(data);
42
40
 
43
- // Half
44
- const halfMargin = MUGlobal.half(margin);
45
-
46
41
  return (
47
42
  <Card
48
43
  sx={{
49
- height: (theme) =>
50
- MUGlobal.adjustWithTheme(itemHeight, margin, theme.spacing),
51
- marginLeft: margin,
52
- marginRight: margin,
53
- marginTop: halfMargin,
54
- marginBottom: halfMargin
44
+ height: itemHeight,
45
+ ...margins
55
46
  }}
56
47
  >
57
48
  <CardHeader
@@ -107,7 +98,13 @@ export function MobileListItemRenderer<T>(
107
98
  subheader={subheader}
108
99
  subheaderTypographyProps={{ variant: 'caption' }}
109
100
  />
110
- <CardContent sx={{ paddingTop: 0 }}>{children}</CardContent>
101
+ <CardContent
102
+ sx={{
103
+ paddingTop: 0
104
+ }}
105
+ >
106
+ {children}
107
+ </CardContent>
111
108
  </Card>
112
109
  );
113
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}`;
@@ -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
- typeof itemSize === 'function'
207
- ? itemSize(itemProps.index)
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={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 { 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