@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,81 @@
1
+ import { ScrollerListProps } from '@etsoo/react';
2
+ import { DataTypes, IdDefaultType } from '@etsoo/shared';
3
+ import React from 'react';
4
+ import { ListChildComponentProps } from 'react-window';
5
+ import { MouseEventWithDataHandler } from './MUGlobal';
6
+ /**
7
+ * Extended ScrollerList inner item renderer props
8
+ */
9
+ export interface ScrollerListExInnerItemRendererProps<T> extends ListChildComponentProps<T> {
10
+ /**
11
+ * Item selected
12
+ */
13
+ selected: boolean;
14
+ /**
15
+ * Item height
16
+ */
17
+ itemHeight: number;
18
+ /**
19
+ * Item space
20
+ */
21
+ space: number;
22
+ /**
23
+ * Default margins
24
+ */
25
+ margins: object;
26
+ }
27
+ /**
28
+ * Extended ScrollerList ItemSize type
29
+ * 1. Callback function
30
+ * 2. Static sets
31
+ * 3. Dynamic calculation
32
+ */
33
+ export declare type ScrollerListExItemSize = ((index: number) => [number, number] | [number, number, object]) | [number, number] | [number, object, boolean?];
34
+ /**
35
+ * Extended ScrollerList Props
36
+ */
37
+ export declare type ScrollerListExProps<T extends object, D extends DataTypes.Keys<T>> = Omit<ScrollerListProps<T>, 'itemRenderer' | 'itemSize'> & {
38
+ /**
39
+ * Alternating colors for odd/even rows
40
+ */
41
+ alternatingColors?: [string?, string?];
42
+ /**
43
+ * Inner item renderer
44
+ */
45
+ innerItemRenderer: (props: ScrollerListExInnerItemRendererProps<T>) => React.ReactNode;
46
+ /**
47
+ * Item renderer
48
+ */
49
+ itemRenderer?: (props: ListChildComponentProps<T>) => React.ReactElement;
50
+ /**
51
+ * Id field
52
+ * Failed: D extends { id: DataTypes.IdType } ? { idField?: D } : { idField: D }
53
+ */
54
+ idField?: D;
55
+ /**
56
+ * Item size, a function indicates its a variable size list
57
+ */
58
+ itemSize: ScrollerListExItemSize;
59
+ /**
60
+ * Double click handler
61
+ */
62
+ onDoubleClick?: MouseEventWithDataHandler<T>;
63
+ /**
64
+ * Click handler
65
+ */
66
+ onClick?: MouseEventWithDataHandler<T>;
67
+ /**
68
+ * On items select change
69
+ */
70
+ onSelectChange?: (selectedItems: T[]) => void;
71
+ /**
72
+ * Selected color
73
+ */
74
+ selectedColor?: string;
75
+ };
76
+ /**
77
+ * Extended ScrollerList
78
+ * @param props Props
79
+ * @returns Component
80
+ */
81
+ export declare function ScrollerListEx<T extends object, D extends DataTypes.Keys<T> = IdDefaultType<T>>(props: ScrollerListExProps<T, D>): JSX.Element;
@@ -0,0 +1,167 @@
1
+ import { css } from '@emotion/css';
2
+ import { ScrollerList } from '@etsoo/react';
3
+ import { DataTypes, Utils } from '@etsoo/shared';
4
+ import { useTheme } from '@mui/material';
5
+ import React from 'react';
6
+ import { MUGlobal } from './MUGlobal';
7
+ // Scroll bar size
8
+ const scrollbarSize = 16;
9
+ // Selected class name
10
+ const selectedClassName = 'ScrollerListEx-Selected';
11
+ const createGridStyle = (alternatingColors, selectedColor) => {
12
+ return css({
13
+ '& .ScrollerListEx-Selected': {
14
+ backgroundColor: selectedColor
15
+ },
16
+ '& .ScrollerListEx-Row0:not(.ScrollerListEx-Selected)': {
17
+ backgroundColor: alternatingColors[0]
18
+ },
19
+ '& .ScrollerListEx-Row1:not(.ScrollerListEx-Selected)': {
20
+ backgroundColor: alternatingColors[1]
21
+ },
22
+ '@media (min-width: 800px)': {
23
+ '::-webkit-scrollbar': {
24
+ width: scrollbarSize,
25
+ height: scrollbarSize,
26
+ backgroundColor: '#f6f6f6'
27
+ },
28
+ '::-webkit-scrollbar-thumb': {
29
+ backgroundColor: 'rgba(0,0,0,0.4)',
30
+ borderRadius: '2px'
31
+ },
32
+ '::-webkit-scrollbar-track-piece:start': {
33
+ background: 'transparent'
34
+ },
35
+ '::-webkit-scrollbar-track-piece:end': {
36
+ background: 'transparent'
37
+ }
38
+ }
39
+ });
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
+ };
68
+ // Default itemRenderer
69
+ function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, selected, style, itemHeight, onClick, onDoubleClick, space, margins }) {
70
+ // Child
71
+ const child = innerItemRenderer({
72
+ index,
73
+ data,
74
+ style,
75
+ selected,
76
+ itemHeight,
77
+ space,
78
+ margins
79
+ });
80
+ let rowClass = `ScrollerListEx-Row${index % 2}`;
81
+ if (selected)
82
+ rowClass += ` ${selectedClassName}`;
83
+ // Layout
84
+ return (React.createElement("div", { className: rowClass, style: style, onMouseDown: (event) => onMouseDown(event.currentTarget, data), onClick: (event) => onClick && onClick(event, data), onDoubleClick: (event) => onDoubleClick && onDoubleClick(event, data) }, child));
85
+ }
86
+ /**
87
+ * Extended ScrollerList
88
+ * @param props Props
89
+ * @returns Component
90
+ */
91
+ export function ScrollerListEx(props) {
92
+ // Selected item ref
93
+ const selectedItem = React.useRef();
94
+ const onMouseDown = (div, data) => {
95
+ var _a;
96
+ // Destruct
97
+ const [selectedDiv, selectedData] = (_a = selectedItem.current) !== null && _a !== void 0 ? _a : [];
98
+ if (selectedData != null && selectedData[idField] === data[idField])
99
+ return;
100
+ selectedDiv === null || selectedDiv === void 0 ? void 0 : selectedDiv.classList.remove(selectedClassName);
101
+ div.classList.add(selectedClassName);
102
+ selectedItem.current = [div, data];
103
+ if (onSelectChange)
104
+ onSelectChange([data]);
105
+ };
106
+ const isSelected = (data) => {
107
+ var _a;
108
+ const [_, selectedData] = (_a = selectedItem.current) !== null && _a !== void 0 ? _a : [];
109
+ const selected = selectedData && data && selectedData[idField] === data[idField]
110
+ ? true
111
+ : false;
112
+ return selected;
113
+ };
114
+ // Destruct
115
+ const { alternatingColors = [undefined, undefined], className, idField = 'id', innerItemRenderer, itemSize, itemKey = (index, data) => { var _a; return (_a = DataTypes.getIdValue1(data, idField)) !== null && _a !== void 0 ? _a : index; }, itemRenderer = (itemProps) => {
116
+ const [itemHeight, space, margins] = calculateItemSize(itemProps.index);
117
+ return defaultItemRenderer({
118
+ itemHeight,
119
+ innerItemRenderer,
120
+ onMouseDown,
121
+ onClick,
122
+ onDoubleClick,
123
+ space,
124
+ margins,
125
+ selected: isSelected(itemProps.data),
126
+ ...itemProps
127
+ });
128
+ }, onClick, onDoubleClick, onSelectChange, selectedColor = '#edf4fb', ...rest } = props;
129
+ // Theme
130
+ const theme = useTheme();
131
+ // Cache calculation
132
+ const itemSizeResult = React.useMemo(() => {
133
+ if (typeof itemSize === 'function')
134
+ return undefined;
135
+ const [size, spaces, isNarrow] = itemSize;
136
+ if (typeof spaces === 'number')
137
+ return [
138
+ size,
139
+ spaces,
140
+ defaultMargin(MUGlobal.pagePaddings, undefined)
141
+ ];
142
+ return [
143
+ size,
144
+ MUGlobal.getSpace(spaces, theme),
145
+ defaultMargin(spaces, isNarrow)
146
+ ];
147
+ }, [itemSize]);
148
+ // Calculate size
149
+ const calculateItemSize = (index) => {
150
+ // Callback function
151
+ if (typeof itemSize === 'function') {
152
+ const result = itemSize(index);
153
+ if (result.length == 2)
154
+ return [...result, defaultMargin(MUGlobal.pagePaddings)];
155
+ return result;
156
+ }
157
+ // Calculation
158
+ return itemSizeResult;
159
+ };
160
+ // Local item size
161
+ const itemSizeLocal = (index) => {
162
+ const [size, space] = calculateItemSize(index);
163
+ return size + space;
164
+ };
165
+ // Layout
166
+ return (React.createElement(ScrollerList, { className: Utils.mergeClasses('ScrollerListEx-Body', className, createGridStyle(alternatingColors, selectedColor)), itemKey: itemKey, itemRenderer: itemRenderer, itemSize: itemSizeLocal, ...rest }));
167
+ }
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ /**
3
+ * Search bar props
4
+ */
5
+ export interface SearchBarProps {
6
+ /**
7
+ * Style class name
8
+ */
9
+ className?: string;
10
+ /**
11
+ * Fields
12
+ */
13
+ fields: React.ReactElement[];
14
+ /**
15
+ * Inner height
16
+ * @default 40
17
+ */
18
+ innerHeight?: number;
19
+ /**
20
+ * On submit callback
21
+ */
22
+ onSubmit: (data: FormData, reset: boolean) => void | PromiseLike<void>;
23
+ }
24
+ /**
25
+ * Search bar
26
+ * @param props Props
27
+ * @returns Component
28
+ */
29
+ export declare function SearchBar(props: SearchBarProps): JSX.Element;
@@ -0,0 +1,260 @@
1
+ import { Button, Drawer, IconButton, Stack, useTheme } from '@mui/material';
2
+ import React from 'react';
3
+ import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
4
+ import { DomUtils } from '@etsoo/shared';
5
+ import { ReactUtils, useDelayedExecutor, useDimensions } from '@etsoo/react';
6
+ import { Labels } from './app/Labels';
7
+ // Cached width attribute name
8
+ const cachedWidthName = 'data-cached-width';
9
+ // Reset form
10
+ const resetForm = (form) => {
11
+ for (const input of form.elements) {
12
+ // Ignore disabled inputs
13
+ if ('disabled' in input && input.disabled)
14
+ continue;
15
+ // All non hidden inputs
16
+ if (input instanceof HTMLInputElement) {
17
+ // Ignore hidden input
18
+ if (input.type === 'hidden')
19
+ continue;
20
+ // Ignore readOnly without data-reset=true inputs
21
+ if (!input.readOnly || input.dataset.reset === 'true') {
22
+ ReactUtils.triggerChange(input, '', true);
23
+ }
24
+ continue;
25
+ }
26
+ // All selects
27
+ if (input instanceof HTMLSelectElement) {
28
+ if (input.options.length > 0 && input.options[0].value === '') {
29
+ input.selectedIndex = 0;
30
+ }
31
+ else {
32
+ input.selectedIndex = -1;
33
+ }
34
+ continue;
35
+ }
36
+ }
37
+ // Trigger reset event
38
+ const resetEvent = new Event('reset');
39
+ form.dispatchEvent(resetEvent);
40
+ };
41
+ // Disable inputs avoid auto trigger change events for them
42
+ const setChildState = (child, enabled) => {
43
+ const inputs = child.getElementsByTagName('input');
44
+ for (const input of inputs) {
45
+ input.disabled = !enabled;
46
+ }
47
+ };
48
+ /**
49
+ * Search bar
50
+ * @param props Props
51
+ * @returns Component
52
+ */
53
+ export function SearchBar(props) {
54
+ // Destruct
55
+ const { className, fields, innerHeight = 40, onSubmit } = props;
56
+ // Labels
57
+ const labels = Labels.CommonPage;
58
+ // Spacing
59
+ const theme = useTheme();
60
+ const gap = parseFloat(theme.spacing(1));
61
+ // Menu index
62
+ const [index, updateIndex] = React.useState();
63
+ // Drawer open / close
64
+ const [open, updateOpen] = React.useState(false);
65
+ // State
66
+ const state = React.useRef({ hasMore: true, lastMaxWidth: 9999 }).current;
67
+ // Watch container
68
+ const { dimensions } = useDimensions(1, (target, rect) => {
69
+ // Same logic from resetButtonRef
70
+ if (rect.width === state.lastMaxWidth ||
71
+ (!state.hasMore && rect.width > state.lastMaxWidth))
72
+ return false;
73
+ // Len
74
+ const len = target.children.length;
75
+ for (let i = 0; i < len; i++) {
76
+ var classList = target.children[i].classList;
77
+ classList.remove('showChild');
78
+ }
79
+ }, 0);
80
+ // Show or hide element
81
+ const setElementVisible = (element, visible) => {
82
+ element.classList.remove(visible ? 'hiddenChild' : 'showChild');
83
+ element.classList.add(visible ? 'showChild' : 'hiddenChild');
84
+ };
85
+ // Reset button ref
86
+ const resetButtonRef = (instance) => {
87
+ // Reset button
88
+ const resetButton = instance;
89
+ if (resetButton == null)
90
+ return;
91
+ // First
92
+ const [_, container, containerRect] = dimensions[0];
93
+ if (container == null ||
94
+ containerRect == null ||
95
+ containerRect.width < 10)
96
+ return;
97
+ // Container width
98
+ let maxWidth = containerRect.width;
99
+ if (maxWidth === state.lastMaxWidth ||
100
+ (!state.hasMore && maxWidth > state.lastMaxWidth)) {
101
+ return;
102
+ }
103
+ state.lastMaxWidth = maxWidth;
104
+ // More button
105
+ const buttonMore = resetButton.previousElementSibling;
106
+ // Cached button width
107
+ const cachedButtonWidth = container.getAttribute(cachedWidthName);
108
+ if (cachedButtonWidth) {
109
+ maxWidth -= Number.parseFloat(cachedButtonWidth);
110
+ }
111
+ else {
112
+ // Reset button rect
113
+ const resetButtonRect = resetButton.getBoundingClientRect();
114
+ // More button rect
115
+ const buttonMoreRect = buttonMore.getBoundingClientRect();
116
+ // Total
117
+ const totalButtonWidth = resetButtonRect.width + buttonMoreRect.width + 3 * gap;
118
+ // Cache
119
+ container.setAttribute(cachedWidthName, totalButtonWidth.toString());
120
+ maxWidth -= totalButtonWidth;
121
+ }
122
+ // Children
123
+ const children = container.children;
124
+ // Len
125
+ const len = children.length;
126
+ // Other elements
127
+ const others = len - 2;
128
+ let hasMore = false;
129
+ let newIndex = others;
130
+ for (let c = 0; c < others; c++) {
131
+ const child = children[c];
132
+ const cachedWidth = child.getAttribute(cachedWidthName);
133
+ let childWidth;
134
+ if (cachedWidth) {
135
+ childWidth = Number.parseFloat(cachedWidth);
136
+ }
137
+ else {
138
+ const childD = child.getBoundingClientRect();
139
+ childWidth = childD.width + gap;
140
+ child.setAttribute(cachedWidthName, childWidth.toString());
141
+ }
142
+ // No gap here, child width includes the gap
143
+ if (childWidth <= maxWidth) {
144
+ maxWidth -= childWidth;
145
+ setChildState(child, true);
146
+ setElementVisible(child, true);
147
+ }
148
+ else {
149
+ setChildState(child, false);
150
+ setElementVisible(child, false);
151
+ if (!hasMore) {
152
+ // Make sure coming logic to the block
153
+ maxWidth = 0;
154
+ // Keep the current index
155
+ newIndex = c;
156
+ // Indicates more
157
+ hasMore = true;
158
+ }
159
+ }
160
+ }
161
+ // Show or hide more button
162
+ state.hasMore = hasMore;
163
+ setElementVisible(buttonMore, hasMore);
164
+ setElementVisible(resetButton, true);
165
+ // Update menu start index
166
+ updateIndex(newIndex);
167
+ };
168
+ // More items creator
169
+ const moreItems = [];
170
+ if (index != null) {
171
+ for (let i = index; i < fields.length; i++) {
172
+ moreItems.push(React.createElement(React.Fragment, { key: i }, fields[i]));
173
+ }
174
+ }
175
+ // Handle main form
176
+ const handleForm = (event) => {
177
+ if (event.nativeEvent.cancelable && !event.nativeEvent.composed)
178
+ return;
179
+ if (state.form == null)
180
+ state.form = event.currentTarget;
181
+ delayed.call();
182
+ };
183
+ // Handle more button click
184
+ const handleMore = () => {
185
+ updateOpen(!open);
186
+ };
187
+ // More form change
188
+ const moreFormChange = (event) => {
189
+ if (event.nativeEvent.cancelable && !event.nativeEvent.composed)
190
+ return;
191
+ if (state.moreForm == null)
192
+ state.moreForm = event.currentTarget;
193
+ delayed.call();
194
+ };
195
+ // Submit at once
196
+ const handleSubmitInstant = (reset = false) => {
197
+ // Prepare data
198
+ const data = new FormData(state.form);
199
+ if (state.moreForm != null) {
200
+ DomUtils.mergeFormData(data, new FormData(state.moreForm));
201
+ }
202
+ onSubmit(data, reset);
203
+ };
204
+ const delayed = useDelayedExecutor(handleSubmitInstant, 480);
205
+ // Reset
206
+ const handleReset = () => {
207
+ // Clear form values
208
+ if (state.form != null)
209
+ resetForm(state.form);
210
+ if (state.moreForm != null)
211
+ resetForm(state.moreForm);
212
+ // Resubmit
213
+ handleSubmitInstant(true);
214
+ };
215
+ React.useEffect(() => {
216
+ // Delayed way
217
+ delayed.call(100);
218
+ return () => {
219
+ delayed.clear();
220
+ };
221
+ }, [className]);
222
+ // Layout
223
+ return (React.createElement(React.Fragment, null,
224
+ React.createElement("form", { id: "SearchBarForm", className: className, onChange: handleForm, ref: (form) => {
225
+ if (form)
226
+ state.form = form;
227
+ } },
228
+ React.createElement(Stack, { ref: dimensions[0][0], justifyContent: "center", alignItems: "center", direction: "row", spacing: 1, height: innerHeight, sx: {
229
+ '& > :not(style)': {
230
+ flexBasis: 'auto',
231
+ flexGrow: 0,
232
+ flexShrink: 0,
233
+ maxWidth: '180px',
234
+ visibility: 'hidden'
235
+ },
236
+ '& > .hiddenChild': {
237
+ display: 'none'
238
+ },
239
+ '& > .showChild': {
240
+ display: 'block',
241
+ visibility: 'visible'
242
+ }
243
+ } },
244
+ fields.map((item, index) => (React.createElement(React.Fragment, { key: index }, item))),
245
+ React.createElement(IconButton, { "aria-label": "delete", size: "medium", onClick: handleMore },
246
+ React.createElement(MoreHorizIcon, null)),
247
+ React.createElement(Button, { variant: "contained", size: "medium", ref: resetButtonRef, onClick: handleReset }, labels.reset))),
248
+ index != null && index < fields.length && (React.createElement(Drawer, { anchor: "right", sx: { minWidth: '250px' }, ModalProps: {
249
+ keepMounted: true // Better open performance on mobile.
250
+ }, open: open, onClose: () => updateOpen(false) },
251
+ React.createElement("form", { onChange: moreFormChange, ref: (form) => {
252
+ if (form)
253
+ state.moreForm = form;
254
+ } },
255
+ React.createElement(Stack, { direction: "column", alignItems: "stretch", spacing: 2, padding: 2, sx: {
256
+ '& > :not(style)': {
257
+ minWidth: '100px'
258
+ }
259
+ } }, moreItems))))));
260
+ }
@@ -0,0 +1,21 @@
1
+ /// <reference types="react" />
2
+ import { TextFieldProps } from '@mui/material';
3
+ /**
4
+ * Search field props
5
+ */
6
+ export declare type SearchFieldProps = TextFieldProps & {
7
+ /**
8
+ * Change delay (ms) to avoid repeatly dispatch onChange
9
+ */
10
+ changeDelay?: number;
11
+ /**
12
+ * Is the field read only?
13
+ */
14
+ readOnly?: boolean;
15
+ };
16
+ /**
17
+ * Search field
18
+ * @param props Props
19
+ * @returns Component
20
+ */
21
+ export declare function SearchField(props: SearchFieldProps): JSX.Element;
@@ -0,0 +1,39 @@
1
+ import { useDelayedExecutor } from '@etsoo/react';
2
+ import { TextField } from '@mui/material';
3
+ import React from 'react';
4
+ import { MUGlobal } from './MUGlobal';
5
+ /**
6
+ * Search field
7
+ * @param props Props
8
+ * @returns Component
9
+ */
10
+ export function SearchField(props) {
11
+ // Destruct
12
+ const { changeDelay, InputLabelProps = {}, InputProps = {}, onChange, readOnly, size = MUGlobal.searchFieldSize, variant = MUGlobal.searchFieldVariant, ...rest } = props;
13
+ // Shrink
14
+ InputLabelProps.shrink = MUGlobal.searchFieldShrink;
15
+ // Read only
16
+ if (readOnly != null)
17
+ InputProps.readOnly = readOnly;
18
+ const isMounted = React.useRef(true);
19
+ const delayed = onChange != null && changeDelay != null && changeDelay >= 1
20
+ ? useDelayedExecutor(onChange, changeDelay)
21
+ : undefined;
22
+ const onChangeEx = (event) => {
23
+ if (onChange == null)
24
+ return;
25
+ if (changeDelay == null || changeDelay < 1) {
26
+ onChange(event);
27
+ return;
28
+ }
29
+ delayed === null || delayed === void 0 ? void 0 : delayed.call(undefined, event);
30
+ };
31
+ React.useEffect(() => {
32
+ return () => {
33
+ isMounted.current = false;
34
+ delayed === null || delayed === void 0 ? void 0 : delayed.clear();
35
+ };
36
+ }, []);
37
+ // Layout
38
+ return (React.createElement(TextField, { InputLabelProps: InputLabelProps, InputProps: InputProps, onChange: onChangeEx, size: size, variant: variant, ...rest }));
39
+ }
@@ -0,0 +1,9 @@
1
+ /// <reference types="react" />
2
+ import { DataTypes, IdDefaultType, LabelDefaultType, ListType } from '@etsoo/shared';
3
+ import { OptionGroupProps } from './OptionGroup';
4
+ /**
5
+ * Search OptionGroup
6
+ * @param props Props
7
+ * @returns Component
8
+ */
9
+ export declare function SearchOptionGroup<T extends object = ListType, D extends DataTypes.Keys<T> = IdDefaultType<T>, L extends DataTypes.Keys<T, string> = LabelDefaultType<T>>(props: OptionGroupProps<T, D, L>): JSX.Element;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { MUGlobal } from './MUGlobal';
3
+ import { OptionGroup } from './OptionGroup';
4
+ /**
5
+ * Search OptionGroup
6
+ * @param props Props
7
+ * @returns Component
8
+ */
9
+ export function SearchOptionGroup(props) {
10
+ // Destruct
11
+ const { row = true, size = MUGlobal.searchFieldSize, sx = { '& .MuiFormLabel-root': { fontSize: '0.75em' } }, ...rest } = props;
12
+ // Layout
13
+ return React.createElement(OptionGroup, { row: row, size: size, sx: sx, ...rest });
14
+ }
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import { ListType1 } from '@etsoo/shared';
3
+ import { SelectExProps } from './SelectEx';
4
+ /**
5
+ * SelectBool props
6
+ */
7
+ export declare type SelectBoolProps = Omit<SelectExProps<ListType1>, 'options' | 'loadData'>;
8
+ /**
9
+ * SelectBool (yes/no)
10
+ * @param props Props
11
+ * @returns Component
12
+ */
13
+ export declare function SelectBool(props: SelectBoolProps): JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { Utils } from '@etsoo/shared';
2
+ import React from 'react';
3
+ import { globalApp } from './app/ReactApp';
4
+ import { SelectEx } from './SelectEx';
5
+ /**
6
+ * SelectBool (yes/no)
7
+ * @param props Props
8
+ * @returns Component
9
+ */
10
+ export function SelectBool(props) {
11
+ // Destruct
12
+ const { search = true, autoAddBlankItem = search, ...rest } = props;
13
+ // Options
14
+ const options = [
15
+ { id: 'false', label: globalApp.get('no') },
16
+ { id: 'true', label: globalApp.get('yes') }
17
+ ];
18
+ if (autoAddBlankItem)
19
+ Utils.addBlankItem(options);
20
+ // Layout
21
+ return React.createElement(SelectEx, { options: options, search: search, ...rest });
22
+ }