@etsoo/materialui 1.0.1

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.
Files changed (250) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.json +38 -0
  3. package/.gitattributes +2 -0
  4. package/.github/workflows/main.yml +48 -0
  5. package/.prettierignore +5 -0
  6. package/.prettierrc +6 -0
  7. package/LICENSE +21 -0
  8. package/README.md +16 -0
  9. package/__tests__/ComboBox.tsx +30 -0
  10. package/__tests__/MUGlobalTests.tsx +58 -0
  11. package/__tests__/NotifierMUTests.tsx +217 -0
  12. package/__tests__/SelectEx.tsx +26 -0
  13. package/__tests__/tsconfig.json +19 -0
  14. package/babel.config.json +11 -0
  15. package/lib/AuditDisplay.d.ts +33 -0
  16. package/lib/AuditDisplay.js +52 -0
  17. package/lib/AutocompleteExtendedProps.d.ts +64 -0
  18. package/lib/AutocompleteExtendedProps.js +1 -0
  19. package/lib/BackButton.d.ts +13 -0
  20. package/lib/BackButton.js +33 -0
  21. package/lib/BridgeCloseButton.d.ts +23 -0
  22. package/lib/BridgeCloseButton.js +32 -0
  23. package/lib/ButtonLink.d.ts +17 -0
  24. package/lib/ButtonLink.js +19 -0
  25. package/lib/ComboBox.d.ts +38 -0
  26. package/lib/ComboBox.js +108 -0
  27. package/lib/CountdownButton.d.ts +23 -0
  28. package/lib/CountdownButton.js +81 -0
  29. package/lib/CustomFabProps.d.ts +27 -0
  30. package/lib/CustomFabProps.js +1 -0
  31. package/lib/DataGridEx.d.ts +94 -0
  32. package/lib/DataGridEx.js +329 -0
  33. package/lib/DataGridRenderers.d.ts +22 -0
  34. package/lib/DataGridRenderers.js +99 -0
  35. package/lib/DialogButton.d.ts +54 -0
  36. package/lib/DialogButton.js +45 -0
  37. package/lib/DnDList.d.ts +87 -0
  38. package/lib/DnDList.js +153 -0
  39. package/lib/DraggablePaperComponent.d.ts +8 -0
  40. package/lib/DraggablePaperComponent.js +12 -0
  41. package/lib/EmailInput.d.ts +11 -0
  42. package/lib/EmailInput.js +15 -0
  43. package/lib/FabBox.d.ts +21 -0
  44. package/lib/FabBox.js +31 -0
  45. package/lib/FlexBox.d.ts +14 -0
  46. package/lib/FlexBox.js +18 -0
  47. package/lib/GridDataFormat.d.ts +10 -0
  48. package/lib/GridDataFormat.js +43 -0
  49. package/lib/IconButtonLink.d.ts +17 -0
  50. package/lib/IconButtonLink.js +16 -0
  51. package/lib/InputField.d.ts +21 -0
  52. package/lib/InputField.js +39 -0
  53. package/lib/ItemList.d.ts +56 -0
  54. package/lib/ItemList.js +69 -0
  55. package/lib/ListItemRightIcon.d.ts +4 -0
  56. package/lib/ListItemRightIcon.js +8 -0
  57. package/lib/ListMoreDisplay.d.ts +35 -0
  58. package/lib/ListMoreDisplay.js +99 -0
  59. package/lib/LoadingButton.d.ts +16 -0
  60. package/lib/LoadingButton.js +41 -0
  61. package/lib/MUGlobal.d.ts +102 -0
  62. package/lib/MUGlobal.js +184 -0
  63. package/lib/MaskInput.d.ts +34 -0
  64. package/lib/MaskInput.js +43 -0
  65. package/lib/MobileListItemRenderer.d.ts +17 -0
  66. package/lib/MobileListItemRenderer.js +35 -0
  67. package/lib/MoreFab.d.ts +45 -0
  68. package/lib/MoreFab.js +95 -0
  69. package/lib/NotifierMU.d.ts +47 -0
  70. package/lib/NotifierMU.js +387 -0
  71. package/lib/NotifierPromptProps.d.ts +22 -0
  72. package/lib/NotifierPromptProps.js +1 -0
  73. package/lib/OptionGroup.d.ts +58 -0
  74. package/lib/OptionGroup.js +81 -0
  75. package/lib/PList.d.ts +15 -0
  76. package/lib/PList.js +12 -0
  77. package/lib/ProgressCount.d.ts +44 -0
  78. package/lib/ProgressCount.js +79 -0
  79. package/lib/PullToRefreshUI.d.ts +9 -0
  80. package/lib/PullToRefreshUI.js +18 -0
  81. package/lib/RLink.d.ts +14 -0
  82. package/lib/RLink.js +37 -0
  83. package/lib/ResponsibleContainer.d.ts +87 -0
  84. package/lib/ResponsibleContainer.js +156 -0
  85. package/lib/ScrollTopFab.d.ts +7 -0
  86. package/lib/ScrollTopFab.js +25 -0
  87. package/lib/ScrollerListEx.d.ts +81 -0
  88. package/lib/ScrollerListEx.js +167 -0
  89. package/lib/SearchBar.d.ts +29 -0
  90. package/lib/SearchBar.js +260 -0
  91. package/lib/SearchField.d.ts +21 -0
  92. package/lib/SearchField.js +39 -0
  93. package/lib/SearchOptionGroup.d.ts +9 -0
  94. package/lib/SearchOptionGroup.js +14 -0
  95. package/lib/SelectBool.d.ts +13 -0
  96. package/lib/SelectBool.js +22 -0
  97. package/lib/SelectEx.d.ts +50 -0
  98. package/lib/SelectEx.js +156 -0
  99. package/lib/ShowDataComparison.d.ts +20 -0
  100. package/lib/ShowDataComparison.js +58 -0
  101. package/lib/Switch.d.ts +29 -0
  102. package/lib/Switch.js +34 -0
  103. package/lib/SwitchAnt.d.ts +25 -0
  104. package/lib/SwitchAnt.js +40 -0
  105. package/lib/TabBox.d.ts +54 -0
  106. package/lib/TabBox.js +31 -0
  107. package/lib/TableEx.d.ts +65 -0
  108. package/lib/TableEx.js +270 -0
  109. package/lib/TextFieldEx.d.ts +101 -0
  110. package/lib/TextFieldEx.js +126 -0
  111. package/lib/Tiplist.d.ts +18 -0
  112. package/lib/Tiplist.js +157 -0
  113. package/lib/TooltipClick.d.ts +15 -0
  114. package/lib/TooltipClick.js +40 -0
  115. package/lib/UserAvatar.d.ts +24 -0
  116. package/lib/UserAvatar.js +25 -0
  117. package/lib/UserAvatarEditor.d.ts +53 -0
  118. package/lib/UserAvatarEditor.js +129 -0
  119. package/lib/app/CommonApp.d.ts +38 -0
  120. package/lib/app/CommonApp.js +149 -0
  121. package/lib/app/IServiceAppSettings.d.ts +11 -0
  122. package/lib/app/IServiceAppSettings.js +1 -0
  123. package/lib/app/IServicePage.d.ts +6 -0
  124. package/lib/app/IServicePage.js +1 -0
  125. package/lib/app/IServiceUser.d.ts +14 -0
  126. package/lib/app/IServiceUser.js +1 -0
  127. package/lib/app/ISmartERPUser.d.ts +14 -0
  128. package/lib/app/ISmartERPUser.js +1 -0
  129. package/lib/app/Labels.d.ts +65 -0
  130. package/lib/app/Labels.js +62 -0
  131. package/lib/app/ReactApp.d.ts +195 -0
  132. package/lib/app/ReactApp.js +296 -0
  133. package/lib/app/ServiceApp.d.ts +78 -0
  134. package/lib/app/ServiceApp.js +244 -0
  135. package/lib/index.d.ts +74 -0
  136. package/lib/index.js +74 -0
  137. package/lib/pages/CommonPage.d.ts +11 -0
  138. package/lib/pages/CommonPage.js +60 -0
  139. package/lib/pages/CommonPageProps.d.ts +59 -0
  140. package/lib/pages/CommonPageProps.js +1 -0
  141. package/lib/pages/DataGridPage.d.ts +9 -0
  142. package/lib/pages/DataGridPage.js +79 -0
  143. package/lib/pages/DataGridPageProps.d.ts +17 -0
  144. package/lib/pages/DataGridPageProps.js +1 -0
  145. package/lib/pages/EditPage.d.ts +33 -0
  146. package/lib/pages/EditPage.js +29 -0
  147. package/lib/pages/FixedListPage.d.ts +15 -0
  148. package/lib/pages/FixedListPage.js +70 -0
  149. package/lib/pages/ListPage.d.ts +9 -0
  150. package/lib/pages/ListPage.js +50 -0
  151. package/lib/pages/ListPageProps.d.ts +7 -0
  152. package/lib/pages/ListPageProps.js +1 -0
  153. package/lib/pages/ResponsivePage.d.ts +9 -0
  154. package/lib/pages/ResponsivePage.js +45 -0
  155. package/lib/pages/ResponsivePageProps.d.ts +39 -0
  156. package/lib/pages/ResponsivePageProps.js +1 -0
  157. package/lib/pages/SearchPageProps.d.ts +30 -0
  158. package/lib/pages/SearchPageProps.js +1 -0
  159. package/lib/pages/TablePage.d.ts +9 -0
  160. package/lib/pages/TablePage.js +69 -0
  161. package/lib/pages/TablePageProps.d.ts +7 -0
  162. package/lib/pages/TablePageProps.js +1 -0
  163. package/lib/pages/ViewPage.d.ts +66 -0
  164. package/lib/pages/ViewPage.js +105 -0
  165. package/lib/texts/DateText.d.ts +34 -0
  166. package/lib/texts/DateText.js +25 -0
  167. package/lib/texts/MoneyText.d.ts +21 -0
  168. package/lib/texts/MoneyText.js +14 -0
  169. package/lib/texts/NumberText.d.ts +25 -0
  170. package/lib/texts/NumberText.js +14 -0
  171. package/package.json +97 -0
  172. package/src/AuditDisplay.tsx +114 -0
  173. package/src/AutocompleteExtendedProps.ts +83 -0
  174. package/src/BackButton.tsx +55 -0
  175. package/src/BridgeCloseButton.tsx +69 -0
  176. package/src/ButtonLink.tsx +32 -0
  177. package/src/ComboBox.tsx +251 -0
  178. package/src/CountdownButton.tsx +119 -0
  179. package/src/CustomFabProps.ts +32 -0
  180. package/src/DataGridEx.tsx +713 -0
  181. package/src/DataGridRenderers.tsx +140 -0
  182. package/src/DialogButton.tsx +163 -0
  183. package/src/DnDList.tsx +344 -0
  184. package/src/DraggablePaperComponent.tsx +19 -0
  185. package/src/EmailInput.tsx +24 -0
  186. package/src/FabBox.tsx +51 -0
  187. package/src/FlexBox.tsx +20 -0
  188. package/src/GridDataFormat.tsx +77 -0
  189. package/src/IconButtonLink.tsx +29 -0
  190. package/src/InputField.tsx +82 -0
  191. package/src/ItemList.tsx +204 -0
  192. package/src/ListItemRightIcon.tsx +9 -0
  193. package/src/ListMoreDisplay.tsx +205 -0
  194. package/src/LoadingButton.tsx +75 -0
  195. package/src/MUGlobal.ts +220 -0
  196. package/src/MaskInput.tsx +107 -0
  197. package/src/MobileListItemRenderer.tsx +79 -0
  198. package/src/MoreFab.tsx +211 -0
  199. package/src/NotifierMU.tsx +654 -0
  200. package/src/NotifierPromptProps.ts +24 -0
  201. package/src/OptionGroup.tsx +223 -0
  202. package/src/PList.tsx +27 -0
  203. package/src/ProgressCount.tsx +166 -0
  204. package/src/PullToRefreshUI.tsx +21 -0
  205. package/src/RLink.tsx +64 -0
  206. package/src/ResponsibleContainer.tsx +394 -0
  207. package/src/ScrollTopFab.tsx +34 -0
  208. package/src/ScrollerListEx.tsx +387 -0
  209. package/src/SearchBar.tsx +396 -0
  210. package/src/SearchField.tsx +82 -0
  211. package/src/SearchOptionGroup.tsx +31 -0
  212. package/src/SelectBool.tsx +33 -0
  213. package/src/SelectEx.tsx +290 -0
  214. package/src/ShowDataComparison.tsx +106 -0
  215. package/src/Switch.tsx +94 -0
  216. package/src/SwitchAnt.tsx +95 -0
  217. package/src/TabBox.tsx +118 -0
  218. package/src/TableEx.tsx +558 -0
  219. package/src/TextFieldEx.tsx +249 -0
  220. package/src/Tiplist.tsx +303 -0
  221. package/src/TooltipClick.tsx +84 -0
  222. package/src/UserAvatar.tsx +64 -0
  223. package/src/UserAvatarEditor.tsx +287 -0
  224. package/src/app/CommonApp.ts +223 -0
  225. package/src/app/IServiceAppSettings.ts +13 -0
  226. package/src/app/IServicePage.ts +6 -0
  227. package/src/app/IServiceUser.ts +17 -0
  228. package/src/app/ISmartERPUser.ts +16 -0
  229. package/src/app/Labels.ts +77 -0
  230. package/src/app/ReactApp.ts +504 -0
  231. package/src/app/ServiceApp.ts +352 -0
  232. package/src/index.ts +77 -0
  233. package/src/pages/CommonPage.tsx +128 -0
  234. package/src/pages/CommonPageProps.ts +70 -0
  235. package/src/pages/DataGridPage.tsx +140 -0
  236. package/src/pages/DataGridPageProps.ts +24 -0
  237. package/src/pages/EditPage.tsx +114 -0
  238. package/src/pages/FixedListPage.tsx +141 -0
  239. package/src/pages/ListPage.tsx +90 -0
  240. package/src/pages/ListPageProps.ts +12 -0
  241. package/src/pages/ResponsivePage.tsx +68 -0
  242. package/src/pages/ResponsivePageProps.ts +57 -0
  243. package/src/pages/SearchPageProps.ts +39 -0
  244. package/src/pages/TablePage.tsx +126 -0
  245. package/src/pages/TablePageProps.ts +12 -0
  246. package/src/pages/ViewPage.tsx +282 -0
  247. package/src/texts/DateText.tsx +74 -0
  248. package/src/texts/MoneyText.tsx +49 -0
  249. package/src/texts/NumberText.tsx +40 -0
  250. package/tsconfig.json +19 -0
