zavadil-react-common 1.2.58 → 1.2.61
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/dist/component/forms/AutocompleteLookupIdSelect.d.ts +9 -0
- package/dist/component/forms/AutocompleteLookupSelect.d.ts +9 -0
- package/dist/component/forms/AutocompleteSelect.d.ts +9 -0
- package/dist/component/forms/LookupSelect.d.ts +2 -1
- package/dist/component/forms/NumberSelect.d.ts +1 -1
- package/dist/component/forms/StringSelect.d.ts +2 -1
- package/dist/component/forms/TextInputWithReset.d.ts +4 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/component/forms/AutocompleteLookupIdSelect.tsx +53 -0
- package/src/component/forms/AutocompleteLookupSelect.tsx +41 -0
- package/src/component/forms/AutocompleteSelect.tsx +101 -0
- package/src/component/forms/LookupSelect.tsx +3 -1
- package/src/component/forms/NumberSelect.tsx +2 -1
- package/src/component/forms/StringSelect.tsx +3 -1
- package/src/component/forms/TextInputWithReset.tsx +7 -2
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {useCallback, useEffect, useMemo, useState} from "react";
|
|
2
|
+
import {CancellablePromise, EntityBase} from "zavadil-ts-common";
|
|
3
|
+
import TextInputWithReset from "./TextInputWithReset";
|
|
4
|
+
import {Badge, Dropdown, Stack} from "react-bootstrap";
|
|
5
|
+
|
|
6
|
+
export type AutocompleteSelectProps<T extends EntityBase> = {
|
|
7
|
+
selected?: T | null;
|
|
8
|
+
onChange: (e: T | null) => any;
|
|
9
|
+
onSearch: (text: string) => Promise<Array<T>>;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
labelGetter?: (item: T) => string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function AutocompleteSelect<T extends EntityBase>({selected, disabled, labelGetter, onChange, onSearch}: AutocompleteSelectProps<T>) {
|
|
15
|
+
const [searchPromise, setSearchPromise] = useState<CancellablePromise>();
|
|
16
|
+
const [searchText, setSearchText] = useState<string>();
|
|
17
|
+
const [itemSelection, setItemSelection] = useState<Array<T>>();
|
|
18
|
+
|
|
19
|
+
const finalLabelGetter = useMemo(
|
|
20
|
+
() => labelGetter ? labelGetter : (item: T) => `[${item.id}]`,
|
|
21
|
+
[labelGetter]
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const finalCss = useMemo(
|
|
25
|
+
() => selected ? 'border-primary' : undefined,
|
|
26
|
+
[selected]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
setSearchText(selected ? finalLabelGetter(selected) : '');
|
|
31
|
+
}, [selected, finalLabelGetter]);
|
|
32
|
+
|
|
33
|
+
const reset = useCallback(
|
|
34
|
+
() => {
|
|
35
|
+
onChange(null)
|
|
36
|
+
setSearchText('');
|
|
37
|
+
setItemSelection(undefined);
|
|
38
|
+
},
|
|
39
|
+
[]
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const userChangedText = useCallback(
|
|
43
|
+
(s: string) => {
|
|
44
|
+
setSearchText(s);
|
|
45
|
+
if (searchPromise) {
|
|
46
|
+
searchPromise.cancel();
|
|
47
|
+
}
|
|
48
|
+
const cancellable = new CancellablePromise(onSearch(s));
|
|
49
|
+
cancellable.promise.then(setItemSelection);
|
|
50
|
+
setSearchPromise(cancellable);
|
|
51
|
+
},
|
|
52
|
+
[searchPromise]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const userLeftSearch = useCallback(
|
|
56
|
+
() => {
|
|
57
|
+
if (searchPromise) {
|
|
58
|
+
searchPromise.cancel();
|
|
59
|
+
setSearchPromise(undefined);
|
|
60
|
+
}
|
|
61
|
+
if (selected) {
|
|
62
|
+
setSearchText(finalLabelGetter(selected));
|
|
63
|
+
} else {
|
|
64
|
+
setSearchText('');
|
|
65
|
+
}
|
|
66
|
+
setItemSelection(undefined);
|
|
67
|
+
},
|
|
68
|
+
[selected, searchPromise, finalLabelGetter]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Dropdown defaultShow={false} show={itemSelection !== null} onBlur={userLeftSearch}>
|
|
73
|
+
<Stack direction="horizontal" gap={2}>
|
|
74
|
+
<TextInputWithReset
|
|
75
|
+
disabled={disabled}
|
|
76
|
+
value={searchText}
|
|
77
|
+
onChange={userChangedText}
|
|
78
|
+
onReset={reset}
|
|
79
|
+
className={finalCss}
|
|
80
|
+
/>
|
|
81
|
+
{
|
|
82
|
+
selected &&
|
|
83
|
+
<Badge>{selected.id}</Badge>
|
|
84
|
+
}
|
|
85
|
+
</Stack>
|
|
86
|
+
|
|
87
|
+
{
|
|
88
|
+
itemSelection &&
|
|
89
|
+
<Dropdown.Menu>
|
|
90
|
+
{
|
|
91
|
+
itemSelection.map(
|
|
92
|
+
(item) => <Dropdown.Item key={item.id} onSelect={() => onChange(item)}>
|
|
93
|
+
{finalLabelGetter(item)}
|
|
94
|
+
</Dropdown.Item>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
</Dropdown.Menu>
|
|
98
|
+
}
|
|
99
|
+
</Dropdown>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -8,12 +8,13 @@ export type LookupSelectProps = {
|
|
|
8
8
|
onChange: (n: number | null | undefined) => any;
|
|
9
9
|
options?: Array<LookupTableEntity> | null;
|
|
10
10
|
showEmptyOption?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
11
12
|
emptyOptionLabel?: string;
|
|
12
13
|
sort?: boolean;
|
|
13
14
|
labelGetter?: <T extends LookupTableEntity>(item: T) => string;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
export function LookupSelect({id, sort, labelGetter, onChange, options, showEmptyOption, emptyOptionLabel}: LookupSelectProps) {
|
|
17
|
+
export function LookupSelect({id, sort, disabled, labelGetter, onChange, options, showEmptyOption, emptyOptionLabel}: LookupSelectProps) {
|
|
17
18
|
const lOptions: GenericSelectOption<number>[] = useMemo(
|
|
18
19
|
() => {
|
|
19
20
|
let result: Array<LookupTableEntity> = []
|
|
@@ -35,6 +36,7 @@ export function LookupSelect({id, sort, labelGetter, onChange, options, showEmpt
|
|
|
35
36
|
|
|
36
37
|
return (
|
|
37
38
|
<NumberSelect
|
|
39
|
+
disabled={disabled}
|
|
38
40
|
value={id}
|
|
39
41
|
options={lOptions}
|
|
40
42
|
onChange={onChange}
|
|
@@ -4,7 +4,7 @@ import {GenericSelectProps, StringSelect} from "./StringSelect";
|
|
|
4
4
|
|
|
5
5
|
export type NumberSelectProps = GenericSelectProps<number>;
|
|
6
6
|
|
|
7
|
-
export function NumberSelect({value, options, onChange, showEmptyOption, emptyOptionLabel}: NumberSelectProps) {
|
|
7
|
+
export function NumberSelect({value, options, disabled, onChange, showEmptyOption, emptyOptionLabel}: NumberSelectProps) {
|
|
8
8
|
const nValue = useMemo(
|
|
9
9
|
() => {
|
|
10
10
|
if (!value) return '';
|
|
@@ -35,6 +35,7 @@ export function NumberSelect({value, options, onChange, showEmptyOption, emptyOp
|
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<StringSelect
|
|
38
|
+
disabled={disabled}
|
|
38
39
|
value={nValue}
|
|
39
40
|
options={nOptions}
|
|
40
41
|
onChange={nChange}
|
|
@@ -11,12 +11,13 @@ export type GenericSelectProps<T> = {
|
|
|
11
11
|
options: Array<GenericSelectOption<T>>;
|
|
12
12
|
onChange: (id: T | null | undefined) => any;
|
|
13
13
|
showEmptyOption?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
14
15
|
emptyOptionLabel?: string;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export type StringSelectProps = GenericSelectProps<string>;
|
|
18
19
|
|
|
19
|
-
export function StringSelect({value, options, onChange, showEmptyOption, emptyOptionLabel}: StringSelectProps) {
|
|
20
|
+
export function StringSelect({value, options, disabled, onChange, showEmptyOption, emptyOptionLabel}: StringSelectProps) {
|
|
20
21
|
if (StringUtil.isEmpty(value) && options.length > 0 && showEmptyOption !== true) {
|
|
21
22
|
onChange(options[0].id);
|
|
22
23
|
return <span>{value} - selecting default {options[0].id}</span>;
|
|
@@ -26,6 +27,7 @@ export function StringSelect({value, options, onChange, showEmptyOption, emptyOp
|
|
|
26
27
|
<Form.Select
|
|
27
28
|
value={value || ''}
|
|
28
29
|
onChange={(e) => onChange(e.target.value)}
|
|
30
|
+
disabled={disabled}
|
|
29
31
|
>
|
|
30
32
|
{
|
|
31
33
|
(showEmptyOption === true) && (
|
|
@@ -7,9 +7,12 @@ export type TextInputWithResetProps = {
|
|
|
7
7
|
value?: string | null;
|
|
8
8
|
onChange: (s: string) => any;
|
|
9
9
|
onReset?: () => any;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
onBlur?: () => any;
|
|
12
|
+
className?: string;
|
|
10
13
|
};
|
|
11
14
|
|
|
12
|
-
export function TextInputWithReset({value, onChange, onReset}: TextInputWithResetProps) {
|
|
15
|
+
export function TextInputWithReset({value, onChange, onReset, onBlur, disabled, className}: TextInputWithResetProps) {
|
|
13
16
|
const actual = useMemo(
|
|
14
17
|
() => StringUtil.getNonEmpty(value),
|
|
15
18
|
[value]
|
|
@@ -24,11 +27,13 @@ export function TextInputWithReset({value, onChange, onReset}: TextInputWithRese
|
|
|
24
27
|
);
|
|
25
28
|
|
|
26
29
|
return (
|
|
27
|
-
<InputGroup>
|
|
30
|
+
<InputGroup className={className}>
|
|
28
31
|
<Form.Control
|
|
29
32
|
type="text"
|
|
33
|
+
disabled={disabled}
|
|
30
34
|
value={actual}
|
|
31
35
|
onChange={(e) => onChange(e.target.value)}
|
|
36
|
+
onBlur={onBlur}
|
|
32
37
|
/>
|
|
33
38
|
<Button onClick={reset}>
|
|
34
39
|
<div className="d-flex align-items-center">
|