@talixo-ds/options-input 1.0.6 → 1.0.7
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/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/{options-input.d.ts → index.d.mts} +22 -8
- package/dist/index.d.ts +57 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +32 -7
- package/dist/components/min-max-value-label.d.ts +0 -7
- package/dist/components/min-max-value-label.js +0 -4
- package/dist/components/min-max-value-label.js.map +0 -1
- package/dist/components/options-input-content-item.d.ts +0 -9
- package/dist/components/options-input-content-item.js +0 -19
- package/dist/components/options-input-content-item.js.map +0 -1
- package/dist/components/options-input-dropdown-item.d.ts +0 -12
- package/dist/components/options-input-dropdown-item.js +0 -54
- package/dist/components/options-input-dropdown-item.js.map +0 -1
- package/dist/options-input.js +0 -140
- package/dist/options-input.js.map +0 -1
- package/dist/types.d.ts +0 -13
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/utils.d.ts +0 -1
- package/dist/utils.js +0 -2
- package/dist/utils.js.map +0 -1
- package/src/__tests__/options-input.spec.tsx +0 -163
- package/src/__tests__/utils.spec.ts +0 -12
- package/src/components/__tests__/min-max-value-label.spec.tsx +0 -24
- package/src/components/__tests__/options-input-content-item.spec.tsx +0 -57
- package/src/components/__tests__/options-input-dropdown-item.spec.tsx +0 -126
- package/src/components/min-max-value-label.tsx +0 -19
- package/src/components/options-input-content-item.tsx +0 -72
- package/src/components/options-input-dropdown-item.tsx +0 -161
- package/src/index.ts +0 -2
- package/src/options-input.tsx +0 -353
- package/src/styles.scss +0 -54
- package/src/types.ts +0 -14
- package/src/utils.ts +0 -2
- package/tsconfig.build.json +0 -8
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import classNames from "classnames";
|
|
3
|
-
import Box from "@mui/material/Box";
|
|
4
|
-
import Typography from "@mui/material/Typography";
|
|
5
|
-
import ButtonGroup from "@mui/material/ButtonGroup";
|
|
6
|
-
import Divider from "@mui/material/Divider";
|
|
7
|
-
import TextField from "@mui/material/TextField";
|
|
8
|
-
import ListItem from "@mui/material/ListItem";
|
|
9
|
-
import Button from "@mui/material/Button";
|
|
10
|
-
import AddIcon from "@mui/icons-material/Add";
|
|
11
|
-
import RemoveIcon from "@mui/icons-material/Remove";
|
|
12
|
-
import * as DesignSystemIcons from "@talixo-ds/icons";
|
|
13
|
-
import { MinMaxValueLabel } from "./min-max-value-label";
|
|
14
|
-
import { capitalize } from "../utils";
|
|
15
|
-
import type { OptionsInputOption } from "../types";
|
|
16
|
-
|
|
17
|
-
export type OptionsInputDropdownItemProps = {
|
|
18
|
-
item: OptionsInputOption;
|
|
19
|
-
onBlur: (event: React.FocusEvent<HTMLInputElement>) => void;
|
|
20
|
-
onChange: (id: string, value: number | string) => void;
|
|
21
|
-
index: number;
|
|
22
|
-
displayMinMax?: boolean;
|
|
23
|
-
error?: boolean;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const OptionsInputDropdownItem = ({
|
|
27
|
-
item: { id, quantity = 0, label, max, min, icon, details, inputQuantity },
|
|
28
|
-
onChange,
|
|
29
|
-
onBlur,
|
|
30
|
-
index,
|
|
31
|
-
displayMinMax,
|
|
32
|
-
error = false
|
|
33
|
-
}: OptionsInputDropdownItemProps) => {
|
|
34
|
-
const [shouldDisplayFullDetails, setShouldDisplayFullDetails] =
|
|
35
|
-
useState<boolean>(false);
|
|
36
|
-
const Icon =
|
|
37
|
-
DesignSystemIcons[capitalize(icon) as keyof typeof DesignSystemIcons] || null;
|
|
38
|
-
|
|
39
|
-
const onIncrement = (inputId: string) => () => {
|
|
40
|
-
const isValueBelowMin = !!(min && quantity < min);
|
|
41
|
-
|
|
42
|
-
onChange(inputId, (isValueBelowMin ? min : quantity + 1)!);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const onDecrement = (inputId: string) => () => {
|
|
46
|
-
const isValueAboveMax = !!(max && quantity > max);
|
|
47
|
-
|
|
48
|
-
return onChange(inputId, (isValueAboveMax ? max : quantity - 1)!);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<>
|
|
53
|
-
{!!index && (
|
|
54
|
-
<Divider sx={{ color: (theme) => theme.palette.primary.main }} />
|
|
55
|
-
)}
|
|
56
|
-
<ListItem
|
|
57
|
-
sx={{
|
|
58
|
-
display: "flex",
|
|
59
|
-
justifyContent: "space-between"
|
|
60
|
-
}}
|
|
61
|
-
className={classNames("options-input__dropdown-item", {
|
|
62
|
-
"options-input__dropdown-item--empty": !quantity
|
|
63
|
-
})}
|
|
64
|
-
>
|
|
65
|
-
<Box display="flex" alignItems="center">
|
|
66
|
-
<Icon fontSize="small" sx={{ color: "black" }} />
|
|
67
|
-
<TextField
|
|
68
|
-
onChange={({ target }) => onChange(id, target.value)}
|
|
69
|
-
onBlur={onBlur}
|
|
70
|
-
value={inputQuantity}
|
|
71
|
-
variant="standard"
|
|
72
|
-
inputProps={{
|
|
73
|
-
inputMode: "numeric",
|
|
74
|
-
pattern: "-?[0-9]*",
|
|
75
|
-
style: {
|
|
76
|
-
textAlign: "center"
|
|
77
|
-
},
|
|
78
|
-
"data-testid": "dropdown-item-input"
|
|
79
|
-
}}
|
|
80
|
-
// eslint-disable-next-line react/jsx-no-duplicate-props
|
|
81
|
-
InputProps={{ disableUnderline: true }}
|
|
82
|
-
className="options-input__dropdown-item-input"
|
|
83
|
-
/>
|
|
84
|
-
<Box
|
|
85
|
-
display="flex"
|
|
86
|
-
flexDirection="column"
|
|
87
|
-
justifyContent="center"
|
|
88
|
-
paddingRight={2}
|
|
89
|
-
paddingLeft={1}
|
|
90
|
-
minWidth="5rem"
|
|
91
|
-
>
|
|
92
|
-
<Typography
|
|
93
|
-
variant="caption"
|
|
94
|
-
fontWeight={600}
|
|
95
|
-
fontSize={13}
|
|
96
|
-
sx={{ my: 0 }}
|
|
97
|
-
color="black"
|
|
98
|
-
>
|
|
99
|
-
{label || id}
|
|
100
|
-
</Typography>
|
|
101
|
-
{details && (
|
|
102
|
-
<Box
|
|
103
|
-
position="relative"
|
|
104
|
-
height="1rem"
|
|
105
|
-
data-testid="option-details-container"
|
|
106
|
-
onMouseEnter={() => setShouldDisplayFullDetails(true)}
|
|
107
|
-
onMouseLeave={() => setShouldDisplayFullDetails(false)}
|
|
108
|
-
>
|
|
109
|
-
<Typography
|
|
110
|
-
variant="caption"
|
|
111
|
-
color="gray"
|
|
112
|
-
sx={{
|
|
113
|
-
my: 0,
|
|
114
|
-
zIndex: 10000,
|
|
115
|
-
position: "fixed",
|
|
116
|
-
...(shouldDisplayFullDetails && {
|
|
117
|
-
backgroundColor: quantity ? "#ffffff" : "#eeeeee",
|
|
118
|
-
border: "thin solid #d3d3d3"
|
|
119
|
-
})
|
|
120
|
-
}}
|
|
121
|
-
data-testid="option-details"
|
|
122
|
-
>
|
|
123
|
-
{details?.length <= 15 || shouldDisplayFullDetails
|
|
124
|
-
? details
|
|
125
|
-
: `${details?.slice(0, 15)}...`}
|
|
126
|
-
</Typography>
|
|
127
|
-
</Box>
|
|
128
|
-
)}
|
|
129
|
-
{displayMinMax && <MinMaxValueLabel min={min} max={max} color="gray" />}
|
|
130
|
-
</Box>
|
|
131
|
-
</Box>
|
|
132
|
-
<ButtonGroup
|
|
133
|
-
variant="outlined"
|
|
134
|
-
size="small"
|
|
135
|
-
className="options-input__dropdown-item-buttons"
|
|
136
|
-
>
|
|
137
|
-
<Button
|
|
138
|
-
onClick={onIncrement(id)}
|
|
139
|
-
disabled={!!(max && quantity && quantity >= max)}
|
|
140
|
-
className="options-input__dropdown-item-button"
|
|
141
|
-
role="button"
|
|
142
|
-
color={error ? "error" : "primary"}
|
|
143
|
-
>
|
|
144
|
-
<AddIcon sx={{ color: error ? "black" : "primary" }} />
|
|
145
|
-
</Button>
|
|
146
|
-
<Button
|
|
147
|
-
onClick={onDecrement(id)}
|
|
148
|
-
disabled={!!(quantity && min) && quantity <= min}
|
|
149
|
-
className="options-input__dropdown-item-button"
|
|
150
|
-
role="button"
|
|
151
|
-
color={error ? "error" : "primary"}
|
|
152
|
-
>
|
|
153
|
-
<RemoveIcon sx={{ color: error ? "black" : "primary" }} />
|
|
154
|
-
</Button>
|
|
155
|
-
</ButtonGroup>
|
|
156
|
-
</ListItem>
|
|
157
|
-
</>
|
|
158
|
-
);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
export default OptionsInputDropdownItem;
|
package/src/index.ts
DELETED
package/src/options-input.tsx
DELETED
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useState,
|
|
3
|
-
useEffect,
|
|
4
|
-
useCallback,
|
|
5
|
-
type ReactNode,
|
|
6
|
-
useMemo,
|
|
7
|
-
useRef
|
|
8
|
-
} from "react";
|
|
9
|
-
import classNames from "classnames";
|
|
10
|
-
import Box from "@mui/material/Box";
|
|
11
|
-
import List from "@mui/material/List";
|
|
12
|
-
import Popper from "@mui/material/Popper";
|
|
13
|
-
import ClickAwayListener from "@mui/material/ClickAwayListener";
|
|
14
|
-
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
|
15
|
-
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
|
|
16
|
-
import * as DesignSystemIcons from "@talixo-ds/icons";
|
|
17
|
-
import type { SxProps } from "@mui/material";
|
|
18
|
-
import type { OptionsInputOption, OptionsInputValue } from "./types";
|
|
19
|
-
import OptionsInputContentItem from "./components/options-input-content-item";
|
|
20
|
-
import OptionsInputDropdownItem from "./components/options-input-dropdown-item";
|
|
21
|
-
import { red } from "@mui/material/colors";
|
|
22
|
-
import "./styles.scss";
|
|
23
|
-
|
|
24
|
-
import "@emotion/react";
|
|
25
|
-
import "@emotion/styled";
|
|
26
|
-
import { capitalize } from "./utils";
|
|
27
|
-
|
|
28
|
-
export type OptionsInputProps = {
|
|
29
|
-
/** Array of objects representing options available to choose from */
|
|
30
|
-
options: OptionsInputOption[];
|
|
31
|
-
/** Object with default values of some options */
|
|
32
|
-
defaultValue?: OptionsInputValue;
|
|
33
|
-
/** Array with ids of options which should remain displayed even if value is 0 */
|
|
34
|
-
persistentOptions?: string[];
|
|
35
|
-
/** Boolean to determine if input is disabled */
|
|
36
|
-
disabled?: boolean;
|
|
37
|
-
/** Boolean to determine if input is readOnly */
|
|
38
|
-
readOnly?: boolean;
|
|
39
|
-
/** Boolean to determine if min and max input values should be displayed */
|
|
40
|
-
displayMinMax?: boolean;
|
|
41
|
-
/** Function which handles options input value change */
|
|
42
|
-
onChange?: (OptionsInputValue: OptionsInputValue) => void;
|
|
43
|
-
/** Function which handles options input focus event */
|
|
44
|
-
onFocus?: (OptionsInputValue: OptionsInputValue) => void;
|
|
45
|
-
/** Function which handles options input blur event */
|
|
46
|
-
onBlur?: (OptionsInputValue: OptionsInputValue) => void;
|
|
47
|
-
/** className attached to an input container */
|
|
48
|
-
className?: string;
|
|
49
|
-
/** id attached to an input container */
|
|
50
|
-
id?: string;
|
|
51
|
-
/** data test id attached to an input container */
|
|
52
|
-
"data-testid"?: string;
|
|
53
|
-
/** Gap between input items */
|
|
54
|
-
itemsGap?: string | number;
|
|
55
|
-
/** Custom styles for container */
|
|
56
|
-
containerSx?: SxProps;
|
|
57
|
-
/** Flag indicating if there is an validation error */
|
|
58
|
-
error?: boolean;
|
|
59
|
-
/** Additional content displayed with small font under the input */
|
|
60
|
-
helperText?: ReactNode;
|
|
61
|
-
/** Custom styles for helper text container */
|
|
62
|
-
helperTextSx?: SxProps;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const OptionsInput = ({
|
|
66
|
-
options,
|
|
67
|
-
onChange,
|
|
68
|
-
onFocus,
|
|
69
|
-
onBlur,
|
|
70
|
-
persistentOptions = [],
|
|
71
|
-
defaultValue,
|
|
72
|
-
displayMinMax = false,
|
|
73
|
-
disabled = false,
|
|
74
|
-
readOnly = false,
|
|
75
|
-
id,
|
|
76
|
-
className,
|
|
77
|
-
itemsGap = 1,
|
|
78
|
-
containerSx = [],
|
|
79
|
-
error = false,
|
|
80
|
-
helperText,
|
|
81
|
-
helperTextSx,
|
|
82
|
-
...rest
|
|
83
|
-
}: OptionsInputProps) => {
|
|
84
|
-
const [currentOptions, setCurrentOptions] = useState<OptionsInputOption[]>([]);
|
|
85
|
-
const [inputContainerWidth, setInputContainerWidth] = useState(0);
|
|
86
|
-
const inputContainerRef = useRef<HTMLElement>();
|
|
87
|
-
const [anchorEl, setAnchorEl] = useState<undefined | HTMLElement>();
|
|
88
|
-
const open = !!anchorEl;
|
|
89
|
-
|
|
90
|
-
useEffect(
|
|
91
|
-
() =>
|
|
92
|
-
setCurrentOptions(
|
|
93
|
-
options.map((option) => {
|
|
94
|
-
const quantity = defaultValue?.[option.id] ?? 0;
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
...option,
|
|
98
|
-
quantity,
|
|
99
|
-
inputQuantity: quantity
|
|
100
|
-
};
|
|
101
|
-
})
|
|
102
|
-
),
|
|
103
|
-
[options, defaultValue]
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
setInputContainerWidth(inputContainerRef?.current?.clientWidth ?? 0);
|
|
108
|
-
}, [inputContainerRef?.current?.clientWidth]);
|
|
109
|
-
|
|
110
|
-
const optionsExceedingBoundaries = useMemo(
|
|
111
|
-
() =>
|
|
112
|
-
currentOptions.reduce((exceedingOptions, { quantity, id, label }) => {
|
|
113
|
-
const option = options.find((option) => option.id === id);
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
label &&
|
|
117
|
-
quantity !== undefined &&
|
|
118
|
-
((option?.max !== undefined && option?.max < quantity) ||
|
|
119
|
-
(option?.min !== undefined && option?.min > quantity))
|
|
120
|
-
) {
|
|
121
|
-
return [...exceedingOptions, label];
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return exceedingOptions;
|
|
125
|
-
}, [] as string[]),
|
|
126
|
-
[currentOptions, options]
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
const isError = useMemo(
|
|
130
|
-
() => error || !!optionsExceedingBoundaries.length,
|
|
131
|
-
[error, optionsExceedingBoundaries]
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
const toggleInput = useCallback(
|
|
135
|
-
(event: React.MouseEvent<HTMLElement>) => {
|
|
136
|
-
const { currentTarget } = event;
|
|
137
|
-
|
|
138
|
-
if (!disabled && !readOnly) {
|
|
139
|
-
setTimeout(() => {
|
|
140
|
-
setAnchorEl((currentAnchor) =>
|
|
141
|
-
currentAnchor ? undefined : currentTarget
|
|
142
|
-
);
|
|
143
|
-
}, 0);
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
[disabled, readOnly, setAnchorEl]
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const onInputFocus = () => {
|
|
150
|
-
if (onFocus) {
|
|
151
|
-
onFocus(
|
|
152
|
-
currentOptions.reduce(
|
|
153
|
-
(currentValues, currentOption) => ({
|
|
154
|
-
...currentValues,
|
|
155
|
-
[currentOption.id]: currentOption.quantity
|
|
156
|
-
}),
|
|
157
|
-
{}
|
|
158
|
-
) as OptionsInputValue
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const onInputBlur = () => {
|
|
164
|
-
if (onBlur) {
|
|
165
|
-
onBlur(
|
|
166
|
-
currentOptions.reduce(
|
|
167
|
-
(currentValues, currentOption) => ({
|
|
168
|
-
...currentValues,
|
|
169
|
-
[currentOption.id]: currentOption.quantity
|
|
170
|
-
}),
|
|
171
|
-
{}
|
|
172
|
-
) as OptionsInputValue
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const onValueChange = (optionId: string, newValue: string | number) => {
|
|
178
|
-
const newQuantity = Number.isNaN(Number(newValue)) ? 0 : Number(newValue);
|
|
179
|
-
|
|
180
|
-
const newCurrentOptions = currentOptions.map((option) => {
|
|
181
|
-
const maxQuantity =
|
|
182
|
-
newQuantity > (option?.max ?? Infinity) ? option?.max : newQuantity;
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
...option,
|
|
186
|
-
...(optionId === option.id && {
|
|
187
|
-
quantity:
|
|
188
|
-
newQuantity < (option?.min ?? -Infinity) ? option?.min : maxQuantity,
|
|
189
|
-
inputQuantity: newValue
|
|
190
|
-
})
|
|
191
|
-
};
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
if (onChange) {
|
|
195
|
-
onChange(
|
|
196
|
-
newCurrentOptions.reduce(
|
|
197
|
-
(currentValues, currentOption) => ({
|
|
198
|
-
...currentValues,
|
|
199
|
-
[currentOption.id]: currentOption.quantity
|
|
200
|
-
}),
|
|
201
|
-
{}
|
|
202
|
-
) as OptionsInputValue
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
setCurrentOptions(newCurrentOptions);
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
const onDropdownItemBlur = (optionId: string) => () =>
|
|
210
|
-
setCurrentOptions(
|
|
211
|
-
currentOptions.map((option) => {
|
|
212
|
-
if (optionId !== option.id) return option;
|
|
213
|
-
|
|
214
|
-
const finalQuantity = Number.isNaN(Number(option?.inputQuantity))
|
|
215
|
-
? 0
|
|
216
|
-
: Number(option?.inputQuantity);
|
|
217
|
-
const maxQuantity =
|
|
218
|
-
finalQuantity > (option?.max ?? Infinity) ? option?.max : finalQuantity;
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
...option,
|
|
222
|
-
inputQuantity:
|
|
223
|
-
finalQuantity < (option?.min ?? -Infinity) ? option?.min : maxQuantity
|
|
224
|
-
};
|
|
225
|
-
})
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
return (
|
|
229
|
-
<>
|
|
230
|
-
<Box>
|
|
231
|
-
<Box
|
|
232
|
-
id={id}
|
|
233
|
-
onClick={toggleInput}
|
|
234
|
-
onBlur={onInputBlur}
|
|
235
|
-
onFocus={onInputFocus}
|
|
236
|
-
ref={inputContainerRef}
|
|
237
|
-
className={classNames("options-input__container", className, {
|
|
238
|
-
"options-input__container--open": open,
|
|
239
|
-
"options-input__container--disabled": disabled,
|
|
240
|
-
"options-input__container--read-only": readOnly,
|
|
241
|
-
"options-input__container--error": isError
|
|
242
|
-
})}
|
|
243
|
-
sx={[
|
|
244
|
-
{ "&:hover": { borderColor: "#d3d3d3" } },
|
|
245
|
-
...(Array.isArray(containerSx) ? containerSx : [containerSx]),
|
|
246
|
-
open && {
|
|
247
|
-
borderColor: (theme) => theme.palette.primary.main,
|
|
248
|
-
"&:hover": { borderColor: (theme) => theme.palette.primary.main }
|
|
249
|
-
},
|
|
250
|
-
isError && {
|
|
251
|
-
borderColor: red[700],
|
|
252
|
-
"&:hover": { borderColor: red[700] }
|
|
253
|
-
}
|
|
254
|
-
]}
|
|
255
|
-
data-testid={rest["data-testid"] || "options-input-container"}
|
|
256
|
-
tabIndex={0}
|
|
257
|
-
>
|
|
258
|
-
<Box display="flex" gap={itemsGap}>
|
|
259
|
-
{currentOptions
|
|
260
|
-
.filter(
|
|
261
|
-
({ quantity, id: optionId, icon }) =>
|
|
262
|
-
!!(
|
|
263
|
-
DesignSystemIcons[
|
|
264
|
-
capitalize(icon) as keyof typeof DesignSystemIcons
|
|
265
|
-
] &&
|
|
266
|
-
(quantity !== 0 || persistentOptions?.includes(optionId))
|
|
267
|
-
)
|
|
268
|
-
)
|
|
269
|
-
.map((option) => (
|
|
270
|
-
<OptionsInputContentItem
|
|
271
|
-
key={option.id}
|
|
272
|
-
item={option}
|
|
273
|
-
disabled={disabled}
|
|
274
|
-
displayMinMax={displayMinMax}
|
|
275
|
-
error={
|
|
276
|
-
!!(option?.label && optionsExceedingBoundaries.includes(option.label))
|
|
277
|
-
}
|
|
278
|
-
/>
|
|
279
|
-
))}
|
|
280
|
-
</Box>
|
|
281
|
-
{!readOnly &&
|
|
282
|
-
(open ? (
|
|
283
|
-
<KeyboardArrowUpIcon sx={{ color: isError ? red[700] : "primary" }} />
|
|
284
|
-
) : (
|
|
285
|
-
<KeyboardArrowDownIcon
|
|
286
|
-
sx={{
|
|
287
|
-
color: (theme) =>
|
|
288
|
-
disabled ? theme.palette.grey[400] : theme.palette.action.focus
|
|
289
|
-
}}
|
|
290
|
-
/>
|
|
291
|
-
))}
|
|
292
|
-
</Box>
|
|
293
|
-
{(helperText || isError) && (
|
|
294
|
-
<Box
|
|
295
|
-
sx={{
|
|
296
|
-
fontSize: "small",
|
|
297
|
-
...(helperTextSx || {}),
|
|
298
|
-
...(isError ? { color: red[700] } : {})
|
|
299
|
-
}}
|
|
300
|
-
marginTop={1}
|
|
301
|
-
marginLeft={2}
|
|
302
|
-
width={inputContainerWidth}
|
|
303
|
-
>
|
|
304
|
-
{optionsExceedingBoundaries.length
|
|
305
|
-
? (() => {
|
|
306
|
-
const messagePluralForm =
|
|
307
|
-
optionsExceedingBoundaries.length > 1 ? "s" : "";
|
|
308
|
-
|
|
309
|
-
return `Value${messagePluralForm} for ${optionsExceedingBoundaries.join(", ")} option${messagePluralForm} ${messagePluralForm ? "are" : "is"} out of range.`;
|
|
310
|
-
})()
|
|
311
|
-
: helperText}
|
|
312
|
-
</Box>
|
|
313
|
-
)}
|
|
314
|
-
</Box>
|
|
315
|
-
<ClickAwayListener onClickAway={() => open && setAnchorEl(undefined)}>
|
|
316
|
-
<Popper
|
|
317
|
-
open={open}
|
|
318
|
-
placement="bottom-start"
|
|
319
|
-
anchorEl={anchorEl}
|
|
320
|
-
sx={(theme) => ({ zIndex: theme.zIndex.modal })}
|
|
321
|
-
>
|
|
322
|
-
<List
|
|
323
|
-
disablePadding
|
|
324
|
-
data-testid="options-dropdown-list"
|
|
325
|
-
className="options-input__dropdown-items-list"
|
|
326
|
-
sx={{
|
|
327
|
-
bgcolor: "Background",
|
|
328
|
-
border: (theme) =>
|
|
329
|
-
`thin solid ${isError ? red[700] : theme.palette.primary.main}`
|
|
330
|
-
}}
|
|
331
|
-
>
|
|
332
|
-
{currentOptions
|
|
333
|
-
.filter(
|
|
334
|
-
({ icon }) =>
|
|
335
|
-
!!DesignSystemIcons[capitalize(icon) as keyof typeof DesignSystemIcons]
|
|
336
|
-
)
|
|
337
|
-
.map((option, index) => (
|
|
338
|
-
<OptionsInputDropdownItem
|
|
339
|
-
key={option.id}
|
|
340
|
-
item={option}
|
|
341
|
-
onBlur={onDropdownItemBlur(option.id)}
|
|
342
|
-
onChange={onValueChange}
|
|
343
|
-
index={index}
|
|
344
|
-
displayMinMax={displayMinMax}
|
|
345
|
-
error={isError}
|
|
346
|
-
/>
|
|
347
|
-
))}
|
|
348
|
-
</List>
|
|
349
|
-
</Popper>
|
|
350
|
-
</ClickAwayListener>
|
|
351
|
-
</>
|
|
352
|
-
);
|
|
353
|
-
};
|
package/src/styles.scss
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
.options-input {
|
|
2
|
-
&__container {
|
|
3
|
-
border: thin solid transparent;
|
|
4
|
-
border-radius: 0.25rem;
|
|
5
|
-
display: flex;
|
|
6
|
-
justify-content: space-between;
|
|
7
|
-
align-items: center;
|
|
8
|
-
padding: 0.25rem;
|
|
9
|
-
gap: 1rem;
|
|
10
|
-
cursor: pointer;
|
|
11
|
-
width: fit-content;
|
|
12
|
-
|
|
13
|
-
&--open {
|
|
14
|
-
border-bottom-width: 0;
|
|
15
|
-
border-bottom-left-radius: 0;
|
|
16
|
-
border-bottom-right-radius: 0;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
&--disabled {
|
|
20
|
-
cursor: unset;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
&--read-only {
|
|
24
|
-
cursor: unset;
|
|
25
|
-
|
|
26
|
-
&:hover {
|
|
27
|
-
border-color: transparent;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
&__dropdown-item {
|
|
33
|
-
gap: 1rem;
|
|
34
|
-
|
|
35
|
-
&--empty {
|
|
36
|
-
background-color: #eeeeee;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
&__dropdown-item-input {
|
|
41
|
-
width: 2rem;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
&__dropdown-item-buttons {
|
|
45
|
-
& > button[role="button"] {
|
|
46
|
-
min-width: 2rem;
|
|
47
|
-
padding: 0;
|
|
48
|
-
|
|
49
|
-
&[disabled] > svg {
|
|
50
|
-
color: #0000001f;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export interface OptionsInputOption {
|
|
2
|
-
id: string;
|
|
3
|
-
icon: string;
|
|
4
|
-
label?: string;
|
|
5
|
-
details?: string;
|
|
6
|
-
min?: number;
|
|
7
|
-
max?: number;
|
|
8
|
-
quantity?: number;
|
|
9
|
-
inputQuantity?: string | number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface OptionsInputValue {
|
|
13
|
-
[key: string]: number;
|
|
14
|
-
}
|
package/src/utils.ts
DELETED