@@ -0,0 +1,713 @@
1
+ import { css } from '@emotion/css';
2
+ import {
3
+ GridAlignGet,
4
+ GridCellFormatterProps,
5
+ GridCellRendererProps,
6
+ GridColumn,
7
+ GridHeaderCellRendererProps,
8
+ GridLoaderStates,
9
+ ScrollerGrid,
10
+ ScrollerGridForwardRef,
11
+ ScrollerGridItemRendererProps,
12
+ ScrollerGridProps,
13
+ useCombinedRefs
14
+ } from '@etsoo/react';
15
+ import { DataTypes, IdDefaultType, Utils } from '@etsoo/shared';
16
+ import {
17
+ Box,
18
+ BoxProps,
19
+ Checkbox,
20
+ Paper,
21
+ TableSortLabel,
22
+ useTheme
23
+ } from '@mui/material';
24
+ import React from 'react';
25
+ import { DataGridRenderers } from './DataGridRenderers';
26
+ import { MouseEventWithDataHandler } from './MUGlobal';
27
+
28
+ /**
29
+ * Footer item renderer props
30
+ */
31
+ export type DataGridExFooterItemRendererProps<T extends object> = {
32
+ column: GridColumn<T>;
33
+ index: number;
34
+ states: GridLoaderStates<T>;
35
+ cellProps: any;
36
+ checkable: boolean;
37
+ };
38
+
39
+ /**
40
+ * Extended DataGrid with VariableSizeGrid props
41
+ */
42
+ export type DataGridExProps<
43
+ T extends object,
44
+ D extends DataTypes.Keys<T>
45
+ > = Omit<
46
+ ScrollerGridProps<T, D>,
47
+ 'itemRenderer' | 'columnCount' | 'columnWidth' | 'width'
48
+ > & {
49
+ /**
50
+ * Alternating colors for odd/even rows
51
+ */
52
+ alternatingColors?: [string?, string?];
53
+
54
+ /**
55
+ * Checkable to choose multiple items
56
+ * @default false
57
+ */
58
+ checkable?: boolean;
59
+
60
+ /**
61
+ * Rows count to have the bottom border
62
+ */
63
+ borderRowsCount?: number;
64
+
65
+ /**
66
+ * Bottom height
67
+ */
68
+ bottomHeight?: number;
69
+
70
+ /**
71
+ * Columns
72
+ */
73
+ columns: GridColumn<T>[];
74
+
75
+ /**
76
+ * Footer item renderer
77
+ */
78
+ footerItemRenderer?: (
79
+ rows: T[],
80
+ props: DataGridExFooterItemRendererProps<T>
81
+ ) => React.ReactNode;
82
+
83
+ /**
84
+ * Header height
85
+ * @default 56
86
+ */
87
+ headerHeight?: number;
88
+
89
+ /**
90
+ * Hide the footer
91
+ * @default false
92
+ */
93
+ hideFooter?: boolean;
94
+
95
+ /**
96
+ * Hover color
97
+ */
98
+ hoverColor?: string;
99
+
100
+ /**
101
+ * Double click handler
102
+ */
103
+ onDoubleClick?: MouseEventWithDataHandler<T>;
104
+
105
+ /**
106
+ * Click handler
107
+ */
108
+ onClick?: MouseEventWithDataHandler<T>;
109
+
110
+ /**
111
+ * Selectable to support hover over and out effect and row clickable
112
+ * @default true
113
+ */
114
+ selectable?: boolean;
115
+
116
+ /**
117
+ * Selected color
118
+ */
119
+ selectedColor?: string;
120
+
121
+ /**
122
+ * Width
123
+ */
124
+ width?: number;
125
+ };
126
+
127
+ // Borders
128
+ const boldBorder = '2px solid rgba(224, 224, 224, 1)';
129
+ const thinBorder = '1px solid rgba(224, 224, 224, 1)';
130
+
131
+ // Scroll bar size
132
+ const scrollbarSize = 16;
133
+
134
+ // Minimum width
135
+ const minWidth = 120;
136
+
137
+ const createGridStyle = (
138
+ alternatingColors: [string?, string?],
139
+ selectedColor: string,
140
+ hoverColor: string
141
+ ) => {
142
+ return css({
143
+ '.DataGridEx-Selected': {
144
+ backgroundColor: selectedColor
145
+ },
146
+ '.DataGridEx-Hover:not(.DataGridEx-Selected)': {
147
+ backgroundColor: hoverColor
148
+ },
149
+ '& .DataGridEx-Cell0:not(.DataGridEx-Hover):not(.DataGridEx-Selected)':
150
+ {
151
+ backgroundColor: alternatingColors[0]
152
+ },
153
+ '& .DataGridEx-Cell1:not(.DataGridEx-Hover):not(.DataGridEx-Selected)':
154
+ {
155
+ backgroundColor: alternatingColors[1]
156
+ },
157
+ '& .DataGridEx-Cell-Border': {
158
+ borderBottom: thinBorder
159
+ }
160
+ });
161
+ };
162
+
163
+ const rowItems = (
164
+ div: HTMLDivElement,
165
+ callback: (div: HTMLDivElement) => void
166
+ ) => {
167
+ const row = div.dataset['row'];
168
+ if (div.parentElement == null || row == null) return;
169
+ doRowItems(div.parentElement, parseFloat(row), callback);
170
+ };
171
+
172
+ const doRowItems = (
173
+ parent: HTMLElement,
174
+ rowIndex: number,
175
+ callback: (div: HTMLDivElement) => void
176
+ ) => {
177
+ if (parent == null || rowIndex == null) return;
178
+
179
+ parent
180
+ ?.querySelectorAll<HTMLDivElement>(`div[data-row="${rowIndex}"]`)
181
+ .forEach((rowItem) => {
182
+ callback(rowItem);
183
+ });
184
+ };
185
+
186
+ /**
187
+ * Extended datagrid columns calculation
188
+ * @param columns
189
+ * @returns Total width and unset items
190
+ */
191
+ export function DataGridExCalColumns<T>(columns: GridColumn<T>[]) {
192
+ return columns.reduce<{ total: number; unset: number }>(
193
+ (previousValue, currentItem) => {
194
+ previousValue.total +=
195
+ currentItem.width ?? currentItem.minWidth ?? minWidth;
196
+ if (currentItem.width == null) previousValue.unset++;
197
+ return previousValue;
198
+ },
199
+ {
200
+ total: 0,
201
+ unset: 0
202
+ }
203
+ );
204
+ }
205
+
206
+ /**
207
+ * Extended DataGrid with VariableSizeGrid
208
+ * @param props Props
209
+ * @returns Component
210
+ */
211
+ export function DataGridEx<
212
+ T extends object,
213
+ D extends DataTypes.Keys<T> = IdDefaultType<T>
214
+ >(props: DataGridExProps<T, D>) {
215
+ // Theme
216
+ const theme = useTheme();
217
+
218
+ const defaultHeaderRenderer = (states: GridLoaderStates<T>) => {
219
+ const { orderBy } = states;
220
+ return (
221
+ <Box
222
+ className="DataGridEx-Header"
223
+ display="flex"
224
+ alignItems="center"
225
+ borderBottom={boldBorder}
226
+ fontWeight={500}
227
+ minWidth={widthCalculator.total}
228
+ height={headerHeight}
229
+ >
230
+ {columns.map((column, index) => {
231
+ // Destruct
232
+ const {
233
+ align,
234
+ field,
235
+ header,
236
+ headerCellRenderer,
237
+ sortable,
238
+ sortAsc = true,
239
+ type
240
+ } = column;
241
+
242
+ // Header text
243
+ const headerText = header ?? field;
244
+
245
+ // Cell props
246
+ const cellProps: BoxProps = {};
247
+
248
+ // Sortable
249
+ let sortLabel: React.ReactNode;
250
+ if (headerCellRenderer) {
251
+ sortLabel = headerCellRenderer({
252
+ cellProps,
253
+ column,
254
+ columnIndex: checkable ? index - 1 : index, // Ignore the checkbox case,
255
+ states
256
+ });
257
+ } else if (sortable && field != null) {
258
+ const active = orderBy === field;
259
+
260
+ sortLabel = (
261
+ <TableSortLabel
262
+ active={active}
263
+ direction={sortAsc ? 'asc' : 'desc'}
264
+ onClick={(_event) => {
265
+ if (active) column.sortAsc = !sortAsc;
266
+
267
+ handleSort(field, column.sortAsc);
268
+ }}
269
+ >
270
+ {headerText}
271
+ </TableSortLabel>
272
+ );
273
+ } else {
274
+ sortLabel = headerText;
275
+ }
276
+
277
+ return (
278
+ <Box
279
+ key={field ?? index.toString()}
280
+ textAlign={GridAlignGet(align, type)}
281
+ width={columnWidth(index)}
282
+ >
283
+ <Box
284
+ className="DataGridEx-Cell"
285
+ onMouseEnter={handleMouseEnter}
286
+ {...cellProps}
287
+ >
288
+ {sortLabel}
289
+ </Box>
290
+ </Box>
291
+ );
292
+ })}
293
+ </Box>
294
+ );
295
+ };
296
+
297
+ function defaultFooterRenderer(rows: T[], states: GridLoaderStates<T>) {
298
+ return (
299
+ <Box
300
+ className="DataGridEx-Footer"
301
+ display="flex"
302
+ alignItems="center"
303
+ borderTop={thinBorder}
304
+ marginTop="1px"
305
+ minWidth={widthCalculator.total}
306
+ height={bottomHeight - 1}
307
+ >
308
+ {columns.map((column, index) => {
309
+ // Destruct
310
+ const { align, field, type } = column;
311
+
312
+ // Cell props
313
+ const cellProps: BoxProps = {};
314
+
315
+ // Cell
316
+ const cell = footerItemRenderer
317
+ ? footerItemRenderer(rows, {
318
+ column,
319
+ index: checkable ? index - 1 : index, // Ignore the checkbox case
320
+ states,
321
+ cellProps,
322
+ checkable
323
+ })
324
+ : undefined;
325
+
326
+ return (
327
+ <Box
328
+ key={'bottom-' + (field ?? index.toString())}
329
+ textAlign={GridAlignGet(align, type)}
330
+ width={columnWidth(index)}
331
+ >
332
+ <Box
333
+ className="DataGridEx-Cell"
334
+ onMouseEnter={handleMouseEnter}
335
+ {...cellProps}
336
+ >
337
+ {cell}
338
+ </Box>
339
+ </Box>
340
+ );
341
+ })}
342
+ </Box>
343
+ );
344
+ }
345
+
346
+ // Destruct
347
+ const {
348
+ alternatingColors = [theme.palette.grey[100], undefined],
349
+ borderRowsCount,
350
+ bottomHeight = 53,
351
+ checkable = false,
352
+ className,
353
+ columns,
354
+ defaultOrderBy,
355
+ height,
356
+ headerHeight = 56,
357
+ headerRenderer = defaultHeaderRenderer,
358
+ footerRenderer = defaultFooterRenderer,
359
+ footerItemRenderer = DataGridRenderers.defaultFooterItemRenderer,
360
+ hideFooter = false,
361
+ hoverColor = '#f6f9fb',
362
+ idField = 'id' as D,
363
+ mRef = React.createRef(),
364
+ onClick,
365
+ onDoubleClick,
366
+ selectable = true,
367
+ selectedColor = '#edf4fb',
368
+ width,
369
+ ...rest
370
+ } = props;
371
+
372
+ if (checkable) {
373
+ const cbColumn: GridColumn<T> = {
374
+ field: 'selected' as any, // Avoid validation from data model
375
+ header: '',
376
+ sortable: false,
377
+ width: 50,
378
+ cellRenderer: ({
379
+ cellProps,
380
+ data,
381
+ selected
382
+ }: GridCellRendererProps<T, BoxProps>) => {
383
+ cellProps.sx = {
384
+ padding: '4px!important'
385
+ };
386
+
387
+ return (
388
+ <Checkbox
389
+ color="primary"
390
+ checked={selected}
391
+ onChange={(_event, checked) => {
392
+ refs.current.ref?.selectItem(data, checked);
393
+ }}
394
+ />
395
+ );
396
+ },
397
+ headerCellRenderer: ({
398
+ cellProps,
399
+ states
400
+ }: GridHeaderCellRendererProps<T, BoxProps>) => {
401
+ // 2 = border height
402
+ const hpad = (headerHeight - 42) / 2;
403
+ cellProps.sx = {
404
+ padding: `${hpad}px 4px ${hpad - 1}px 4px!important`
405
+ };
406
+
407
+ return (
408
+ <Checkbox
409
+ color="primary"
410
+ indeterminate={
411
+ states.selectedItems.length > 0 &&
412
+ states.selectedItems.length < states.loadedItems
413
+ }
414
+ checked={states.selectedItems.length > 0}
415
+ onChange={(_event, checked) =>
416
+ refs.current.ref?.selectAll(checked)
417
+ }
418
+ />
419
+ );
420
+ }
421
+ };
422
+
423
+ // Update to the latest version
424
+ if (columns[0].field === 'selected') {
425
+ columns[0] = cbColumn;
426
+ } else {
427
+ columns.unshift(cbColumn);
428
+ }
429
+ }
430
+
431
+ const refs = React.useRef<{ ref?: ScrollerGridForwardRef<T> }>({});
432
+
433
+ const mRefLocal = useCombinedRefs(
434
+ mRef,
435
+ (ref: ScrollerGridForwardRef<T>) => {
436
+ if (ref == null) return;
437
+ refs.current.ref = ref;
438
+ }
439
+ );
440
+
441
+ // New sort
442
+ const handleSort = (field: string, asc?: boolean) => {
443
+ reset({ orderBy: field, orderByAsc: asc });
444
+ };
445
+
446
+ // Reset
447
+ const reset = (add: object) => {
448
+ refs.current.ref?.reset(add);
449
+ };
450
+
451
+ // Show hover tooltip for trucated text
452
+ const handleMouseEnter = (event: React.MouseEvent<HTMLDivElement>) => {
453
+ const div = event.currentTarget;
454
+ const { innerText, offsetWidth, scrollWidth } = div;
455
+ if (offsetWidth < scrollWidth) {
456
+ div.title = innerText;
457
+ } else {
458
+ div.title = '';
459
+ }
460
+ };
461
+
462
+ // selectedRowIndex state
463
+ const selectedRowIndex = React.useRef(-1);
464
+
465
+ const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
466
+ const div = event.currentTarget;
467
+ const row = div.dataset['row'];
468
+ if (div.parentElement == null || row == null) return;
469
+
470
+ const rowIndex = parseFloat(row);
471
+
472
+ // No change
473
+ if (isNaN(rowIndex) || rowIndex === selectedRowIndex.current) return;
474
+
475
+ if (selectedRowIndex.current != -1) {
476
+ doRowItems(
477
+ div.parentElement,
478
+ selectedRowIndex.current,
479
+ (preDiv) => {
480
+ preDiv.classList.remove('DataGridEx-Selected');
481
+ }
482
+ );
483
+ }
484
+
485
+ rowItems(div, (currentDiv) => {
486
+ currentDiv.classList.add('DataGridEx-Selected');
487
+ });
488
+
489
+ selectedRowIndex.current = rowIndex;
490
+ };
491
+
492
+ const handleMouseOver = (event: React.MouseEvent<HTMLDivElement>) => {
493
+ rowItems(event.currentTarget, (div) => {
494
+ div.classList.add('DataGridEx-Hover');
495
+ });
496
+ };
497
+
498
+ const handleMouseOut = (event: React.MouseEvent<HTMLDivElement>) => {
499
+ rowItems(event.currentTarget, (div) => {
500
+ div.classList.remove('DataGridEx-Hover');
501
+ });
502
+ };
503
+
504
+ /**
505
+ * Item renderer
506
+ */
507
+ const itemRenderer = ({
508
+ columnIndex,
509
+ rowIndex,
510
+ style,
511
+ data,
512
+ selectedItems
513
+ }: ScrollerGridItemRendererProps<T>) => {
514
+ // Column
515
+ const {
516
+ align,
517
+ cellRenderer = DataGridRenderers.defaultCellRenderer,
518
+ field,
519
+ type,
520
+ valueFormatter,
521
+ renderProps
522
+ } = columns[columnIndex];
523
+
524
+ // Props
525
+ const formatProps: GridCellFormatterProps<T> = {
526
+ data,
527
+ field,
528
+ rowIndex,
529
+ columnIndex
530
+ };
531
+
532
+ let rowClass = `DataGridEx-Cell${rowIndex % 2}`;
533
+ if (
534
+ borderRowsCount != null &&
535
+ borderRowsCount > 0 &&
536
+ (rowIndex + 1) % borderRowsCount === 0
537
+ ) {
538
+ rowClass += ` DataGridEx-Cell-Border`;
539
+ }
540
+
541
+ // Selected
542
+ const selected =
543
+ data != null &&
544
+ (selectedRowIndex.current === rowIndex ||
545
+ selectedItems.some(
546
+ (selectedItem) =>
547
+ selectedItem != null &&
548
+ selectedItem[idField] === data[idField]
549
+ ));
550
+
551
+ if (selected) {
552
+ rowClass += ` DataGridEx-Selected`;
553
+ }
554
+
555
+ const cellProps: BoxProps = {
556
+ className: 'DataGridEx-Cell',
557
+ textAlign: GridAlignGet(align, type)
558
+ };
559
+
560
+ const child = cellRenderer({
561
+ data,
562
+ field,
563
+ formattedValue: valueFormatter
564
+ ? valueFormatter(formatProps)
565
+ : undefined,
566
+ selected,
567
+ type,
568
+ rowIndex,
569
+ columnIndex,
570
+ cellProps,
571
+ renderProps
572
+ });
573
+
574
+ return (
575
+ <div
576
+ className={rowClass}
577
+ style={style}
578
+ data-row={rowIndex}
579
+ data-column={columnIndex}
580
+ onMouseDown={
581
+ selectable && !checkable ? handleMouseDown : undefined
582
+ }
583
+ onMouseOver={selectable ? handleMouseOver : undefined}
584
+ onMouseOut={selectable ? handleMouseOut : undefined}
585
+ onClick={(event) =>
586
+ onClick && data != null && onClick(event, data)
587
+ }
588
+ onDoubleClick={(event) =>
589
+ onDoubleClick && data != null && onDoubleClick(event, data)
590
+ }
591
+ >
592
+ <Box {...cellProps} onMouseEnter={handleMouseEnter}>
593
+ {child}
594
+ </Box>
595
+ </div>
596
+ );
597
+ };
598
+
599
+ // Column width calculator
600
+ const widthCalculator = React.useMemo(
601
+ () => DataGridExCalColumns(columns),
602
+ [columns]
603
+ );
604
+
605
+ // Column width
606
+ const columnWidth = React.useCallback(
607
+ (index: number) => {
608
+ // Ignore null case
609
+ if (width == null) return 0;
610
+
611
+ // Column
612
+ const column = columns[index];
613
+ if (column.width != null) return column.width;
614
+
615
+ // More space
616
+ const leftWidth =
617
+ width -
618
+ widthCalculator.total -
619
+ (width < 800 ? 0 : scrollbarSize);
620
+
621
+ // Shared width
622
+ const sharedWidth =
623
+ leftWidth > 0 ? leftWidth / widthCalculator.unset : 0;
624
+
625
+ return (column.minWidth || minWidth) + sharedWidth;
626
+ },
627
+ [columns, width]
628
+ );
629
+
630
+ // Table
631
+ const table = React.useMemo(() => {
632
+ const defaultOrderByAsc = defaultOrderBy
633
+ ? columns.find((column) => column.field === defaultOrderBy)?.sortAsc
634
+ : undefined;
635
+
636
+ return (
637
+ <ScrollerGrid<T, D>
638
+ className={Utils.mergeClasses(
639
+ 'DataGridEx-Body',
640
+ 'DataGridEx-CustomBar',
641
+ className,
642
+ createGridStyle(
643
+ alternatingColors,
644
+ selectedColor,
645
+ hoverColor
646
+ )
647
+ )}
648
+ columnCount={columns.length}
649
+ columnWidth={columnWidth}
650
+ defaultOrderBy={defaultOrderBy}
651
+ defaultOrderByAsc={defaultOrderByAsc}
652
+ height={
653
+ height -
654
+ headerHeight -
655
+ (hideFooter ? 0 : bottomHeight + 1) -
656
+ scrollbarSize
657
+ }
658
+ headerRenderer={headerRenderer}
659
+ idField={idField}
660
+ itemRenderer={itemRenderer}
661
+ footerRenderer={hideFooter ? undefined : footerRenderer}
662
+ width={Math.max(width ?? 0, widthCalculator.total)}
663
+ mRef={mRefLocal}
664
+ {...rest}
665
+ />
666
+ );
667
+ }, [width]);
668
+
669
+ return (
670
+ <Paper
671
+ sx={{
672
+ fontSize: '0.875rem',
673
+ height,
674
+ '& .DataGridEx-Cell': {
675
+ padding: 2,
676
+ whiteSpace: 'nowrap',
677
+ overflow: 'hidden',
678
+ textOverflow: 'ellipsis'
679
+ },
680
+ '& .DataGridEx-CustomBar': {
681
+ '@media (min-width: 800px)': {
682
+ '::-webkit-scrollbar': {
683
+ width: scrollbarSize,
684
+ height: scrollbarSize,
685
+ backgroundColor: '#f6f6f6'
686
+ },
687
+ '::-webkit-scrollbar-thumb': {
688
+ backgroundColor: 'rgba(0,0,0,0.4)',
689
+ borderRadius: '2px'
690
+ },
691
+ '::-webkit-scrollbar-track-piece:start': {
692
+ background: 'transparent'
693
+ },
694
+ '::-webkit-scrollbar-track-piece:end': {
695
+ background: 'transparent'
696
+ }
697
+ }
698
+ }
699
+ }}
700
+ >
701
+ <div
702
+ className="DataGridEx-CustomBar"
703
+ style={{
704
+ width,
705
+ overflowX: 'auto',
706
+ overflowY: 'hidden'
707
+ }}
708
+ >
709
+ {table}
710
+ </div>
711
+ </Paper>
712
+ );
713
+ }