@etsoo/react 1.4.74 → 1.4.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/app/Utils.d.ts +7 -0
- package/lib/app/Utils.js +26 -0
- package/lib/components/GridColumn.d.ts +1 -1
- package/lib/components/ScrollerGrid.d.ts +1 -1
- package/lib/mu/AutocompleteExtendedProps.d.ts +1 -1
- package/lib/mu/ComboBox.d.ts +1 -1
- package/lib/mu/DataGridEx.d.ts +9 -0
- package/lib/mu/DataGridEx.js +2 -2
- package/lib/mu/DnDList.d.ts +1 -1
- package/lib/mu/ItemList.d.ts +2 -2
- package/lib/mu/MUGlobal.d.ts +8 -0
- package/lib/mu/MUGlobal.js +3 -0
- package/lib/mu/MobileListItemRenderer.js +0 -1
- package/lib/mu/OptionGroup.d.ts +2 -2
- package/lib/mu/ResponsibleContainer.d.ts +4 -0
- package/lib/mu/ResponsibleContainer.js +6 -3
- package/lib/mu/ScrollerListEx.d.ts +10 -1
- package/lib/mu/ScrollerListEx.js +5 -3
- package/lib/mu/SelectEx.d.ts +2 -2
- package/lib/mu/SelectEx.js +19 -8
- package/lib/mu/TableEx.d.ts +1 -1
- package/lib/mu/Tiplist.js +3 -1
- package/lib/mu/pages/ResponsivePageProps.d.ts +4 -0
- package/lib/mu/pages/ViewPage.d.ts +1 -1
- package/package.json +2 -2
- package/src/app/Utils.ts +32 -0
- package/src/components/GridColumn.ts +1 -1
- package/src/components/ScrollerGrid.tsx +1 -1
- package/src/mu/AutocompleteExtendedProps.ts +1 -1
- package/src/mu/ComboBox.tsx +1 -1
- package/src/mu/DataGridEx.tsx +19 -0
- package/src/mu/DnDList.tsx +1 -1
- package/src/mu/ItemList.tsx +2 -2
- package/src/mu/MUGlobal.ts +11 -0
- package/src/mu/MobileListItemRenderer.tsx +0 -2
- package/src/mu/OptionGroup.tsx +2 -2
- package/src/mu/ResponsibleContainer.tsx +15 -0
- package/src/mu/ScrollerListEx.tsx +32 -2
- package/src/mu/SelectEx.tsx +24 -14
- package/src/mu/TableEx.tsx +2 -2
- package/src/mu/Tiplist.tsx +7 -1
- package/src/mu/pages/ResponsivePageProps.ts +5 -0
- package/src/mu/pages/ViewPage.tsx +1 -1
package/lib/app/Utils.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
/**
|
|
2
3
|
* React utils
|
|
3
4
|
*/
|
|
@@ -8,6 +9,12 @@ export declare namespace Utils {
|
|
|
8
9
|
* @returns Formatted value
|
|
9
10
|
*/
|
|
10
11
|
function formatInputValue(value: unknown): string | number | any[] | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Is safe click
|
|
14
|
+
* @param event Mouse event
|
|
15
|
+
* @returns Result
|
|
16
|
+
*/
|
|
17
|
+
function isSafeClick(event: React.MouseEvent<HTMLElement>): boolean;
|
|
11
18
|
/**
|
|
12
19
|
* Trigger input change event
|
|
13
20
|
* @param input Form input
|
package/lib/app/Utils.js
CHANGED
|
@@ -20,6 +20,32 @@ export var Utils;
|
|
|
20
20
|
return String(value);
|
|
21
21
|
}
|
|
22
22
|
Utils.formatInputValue = formatInputValue;
|
|
23
|
+
/**
|
|
24
|
+
* Is safe click
|
|
25
|
+
* @param event Mouse event
|
|
26
|
+
* @returns Result
|
|
27
|
+
*/
|
|
28
|
+
function isSafeClick(event) {
|
|
29
|
+
// No target
|
|
30
|
+
// HTMLElement <= Element, SVGElement <= Element
|
|
31
|
+
if (!(event.target instanceof Element))
|
|
32
|
+
return true;
|
|
33
|
+
// Outside of the currentTarget
|
|
34
|
+
let target = event.target;
|
|
35
|
+
if (!event.currentTarget.contains(target))
|
|
36
|
+
return false;
|
|
37
|
+
while (target != null && target != event.currentTarget) {
|
|
38
|
+
const nodeName = target.nodeName.toUpperCase();
|
|
39
|
+
if (nodeName === 'INPUT' ||
|
|
40
|
+
nodeName === 'BUTTON' ||
|
|
41
|
+
nodeName === 'A' ||
|
|
42
|
+
target.hasAttribute('onClick'))
|
|
43
|
+
return false;
|
|
44
|
+
target = target.parentElement;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
Utils.isSafeClick = isSafeClick;
|
|
23
49
|
/**
|
|
24
50
|
* Trigger input change event
|
|
25
51
|
* @param input Form input
|
package/lib/mu/ComboBox.d.ts
CHANGED
package/lib/mu/DataGridEx.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { GridColumn } from '../components/GridColumn';
|
|
3
3
|
import { GridLoaderStates } from '../components/GridLoader';
|
|
4
4
|
import { ScrollerGridProps } from '../components/ScrollerGrid';
|
|
5
|
+
import { MouseEventWithDataHandler } from './MUGlobal';
|
|
5
6
|
/**
|
|
6
7
|
* Footer item renderer props
|
|
7
8
|
*/
|
|
@@ -55,6 +56,14 @@ export interface DataGridExProps<T extends Record<string, any>> extends Omit<Scr
|
|
|
55
56
|
* Hover color
|
|
56
57
|
*/
|
|
57
58
|
hoverColor?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Double click handler
|
|
61
|
+
*/
|
|
62
|
+
onDoubleClick?: MouseEventWithDataHandler<T>;
|
|
63
|
+
/**
|
|
64
|
+
* Click handler
|
|
65
|
+
*/
|
|
66
|
+
onClick?: MouseEventWithDataHandler<T>;
|
|
58
67
|
/**
|
|
59
68
|
* Selectable to support hover over and out effect and row clickable
|
|
60
69
|
* @default true
|
package/lib/mu/DataGridEx.js
CHANGED
|
@@ -126,7 +126,7 @@ export function DataGridEx(props) {
|
|
|
126
126
|
})));
|
|
127
127
|
}
|
|
128
128
|
// Destruct
|
|
129
|
-
const { alternatingColors = [theme.palette.grey[100], undefined], borderRowsCount, bottomHeight = 53, checkable = false, className, columns, defaultOrderBy, height, headerHeight = 56, headerRenderer = defaultHeaderRenderer, footerRenderer = defaultFooterRenderer, footerItemRenderer = DataGridRenderers.defaultFooterItemRenderer, hideFooter = false, hoverColor = '#f6f9fb', idField = 'id', mRef = React.createRef(), selectable = true, selectedColor = '#edf4fb', width, ...rest } = props;
|
|
129
|
+
const { alternatingColors = [theme.palette.grey[100], undefined], borderRowsCount, bottomHeight = 53, checkable = false, className, columns, defaultOrderBy, height, headerHeight = 56, headerRenderer = defaultHeaderRenderer, footerRenderer = defaultFooterRenderer, footerItemRenderer = DataGridRenderers.defaultFooterItemRenderer, hideFooter = false, hoverColor = '#f6f9fb', idField = 'id', mRef = React.createRef(), onClick, onDoubleClick, selectable = true, selectedColor = '#edf4fb', width, ...rest } = props;
|
|
130
130
|
if (checkable) {
|
|
131
131
|
const cbColumn = {
|
|
132
132
|
field: 'selected',
|
|
@@ -261,7 +261,7 @@ export function DataGridEx(props) {
|
|
|
261
261
|
cellProps,
|
|
262
262
|
renderProps
|
|
263
263
|
});
|
|
264
|
-
return (React.createElement("div", { className: rowClass, style: style, "data-row": rowIndex, "data-column": columnIndex, onMouseDown: selectable && !checkable ? handleMouseDown : undefined, onMouseOver: selectable ? handleMouseOver : undefined, onMouseOut: selectable ? handleMouseOut : undefined },
|
|
264
|
+
return (React.createElement("div", { className: rowClass, style: style, "data-row": rowIndex, "data-column": columnIndex, onMouseDown: selectable && !checkable ? handleMouseDown : undefined, onMouseOver: selectable ? handleMouseOver : undefined, onMouseOut: selectable ? handleMouseOut : undefined, onClick: (event) => onClick && data != null && onClick(event, data), onDoubleClick: (event) => onDoubleClick && data != null && onDoubleClick(event, data) },
|
|
265
265
|
React.createElement(Box, { ...cellProps, onMouseEnter: handleMouseEnter }, child)));
|
|
266
266
|
};
|
|
267
267
|
// Column width calculator
|
package/lib/mu/DnDList.d.ts
CHANGED
package/lib/mu/ItemList.d.ts
CHANGED
|
@@ -10,11 +10,11 @@ export interface ItemListProps<T extends Record<string, unknown>> {
|
|
|
10
10
|
/**
|
|
11
11
|
* Id field name
|
|
12
12
|
*/
|
|
13
|
-
idField?: keyof T;
|
|
13
|
+
idField?: string & keyof T;
|
|
14
14
|
/**
|
|
15
15
|
* Label field name or callback
|
|
16
16
|
*/
|
|
17
|
-
labelField?: keyof T | ((item: T) => string);
|
|
17
|
+
labelField?: (string & keyof T) | ((item: T) => string);
|
|
18
18
|
/**
|
|
19
19
|
* Button icon
|
|
20
20
|
*/
|
package/lib/mu/MUGlobal.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import { Theme } from '@mui/material';
|
|
3
|
+
/**
|
|
4
|
+
* Mouse event handler with data
|
|
5
|
+
*/
|
|
6
|
+
export declare type MouseEventWithDataHandler<T> = (event: React.MouseEvent<HTMLDivElement>, data: T) => void;
|
|
7
|
+
/**
|
|
8
|
+
* MUGlobal for global configurations
|
|
9
|
+
*/
|
|
2
10
|
export declare class MUGlobal {
|
|
3
11
|
/**
|
|
4
12
|
* Search field shrink
|
package/lib/mu/MUGlobal.js
CHANGED
|
@@ -22,7 +22,6 @@ export function MobileListItemRenderer({ data, itemHeight, margins }, renderer)
|
|
|
22
22
|
// Loading
|
|
23
23
|
if (data == null)
|
|
24
24
|
return React.createElement(LinearProgress, null);
|
|
25
|
-
console.log('margins', margins);
|
|
26
25
|
// Elements
|
|
27
26
|
const [title, subheader, actions, children, cardActions] = renderer(data);
|
|
28
27
|
return (React.createElement(Card, { sx: {
|
package/lib/mu/OptionGroup.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface OptionGroupProps<T extends Record<string, any> = IdLabelDto, D
|
|
|
17
17
|
/**
|
|
18
18
|
* Id field, default is id
|
|
19
19
|
*/
|
|
20
|
-
idField?: keyof T;
|
|
20
|
+
idField?: string & keyof T;
|
|
21
21
|
/**
|
|
22
22
|
* Label
|
|
23
23
|
*/
|
|
@@ -25,7 +25,7 @@ export interface OptionGroupProps<T extends Record<string, any> = IdLabelDto, D
|
|
|
25
25
|
/**
|
|
26
26
|
* Label field, default is label
|
|
27
27
|
*/
|
|
28
|
-
labelField?: keyof T;
|
|
28
|
+
labelField?: string & keyof T;
|
|
29
29
|
/**
|
|
30
30
|
* Multiple choose item
|
|
31
31
|
*/
|
|
@@ -72,6 +72,10 @@ export interface ResponsibleContainerProps<T extends {}, F extends DataTypes.Bas
|
|
|
72
72
|
* Pull to refresh data
|
|
73
73
|
*/
|
|
74
74
|
pullToRefresh?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Quick action for double click or click under mobile
|
|
77
|
+
*/
|
|
78
|
+
quickAction?: (data: T) => void;
|
|
75
79
|
/**
|
|
76
80
|
* Size ready to read miliseconds span
|
|
77
81
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Box, Stack } from '@mui/material';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Labels } from '../app/Labels';
|
|
4
|
+
import { Utils } from '../app/Utils';
|
|
4
5
|
import { GridDataGet } from '../components/GridLoader';
|
|
5
6
|
import useCombinedRefs from '../uses/useCombinedRefs';
|
|
6
7
|
import { useDimensions } from '../uses/useDimensions';
|
|
@@ -24,7 +25,7 @@ function defaultContainerBoxSx(paddings, hasField, _dataGrid) {
|
|
|
24
25
|
*/
|
|
25
26
|
export function ResponsibleContainer(props) {
|
|
26
27
|
// Destruct
|
|
27
|
-
const { adjustHeight, columns, containerBoxSx = defaultContainerBoxSx, dataGridMinWidth = Math.max(576, DataGridExCalColumns(columns).total), elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal.pagePaddings, pullToRefresh = true, sizeReadyMiliseconds = 0, ...rest } = props;
|
|
28
|
+
const { adjustHeight, columns, containerBoxSx = defaultContainerBoxSx, dataGridMinWidth = Math.max(576, DataGridExCalColumns(columns).total), elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal.pagePaddings, pullToRefresh = true, quickAction, sizeReadyMiliseconds = 0, ...rest } = props;
|
|
28
29
|
// Labels
|
|
29
30
|
const labels = Labels.CommonPage;
|
|
30
31
|
// Refs
|
|
@@ -106,7 +107,7 @@ export function ResponsibleContainer(props) {
|
|
|
106
107
|
delete rest.itemRenderer;
|
|
107
108
|
return [
|
|
108
109
|
React.createElement(Box, { className: "DataGridBox" },
|
|
109
|
-
React.createElement(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, outerRef: (element) => {
|
|
110
|
+
React.createElement(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, onDoubleClick: (_, data) => quickAction && quickAction(data), outerRef: (element) => {
|
|
110
111
|
if (element != null && elementReady)
|
|
111
112
|
elementReady(element, true);
|
|
112
113
|
}, columns: columns, ...rest })),
|
|
@@ -124,7 +125,9 @@ export function ResponsibleContainer(props) {
|
|
|
124
125
|
delete rest.selectable;
|
|
125
126
|
return [
|
|
126
127
|
React.createElement(Box, { className: "ListBox", sx: { height: heightLocal } },
|
|
127
|
-
React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs,
|
|
128
|
+
React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs, onClick: (event, data) => quickAction &&
|
|
129
|
+
Utils.isSafeClick(event) &&
|
|
130
|
+
quickAction(data), oRef: (element) => {
|
|
128
131
|
if (element != null && elementReady)
|
|
129
132
|
elementReady(element, false);
|
|
130
133
|
}, ...rest })),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ListChildComponentProps } from 'react-window';
|
|
3
3
|
import { ScrollerListProps } from '../components/ScrollerList';
|
|
4
|
+
import { MouseEventWithDataHandler } from './MUGlobal';
|
|
4
5
|
/**
|
|
5
6
|
* Extended ScrollerList inner item renderer props
|
|
6
7
|
*/
|
|
@@ -40,7 +41,7 @@ export interface ScrollerListExProps<T> extends Omit<ScrollerListProps<T>, 'item
|
|
|
40
41
|
/**
|
|
41
42
|
* Id field
|
|
42
43
|
*/
|
|
43
|
-
idField?: keyof T;
|
|
44
|
+
idField?: string & keyof T;
|
|
44
45
|
/**
|
|
45
46
|
* Inner item renderer
|
|
46
47
|
*/
|
|
@@ -53,6 +54,14 @@ export interface ScrollerListExProps<T> extends Omit<ScrollerListProps<T>, 'item
|
|
|
53
54
|
* Item size, a function indicates its a variable size list
|
|
54
55
|
*/
|
|
55
56
|
itemSize: ScrollerListExItemSize;
|
|
57
|
+
/**
|
|
58
|
+
* Double click handler
|
|
59
|
+
*/
|
|
60
|
+
onDoubleClick?: MouseEventWithDataHandler<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Click handler
|
|
63
|
+
*/
|
|
64
|
+
onClick?: MouseEventWithDataHandler<T>;
|
|
56
65
|
/**
|
|
57
66
|
* On items select change
|
|
58
67
|
*/
|
package/lib/mu/ScrollerListEx.js
CHANGED
|
@@ -66,7 +66,7 @@ const defaultMargin = (margin, isNarrow) => {
|
|
|
66
66
|
};
|
|
67
67
|
};
|
|
68
68
|
// Default itemRenderer
|
|
69
|
-
function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, selected, style, itemHeight, space, margins }) {
|
|
69
|
+
function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, selected, style, itemHeight, onClick, onDoubleClick, space, margins }) {
|
|
70
70
|
// Child
|
|
71
71
|
const child = innerItemRenderer({
|
|
72
72
|
index,
|
|
@@ -81,7 +81,7 @@ function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, sele
|
|
|
81
81
|
if (selected)
|
|
82
82
|
rowClass += ` ${selectedClassName}`;
|
|
83
83
|
// Layout
|
|
84
|
-
return (React.createElement("div", { className: rowClass, style: style, onMouseDown: (event) => onMouseDown(event.currentTarget, data) }, child));
|
|
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
85
|
}
|
|
86
86
|
/**
|
|
87
87
|
* Extended ScrollerList
|
|
@@ -118,12 +118,14 @@ export function ScrollerListEx(props) {
|
|
|
118
118
|
itemHeight,
|
|
119
119
|
innerItemRenderer,
|
|
120
120
|
onMouseDown,
|
|
121
|
+
onClick,
|
|
122
|
+
onDoubleClick,
|
|
121
123
|
space,
|
|
122
124
|
margins,
|
|
123
125
|
selected: isSelected(itemProps.data),
|
|
124
126
|
...itemProps
|
|
125
127
|
});
|
|
126
|
-
}, onSelectChange, selectedColor = '#edf4fb', ...rest } = props;
|
|
128
|
+
}, onClick, onDoubleClick, onSelectChange, selectedColor = '#edf4fb', ...rest } = props;
|
|
127
129
|
// Theme
|
|
128
130
|
const theme = useTheme();
|
|
129
131
|
// Cache calculation
|
package/lib/mu/SelectEx.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface SelectExProps<T extends {}> extends Omit<SelectProps, 'labelId'
|
|
|
8
8
|
/**
|
|
9
9
|
* Id field, default is id
|
|
10
10
|
*/
|
|
11
|
-
idField?: keyof T;
|
|
11
|
+
idField?: string & keyof T;
|
|
12
12
|
/**
|
|
13
13
|
* Item icon renderer
|
|
14
14
|
*/
|
|
@@ -16,7 +16,7 @@ export interface SelectExProps<T extends {}> extends Omit<SelectProps, 'labelId'
|
|
|
16
16
|
/**
|
|
17
17
|
* Label field, default is label
|
|
18
18
|
*/
|
|
19
|
-
labelField?: ((option: T) => string) | keyof T;
|
|
19
|
+
labelField?: ((option: T) => string) | (string & keyof T);
|
|
20
20
|
/**
|
|
21
21
|
* Load data callback
|
|
22
22
|
*/
|
package/lib/mu/SelectEx.js
CHANGED
|
@@ -68,6 +68,16 @@ export function SelectEx(props) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
|
+
// Get option id
|
|
72
|
+
const getId = (option) => {
|
|
73
|
+
return Reflect.get(option, idField);
|
|
74
|
+
};
|
|
75
|
+
// Get option label
|
|
76
|
+
const getLabel = (option) => {
|
|
77
|
+
return typeof labelField === 'function'
|
|
78
|
+
? labelField(option)
|
|
79
|
+
: Reflect.get(option, labelField);
|
|
80
|
+
};
|
|
71
81
|
// Refs
|
|
72
82
|
const divRef = React.useRef();
|
|
73
83
|
// When layout ready
|
|
@@ -107,18 +117,19 @@ export function SelectEx(props) {
|
|
|
107
117
|
}, renderValue: (selected) => {
|
|
108
118
|
// The text shows up
|
|
109
119
|
return localOptions
|
|
110
|
-
.filter((option) =>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
.filter((option) => {
|
|
121
|
+
const id = getId(option);
|
|
122
|
+
return Array.isArray(selected)
|
|
123
|
+
? selected.indexOf(id) !== -1
|
|
124
|
+
: selected === id;
|
|
125
|
+
})
|
|
126
|
+
.map((option) => getLabel(option))
|
|
114
127
|
.join(', ');
|
|
115
128
|
}, sx: { minWidth: '150px' }, ...rest }, localOptions.map((option) => {
|
|
116
129
|
// Option id
|
|
117
|
-
const id = option
|
|
130
|
+
const id = getId(option);
|
|
118
131
|
// Option label
|
|
119
|
-
const label =
|
|
120
|
-
? labelField(option)
|
|
121
|
-
: option[labelField];
|
|
132
|
+
const label = getLabel(option);
|
|
122
133
|
// Option
|
|
123
134
|
return (React.createElement(MenuItem, { key: id, value: id, onClick: (event) => {
|
|
124
135
|
if (onItemClick) {
|
package/lib/mu/TableEx.d.ts
CHANGED
package/lib/mu/Tiplist.js
CHANGED
|
@@ -29,6 +29,8 @@ export function Tiplist(props) {
|
|
|
29
29
|
options: [],
|
|
30
30
|
value: null
|
|
31
31
|
});
|
|
32
|
+
// Input value
|
|
33
|
+
const inputValue = React.useMemo(() => states.value && Reflect.get(states.value, idField), [states.value]);
|
|
32
34
|
React.useEffect(() => {
|
|
33
35
|
if (localValue != null)
|
|
34
36
|
stateUpdate({ value: localValue });
|
|
@@ -133,7 +135,7 @@ export function Tiplist(props) {
|
|
|
133
135
|
}, []);
|
|
134
136
|
// Layout
|
|
135
137
|
return (React.createElement("div", null,
|
|
136
|
-
React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: 'none' }, name: name, value:
|
|
138
|
+
React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: 'none' }, name: name, value: inputValue !== null && inputValue !== void 0 ? inputValue : '', readOnly: true, onChange: inputOnChange }),
|
|
137
139
|
React.createElement(Autocomplete, { filterOptions: (options, _state) => options, value: states.value, options: states.options, onChange: (event, value, reason, details) => {
|
|
138
140
|
// Set value
|
|
139
141
|
setInputValue(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.78",
|
|
4
4
|
"description": "TypeScript ReactJs framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@emotion/styled": "^11.6.0",
|
|
53
53
|
"@etsoo/appscript": "^1.2.28",
|
|
54
54
|
"@etsoo/notificationbase": "^1.1.0",
|
|
55
|
-
"@etsoo/shared": "^1.1.
|
|
55
|
+
"@etsoo/shared": "^1.1.7",
|
|
56
56
|
"@mui/icons-material": "^5.3.1",
|
|
57
57
|
"@mui/material": "^5.3.1",
|
|
58
58
|
"@reach/router": "^1.3.4",
|
package/src/app/Utils.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* React utils
|
|
3
5
|
*/
|
|
@@ -19,6 +21,36 @@ export namespace Utils {
|
|
|
19
21
|
return String(value);
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Is safe click
|
|
26
|
+
* @param event Mouse event
|
|
27
|
+
* @returns Result
|
|
28
|
+
*/
|
|
29
|
+
export function isSafeClick(event: React.MouseEvent<HTMLElement>) {
|
|
30
|
+
// No target
|
|
31
|
+
// HTMLElement <= Element, SVGElement <= Element
|
|
32
|
+
if (!(event.target instanceof Element)) return true;
|
|
33
|
+
|
|
34
|
+
// Outside of the currentTarget
|
|
35
|
+
let target: Element | null = event.target;
|
|
36
|
+
if (!event.currentTarget.contains(target)) return false;
|
|
37
|
+
|
|
38
|
+
while (target != null && target != event.currentTarget) {
|
|
39
|
+
const nodeName = target.nodeName.toUpperCase();
|
|
40
|
+
if (
|
|
41
|
+
nodeName === 'INPUT' ||
|
|
42
|
+
nodeName === 'BUTTON' ||
|
|
43
|
+
nodeName === 'A' ||
|
|
44
|
+
target.hasAttribute('onClick')
|
|
45
|
+
)
|
|
46
|
+
return false;
|
|
47
|
+
|
|
48
|
+
target = target.parentElement;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
22
54
|
/**
|
|
23
55
|
* Trigger input change event
|
|
24
56
|
* @param input Form input
|
package/src/mu/ComboBox.tsx
CHANGED
package/src/mu/DataGridEx.tsx
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from '../components/ScrollerGrid';
|
|
26
26
|
import useCombinedRefs from '../uses/useCombinedRefs';
|
|
27
27
|
import { DataGridRenderers } from './DataGridRenderers';
|
|
28
|
+
import { MouseEventWithDataHandler } from './MUGlobal';
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Footer item renderer props
|
|
@@ -98,6 +99,16 @@ export interface DataGridExProps<T extends Record<string, any>>
|
|
|
98
99
|
*/
|
|
99
100
|
hoverColor?: string;
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Double click handler
|
|
104
|
+
*/
|
|
105
|
+
onDoubleClick?: MouseEventWithDataHandler<T>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Click handler
|
|
109
|
+
*/
|
|
110
|
+
onClick?: MouseEventWithDataHandler<T>;
|
|
111
|
+
|
|
101
112
|
/**
|
|
102
113
|
* Selectable to support hover over and out effect and row clickable
|
|
103
114
|
* @default true
|
|
@@ -351,6 +362,8 @@ export function DataGridEx<T extends Record<string, any>>(
|
|
|
351
362
|
hoverColor = '#f6f9fb',
|
|
352
363
|
idField = 'id',
|
|
353
364
|
mRef = React.createRef(),
|
|
365
|
+
onClick,
|
|
366
|
+
onDoubleClick,
|
|
354
367
|
selectable = true,
|
|
355
368
|
selectedColor = '#edf4fb',
|
|
356
369
|
width,
|
|
@@ -567,6 +580,12 @@ export function DataGridEx<T extends Record<string, any>>(
|
|
|
567
580
|
}
|
|
568
581
|
onMouseOver={selectable ? handleMouseOver : undefined}
|
|
569
582
|
onMouseOut={selectable ? handleMouseOut : undefined}
|
|
583
|
+
onClick={(event) =>
|
|
584
|
+
onClick && data != null && onClick(event, data)
|
|
585
|
+
}
|
|
586
|
+
onDoubleClick={(event) =>
|
|
587
|
+
onDoubleClick && data != null && onDoubleClick(event, data)
|
|
588
|
+
}
|
|
570
589
|
>
|
|
571
590
|
<Box {...cellProps} onMouseEnter={handleMouseEnter}>
|
|
572
591
|
{child}
|
package/src/mu/DnDList.tsx
CHANGED
package/src/mu/ItemList.tsx
CHANGED
|
@@ -22,12 +22,12 @@ export interface ItemListProps<T extends Record<string, unknown>> {
|
|
|
22
22
|
/**
|
|
23
23
|
* Id field name
|
|
24
24
|
*/
|
|
25
|
-
idField?: keyof T;
|
|
25
|
+
idField?: string & keyof T;
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Label field name or callback
|
|
29
29
|
*/
|
|
30
|
-
labelField?: keyof T | ((item: T) => string);
|
|
30
|
+
labelField?: (string & keyof T) | ((item: T) => string);
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Button icon
|
package/src/mu/MUGlobal.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { NumberUtils } from '@etsoo/shared';
|
|
2
2
|
import { Breakpoint, Theme } from '@mui/material';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Mouse event handler with data
|
|
6
|
+
*/
|
|
7
|
+
export type MouseEventWithDataHandler<T> = (
|
|
8
|
+
event: React.MouseEvent<HTMLDivElement>,
|
|
9
|
+
data: T
|
|
10
|
+
) => void;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* MUGlobal for global configurations
|
|
14
|
+
*/
|
|
4
15
|
export class MUGlobal {
|
|
5
16
|
/**
|
|
6
17
|
* Search field shrink
|
package/src/mu/OptionGroup.tsx
CHANGED
|
@@ -32,7 +32,7 @@ export interface OptionGroupProps<
|
|
|
32
32
|
/**
|
|
33
33
|
* Id field, default is id
|
|
34
34
|
*/
|
|
35
|
-
idField?: keyof T;
|
|
35
|
+
idField?: string & keyof T;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Label
|
|
@@ -42,7 +42,7 @@ export interface OptionGroupProps<
|
|
|
42
42
|
/**
|
|
43
43
|
* Label field, default is label
|
|
44
44
|
*/
|
|
45
|
-
labelField?: keyof T;
|
|
45
|
+
labelField?: string & keyof T;
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Multiple choose item
|
|
@@ -3,6 +3,7 @@ import { Box, Stack, SxProps, Theme } from '@mui/material';
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { ListChildComponentProps } from 'react-window';
|
|
5
5
|
import { Labels } from '../app/Labels';
|
|
6
|
+
import { Utils } from '../app/Utils';
|
|
6
7
|
import { GridColumn } from '../components/GridColumn';
|
|
7
8
|
import {
|
|
8
9
|
GridDataGet,
|
|
@@ -125,6 +126,11 @@ export interface ResponsibleContainerProps<
|
|
|
125
126
|
*/
|
|
126
127
|
pullToRefresh?: boolean;
|
|
127
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Quick action for double click or click under mobile
|
|
131
|
+
*/
|
|
132
|
+
quickAction?: (data: T) => void;
|
|
133
|
+
|
|
128
134
|
/**
|
|
129
135
|
* Size ready to read miliseconds span
|
|
130
136
|
*/
|
|
@@ -173,6 +179,7 @@ export function ResponsibleContainer<
|
|
|
173
179
|
mRef,
|
|
174
180
|
paddings = MUGlobal.pagePaddings,
|
|
175
181
|
pullToRefresh = true,
|
|
182
|
+
quickAction,
|
|
176
183
|
sizeReadyMiliseconds = 0,
|
|
177
184
|
...rest
|
|
178
185
|
} = props;
|
|
@@ -285,6 +292,9 @@ export function ResponsibleContainer<
|
|
|
285
292
|
width={rect.width}
|
|
286
293
|
loadData={localLoadData}
|
|
287
294
|
mRef={mRefs}
|
|
295
|
+
onDoubleClick={(_, data) =>
|
|
296
|
+
quickAction && quickAction(data)
|
|
297
|
+
}
|
|
288
298
|
outerRef={(element?: HTMLDivElement) => {
|
|
289
299
|
if (element != null && elementReady)
|
|
290
300
|
elementReady(element, true);
|
|
@@ -314,6 +324,11 @@ export function ResponsibleContainer<
|
|
|
314
324
|
height={heightLocal}
|
|
315
325
|
loadData={localLoadData}
|
|
316
326
|
mRef={mRefs}
|
|
327
|
+
onClick={(event, data) =>
|
|
328
|
+
quickAction &&
|
|
329
|
+
Utils.isSafeClick(event) &&
|
|
330
|
+
quickAction(data)
|
|
331
|
+
}
|
|
317
332
|
oRef={(element) => {
|
|
318
333
|
if (element != null && elementReady)
|
|
319
334
|
elementReady(element, false);
|
|
@@ -4,7 +4,7 @@ import { useTheme } from '@mui/material';
|
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { ListChildComponentProps } from 'react-window';
|
|
6
6
|
import { ScrollerList, ScrollerListProps } from '../components/ScrollerList';
|
|
7
|
-
import { MUGlobal } from './MUGlobal';
|
|
7
|
+
import { MouseEventWithDataHandler, MUGlobal } from './MUGlobal';
|
|
8
8
|
|
|
9
9
|
// Scroll bar size
|
|
10
10
|
const scrollbarSize = 16;
|
|
@@ -127,7 +127,7 @@ export interface ScrollerListExProps<T>
|
|
|
127
127
|
/**
|
|
128
128
|
* Id field
|
|
129
129
|
*/
|
|
130
|
-
idField?: keyof T;
|
|
130
|
+
idField?: string & keyof T;
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
133
|
* Inner item renderer
|
|
@@ -146,6 +146,16 @@ export interface ScrollerListExProps<T>
|
|
|
146
146
|
*/
|
|
147
147
|
itemSize: ScrollerListExItemSize;
|
|
148
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Double click handler
|
|
151
|
+
*/
|
|
152
|
+
onDoubleClick?: MouseEventWithDataHandler<T>;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Click handler
|
|
156
|
+
*/
|
|
157
|
+
onClick?: MouseEventWithDataHandler<T>;
|
|
158
|
+
|
|
149
159
|
/**
|
|
150
160
|
* On items select change
|
|
151
161
|
*/
|
|
@@ -175,6 +185,16 @@ interface defaultItemRendererProps<T> extends ListChildComponentProps<T> {
|
|
|
175
185
|
*/
|
|
176
186
|
itemHeight: number;
|
|
177
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Double click handler
|
|
190
|
+
*/
|
|
191
|
+
onDoubleClick?: MouseEventWithDataHandler<T>;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Click handler
|
|
195
|
+
*/
|
|
196
|
+
onClick?: MouseEventWithDataHandler<T>;
|
|
197
|
+
|
|
178
198
|
/**
|
|
179
199
|
* Item space
|
|
180
200
|
*/
|
|
@@ -200,6 +220,8 @@ function defaultItemRenderer<T>({
|
|
|
200
220
|
selected,
|
|
201
221
|
style,
|
|
202
222
|
itemHeight,
|
|
223
|
+
onClick,
|
|
224
|
+
onDoubleClick,
|
|
203
225
|
space,
|
|
204
226
|
margins
|
|
205
227
|
}: defaultItemRendererProps<T>) {
|
|
@@ -223,6 +245,10 @@ function defaultItemRenderer<T>({
|
|
|
223
245
|
className={rowClass}
|
|
224
246
|
style={style}
|
|
225
247
|
onMouseDown={(event) => onMouseDown(event.currentTarget, data)}
|
|
248
|
+
onClick={(event) => onClick && onClick(event, data)}
|
|
249
|
+
onDoubleClick={(event) =>
|
|
250
|
+
onDoubleClick && onDoubleClick(event, data)
|
|
251
|
+
}
|
|
226
252
|
>
|
|
227
253
|
{child}
|
|
228
254
|
</div>
|
|
@@ -282,12 +308,16 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
|
|
|
282
308
|
itemHeight,
|
|
283
309
|
innerItemRenderer,
|
|
284
310
|
onMouseDown,
|
|
311
|
+
onClick,
|
|
312
|
+
onDoubleClick,
|
|
285
313
|
space,
|
|
286
314
|
margins,
|
|
287
315
|
selected: isSelected(itemProps.data),
|
|
288
316
|
...itemProps
|
|
289
317
|
});
|
|
290
318
|
},
|
|
319
|
+
onClick,
|
|
320
|
+
onDoubleClick,
|
|
291
321
|
onSelectChange,
|
|
292
322
|
selectedColor = '#edf4fb',
|
|
293
323
|
...rest
|
package/src/mu/SelectEx.tsx
CHANGED
|
@@ -23,7 +23,7 @@ export interface SelectExProps<T extends {}>
|
|
|
23
23
|
/**
|
|
24
24
|
* Id field, default is id
|
|
25
25
|
*/
|
|
26
|
-
idField?: keyof T;
|
|
26
|
+
idField?: string & keyof T;
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Item icon renderer
|
|
@@ -33,7 +33,7 @@ export interface SelectExProps<T extends {}>
|
|
|
33
33
|
/**
|
|
34
34
|
* Label field, default is label
|
|
35
35
|
*/
|
|
36
|
-
labelField?: ((option: T) => string) | keyof T;
|
|
36
|
+
labelField?: ((option: T) => string) | (string & keyof T);
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Load data callback
|
|
@@ -143,6 +143,18 @@ export function SelectEx<T extends {} = IdLabelDto>(props: SelectExProps<T>) {
|
|
|
143
143
|
}
|
|
144
144
|
};
|
|
145
145
|
|
|
146
|
+
// Get option id
|
|
147
|
+
const getId = (option: T) => {
|
|
148
|
+
return Reflect.get(option, idField);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Get option label
|
|
152
|
+
const getLabel = (option: T) => {
|
|
153
|
+
return typeof labelField === 'function'
|
|
154
|
+
? labelField(option)
|
|
155
|
+
: Reflect.get(option, labelField);
|
|
156
|
+
};
|
|
157
|
+
|
|
146
158
|
// Refs
|
|
147
159
|
const divRef = React.useRef<HTMLDivElement>();
|
|
148
160
|
|
|
@@ -198,26 +210,24 @@ export function SelectEx<T extends {} = IdLabelDto>(props: SelectExProps<T>) {
|
|
|
198
210
|
renderValue={(selected) => {
|
|
199
211
|
// The text shows up
|
|
200
212
|
return localOptions
|
|
201
|
-
.filter((option
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
213
|
+
.filter((option) => {
|
|
214
|
+
const id = getId(option);
|
|
215
|
+
return Array.isArray(selected)
|
|
216
|
+
? selected.indexOf(id) !== -1
|
|
217
|
+
: selected === id;
|
|
218
|
+
})
|
|
219
|
+
.map((option) => getLabel(option))
|
|
207
220
|
.join(', ');
|
|
208
221
|
}}
|
|
209
222
|
sx={{ minWidth: '150px' }}
|
|
210
223
|
{...rest}
|
|
211
224
|
>
|
|
212
|
-
{localOptions.map((option
|
|
225
|
+
{localOptions.map((option) => {
|
|
213
226
|
// Option id
|
|
214
|
-
const id = option
|
|
227
|
+
const id = getId(option);
|
|
215
228
|
|
|
216
229
|
// Option label
|
|
217
|
-
const label =
|
|
218
|
-
typeof labelField === 'function'
|
|
219
|
-
? labelField(option)
|
|
220
|
-
: option[labelField];
|
|
230
|
+
const label = getLabel(option);
|
|
221
231
|
|
|
222
232
|
// Option
|
|
223
233
|
return (
|
package/src/mu/TableEx.tsx
CHANGED
|
@@ -68,7 +68,7 @@ export interface TableExProps<T extends Record<string, any>>
|
|
|
68
68
|
/**
|
|
69
69
|
* Id field
|
|
70
70
|
*/
|
|
71
|
-
idField?: keyof T;
|
|
71
|
+
idField?: string & keyof T;
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* Max height
|
|
@@ -107,7 +107,7 @@ export function TableEx<T extends Record<string, unknown>>(
|
|
|
107
107
|
// Theme
|
|
108
108
|
const theme = useTheme();
|
|
109
109
|
|
|
110
|
-
type keyType = keyof T;
|
|
110
|
+
type keyType = string & keyof T;
|
|
111
111
|
|
|
112
112
|
// Destruct
|
|
113
113
|
const {
|
package/src/mu/Tiplist.tsx
CHANGED
|
@@ -83,6 +83,12 @@ export function Tiplist<T extends {} = IdLabelDto>(props: TiplistProps<T>) {
|
|
|
83
83
|
}
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
+
// Input value
|
|
87
|
+
const inputValue = React.useMemo(
|
|
88
|
+
() => states.value && Reflect.get(states.value, idField),
|
|
89
|
+
[states.value]
|
|
90
|
+
);
|
|
91
|
+
|
|
86
92
|
React.useEffect(() => {
|
|
87
93
|
if (localValue != null) stateUpdate({ value: localValue });
|
|
88
94
|
}, [localValue]);
|
|
@@ -219,7 +225,7 @@ export function Tiplist<T extends {} = IdLabelDto>(props: TiplistProps<T>) {
|
|
|
219
225
|
type="text"
|
|
220
226
|
style={{ display: 'none' }}
|
|
221
227
|
name={name}
|
|
222
|
-
value={
|
|
228
|
+
value={inputValue ?? ''}
|
|
223
229
|
readOnly
|
|
224
230
|
onChange={inputOnChange}
|
|
225
231
|
/>
|