@etsoo/materialui 1.5.87 → 1.5.89
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/__tests__/ComboBox.tsx +16 -17
- package/__tests__/CustomFields.tsx +2 -2
- package/__tests__/InputTipField.tsx +76 -0
- package/lib/cjs/ComboBoxMultiple.js +2 -2
- package/lib/cjs/ComboBoxPro.js +2 -2
- package/lib/cjs/InputTipField.d.ts +38 -28
- package/lib/cjs/InputTipField.js +1 -2
- package/lib/cjs/TagListPro.js +3 -3
- package/lib/cjs/Tiplist.js +2 -2
- package/lib/cjs/TiplistPro.js +2 -2
- package/lib/mjs/ComboBoxMultiple.js +2 -2
- package/lib/mjs/ComboBoxPro.js +2 -2
- package/lib/mjs/InputTipField.d.ts +38 -28
- package/lib/mjs/InputTipField.js +1 -2
- package/lib/mjs/TagListPro.js +3 -3
- package/lib/mjs/Tiplist.js +2 -2
- package/lib/mjs/TiplistPro.js +2 -2
- package/package.json +5 -5
- package/src/ComboBoxMultiple.tsx +2 -0
- package/src/ComboBoxPro.tsx +6 -3
- package/src/InputTipField.tsx +52 -44
- package/src/TagListPro.tsx +5 -2
- package/src/Tiplist.tsx +2 -0
- package/src/TiplistPro.tsx +3 -0
package/__tests__/ComboBox.tsx
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { ComboBox } from "../src";
|
|
3
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
act,
|
|
4
|
+
fireEvent,
|
|
5
|
+
render,
|
|
6
|
+
screen,
|
|
7
|
+
waitFor
|
|
8
|
+
} from "@testing-library/react";
|
|
4
9
|
|
|
5
10
|
it("Render ComboBox", async () => {
|
|
6
11
|
// Arrange
|
|
@@ -21,21 +26,15 @@ it("Render ComboBox", async () => {
|
|
|
21
26
|
);
|
|
22
27
|
});
|
|
23
28
|
|
|
24
|
-
await
|
|
25
|
-
|
|
26
|
-
await screen.findByRole("button");
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
timeout: 500, // default is 1000
|
|
30
|
-
interval: 20 // default is 50
|
|
31
|
-
}
|
|
32
|
-
);
|
|
29
|
+
await waitFor(async () => {
|
|
30
|
+
const button = await screen.findByRole("button");
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
// Act, click the list
|
|
33
|
+
const clicked = fireEvent.click(button);
|
|
34
|
+
expect(clicked).toBeTruthy();
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
// Get list item
|
|
37
|
+
const item = await screen.findByText("Name 1");
|
|
38
|
+
expect(item.nodeName).toBe("LI");
|
|
39
|
+
});
|
|
41
40
|
});
|
|
@@ -137,13 +137,13 @@ it("Render FieldSelect", async () => {
|
|
|
137
137
|
);
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
const button = screen.
|
|
140
|
+
const button = await screen.findByRole("combobox");
|
|
141
141
|
|
|
142
142
|
act(() => {
|
|
143
143
|
// Act, click to open the dropdown list
|
|
144
144
|
vi.useFakeTimers();
|
|
145
145
|
fireEvent.mouseDown(button);
|
|
146
|
-
vi.
|
|
146
|
+
vi.runAllTimers();
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
const input = document.querySelector<HTMLInputElement>("input");
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
2
|
+
import { act } from "react";
|
|
3
|
+
import { InputTipField } from "../src";
|
|
4
|
+
|
|
5
|
+
it("Render default InputTipField", async () => {
|
|
6
|
+
// Render component
|
|
7
|
+
act(() => {
|
|
8
|
+
render(
|
|
9
|
+
<InputTipField
|
|
10
|
+
name="amount"
|
|
11
|
+
type="number"
|
|
12
|
+
componentProps={{
|
|
13
|
+
loadData: (_value) => Promise.resolve([])
|
|
14
|
+
}}
|
|
15
|
+
slotProps={{ htmlInput: { role: "input" } }}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const input = screen.getByRole<HTMLInputElement>("input");
|
|
21
|
+
expect(input.type).toBe("number");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("Render email InputTipField", async () => {
|
|
25
|
+
// Arrange
|
|
26
|
+
type T = { id: number; name: string };
|
|
27
|
+
const options: T[] = [
|
|
28
|
+
{ id: 1, name: "Name 1" },
|
|
29
|
+
{ id: 2, name: "Name 2" }
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const changeHandler = vi.fn();
|
|
33
|
+
|
|
34
|
+
const flag = "2 items";
|
|
35
|
+
|
|
36
|
+
// Render component
|
|
37
|
+
act(() => {
|
|
38
|
+
render(
|
|
39
|
+
<InputTipField<T>
|
|
40
|
+
component="email"
|
|
41
|
+
componentProps={{
|
|
42
|
+
loadData: (_value) => Promise.resolve([options, flag]),
|
|
43
|
+
itemLabel: (item) => item.name + ` (${item.id})`
|
|
44
|
+
}}
|
|
45
|
+
onChangeDelay={changeHandler}
|
|
46
|
+
slotProps={{ htmlInput: { role: "input" } }}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const input = screen.getByRole<HTMLInputElement>("input");
|
|
52
|
+
expect(input.type).toBe("email");
|
|
53
|
+
|
|
54
|
+
act(() => {
|
|
55
|
+
vi.useFakeTimers();
|
|
56
|
+
|
|
57
|
+
fireEvent.change(input, { target: { value: "info@etsoo.com" } });
|
|
58
|
+
expect(input.value).toBe("info@etsoo.com");
|
|
59
|
+
|
|
60
|
+
vi.runAllTimers();
|
|
61
|
+
expect(changeHandler).toHaveBeenCalled();
|
|
62
|
+
|
|
63
|
+
// Restore timers, otherwise 'waitFor' will fail
|
|
64
|
+
vi.useRealTimers();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
await waitFor(() => {
|
|
68
|
+
const button = screen.getByText(flag);
|
|
69
|
+
expect(button.nodeName).toBe("P");
|
|
70
|
+
|
|
71
|
+
fireEvent.click(button);
|
|
72
|
+
|
|
73
|
+
const item = screen.getByText("Name 2 (2)");
|
|
74
|
+
expect(item.nodeName).toBe("LI");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -29,7 +29,7 @@ function ComboBoxMultiple(props) {
|
|
|
29
29
|
// Labels
|
|
30
30
|
const labels = app?.getLabels("noOptions", "loading");
|
|
31
31
|
// Destruct
|
|
32
|
-
const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "off", options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = (props, option, { selected }) => ((0, jsx_runtime_1.jsxs)("li", { ...props, children: [(0, jsx_runtime_1.jsx)(Checkbox_1.default, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }), `${option[labelField]}`] })), getOptionLabel = (option) => `${option[labelField]}`, sx = { minWidth: "150px" }, noOptionsText = labels?.noOptions, loadingText = labels?.loading, ...rest } = props;
|
|
32
|
+
const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "off", options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = (props, option, { selected }) => ((0, jsx_runtime_1.jsxs)("li", { ...props, children: [(0, jsx_runtime_1.jsx)(Checkbox_1.default, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }), `${option[labelField]}`] })), getOptionLabel = (option) => `${option[labelField]}`, getOptionKey = (option) => `${option[idField]}`, sx = { minWidth: "150px" }, noOptionsText = labels?.noOptions, loadingText = labels?.loading, ...rest } = props;
|
|
33
33
|
// Value input ref
|
|
34
34
|
const inputRef = react_1.default.createRef();
|
|
35
35
|
// Options state
|
|
@@ -125,7 +125,7 @@ function ComboBoxMultiple(props) {
|
|
|
125
125
|
? []
|
|
126
126
|
: Array.isArray(stateValue)
|
|
127
127
|
? stateValue
|
|
128
|
-
: [stateValue], disableCloseOnSelect: disableCloseOnSelect, getOptionLabel: getOptionLabel, multiple: true, isOptionEqualToValue: (option, value) => option[idField] === value[idField], onChange: (event, value, reason, details) => {
|
|
128
|
+
: [stateValue], disableCloseOnSelect: disableCloseOnSelect, getOptionLabel: getOptionLabel, getOptionKey: getOptionKey, multiple: true, isOptionEqualToValue: (option, value) => option[idField] === value[idField], onChange: (event, value, reason, details) => {
|
|
129
129
|
// Set value
|
|
130
130
|
setInputValue(value.concat());
|
|
131
131
|
// Custom
|
package/lib/cjs/ComboBoxPro.js
CHANGED
|
@@ -16,7 +16,7 @@ function ComboBoxPro(props) {
|
|
|
16
16
|
// Labels
|
|
17
17
|
const { noOptions, loading: loadingLabel, open: openDefault } = app?.getLabels("noOptions", "loading", "open") ?? {};
|
|
18
18
|
// Destruct
|
|
19
|
-
const { noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, options, openOnFocus = true, label, inputProps, name, value, idValue, onChange, onValueChange, ...rest } = props;
|
|
19
|
+
const { getOptionKey = (option) => typeof option === "string" ? option : option.id, getOptionLabel = (option) => typeof option === "object" ? shared_1.DataTypes.getListItemLabel(option) : option, noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, options, openOnFocus = true, label, inputProps, name, value, idValue, onChange, onValueChange, ...rest } = props;
|
|
20
20
|
const [open, setOpen] = react_1.default.useState(false);
|
|
21
21
|
const [localOptions, setOptions] = react_1.default.useState([]);
|
|
22
22
|
const [localValue, setValue] = react_1.default.useState(null);
|
|
@@ -61,7 +61,7 @@ function ComboBoxPro(props) {
|
|
|
61
61
|
if (!localValue && localValue != value)
|
|
62
62
|
onChange(event, value, "blur", undefined);
|
|
63
63
|
}
|
|
64
|
-
} })), getOptionLabel:
|
|
64
|
+
} })), getOptionLabel: getOptionLabel, getOptionKey: getOptionKey, isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, onChange: (event, value, reason, details) => {
|
|
65
65
|
setValue(value);
|
|
66
66
|
if (onChange)
|
|
67
67
|
onChange(event, value, reason, details);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IdType } from "@etsoo/shared";
|
|
2
2
|
import { TypographyProps } from "@mui/material/Typography";
|
|
3
3
|
import React from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { InputFieldProps } from "./InputField";
|
|
5
5
|
import { EmailInput } from "./EmailInput";
|
|
6
6
|
import { MobileInput } from "./MobileInput";
|
|
7
7
|
import { PhoneInput } from "./PhoneInput";
|
|
@@ -9,52 +9,62 @@ type ItemType = {
|
|
|
9
9
|
id: IdType;
|
|
10
10
|
};
|
|
11
11
|
declare const componentMap: {
|
|
12
|
-
input: typeof InputField;
|
|
13
12
|
email: typeof EmailInput;
|
|
14
13
|
phone: typeof PhoneInput;
|
|
15
14
|
mobile: typeof MobileInput;
|
|
16
15
|
};
|
|
17
16
|
type ComponentMap = typeof componentMap;
|
|
18
17
|
type ComponentKey = keyof ComponentMap;
|
|
18
|
+
type ComponentProps<T extends ItemType> = {
|
|
19
|
+
/**
|
|
20
|
+
* Load data
|
|
21
|
+
* @param value Duplicate test value
|
|
22
|
+
*/
|
|
23
|
+
loadData(value: string): Promise<[T[]?, string?]>;
|
|
24
|
+
/**
|
|
25
|
+
* Label props
|
|
26
|
+
*/
|
|
27
|
+
labelProps?: Omit<TypographyProps, "onClick">;
|
|
28
|
+
/**
|
|
29
|
+
* Custom item label
|
|
30
|
+
* @param item List item data
|
|
31
|
+
* @returns Result
|
|
32
|
+
*/
|
|
33
|
+
itemLabel?: (item: T) => React.ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Custom render item
|
|
36
|
+
* @param item List item data
|
|
37
|
+
* @returns Result
|
|
38
|
+
*/
|
|
39
|
+
renderItem?: (item: T) => React.ReactNode;
|
|
40
|
+
};
|
|
19
41
|
/**
|
|
20
42
|
* InputField with tips properties
|
|
21
43
|
*/
|
|
22
|
-
export type InputTipFieldProps<T extends ItemType = ItemType
|
|
44
|
+
export type InputTipFieldProps<T extends ItemType = ItemType> = {
|
|
23
45
|
/**
|
|
24
|
-
* Component
|
|
46
|
+
* Component properties
|
|
25
47
|
*/
|
|
26
|
-
|
|
48
|
+
componentProps: ComponentProps<T>;
|
|
49
|
+
} & (({
|
|
27
50
|
/**
|
|
28
51
|
* Component properties
|
|
29
52
|
*/
|
|
30
|
-
componentProps:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* @param value Duplicate test value
|
|
34
|
-
*/
|
|
35
|
-
loadData(value: string): Promise<[T[]?, string?]>;
|
|
36
|
-
/**
|
|
37
|
-
* Label props
|
|
38
|
-
*/
|
|
39
|
-
labelProps?: Omit<TypographyProps, "onClick">;
|
|
40
|
-
/**
|
|
41
|
-
* Custom item label
|
|
42
|
-
* @param item List item data
|
|
43
|
-
* @returns Result
|
|
44
|
-
*/
|
|
45
|
-
itemLabel?: (item: T) => React.ReactNode;
|
|
53
|
+
componentProps: ComponentProps<T>;
|
|
54
|
+
} & {
|
|
55
|
+
[K in ComponentKey]: {
|
|
46
56
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @param item List item data
|
|
49
|
-
* @returns Result
|
|
57
|
+
* Component key
|
|
50
58
|
*/
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
}
|
|
59
|
+
component: K;
|
|
60
|
+
} & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
|
|
61
|
+
}[ComponentKey]) | ({
|
|
62
|
+
component?: "input";
|
|
63
|
+
} & Omit<InputFieldProps, "component">));
|
|
54
64
|
/**
|
|
55
65
|
* InputField with tips
|
|
56
66
|
* @param props Props
|
|
57
67
|
* @returns Component
|
|
58
68
|
*/
|
|
59
|
-
export declare function InputTipField<T extends ItemType = ItemType
|
|
69
|
+
export declare function InputTipField<T extends ItemType = ItemType>(props: InputTipFieldProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
60
70
|
export {};
|
package/lib/cjs/InputTipField.js
CHANGED
|
@@ -18,7 +18,6 @@ const EmailInput_1 = require("./EmailInput");
|
|
|
18
18
|
const MobileInput_1 = require("./MobileInput");
|
|
19
19
|
const PhoneInput_1 = require("./PhoneInput");
|
|
20
20
|
const componentMap = {
|
|
21
|
-
input: InputField_1.InputField,
|
|
22
21
|
email: EmailInput_1.EmailInput,
|
|
23
22
|
phone: PhoneInput_1.PhoneInput,
|
|
24
23
|
mobile: MobileInput_1.MobileInput
|
|
@@ -42,7 +41,7 @@ function InputTipField(props) {
|
|
|
42
41
|
sx: { color: (theme) => theme.palette.error.main, cursor: "pointer" }
|
|
43
42
|
}, loadData, itemLabel = (item) => shared_1.DataTypes.getObjectItemLabel(item), renderItem = (item) => (0, jsx_runtime_1.jsx)(ListItem_1.default, { children: itemLabel(item) }, item.id) } = componentProps;
|
|
44
43
|
const { input, ...slotRests } = slotProps;
|
|
45
|
-
const Component = componentMap[component];
|
|
44
|
+
const Component = component === "input" ? InputField_1.InputField : componentMap[component];
|
|
46
45
|
const load = (value) => {
|
|
47
46
|
if (value.length < 2) {
|
|
48
47
|
setTitle(undefined);
|
package/lib/cjs/TagListPro.js
CHANGED
|
@@ -22,7 +22,7 @@ function TagListPro(props) {
|
|
|
22
22
|
const moreLabel = more + "...";
|
|
23
23
|
const getLabel = (item) => shared_1.DataTypes.getListItemLabel(item);
|
|
24
24
|
// Destruct
|
|
25
|
-
const { renderOption = ({ key, ...props }, option, { selected }) => ((0, jsx_runtime_1.jsx)("li", { ...props, children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Checkbox_1.default, { icon: (0, jsx_runtime_1.jsx)(CheckBoxOutlineBlank_1.default, { fontSize: "small" }), checkedIcon: (0, jsx_runtime_1.jsx)(CheckBox_1.default, { fontSize: "small" }), style: { marginRight: 8 }, checked: selected }), getLabel(option)] }) }, key)),
|
|
25
|
+
const { getOptionKey = (option) => typeof option === "string" ? option : option.id, renderOption = ({ key, ...props }, option, { selected }) => ((0, jsx_runtime_1.jsx)("li", { ...props, children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Checkbox_1.default, { icon: (0, jsx_runtime_1.jsx)(CheckBoxOutlineBlank_1.default, { fontSize: "small" }), checkedIcon: (0, jsx_runtime_1.jsx)(CheckBox_1.default, { fontSize: "small" }), style: { marginRight: 8 }, checked: selected }), getLabel(option)] }) }, key)), renderValue = (value, getTagProps) => value.map((option, index) => {
|
|
26
26
|
const { key, ...rest } = getTagProps({ index });
|
|
27
27
|
return ((0, jsx_runtime_1.jsx)(Chip_1.default, { variant: "outlined", label: getLabel(option), ...rest }, key));
|
|
28
28
|
}), noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, loadData, maxItems = 16, disableCloseOnSelect = true, openOnFocus = true, label, inputProps, onChange, value, ...rest } = props;
|
|
@@ -56,7 +56,7 @@ function TagListPro(props) {
|
|
|
56
56
|
}
|
|
57
57
|
}, onClose: () => {
|
|
58
58
|
setOpen(false);
|
|
59
|
-
}, options: options, loading: loading, disableCloseOnSelect: disableCloseOnSelect, openOnFocus: openOnFocus, renderOption: renderOption,
|
|
59
|
+
}, options: options, loading: loading, disableCloseOnSelect: disableCloseOnSelect, openOnFocus: openOnFocus, renderOption: renderOption, renderValue: renderValue, renderInput: (params) => ((0, jsx_runtime_1.jsx)(InputField_1.InputField, { label: label, changeDelay: 480, onChange: async (event) => {
|
|
60
60
|
// Stop bubble
|
|
61
61
|
event.preventDefault();
|
|
62
62
|
event.stopPropagation();
|
|
@@ -65,7 +65,7 @@ function TagListPro(props) {
|
|
|
65
65
|
return (typeof item.id === "number" &&
|
|
66
66
|
item.id < 0 &&
|
|
67
67
|
getLabel(item) === moreLabel);
|
|
68
|
-
}, getOptionLabel: (item) => getLabel(item), isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, value: value, onChange: (event, value, reason, details) => {
|
|
68
|
+
}, getOptionLabel: (item) => getLabel(item), getOptionKey: getOptionKey, isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, value: value, onChange: (event, value, reason, details) => {
|
|
69
69
|
currentValue.current = value;
|
|
70
70
|
if (onChange)
|
|
71
71
|
onChange(event, value, reason, details);
|
package/lib/cjs/Tiplist.js
CHANGED
|
@@ -23,7 +23,7 @@ function Tiplist(props) {
|
|
|
23
23
|
// Labels
|
|
24
24
|
const { noOptions, loading, more1 = "More", open: openDefault } = app?.getLabels("noOptions", "loading", "more1", "open") ?? {};
|
|
25
25
|
// Destruct
|
|
26
|
-
const { search = false, idField = "id", idValue, idIsString = false, inputAutoComplete = "off", inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, label, loadData, defaultValue, value, maxItems = 16, width = search ? 160 : undefined, name, readOnly, onChange, onValueChange, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionLabel, getOptionDisabled, sx = {}, minChars, ...rest } = props;
|
|
26
|
+
const { search = false, idField = "id", idValue, idIsString = false, inputAutoComplete = "off", inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, label, loadData, defaultValue, value, maxItems = 16, width = search ? 160 : undefined, name, readOnly, onChange, onValueChange, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionKey = (option) => `${option[idField]}`, getOptionLabel, getOptionDisabled, sx = {}, minChars, ...rest } = props;
|
|
27
27
|
if (width && sx)
|
|
28
28
|
Object.assign(sx, { width: `${width}px` });
|
|
29
29
|
// Value input ref
|
|
@@ -209,5 +209,5 @@ function Tiplist(props) {
|
|
|
209
209
|
return getOptionLabel
|
|
210
210
|
? getOptionLabel(item)
|
|
211
211
|
: shared_1.DataTypes.getObjectItemLabel(item);
|
|
212
|
-
}, ...rest })] }));
|
|
212
|
+
}, getOptionKey: getOptionKey, ...rest })] }));
|
|
213
213
|
}
|
package/lib/cjs/TiplistPro.js
CHANGED
|
@@ -22,7 +22,7 @@ function TiplistPro(props) {
|
|
|
22
22
|
// Labels
|
|
23
23
|
const { noOptions, loading, more, open: openDefault } = app?.getLabels("noOptions", "loading", "more", "open") ?? {};
|
|
24
24
|
// Destruct
|
|
25
|
-
const { label, loadData, defaultValue, value, idValue, idIsString = false, maxItems = 16, width, name, inputOnChange, inputProps, inputReset, sx, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionDisabled, getOptionLabel, onChange, onValueChange, minChars, ...rest } = props;
|
|
25
|
+
const { label, loadData, defaultValue, value, idValue, idIsString = false, maxItems = 16, width, name, inputOnChange, inputProps, inputReset, sx, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionDisabled, getOptionLabel, getOptionKey = (option) => typeof option === "string" ? option : option.id, onChange, onValueChange, minChars, ...rest } = props;
|
|
26
26
|
if (width && sx)
|
|
27
27
|
Object.assign(sx, { width: `${width}px` });
|
|
28
28
|
// Value input ref
|
|
@@ -192,7 +192,7 @@ function TiplistPro(props) {
|
|
|
192
192
|
}, loading: states.loading, renderInput: (params) => ((0, jsx_runtime_1.jsx)(InputField_1.InputField, { minChars: minChars, ...inputProps, ...params, onChange: changeHandle, label: label, name: name + "Input", onBlur: (event) => {
|
|
193
193
|
if (states.value == null && onChange)
|
|
194
194
|
onChange(event, event.target.value, "blur", undefined);
|
|
195
|
-
}, "data-reset": inputReset })), isOptionEqualToValue: (option, value) => option.id === value.id, sx: sx, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, getOptionDisabled: (item) => {
|
|
195
|
+
}, "data-reset": inputReset })), isOptionEqualToValue: (option, value) => option.id === value.id, sx: sx, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, getOptionKey: getOptionKey, getOptionDisabled: (item) => {
|
|
196
196
|
if (item.id === -1)
|
|
197
197
|
return true;
|
|
198
198
|
return getOptionDisabled ? getOptionDisabled(item) : false;
|
|
@@ -23,7 +23,7 @@ export function ComboBoxMultiple(props) {
|
|
|
23
23
|
// Labels
|
|
24
24
|
const labels = app?.getLabels("noOptions", "loading");
|
|
25
25
|
// Destruct
|
|
26
|
-
const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "off", options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = (props, option, { selected }) => (_jsxs("li", { ...props, children: [_jsx(Checkbox, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }), `${option[labelField]}`] })), getOptionLabel = (option) => `${option[labelField]}`, sx = { minWidth: "150px" }, noOptionsText = labels?.noOptions, loadingText = labels?.loading, ...rest } = props;
|
|
26
|
+
const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "off", options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = (props, option, { selected }) => (_jsxs("li", { ...props, children: [_jsx(Checkbox, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }), `${option[labelField]}`] })), getOptionLabel = (option) => `${option[labelField]}`, getOptionKey = (option) => `${option[idField]}`, sx = { minWidth: "150px" }, noOptionsText = labels?.noOptions, loadingText = labels?.loading, ...rest } = props;
|
|
27
27
|
// Value input ref
|
|
28
28
|
const inputRef = React.createRef();
|
|
29
29
|
// Options state
|
|
@@ -119,7 +119,7 @@ export function ComboBoxMultiple(props) {
|
|
|
119
119
|
? []
|
|
120
120
|
: Array.isArray(stateValue)
|
|
121
121
|
? stateValue
|
|
122
|
-
: [stateValue], disableCloseOnSelect: disableCloseOnSelect, getOptionLabel: getOptionLabel, multiple: true, isOptionEqualToValue: (option, value) => option[idField] === value[idField], onChange: (event, value, reason, details) => {
|
|
122
|
+
: [stateValue], disableCloseOnSelect: disableCloseOnSelect, getOptionLabel: getOptionLabel, getOptionKey: getOptionKey, multiple: true, isOptionEqualToValue: (option, value) => option[idField] === value[idField], onChange: (event, value, reason, details) => {
|
|
123
123
|
// Set value
|
|
124
124
|
setInputValue(value.concat());
|
|
125
125
|
// Custom
|
package/lib/mjs/ComboBoxPro.js
CHANGED
|
@@ -10,7 +10,7 @@ export function ComboBoxPro(props) {
|
|
|
10
10
|
// Labels
|
|
11
11
|
const { noOptions, loading: loadingLabel, open: openDefault } = app?.getLabels("noOptions", "loading", "open") ?? {};
|
|
12
12
|
// Destruct
|
|
13
|
-
const { noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, options, openOnFocus = true, label, inputProps, name, value, idValue, onChange, onValueChange, ...rest } = props;
|
|
13
|
+
const { getOptionKey = (option) => typeof option === "string" ? option : option.id, getOptionLabel = (option) => typeof option === "object" ? DataTypes.getListItemLabel(option) : option, noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, options, openOnFocus = true, label, inputProps, name, value, idValue, onChange, onValueChange, ...rest } = props;
|
|
14
14
|
const [open, setOpen] = React.useState(false);
|
|
15
15
|
const [localOptions, setOptions] = React.useState([]);
|
|
16
16
|
const [localValue, setValue] = React.useState(null);
|
|
@@ -55,7 +55,7 @@ export function ComboBoxPro(props) {
|
|
|
55
55
|
if (!localValue && localValue != value)
|
|
56
56
|
onChange(event, value, "blur", undefined);
|
|
57
57
|
}
|
|
58
|
-
} })), getOptionLabel:
|
|
58
|
+
} })), getOptionLabel: getOptionLabel, getOptionKey: getOptionKey, isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, onChange: (event, value, reason, details) => {
|
|
59
59
|
setValue(value);
|
|
60
60
|
if (onChange)
|
|
61
61
|
onChange(event, value, reason, details);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IdType } from "@etsoo/shared";
|
|
2
2
|
import { TypographyProps } from "@mui/material/Typography";
|
|
3
3
|
import React from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { InputFieldProps } from "./InputField";
|
|
5
5
|
import { EmailInput } from "./EmailInput";
|
|
6
6
|
import { MobileInput } from "./MobileInput";
|
|
7
7
|
import { PhoneInput } from "./PhoneInput";
|
|
@@ -9,52 +9,62 @@ type ItemType = {
|
|
|
9
9
|
id: IdType;
|
|
10
10
|
};
|
|
11
11
|
declare const componentMap: {
|
|
12
|
-
input: typeof InputField;
|
|
13
12
|
email: typeof EmailInput;
|
|
14
13
|
phone: typeof PhoneInput;
|
|
15
14
|
mobile: typeof MobileInput;
|
|
16
15
|
};
|
|
17
16
|
type ComponentMap = typeof componentMap;
|
|
18
17
|
type ComponentKey = keyof ComponentMap;
|
|
18
|
+
type ComponentProps<T extends ItemType> = {
|
|
19
|
+
/**
|
|
20
|
+
* Load data
|
|
21
|
+
* @param value Duplicate test value
|
|
22
|
+
*/
|
|
23
|
+
loadData(value: string): Promise<[T[]?, string?]>;
|
|
24
|
+
/**
|
|
25
|
+
* Label props
|
|
26
|
+
*/
|
|
27
|
+
labelProps?: Omit<TypographyProps, "onClick">;
|
|
28
|
+
/**
|
|
29
|
+
* Custom item label
|
|
30
|
+
* @param item List item data
|
|
31
|
+
* @returns Result
|
|
32
|
+
*/
|
|
33
|
+
itemLabel?: (item: T) => React.ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Custom render item
|
|
36
|
+
* @param item List item data
|
|
37
|
+
* @returns Result
|
|
38
|
+
*/
|
|
39
|
+
renderItem?: (item: T) => React.ReactNode;
|
|
40
|
+
};
|
|
19
41
|
/**
|
|
20
42
|
* InputField with tips properties
|
|
21
43
|
*/
|
|
22
|
-
export type InputTipFieldProps<T extends ItemType = ItemType
|
|
44
|
+
export type InputTipFieldProps<T extends ItemType = ItemType> = {
|
|
23
45
|
/**
|
|
24
|
-
* Component
|
|
46
|
+
* Component properties
|
|
25
47
|
*/
|
|
26
|
-
|
|
48
|
+
componentProps: ComponentProps<T>;
|
|
49
|
+
} & (({
|
|
27
50
|
/**
|
|
28
51
|
* Component properties
|
|
29
52
|
*/
|
|
30
|
-
componentProps:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* @param value Duplicate test value
|
|
34
|
-
*/
|
|
35
|
-
loadData(value: string): Promise<[T[]?, string?]>;
|
|
36
|
-
/**
|
|
37
|
-
* Label props
|
|
38
|
-
*/
|
|
39
|
-
labelProps?: Omit<TypographyProps, "onClick">;
|
|
40
|
-
/**
|
|
41
|
-
* Custom item label
|
|
42
|
-
* @param item List item data
|
|
43
|
-
* @returns Result
|
|
44
|
-
*/
|
|
45
|
-
itemLabel?: (item: T) => React.ReactNode;
|
|
53
|
+
componentProps: ComponentProps<T>;
|
|
54
|
+
} & {
|
|
55
|
+
[K in ComponentKey]: {
|
|
46
56
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @param item List item data
|
|
49
|
-
* @returns Result
|
|
57
|
+
* Component key
|
|
50
58
|
*/
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
}
|
|
59
|
+
component: K;
|
|
60
|
+
} & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
|
|
61
|
+
}[ComponentKey]) | ({
|
|
62
|
+
component?: "input";
|
|
63
|
+
} & Omit<InputFieldProps, "component">));
|
|
54
64
|
/**
|
|
55
65
|
* InputField with tips
|
|
56
66
|
* @param props Props
|
|
57
67
|
* @returns Component
|
|
58
68
|
*/
|
|
59
|
-
export declare function InputTipField<T extends ItemType = ItemType
|
|
69
|
+
export declare function InputTipField<T extends ItemType = ItemType>(props: InputTipFieldProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
60
70
|
export {};
|
package/lib/mjs/InputTipField.js
CHANGED
|
@@ -12,7 +12,6 @@ import { EmailInput } from "./EmailInput";
|
|
|
12
12
|
import { MobileInput } from "./MobileInput";
|
|
13
13
|
import { PhoneInput } from "./PhoneInput";
|
|
14
14
|
const componentMap = {
|
|
15
|
-
input: InputField,
|
|
16
15
|
email: EmailInput,
|
|
17
16
|
phone: PhoneInput,
|
|
18
17
|
mobile: MobileInput
|
|
@@ -36,7 +35,7 @@ export function InputTipField(props) {
|
|
|
36
35
|
sx: { color: (theme) => theme.palette.error.main, cursor: "pointer" }
|
|
37
36
|
}, loadData, itemLabel = (item) => DataTypes.getObjectItemLabel(item), renderItem = (item) => _jsx(ListItem, { children: itemLabel(item) }, item.id) } = componentProps;
|
|
38
37
|
const { input, ...slotRests } = slotProps;
|
|
39
|
-
const Component = componentMap[component];
|
|
38
|
+
const Component = component === "input" ? InputField : componentMap[component];
|
|
40
39
|
const load = (value) => {
|
|
41
40
|
if (value.length < 2) {
|
|
42
41
|
setTitle(undefined);
|
package/lib/mjs/TagListPro.js
CHANGED
|
@@ -16,7 +16,7 @@ export function TagListPro(props) {
|
|
|
16
16
|
const moreLabel = more + "...";
|
|
17
17
|
const getLabel = (item) => DataTypes.getListItemLabel(item);
|
|
18
18
|
// Destruct
|
|
19
|
-
const { renderOption = ({ key, ...props }, option, { selected }) => (_jsx("li", { ...props, children: _jsxs(_Fragment, { children: [_jsx(Checkbox, { icon: _jsx(CheckBoxOutlineBlankIcon, { fontSize: "small" }), checkedIcon: _jsx(CheckBoxIcon, { fontSize: "small" }), style: { marginRight: 8 }, checked: selected }), getLabel(option)] }) }, key)),
|
|
19
|
+
const { getOptionKey = (option) => typeof option === "string" ? option : option.id, renderOption = ({ key, ...props }, option, { selected }) => (_jsx("li", { ...props, children: _jsxs(_Fragment, { children: [_jsx(Checkbox, { icon: _jsx(CheckBoxOutlineBlankIcon, { fontSize: "small" }), checkedIcon: _jsx(CheckBoxIcon, { fontSize: "small" }), style: { marginRight: 8 }, checked: selected }), getLabel(option)] }) }, key)), renderValue = (value, getTagProps) => value.map((option, index) => {
|
|
20
20
|
const { key, ...rest } = getTagProps({ index });
|
|
21
21
|
return (_jsx(Chip, { variant: "outlined", label: getLabel(option), ...rest }, key));
|
|
22
22
|
}), noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, loadData, maxItems = 16, disableCloseOnSelect = true, openOnFocus = true, label, inputProps, onChange, value, ...rest } = props;
|
|
@@ -50,7 +50,7 @@ export function TagListPro(props) {
|
|
|
50
50
|
}
|
|
51
51
|
}, onClose: () => {
|
|
52
52
|
setOpen(false);
|
|
53
|
-
}, options: options, loading: loading, disableCloseOnSelect: disableCloseOnSelect, openOnFocus: openOnFocus, renderOption: renderOption,
|
|
53
|
+
}, options: options, loading: loading, disableCloseOnSelect: disableCloseOnSelect, openOnFocus: openOnFocus, renderOption: renderOption, renderValue: renderValue, renderInput: (params) => (_jsx(InputField, { label: label, changeDelay: 480, onChange: async (event) => {
|
|
54
54
|
// Stop bubble
|
|
55
55
|
event.preventDefault();
|
|
56
56
|
event.stopPropagation();
|
|
@@ -59,7 +59,7 @@ export function TagListPro(props) {
|
|
|
59
59
|
return (typeof item.id === "number" &&
|
|
60
60
|
item.id < 0 &&
|
|
61
61
|
getLabel(item) === moreLabel);
|
|
62
|
-
}, getOptionLabel: (item) => getLabel(item), isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, value: value, onChange: (event, value, reason, details) => {
|
|
62
|
+
}, getOptionLabel: (item) => getLabel(item), getOptionKey: getOptionKey, isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, value: value, onChange: (event, value, reason, details) => {
|
|
63
63
|
currentValue.current = value;
|
|
64
64
|
if (onChange)
|
|
65
65
|
onChange(event, value, reason, details);
|
package/lib/mjs/Tiplist.js
CHANGED
|
@@ -17,7 +17,7 @@ export function Tiplist(props) {
|
|
|
17
17
|
// Labels
|
|
18
18
|
const { noOptions, loading, more1 = "More", open: openDefault } = app?.getLabels("noOptions", "loading", "more1", "open") ?? {};
|
|
19
19
|
// Destruct
|
|
20
|
-
const { search = false, idField = "id", idValue, idIsString = false, inputAutoComplete = "off", inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, label, loadData, defaultValue, value, maxItems = 16, width = search ? 160 : undefined, name, readOnly, onChange, onValueChange, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionLabel, getOptionDisabled, sx = {}, minChars, ...rest } = props;
|
|
20
|
+
const { search = false, idField = "id", idValue, idIsString = false, inputAutoComplete = "off", inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputReset, inputVariant, label, loadData, defaultValue, value, maxItems = 16, width = search ? 160 : undefined, name, readOnly, onChange, onValueChange, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionKey = (option) => `${option[idField]}`, getOptionLabel, getOptionDisabled, sx = {}, minChars, ...rest } = props;
|
|
21
21
|
if (width && sx)
|
|
22
22
|
Object.assign(sx, { width: `${width}px` });
|
|
23
23
|
// Value input ref
|
|
@@ -203,5 +203,5 @@ export function Tiplist(props) {
|
|
|
203
203
|
return getOptionLabel
|
|
204
204
|
? getOptionLabel(item)
|
|
205
205
|
: DataTypes.getObjectItemLabel(item);
|
|
206
|
-
}, ...rest })] }));
|
|
206
|
+
}, getOptionKey: getOptionKey, ...rest })] }));
|
|
207
207
|
}
|
package/lib/mjs/TiplistPro.js
CHANGED
|
@@ -16,7 +16,7 @@ export function TiplistPro(props) {
|
|
|
16
16
|
// Labels
|
|
17
17
|
const { noOptions, loading, more, open: openDefault } = app?.getLabels("noOptions", "loading", "more", "open") ?? {};
|
|
18
18
|
// Destruct
|
|
19
|
-
const { label, loadData, defaultValue, value, idValue, idIsString = false, maxItems = 16, width, name, inputOnChange, inputProps, inputReset, sx, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionDisabled, getOptionLabel, onChange, onValueChange, minChars, ...rest } = props;
|
|
19
|
+
const { label, loadData, defaultValue, value, idValue, idIsString = false, maxItems = 16, width, name, inputOnChange, inputProps, inputReset, sx, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionDisabled, getOptionLabel, getOptionKey = (option) => typeof option === "string" ? option : option.id, onChange, onValueChange, minChars, ...rest } = props;
|
|
20
20
|
if (width && sx)
|
|
21
21
|
Object.assign(sx, { width: `${width}px` });
|
|
22
22
|
// Value input ref
|
|
@@ -186,7 +186,7 @@ export function TiplistPro(props) {
|
|
|
186
186
|
}, loading: states.loading, renderInput: (params) => (_jsx(InputField, { minChars: minChars, ...inputProps, ...params, onChange: changeHandle, label: label, name: name + "Input", onBlur: (event) => {
|
|
187
187
|
if (states.value == null && onChange)
|
|
188
188
|
onChange(event, event.target.value, "blur", undefined);
|
|
189
|
-
}, "data-reset": inputReset })), isOptionEqualToValue: (option, value) => option.id === value.id, sx: sx, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, getOptionDisabled: (item) => {
|
|
189
|
+
}, "data-reset": inputReset })), isOptionEqualToValue: (option, value) => option.id === value.id, sx: sx, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, getOptionKey: getOptionKey, getOptionDisabled: (item) => {
|
|
190
190
|
if (item.id === -1)
|
|
191
191
|
return true;
|
|
192
192
|
return getOptionDisabled ? getOptionDisabled(item) : false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/materialui",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.89",
|
|
4
4
|
"description": "TypeScript Material-UI Implementation",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/mjs/index.js",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"@etsoo/appscript": "^1.6.48",
|
|
44
44
|
"@etsoo/notificationbase": "^1.1.66",
|
|
45
45
|
"@etsoo/react": "^1.8.63",
|
|
46
|
-
"@etsoo/shared": "^1.2.
|
|
46
|
+
"@etsoo/shared": "^1.2.80",
|
|
47
47
|
"@mui/icons-material": "^7.3.5",
|
|
48
48
|
"@mui/material": "^7.3.5",
|
|
49
|
-
"@mui/x-data-grid": "^8.
|
|
49
|
+
"@mui/x-data-grid": "^8.19.0",
|
|
50
50
|
"chart.js": "^4.5.1",
|
|
51
51
|
"chartjs-plugin-datalabels": "^2.2.0",
|
|
52
52
|
"dompurify": "^3.3.0",
|
|
@@ -76,13 +76,13 @@
|
|
|
76
76
|
"@testing-library/react": "^16.3.0",
|
|
77
77
|
"@types/pica": "^9.0.5",
|
|
78
78
|
"@types/pulltorefreshjs": "^0.1.7",
|
|
79
|
-
"@types/react": "^19.2.
|
|
79
|
+
"@types/react": "^19.2.7",
|
|
80
80
|
"@types/react-avatar-editor": "^13.0.4",
|
|
81
81
|
"@types/react-dom": "^19.2.3",
|
|
82
82
|
"@types/react-input-mask": "^3.0.6",
|
|
83
83
|
"@vitejs/plugin-react": "^5.1.1",
|
|
84
84
|
"jsdom": "^27.2.0",
|
|
85
85
|
"typescript": "^5.9.3",
|
|
86
|
-
"vitest": "^4.0.
|
|
86
|
+
"vitest": "^4.0.14"
|
|
87
87
|
}
|
|
88
88
|
}
|
package/src/ComboBoxMultiple.tsx
CHANGED
|
@@ -122,6 +122,7 @@ export function ComboBoxMultiple<
|
|
|
122
122
|
</li>
|
|
123
123
|
),
|
|
124
124
|
getOptionLabel = (option: T) => `${option[labelField]}`,
|
|
125
|
+
getOptionKey = (option: T) => `${option[idField]}`,
|
|
125
126
|
sx = { minWidth: "150px" },
|
|
126
127
|
noOptionsText = labels?.noOptions,
|
|
127
128
|
loadingText = labels?.loading,
|
|
@@ -260,6 +261,7 @@ export function ComboBoxMultiple<
|
|
|
260
261
|
}
|
|
261
262
|
disableCloseOnSelect={disableCloseOnSelect}
|
|
262
263
|
getOptionLabel={getOptionLabel}
|
|
264
|
+
getOptionKey={getOptionKey}
|
|
263
265
|
multiple
|
|
264
266
|
isOptionEqualToValue={(option: T, value: T) =>
|
|
265
267
|
option[idField] === value[idField]
|
package/src/ComboBoxPro.tsx
CHANGED
|
@@ -55,6 +55,10 @@ export function ComboBoxPro<D extends ListType2 = ListType2>(
|
|
|
55
55
|
|
|
56
56
|
// Destruct
|
|
57
57
|
const {
|
|
58
|
+
getOptionKey = (option) =>
|
|
59
|
+
typeof option === "string" ? option : option.id,
|
|
60
|
+
getOptionLabel = (option) =>
|
|
61
|
+
typeof option === "object" ? DataTypes.getListItemLabel(option) : option,
|
|
58
62
|
noOptionsText = noOptions,
|
|
59
63
|
loadingText = loadingLabel,
|
|
60
64
|
openText = openDefault,
|
|
@@ -132,9 +136,8 @@ export function ComboBoxPro<D extends ListType2 = ListType2>(
|
|
|
132
136
|
}}
|
|
133
137
|
/>
|
|
134
138
|
)}
|
|
135
|
-
getOptionLabel={
|
|
136
|
-
|
|
137
|
-
}
|
|
139
|
+
getOptionLabel={getOptionLabel}
|
|
140
|
+
getOptionKey={getOptionKey}
|
|
138
141
|
isOptionEqualToValue={(option, value) => option.id === value.id}
|
|
139
142
|
noOptionsText={noOptionsText}
|
|
140
143
|
loadingText={loadingText}
|
package/src/InputTipField.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DataTypes, IdType } from "@etsoo/shared";
|
|
2
2
|
import Typography, { TypographyProps } from "@mui/material/Typography";
|
|
3
3
|
import React from "react";
|
|
4
|
-
import { InputField } from "./InputField";
|
|
4
|
+
import { InputField, InputFieldProps } from "./InputField";
|
|
5
5
|
import { useAppContext } from "./app/ReactApp";
|
|
6
6
|
import ListItem from "@mui/material/ListItem";
|
|
7
7
|
import Popover from "@mui/material/Popover";
|
|
@@ -16,7 +16,6 @@ type ItemType = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const componentMap = {
|
|
19
|
-
input: InputField,
|
|
20
19
|
email: EmailInput,
|
|
21
20
|
phone: PhoneInput,
|
|
22
21
|
mobile: MobileInput
|
|
@@ -25,58 +24,66 @@ const componentMap = {
|
|
|
25
24
|
type ComponentMap = typeof componentMap;
|
|
26
25
|
type ComponentKey = keyof ComponentMap;
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
* InputField with tips properties
|
|
30
|
-
*/
|
|
31
|
-
export type InputTipFieldProps<
|
|
32
|
-
T extends ItemType = ItemType,
|
|
33
|
-
K extends ComponentKey = "input"
|
|
34
|
-
> = Omit<React.ComponentProps<ComponentMap[K]>, "component"> & {
|
|
27
|
+
type ComponentProps<T extends ItemType> = {
|
|
35
28
|
/**
|
|
36
|
-
*
|
|
29
|
+
* Load data
|
|
30
|
+
* @param value Duplicate test value
|
|
37
31
|
*/
|
|
38
|
-
|
|
32
|
+
loadData(value: string): Promise<[T[]?, string?]>;
|
|
39
33
|
|
|
40
34
|
/**
|
|
41
|
-
*
|
|
35
|
+
* Label props
|
|
42
36
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* @returns Result
|
|
59
|
-
*/
|
|
60
|
-
itemLabel?: (item: T) => React.ReactNode;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Custom render item
|
|
64
|
-
* @param item List item data
|
|
65
|
-
* @returns Result
|
|
66
|
-
*/
|
|
67
|
-
renderItem?: (item: T) => React.ReactNode;
|
|
68
|
-
};
|
|
37
|
+
labelProps?: Omit<TypographyProps, "onClick">;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Custom item label
|
|
41
|
+
* @param item List item data
|
|
42
|
+
* @returns Result
|
|
43
|
+
*/
|
|
44
|
+
itemLabel?: (item: T) => React.ReactNode;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Custom render item
|
|
48
|
+
* @param item List item data
|
|
49
|
+
* @returns Result
|
|
50
|
+
*/
|
|
51
|
+
renderItem?: (item: T) => React.ReactNode;
|
|
69
52
|
};
|
|
70
53
|
|
|
54
|
+
/**
|
|
55
|
+
* InputField with tips properties
|
|
56
|
+
*/
|
|
57
|
+
export type InputTipFieldProps<T extends ItemType = ItemType> = {
|
|
58
|
+
/**
|
|
59
|
+
* Component properties
|
|
60
|
+
*/
|
|
61
|
+
componentProps: ComponentProps<T>;
|
|
62
|
+
} & (
|
|
63
|
+
| ({
|
|
64
|
+
/**
|
|
65
|
+
* Component properties
|
|
66
|
+
*/
|
|
67
|
+
componentProps: ComponentProps<T>;
|
|
68
|
+
} & {
|
|
69
|
+
[K in ComponentKey]: {
|
|
70
|
+
/**
|
|
71
|
+
* Component key
|
|
72
|
+
*/
|
|
73
|
+
component: K;
|
|
74
|
+
} & Omit<React.ComponentProps<ComponentMap[K]>, "component">;
|
|
75
|
+
}[ComponentKey])
|
|
76
|
+
| ({ component?: "input" } & Omit<InputFieldProps, "component">)
|
|
77
|
+
);
|
|
78
|
+
|
|
71
79
|
/**
|
|
72
80
|
* InputField with tips
|
|
73
81
|
* @param props Props
|
|
74
82
|
* @returns Component
|
|
75
83
|
*/
|
|
76
|
-
export function InputTipField<
|
|
77
|
-
T
|
|
78
|
-
|
|
79
|
-
>(props: InputTipFieldProps<T, K>) {
|
|
84
|
+
export function InputTipField<T extends ItemType = ItemType>(
|
|
85
|
+
props: InputTipFieldProps<T>
|
|
86
|
+
) {
|
|
80
87
|
// Global app
|
|
81
88
|
const app = useAppContext();
|
|
82
89
|
|
|
@@ -108,7 +115,8 @@ export function InputTipField<
|
|
|
108
115
|
|
|
109
116
|
const { input, ...slotRests } = slotProps;
|
|
110
117
|
|
|
111
|
-
const Component =
|
|
118
|
+
const Component =
|
|
119
|
+
component === "input" ? InputField : componentMap[component];
|
|
112
120
|
|
|
113
121
|
const load = (value: string) => {
|
|
114
122
|
if (value.length < 2) {
|
|
@@ -160,7 +168,7 @@ export function InputTipField<
|
|
|
160
168
|
},
|
|
161
169
|
...slotRests
|
|
162
170
|
}}
|
|
163
|
-
{...
|
|
171
|
+
{...rest}
|
|
164
172
|
/>
|
|
165
173
|
</React.Fragment>
|
|
166
174
|
);
|
package/src/TagListPro.tsx
CHANGED
|
@@ -56,6 +56,8 @@ export function TagListPro<D extends ListType2 = ListType2>(
|
|
|
56
56
|
|
|
57
57
|
// Destruct
|
|
58
58
|
const {
|
|
59
|
+
getOptionKey = (option) =>
|
|
60
|
+
typeof option === "string" ? option : option.id,
|
|
59
61
|
renderOption = ({ key, ...props }, option, { selected }) => (
|
|
60
62
|
<li key={key} {...props}>
|
|
61
63
|
<>
|
|
@@ -69,7 +71,7 @@ export function TagListPro<D extends ListType2 = ListType2>(
|
|
|
69
71
|
</>
|
|
70
72
|
</li>
|
|
71
73
|
),
|
|
72
|
-
|
|
74
|
+
renderValue = (value: readonly D[], getTagProps) =>
|
|
73
75
|
value.map((option, index) => {
|
|
74
76
|
const { key, ...rest } = getTagProps({ index });
|
|
75
77
|
return (
|
|
@@ -141,7 +143,7 @@ export function TagListPro<D extends ListType2 = ListType2>(
|
|
|
141
143
|
disableCloseOnSelect={disableCloseOnSelect}
|
|
142
144
|
openOnFocus={openOnFocus}
|
|
143
145
|
renderOption={renderOption}
|
|
144
|
-
|
|
146
|
+
renderValue={renderValue}
|
|
145
147
|
renderInput={(params) => (
|
|
146
148
|
<InputField
|
|
147
149
|
label={label}
|
|
@@ -165,6 +167,7 @@ export function TagListPro<D extends ListType2 = ListType2>(
|
|
|
165
167
|
);
|
|
166
168
|
}}
|
|
167
169
|
getOptionLabel={(item) => getLabel(item)}
|
|
170
|
+
getOptionKey={getOptionKey}
|
|
168
171
|
isOptionEqualToValue={(option, value) => option.id === value.id}
|
|
169
172
|
noOptionsText={noOptionsText}
|
|
170
173
|
loadingText={loadingText}
|
package/src/Tiplist.tsx
CHANGED
|
@@ -97,6 +97,7 @@ export function Tiplist<
|
|
|
97
97
|
noOptionsText = noOptions,
|
|
98
98
|
loadingText = loading,
|
|
99
99
|
openText = openDefault,
|
|
100
|
+
getOptionKey = (option) => `${option[idField]}`,
|
|
100
101
|
getOptionLabel,
|
|
101
102
|
getOptionDisabled,
|
|
102
103
|
sx = {},
|
|
@@ -389,6 +390,7 @@ export function Tiplist<
|
|
|
389
390
|
? getOptionLabel(item)
|
|
390
391
|
: DataTypes.getObjectItemLabel(item);
|
|
391
392
|
}}
|
|
393
|
+
getOptionKey={getOptionKey}
|
|
392
394
|
{...rest}
|
|
393
395
|
/>
|
|
394
396
|
</div>
|
package/src/TiplistPro.tsx
CHANGED
|
@@ -127,6 +127,8 @@ export function TiplistPro<T extends ListType2 = ListType2>(
|
|
|
127
127
|
openText = openDefault,
|
|
128
128
|
getOptionDisabled,
|
|
129
129
|
getOptionLabel,
|
|
130
|
+
getOptionKey = (option) =>
|
|
131
|
+
typeof option === "string" ? option : option.id,
|
|
130
132
|
onChange,
|
|
131
133
|
onValueChange,
|
|
132
134
|
minChars,
|
|
@@ -379,6 +381,7 @@ export function TiplistPro<T extends ListType2 = ListType2>(
|
|
|
379
381
|
noOptionsText={noOptionsText}
|
|
380
382
|
loadingText={loadingText}
|
|
381
383
|
openText={openText}
|
|
384
|
+
getOptionKey={getOptionKey}
|
|
382
385
|
getOptionDisabled={(item) => {
|
|
383
386
|
if (item.id === -1) return true;
|
|
384
387
|
return getOptionDisabled ? getOptionDisabled(item) : false;
|