@etsoo/react 1.7.94 → 1.7.95
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/README.md +2 -1
- package/__tests__/EventWatcher.tsx +21 -21
- package/__tests__/ReactUtils.ts +4 -4
- package/__tests__/tsconfig.json +17 -17
- package/babel.config.json +8 -8
- package/lib/app/CoreConstants.js +2 -2
- package/lib/app/EventWatcher.d.ts +1 -1
- package/lib/app/EventWatcher.js +3 -5
- package/lib/app/InputDialogProps.d.ts +2 -2
- package/lib/app/ReactUtils.d.ts +2 -2
- package/lib/app/ReactUtils.js +20 -19
- package/lib/components/DnDList.d.ts +3 -3
- package/lib/components/DnDList.js +4 -4
- package/lib/components/DynamicRouter.d.ts +2 -2
- package/lib/components/DynamicRouter.js +2 -2
- package/lib/components/GridColumn.d.ts +6 -6
- package/lib/components/GridColumn.js +7 -7
- package/lib/components/GridLoader.d.ts +4 -4
- package/lib/components/GridLoader.js +2 -2
- package/lib/components/GridMethodRef.d.ts +2 -2
- package/lib/components/ListItemReact.d.ts +2 -2
- package/lib/components/ScrollRestoration.js +3 -3
- package/lib/components/ScrollerGrid.d.ts +7 -12
- package/lib/components/ScrollerGrid.js +13 -17
- package/lib/components/ScrollerList.d.ts +6 -10
- package/lib/components/ScrollerList.js +15 -14
- package/lib/custom/CustomFieldReact.d.ts +1 -1
- package/lib/index.d.ts +32 -32
- package/lib/index.js +31 -31
- package/lib/notifier/Notifier.d.ts +5 -5
- package/lib/notifier/Notifier.js +7 -7
- package/lib/states/CultureState.d.ts +3 -3
- package/lib/states/CultureState.js +3 -3
- package/lib/states/IState.d.ts +2 -2
- package/lib/states/PageState.d.ts +2 -2
- package/lib/states/PageState.js +2 -3
- package/lib/states/State.d.ts +3 -3
- package/lib/states/State.js +2 -2
- package/lib/states/UserState.d.ts +2 -2
- package/lib/states/UserState.js +5 -5
- package/lib/uses/useAsyncState.d.ts +1 -1
- package/lib/uses/useAsyncState.js +1 -1
- package/lib/uses/useCombinedRefs.js +2 -2
- package/lib/uses/useDelayedExecutor.d.ts +1 -1
- package/lib/uses/useDelayedExecutor.js +2 -2
- package/lib/uses/useDimensions.d.ts +1 -1
- package/lib/uses/useDimensions.js +3 -3
- package/lib/uses/useParamsEx.d.ts +1 -1
- package/lib/uses/useParamsEx.js +2 -2
- package/lib/uses/useRefs.d.ts +2 -2
- package/lib/uses/useRefs.js +1 -1
- package/lib/uses/useSearchParamsEx.d.ts +1 -1
- package/lib/uses/useSearchParamsEx.js +3 -3
- package/lib/uses/useTimeout.js +2 -2
- package/lib/uses/useWindowScroll.js +3 -3
- package/lib/uses/useWindowSize.js +4 -5
- package/package.json +72 -74
- package/src/app/CoreConstants.ts +8 -8
- package/src/app/EventWatcher.ts +50 -52
- package/src/app/InputDialogProps.ts +16 -16
- package/src/app/ReactUtils.ts +206 -208
- package/src/components/DnDList.tsx +268 -283
- package/src/components/DynamicRouter.tsx +35 -35
- package/src/components/GridColumn.ts +201 -201
- package/src/components/GridLoader.ts +121 -121
- package/src/components/GridMethodRef.ts +26 -26
- package/src/components/ListItemReact.ts +2 -2
- package/src/components/ScrollRestoration.tsx +24 -24
- package/src/components/ScrollerGrid.tsx +428 -448
- package/src/components/ScrollerList.tsx +320 -332
- package/src/custom/CustomFieldReact.ts +12 -12
- package/src/index.ts +35 -35
- package/src/notifier/Notifier.ts +229 -240
- package/src/states/CultureState.ts +51 -52
- package/src/states/IState.ts +19 -19
- package/src/states/PageState.ts +63 -66
- package/src/states/State.tsx +47 -51
- package/src/states/UserState.ts +98 -98
- package/src/uses/useAsyncState.ts +37 -39
- package/src/uses/useCombinedRefs.ts +16 -16
- package/src/uses/useDelayedExecutor.ts +8 -8
- package/src/uses/useDimensions.ts +102 -103
- package/src/uses/useParamsEx.ts +6 -6
- package/src/uses/useRefs.ts +6 -6
- package/src/uses/useSearchParamsEx.ts +13 -13
- package/src/uses/useTimeout.ts +17 -17
- package/src/uses/useWindowScroll.ts +43 -43
- package/src/uses/useWindowSize.ts +46 -49
- package/tsconfig.json +17 -17
- package/.eslintignore +0 -3
- package/.eslintrc.json +0 -38
- package/.prettierignore +0 -5
- package/.prettierrc +0 -6
package/src/app/ReactUtils.ts
CHANGED
|
@@ -1,221 +1,219 @@
|
|
|
1
|
-
import { DataTypes, DateUtils, DomUtils, Utils } from
|
|
2
|
-
import React from
|
|
1
|
+
import { DataTypes, DateUtils, DomUtils, Utils } from "@etsoo/shared";
|
|
2
|
+
import React from "react";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* React utils
|
|
6
6
|
*/
|
|
7
7
|
export namespace ReactUtils {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Format input value
|
|
10
|
+
* @param value Input value
|
|
11
|
+
* @returns Formatted value
|
|
12
|
+
*/
|
|
13
|
+
export function formatInputValue(value: unknown) {
|
|
14
|
+
if (value === null) return undefined;
|
|
15
|
+
|
|
16
|
+
if (typeof value === "number") return value;
|
|
17
|
+
|
|
18
|
+
if (typeof value === "string") return value;
|
|
19
|
+
|
|
20
|
+
if (Array.isArray(value)) return value;
|
|
21
|
+
|
|
22
|
+
return String(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Is safe click
|
|
27
|
+
* @param event Mouse event
|
|
28
|
+
* @returns Result
|
|
29
|
+
*/
|
|
30
|
+
export function isSafeClick(event: React.MouseEvent<HTMLElement>) {
|
|
31
|
+
// No target
|
|
32
|
+
// HTMLElement <= Element, SVGElement <= Element
|
|
33
|
+
if (!(event.target instanceof Element)) return true;
|
|
34
|
+
|
|
35
|
+
// Outside of the currentTarget
|
|
36
|
+
let target: Element | null = event.target;
|
|
37
|
+
if (!event.currentTarget.contains(target)) return false;
|
|
38
|
+
|
|
39
|
+
while (target != null && target != event.currentTarget) {
|
|
40
|
+
const nodeName = target.nodeName.toUpperCase();
|
|
41
|
+
if (
|
|
42
|
+
nodeName === "INPUT" ||
|
|
43
|
+
nodeName === "BUTTON" ||
|
|
44
|
+
nodeName === "A" ||
|
|
45
|
+
target.hasAttribute("onClick")
|
|
46
|
+
)
|
|
47
|
+
return false;
|
|
48
|
+
|
|
49
|
+
target = target.parentElement;
|
|
23
50
|
}
|
|
24
51
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Trigger input change event
|
|
57
|
+
* @param input Form input
|
|
58
|
+
* @param value New value
|
|
59
|
+
* @param cancelable Cancelable
|
|
60
|
+
*/
|
|
61
|
+
export function triggerChange(
|
|
62
|
+
input: HTMLInputElement,
|
|
63
|
+
value: string,
|
|
64
|
+
cancelable: boolean = false
|
|
65
|
+
) {
|
|
66
|
+
// Radio type not supported
|
|
67
|
+
if (input.type === "radio") return;
|
|
68
|
+
|
|
69
|
+
// checked?
|
|
70
|
+
const checked = input.type === "checkbox";
|
|
71
|
+
|
|
72
|
+
// Property name
|
|
73
|
+
const property = checked ? "checked" : "value";
|
|
74
|
+
|
|
75
|
+
// input.value = newValue will not trigger the change event
|
|
76
|
+
// input type = 'hidden' will also not trigger the event
|
|
77
|
+
// https://coryrylan.com/blog/trigger-input-updates-with-react-controlled-inputs
|
|
78
|
+
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(
|
|
79
|
+
HTMLInputElement.prototype,
|
|
80
|
+
property
|
|
81
|
+
)?.set;
|
|
82
|
+
|
|
83
|
+
if (checked) {
|
|
84
|
+
const checkedValue = input.value == value;
|
|
85
|
+
nativeInputValueSetter?.call(input, checkedValue);
|
|
86
|
+
|
|
87
|
+
const clickEvent = new Event("click", {
|
|
88
|
+
bubbles: true,
|
|
89
|
+
cancelable
|
|
90
|
+
});
|
|
91
|
+
input.dispatchEvent(clickEvent);
|
|
92
|
+
} else {
|
|
93
|
+
nativeInputValueSetter?.call(input, value);
|
|
94
|
+
|
|
95
|
+
const inputEvent = new Event("change", {
|
|
96
|
+
bubbles: true,
|
|
97
|
+
cancelable
|
|
98
|
+
});
|
|
99
|
+
input.dispatchEvent(inputEvent);
|
|
53
100
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Update refs
|
|
105
|
+
* @param refs Refs
|
|
106
|
+
* @param data Data
|
|
107
|
+
* @param callback Callback to update refs' value, return false continue to process
|
|
108
|
+
*/
|
|
109
|
+
export function updateRefs<D extends object, T = HTMLInputElement>(
|
|
110
|
+
refs: Partial<
|
|
111
|
+
DataTypes.DI<
|
|
112
|
+
ReadonlyArray<keyof D & string>,
|
|
113
|
+
React.MutableRefObject<T | null>
|
|
114
|
+
>
|
|
115
|
+
>,
|
|
116
|
+
data: D,
|
|
117
|
+
callback?:
|
|
118
|
+
| ((item: T, value: D[keyof D & string]) => void | boolean)
|
|
119
|
+
| keyof T
|
|
120
|
+
) {
|
|
121
|
+
const local: typeof callback =
|
|
122
|
+
callback == null
|
|
123
|
+
? undefined
|
|
124
|
+
: typeof callback === "function"
|
|
125
|
+
? callback
|
|
126
|
+
: (item, value) => {
|
|
127
|
+
item[callback] = value as any;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
let k: keyof typeof refs;
|
|
131
|
+
for (k in refs) {
|
|
132
|
+
const ref = refs[k];
|
|
133
|
+
const item = ref?.current;
|
|
134
|
+
if (item == null) continue;
|
|
135
|
+
|
|
136
|
+
if (local && local(item, data[k]) !== false) {
|
|
137
|
+
continue;
|
|
138
|
+
} else if (
|
|
139
|
+
item instanceof HTMLInputElement ||
|
|
140
|
+
item instanceof HTMLTextAreaElement ||
|
|
141
|
+
item instanceof HTMLSelectElement
|
|
142
|
+
) {
|
|
143
|
+
const value = Utils.getNestedValue(data, item.name || k);
|
|
144
|
+
|
|
145
|
+
const isDateTime = item.type === "datetime-local";
|
|
146
|
+
if (isDateTime || item.type === "date") {
|
|
147
|
+
item.value =
|
|
148
|
+
DateUtils.formatForInput(value, isDateTime ? false : undefined) ??
|
|
149
|
+
"";
|
|
92
150
|
} else {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const inputEvent = new Event('change', {
|
|
96
|
-
bubbles: true,
|
|
97
|
-
cancelable
|
|
98
|
-
});
|
|
99
|
-
input.dispatchEvent(inputEvent);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Update refs
|
|
105
|
-
* @param refs Refs
|
|
106
|
-
* @param data Data
|
|
107
|
-
* @param callback Callback to update refs' value, return false continue to process
|
|
108
|
-
*/
|
|
109
|
-
export function updateRefs<D extends object, T = HTMLInputElement>(
|
|
110
|
-
refs: Partial<
|
|
111
|
-
DataTypes.DI<
|
|
112
|
-
ReadonlyArray<keyof D & string>,
|
|
113
|
-
React.MutableRefObject<T | null>
|
|
114
|
-
>
|
|
115
|
-
>,
|
|
116
|
-
data: D,
|
|
117
|
-
callback?:
|
|
118
|
-
| ((item: T, value: D[keyof D & string]) => void | boolean)
|
|
119
|
-
| keyof T
|
|
120
|
-
) {
|
|
121
|
-
const local: typeof callback =
|
|
122
|
-
callback == null
|
|
123
|
-
? undefined
|
|
124
|
-
: typeof callback === 'function'
|
|
125
|
-
? callback
|
|
126
|
-
: (item, value) => {
|
|
127
|
-
item[callback] = value as any;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
let k: keyof typeof refs;
|
|
131
|
-
for (k in refs) {
|
|
132
|
-
const ref = refs[k];
|
|
133
|
-
const item = ref?.current;
|
|
134
|
-
if (item == null) continue;
|
|
135
|
-
|
|
136
|
-
if (local && local(item, data[k]) !== false) {
|
|
137
|
-
continue;
|
|
138
|
-
} else if (
|
|
139
|
-
item instanceof HTMLInputElement ||
|
|
140
|
-
item instanceof HTMLTextAreaElement ||
|
|
141
|
-
item instanceof HTMLSelectElement
|
|
142
|
-
) {
|
|
143
|
-
const value = Utils.getNestedValue(data, item.name || k);
|
|
144
|
-
|
|
145
|
-
const isDateTime = item.type === 'datetime-local';
|
|
146
|
-
if (isDateTime || item.type === 'date') {
|
|
147
|
-
item.value =
|
|
148
|
-
DateUtils.formatForInput(
|
|
149
|
-
value,
|
|
150
|
-
isDateTime ? false : undefined
|
|
151
|
-
) ?? '';
|
|
152
|
-
} else {
|
|
153
|
-
item.value = `${value ?? ''}`;
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
(item as any).value = data[k];
|
|
157
|
-
}
|
|
151
|
+
item.value = `${value ?? ""}`;
|
|
158
152
|
}
|
|
153
|
+
} else {
|
|
154
|
+
(item as any).value = data[k];
|
|
155
|
+
}
|
|
159
156
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Update data with refs
|
|
161
|
+
* @param refs Refs
|
|
162
|
+
* @param data Data
|
|
163
|
+
* @param callback Callback to return new value
|
|
164
|
+
* @param ignoreEmpty Ignore empty string or not, default true
|
|
165
|
+
*/
|
|
166
|
+
export function updateRefValues<D extends object, T = HTMLInputElement>(
|
|
167
|
+
refs: Partial<
|
|
168
|
+
DataTypes.DI<
|
|
169
|
+
ReadonlyArray<keyof D & string>,
|
|
170
|
+
React.MutableRefObject<T | null>
|
|
171
|
+
>
|
|
172
|
+
>,
|
|
173
|
+
data: D,
|
|
174
|
+
callback?: ((item: T) => any) | keyof T,
|
|
175
|
+
ignoreEmpty: boolean = true
|
|
176
|
+
) {
|
|
177
|
+
const local: typeof callback =
|
|
178
|
+
callback == null
|
|
179
|
+
? undefined
|
|
180
|
+
: typeof callback === "function"
|
|
181
|
+
? callback
|
|
182
|
+
: (item) => item[callback];
|
|
183
|
+
|
|
184
|
+
const formatValue = (value: unknown) => {
|
|
185
|
+
if (ignoreEmpty && value === "") return null;
|
|
186
|
+
return value;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
let k: keyof typeof refs;
|
|
190
|
+
for (k in refs) {
|
|
191
|
+
const ref = refs[k];
|
|
192
|
+
const item = ref?.current;
|
|
193
|
+
if (item == null) continue;
|
|
194
|
+
|
|
195
|
+
if (local) {
|
|
196
|
+
data[k] = local(item);
|
|
197
|
+
} else if (item instanceof HTMLInputElement) {
|
|
198
|
+
Utils.setNestedValue(
|
|
199
|
+
data,
|
|
200
|
+
item.name || k,
|
|
201
|
+
formatValue(DomUtils.getInputValue(item)),
|
|
202
|
+
true
|
|
203
|
+
);
|
|
204
|
+
} else if (
|
|
205
|
+
item instanceof HTMLTextAreaElement ||
|
|
206
|
+
item instanceof HTMLSelectElement
|
|
207
|
+
) {
|
|
208
|
+
Utils.setNestedValue(
|
|
209
|
+
data,
|
|
210
|
+
item.name || k,
|
|
211
|
+
formatValue(item.value),
|
|
212
|
+
true
|
|
213
|
+
);
|
|
214
|
+
} else {
|
|
215
|
+
data[k] = (item as any).value;
|
|
216
|
+
}
|
|
220
217
|
}
|
|
218
|
+
}
|
|
221
219
|
}
|