@flozy/editor 10.4.6 → 10.4.8
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/Editor/Elements/DataView/Layouts/DataTypes/Components/MultiSelect.js +36 -9
- package/dist/Editor/Elements/DataView/Layouts/DataTypes/Components/SelectV1.js +513 -0
- package/dist/Editor/Elements/DataView/Layouts/DataTypes/MultiSelectType.js +5 -4
- package/dist/Editor/Elements/DataView/Layouts/DataTypes/SelectType.js +29 -9
- package/dist/Editor/Elements/DataView/Layouts/Options/AddOptions.js +2 -1
- package/dist/Editor/Elements/DataView/Layouts/Options/EditOption.js +40 -14
- package/dist/Editor/theme/index.js +1 -1
- package/package.json +1 -1
@@ -10,10 +10,10 @@ import List from "@mui/material/List";
|
|
10
10
|
import ListItem from "@mui/material/ListItem";
|
11
11
|
import ListItemButton from "@mui/material/ListItemButton";
|
12
12
|
import IconButton from "@mui/material/IconButton";
|
13
|
-
import SwipeableDrawer from "@mui/material/SwipeableDrawer";
|
14
13
|
import Tooltip from "@mui/material/Tooltip";
|
15
14
|
import { CloseIcon } from "../../../../../common/iconslist";
|
16
15
|
import { useEditorContext } from "../../../../../hooks/useMouseMove";
|
16
|
+
import SwipeableDrawer from "@mui/material/SwipeableDrawer";
|
17
17
|
import Icon from "../../../../../common/Icon";
|
18
18
|
import { colors } from "../../../../Color Picker/defaultColors";
|
19
19
|
import PropertySettings from "../../Options";
|
@@ -26,6 +26,11 @@ const generateRandomColor = () => {
|
|
26
26
|
const randomIndex = Math.floor(Math.random() * DEFAULT_COLORS?.length);
|
27
27
|
return DEFAULT_COLORS[randomIndex];
|
28
28
|
};
|
29
|
+
const hasIds = arr => Array.isArray(arr) && arr.every(item => 'id' in item);
|
30
|
+
const generateStableIds = arr => arr.map((item, index) => ({
|
31
|
+
...item,
|
32
|
+
id: `multi_${item.value}_${index}`
|
33
|
+
}));
|
29
34
|
const MultiSelectWithPopover = props => {
|
30
35
|
const {
|
31
36
|
options = [],
|
@@ -34,13 +39,13 @@ const MultiSelectWithPopover = props => {
|
|
34
39
|
onUpdate,
|
35
40
|
property,
|
36
41
|
wrapColumn = false,
|
37
|
-
translation
|
42
|
+
translation = () => {}
|
38
43
|
} = props;
|
39
44
|
const [anchorEl, setAnchorEl] = useState(null);
|
40
45
|
const [anchorElOption, setAnchorElOption] = useState(null);
|
41
46
|
const [currentIndex, setCurrentIndex] = useState(null);
|
42
|
-
const [selectedOptions, setSelectedOptions] = useState(
|
43
|
-
const [availableOptions, setAvailableOptions] = useState(
|
47
|
+
const [selectedOptions, setSelectedOptions] = useState([]);
|
48
|
+
const [availableOptions, setAvailableOptions] = useState([]);
|
44
49
|
const [showSnackBar, setShowSnackBar] = useState(false);
|
45
50
|
const [chipColor, setChipColor] = useState(generateRandomColor());
|
46
51
|
const [inputValue, setInputValue] = useState("");
|
@@ -49,6 +54,21 @@ const MultiSelectWithPopover = props => {
|
|
49
54
|
} = useEditorContext();
|
50
55
|
const isMobile = window.matchMedia("(max-width: 899px)")?.matches || false;
|
51
56
|
const PopoverComponent = isMobile ? SwipeableDrawer : Popover;
|
57
|
+
useEffect(() => {
|
58
|
+
console.log("Options received:", options);
|
59
|
+
const enrichedAvailable = hasIds(options) ? options : generateStableIds(options);
|
60
|
+
console.log("Enriched available options:", enrichedAvailable);
|
61
|
+
setAvailableOptions(enrichedAvailable);
|
62
|
+
const enrichedSelected = hasIds(value) ? value : value.map(sel => {
|
63
|
+
const match = enrichedAvailable.find(opt => opt.value === sel.value);
|
64
|
+
return match ? {
|
65
|
+
...sel,
|
66
|
+
id: match.id
|
67
|
+
} : sel;
|
68
|
+
});
|
69
|
+
console.log("Enriched selected options:", enrichedSelected);
|
70
|
+
setSelectedOptions(enrichedSelected);
|
71
|
+
}, []);
|
52
72
|
const mode = useMemo(() => ({
|
53
73
|
type: "editOptionMulti",
|
54
74
|
edit: {
|
@@ -56,11 +76,11 @@ const MultiSelectWithPopover = props => {
|
|
56
76
|
visible: true,
|
57
77
|
key: property,
|
58
78
|
type: "multi-select",
|
59
|
-
options:
|
79
|
+
options: availableOptions || [],
|
60
80
|
optionIndex: currentIndex,
|
61
81
|
hideBackButton: true
|
62
82
|
}
|
63
|
-
}), [
|
83
|
+
}), [availableOptions, property, currentIndex]);
|
64
84
|
const customScrollStyles = {
|
65
85
|
scrollbarWidth: "thin",
|
66
86
|
scrollbarColor: `${theme?.palette?.editor?.brainPopupScroll} transparent`,
|
@@ -81,10 +101,17 @@ const MultiSelectWithPopover = props => {
|
|
81
101
|
}
|
82
102
|
}, [inputValue, chipColor]);
|
83
103
|
useEffect(() => {
|
84
|
-
if (
|
85
|
-
|
104
|
+
if (inputValue?.trim() && !chipColor) {
|
105
|
+
setChipColor(generateRandomColor());
|
106
|
+
}
|
107
|
+
}, [inputValue, chipColor]);
|
108
|
+
useEffect(() => {
|
109
|
+
const enriched = hasIds(options) ? options : generateStableIds(options);
|
110
|
+
const isDifferent = JSON.stringify(enriched) !== JSON.stringify(availableOptions);
|
111
|
+
if (isDifferent) {
|
112
|
+
setAvailableOptions(enriched);
|
86
113
|
}
|
87
|
-
}, [options
|
114
|
+
}, [options]);
|
88
115
|
const handleOpenPopover = useCallback(event => {
|
89
116
|
setAnchorEl(event.currentTarget);
|
90
117
|
}, []);
|
@@ -0,0 +1,513 @@
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
2
|
+
import Autocomplete from "@mui/material/Autocomplete";
|
3
|
+
import Box from "@mui/material/Box";
|
4
|
+
import Chip from "@mui/material/Chip";
|
5
|
+
import Divider from "@mui/material/Divider";
|
6
|
+
import Popover from "@mui/material/Popover";
|
7
|
+
import TextField from "@mui/material/TextField";
|
8
|
+
import Typography from "@mui/material/Typography";
|
9
|
+
import List from "@mui/material/List";
|
10
|
+
import ListItem from "@mui/material/ListItem";
|
11
|
+
import ListItemButton from "@mui/material/ListItemButton";
|
12
|
+
import IconButton from "@mui/material/IconButton";
|
13
|
+
import Tooltip from "@mui/material/Tooltip";
|
14
|
+
import { CloseIcon } from "../../../../../common/iconslist";
|
15
|
+
import { useEditorContext } from "../../../../../hooks/useMouseMove";
|
16
|
+
import SwipeableDrawer from "@mui/material/SwipeableDrawer";
|
17
|
+
import Icon from "../../../../../common/Icon";
|
18
|
+
import { colors } from "../../../../Color Picker/defaultColors";
|
19
|
+
import PropertySettings from "../../Options";
|
20
|
+
import SnackbarAlert from "../../../../../common/SnackBar";
|
21
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
22
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
23
|
+
const EXCLUDED_COLORS = new Set(["#000000", "#0F172A", "#2563EB", "#FFFFFF", "#64748B"]);
|
24
|
+
const DEFAULT_COLORS = colors?.filter(f => !f?.includes("linear") && !EXCLUDED_COLORS?.has(f));
|
25
|
+
const generateRandomColor = () => {
|
26
|
+
const randomIndex = Math.floor(Math.random() * DEFAULT_COLORS?.length);
|
27
|
+
return DEFAULT_COLORS[randomIndex];
|
28
|
+
};
|
29
|
+
const hasIds = arr => Array.isArray(arr) && arr.every(item => 'id' in item);
|
30
|
+
const generateStableIds = arr => arr.map((item, index) => ({
|
31
|
+
...item,
|
32
|
+
id: `multi_${item.value}_${index}`
|
33
|
+
}));
|
34
|
+
const SelectV1 = props => {
|
35
|
+
const {
|
36
|
+
value,
|
37
|
+
options = [],
|
38
|
+
selectMultiple,
|
39
|
+
property,
|
40
|
+
wrapColumn = false,
|
41
|
+
onChange,
|
42
|
+
onUpdate,
|
43
|
+
translation
|
44
|
+
} = props;
|
45
|
+
const [anchorEl, setAnchorEl] = useState(null);
|
46
|
+
const [anchorElOption, setAnchorElOption] = useState(null);
|
47
|
+
const [currentIndex, setCurrentIndex] = useState(null);
|
48
|
+
const [selectedOptions, setSelectedOptions] = useState([]);
|
49
|
+
const [availableOptions, setAvailableOptions] = useState([]);
|
50
|
+
const [showSnackBar, setShowSnackBar] = useState(false);
|
51
|
+
const [chipColor, setChipColor] = useState(generateRandomColor());
|
52
|
+
const [inputValue, setInputValue] = useState("");
|
53
|
+
const [availableOptionsMap, setAvailableOptionsMap] = useState({});
|
54
|
+
const [resolvedSelectedOptions, setResolvedSelectedOptions] = useState([]);
|
55
|
+
const {
|
56
|
+
theme
|
57
|
+
} = useEditorContext();
|
58
|
+
const isMobile = window.matchMedia("(max-width: 899px)")?.matches || false;
|
59
|
+
const PopoverComponent = isMobile ? SwipeableDrawer : Popover;
|
60
|
+
useEffect(() => {
|
61
|
+
const obj = {};
|
62
|
+
for (const opt of availableOptions) {
|
63
|
+
if (opt?.id != null) {
|
64
|
+
obj[opt.id] = opt;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
setAvailableOptionsMap(obj);
|
68
|
+
}, [availableOptions]);
|
69
|
+
useEffect(() => {
|
70
|
+
const resolved = selectedOptions?.filter(sel => sel?.id && availableOptionsMap?.[sel.id])?.map(sel => availableOptionsMap[sel?.id]) ?? [];
|
71
|
+
setResolvedSelectedOptions(resolved);
|
72
|
+
}, [selectedOptions, availableOptionsMap]);
|
73
|
+
useEffect(() => {
|
74
|
+
// console.log("Options received:", options);
|
75
|
+
const enrichedAvailable = hasIds(options) ? options : generateStableIds(options);
|
76
|
+
// console.log("Enriched available options:", enrichedAvailable);
|
77
|
+
setAvailableOptions(enrichedAvailable);
|
78
|
+
const enrichedSelected = hasIds(value) ? value : value?.map(sel => {
|
79
|
+
const match = enrichedAvailable.find(opt => opt?.value === sel?.value);
|
80
|
+
return match ? {
|
81
|
+
id: match.id
|
82
|
+
} : sel;
|
83
|
+
});
|
84
|
+
// console.log("Enriched selected options:", enrichedSelected);
|
85
|
+
setSelectedOptions(enrichedSelected);
|
86
|
+
}, []);
|
87
|
+
const mode = useMemo(() => ({
|
88
|
+
type: "editOptionMulti",
|
89
|
+
edit: {
|
90
|
+
label: selectMultiple ? "Multi Select" : "Select",
|
91
|
+
visible: true,
|
92
|
+
key: property,
|
93
|
+
type: selectMultiple ? "multi-select" : "select",
|
94
|
+
options: availableOptions || [],
|
95
|
+
optionIndex: currentIndex,
|
96
|
+
hideBackButton: true
|
97
|
+
}
|
98
|
+
}), [availableOptions, property, currentIndex, selectMultiple]);
|
99
|
+
const customScrollStyles = {
|
100
|
+
scrollbarWidth: "thin",
|
101
|
+
scrollbarColor: `${theme?.palette?.editor?.brainPopupScroll} transparent`,
|
102
|
+
"&::-webkit-scrollbar": {
|
103
|
+
width: "6px"
|
104
|
+
},
|
105
|
+
"&::-webkit-scrollbar-thumb": {
|
106
|
+
backgroundColor: theme?.palette?.editor?.brainPopupScroll,
|
107
|
+
borderRadius: "3px"
|
108
|
+
},
|
109
|
+
"&::-webkit-scrollbar-track": {
|
110
|
+
display: "none"
|
111
|
+
}
|
112
|
+
};
|
113
|
+
useEffect(() => {
|
114
|
+
if (inputValue?.trim() && !chipColor) {
|
115
|
+
setChipColor(generateRandomColor());
|
116
|
+
}
|
117
|
+
}, [inputValue, chipColor]);
|
118
|
+
useEffect(() => {
|
119
|
+
const enriched = hasIds(options) ? options : generateStableIds(options);
|
120
|
+
const isDifferent = JSON.stringify(enriched) !== JSON.stringify(availableOptions);
|
121
|
+
if (isDifferent) {
|
122
|
+
setAvailableOptions(enriched);
|
123
|
+
}
|
124
|
+
}, [options]);
|
125
|
+
const handleOpenPopover = useCallback(event => {
|
126
|
+
setAnchorEl(event.currentTarget);
|
127
|
+
}, []);
|
128
|
+
const handleClosePopover = useCallback(e => {
|
129
|
+
e?.stopPropagation();
|
130
|
+
setAnchorEl(null);
|
131
|
+
}, []);
|
132
|
+
const handleAddOption = newValue => {
|
133
|
+
const trimmedValue = newValue?.trim?.();
|
134
|
+
if (!trimmedValue) return;
|
135
|
+
const isDuplicate = availableOptions.some(opt => opt.value.toLowerCase() === trimmedValue.toLowerCase());
|
136
|
+
if (isDuplicate) {
|
137
|
+
const existing = availableOptions.find(opt => opt?.value?.toLowerCase() === trimmedValue?.toLowerCase());
|
138
|
+
const alreadySelected = selectedOptions?.some(sel => sel?.id === existing?.id);
|
139
|
+
if (!alreadySelected) {
|
140
|
+
const updatedSelected = selectMultiple ? [...selectedOptions, {
|
141
|
+
id: existing.id
|
142
|
+
}] : [{
|
143
|
+
id: existing.id
|
144
|
+
}];
|
145
|
+
setSelectedOptions(updatedSelected);
|
146
|
+
onChange?.(updatedSelected);
|
147
|
+
}
|
148
|
+
setInputValue("");
|
149
|
+
setChipColor("");
|
150
|
+
return;
|
151
|
+
}
|
152
|
+
const newOption = {
|
153
|
+
value: trimmedValue,
|
154
|
+
color: chipColor,
|
155
|
+
id: `multi_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 5)}`
|
156
|
+
};
|
157
|
+
const updatedAvailableOptions = [...availableOptions, newOption];
|
158
|
+
const updatedSelectedOptions = selectMultiple ? [...selectedOptions, {
|
159
|
+
id: newOption.id
|
160
|
+
}] : [{
|
161
|
+
id: newOption.id
|
162
|
+
}];
|
163
|
+
setAvailableOptions(updatedAvailableOptions);
|
164
|
+
setSelectedOptions(updatedSelectedOptions);
|
165
|
+
onUpdate?.(updatedAvailableOptions);
|
166
|
+
onChange?.(updatedSelectedOptions);
|
167
|
+
setInputValue("");
|
168
|
+
setChipColor("");
|
169
|
+
};
|
170
|
+
const onClose = () => {
|
171
|
+
setAnchorEl(anchorElOption);
|
172
|
+
setAnchorElOption(null);
|
173
|
+
};
|
174
|
+
const onEditOption = (type, data) => {
|
175
|
+
const updateData = data?.edit ? data?.edit?.options : data?.options;
|
176
|
+
onUpdate(updateData);
|
177
|
+
};
|
178
|
+
const handleEditOption = (e, index) => {
|
179
|
+
e.stopPropagation();
|
180
|
+
setCurrentIndex(index);
|
181
|
+
setAnchorElOption(anchorEl);
|
182
|
+
setAnchorEl(null);
|
183
|
+
};
|
184
|
+
const handleSelectOption = option => {
|
185
|
+
const isAlreadySelected = selectedOptions.some(opt => opt?.id === option?.id);
|
186
|
+
if (isAlreadySelected) {
|
187
|
+
setShowSnackBar(true);
|
188
|
+
return;
|
189
|
+
}
|
190
|
+
const updatedOptions = selectMultiple ? [...selectedOptions, {
|
191
|
+
id: option?.id
|
192
|
+
}] : [{
|
193
|
+
id: option?.id
|
194
|
+
}];
|
195
|
+
setSelectedOptions(updatedOptions);
|
196
|
+
onChange(updatedOptions);
|
197
|
+
if (!selectMultiple) {
|
198
|
+
handleClosePopover();
|
199
|
+
}
|
200
|
+
};
|
201
|
+
const handleClearSelection = () => {
|
202
|
+
setSelectedOptions([]);
|
203
|
+
};
|
204
|
+
const handleDeleteChip = (event, option) => {
|
205
|
+
event.stopPropagation();
|
206
|
+
const updatedOptions = selectedOptions?.filter(selected => selected?.id !== option?.id);
|
207
|
+
setSelectedOptions(updatedOptions);
|
208
|
+
onChange(selectMultiple ? updatedOptions : updatedOptions[0] || null);
|
209
|
+
};
|
210
|
+
const filteredOptions = availableOptions?.filter(option => option?.value?.toLowerCase()?.includes(inputValue?.toLowerCase()));
|
211
|
+
const isExactMatch = availableOptions?.some(opt => opt?.value?.toLowerCase() === inputValue?.toLowerCase());
|
212
|
+
const open = Boolean(anchorEl);
|
213
|
+
const openEditOption = Boolean(anchorElOption);
|
214
|
+
const id = open ? "autocomplete-popover" : undefined;
|
215
|
+
return /*#__PURE__*/_jsxs("div", {
|
216
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
217
|
+
sx: {
|
218
|
+
display: "flex",
|
219
|
+
flexWrap: wrapColumn ? "wrap" : "nowrap",
|
220
|
+
overflowX: wrapColumn ? "hidden" : "auto",
|
221
|
+
gap: 0.5,
|
222
|
+
padding: "8px",
|
223
|
+
cursor: "pointer"
|
224
|
+
},
|
225
|
+
onClick: handleOpenPopover,
|
226
|
+
children: resolvedSelectedOptions?.map((option, index) => /*#__PURE__*/_jsx(Chip, {
|
227
|
+
label: option?.value,
|
228
|
+
onDelete: event => {
|
229
|
+
handleDeleteChip(event, option);
|
230
|
+
},
|
231
|
+
deleteIcon: /*#__PURE__*/_jsx(CloseIcon, {}),
|
232
|
+
variant: "filled",
|
233
|
+
sx: {
|
234
|
+
backgroundColor: option?.color,
|
235
|
+
color: '#0F172A',
|
236
|
+
"& .MuiChip-deleteIcon": {
|
237
|
+
flexShrink: 0,
|
238
|
+
"& path": {
|
239
|
+
stroke: '#0F172A !important'
|
240
|
+
}
|
241
|
+
},
|
242
|
+
"&:hover": {
|
243
|
+
opacity: 0.8
|
244
|
+
}
|
245
|
+
}
|
246
|
+
}, index))
|
247
|
+
}), /*#__PURE__*/_jsx(PopoverComponent, {
|
248
|
+
id: id,
|
249
|
+
open: open,
|
250
|
+
anchorEl: anchorEl,
|
251
|
+
anchor: "bottom",
|
252
|
+
onClose: e => handleClosePopover(e),
|
253
|
+
anchorOrigin: {
|
254
|
+
vertical: "top",
|
255
|
+
horizontal: "left"
|
256
|
+
},
|
257
|
+
transformOrigin: {
|
258
|
+
vertical: "top",
|
259
|
+
horizontal: "left"
|
260
|
+
},
|
261
|
+
sx: {
|
262
|
+
"& .MuiPaper-root": {
|
263
|
+
borderRadius: "20px",
|
264
|
+
background: theme?.palette?.editor?.textFormatBgColor,
|
265
|
+
border: `1px solid ${theme?.palette?.editor?.popUpBorderColor}`,
|
266
|
+
boxShadow: "0px 4px 10px 0px #00000029"
|
267
|
+
}
|
268
|
+
},
|
269
|
+
disableAutoFocus: true,
|
270
|
+
disableEnforceFocus: true,
|
271
|
+
disableRestoreFocus: true,
|
272
|
+
children: /*#__PURE__*/_jsxs(Box, {
|
273
|
+
sx: {
|
274
|
+
width: isMobile ? "100%" : 300
|
275
|
+
},
|
276
|
+
children: [/*#__PURE__*/_jsx(Autocomplete, {
|
277
|
+
multiple: true,
|
278
|
+
freeSolo: true,
|
279
|
+
disablePortal: true,
|
280
|
+
PopperComponent: () => null,
|
281
|
+
sx: {
|
282
|
+
"& .MuiFormControl-root": {
|
283
|
+
maxHeight: "250px",
|
284
|
+
overflowY: "auto",
|
285
|
+
overflowX: "hidden",
|
286
|
+
pr: '12px',
|
287
|
+
pl: '12px',
|
288
|
+
marginTop: '12px',
|
289
|
+
...customScrollStyles
|
290
|
+
}
|
291
|
+
},
|
292
|
+
disableClearable: true,
|
293
|
+
options: [],
|
294
|
+
getOptionLabel: () => "",
|
295
|
+
value: resolvedSelectedOptions,
|
296
|
+
onChange: (event, newValues) => {
|
297
|
+
const stringOptions = newValues.filter(val => typeof val === "string" && val.trim());
|
298
|
+
for (const str of stringOptions) {
|
299
|
+
handleAddOption(str);
|
300
|
+
}
|
301
|
+
},
|
302
|
+
inputValue: inputValue,
|
303
|
+
onInputChange: (event, newInputValue) => setInputValue(newInputValue),
|
304
|
+
onKeyDown: event => {
|
305
|
+
if (event.key === "Enter" && inputValue.trim()) {
|
306
|
+
event.preventDefault();
|
307
|
+
handleAddOption(inputValue);
|
308
|
+
}
|
309
|
+
},
|
310
|
+
filterOptions: (options, params) => options?.filter(option => option?.value?.toLowerCase()?.includes(params?.inputValue?.toLowerCase())),
|
311
|
+
renderInput: params => /*#__PURE__*/_jsx(TextField, {
|
312
|
+
...params,
|
313
|
+
variant: "standard",
|
314
|
+
InputProps: {
|
315
|
+
...params.InputProps,
|
316
|
+
disableUnderline: true,
|
317
|
+
sx: {
|
318
|
+
display: "flex",
|
319
|
+
flexWrap: "wrap",
|
320
|
+
fontFamily: "Inter",
|
321
|
+
fontWeight: 400,
|
322
|
+
fontSize: "12px",
|
323
|
+
color: theme?.palette?.editor?.secondaryTextColor,
|
324
|
+
"&::placeholder": {
|
325
|
+
color: theme?.palette?.editor?.secondaryTextColor
|
326
|
+
},
|
327
|
+
"& .MuiAutocomplete-input": {
|
328
|
+
minWidth: "100px !important"
|
329
|
+
}
|
330
|
+
},
|
331
|
+
endAdornment: /*#__PURE__*/_jsx(Tooltip, {
|
332
|
+
arrow: true,
|
333
|
+
title: "Clear Selected",
|
334
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
335
|
+
onClick: handleClearSelection,
|
336
|
+
sx: {
|
337
|
+
padding: 0,
|
338
|
+
minWidth: "unset",
|
339
|
+
"& .MuiSvgIcon-root": {
|
340
|
+
fontSize: 20
|
341
|
+
},
|
342
|
+
'& rect': {
|
343
|
+
fill: theme?.palette?.editor?.closeButtonSvgStroke
|
344
|
+
},
|
345
|
+
'&:hover': {
|
346
|
+
backgroundColor: 'transparent'
|
347
|
+
}
|
348
|
+
},
|
349
|
+
children: /*#__PURE__*/_jsx(Icon, {
|
350
|
+
icon: "resetIconNew"
|
351
|
+
})
|
352
|
+
})
|
353
|
+
})
|
354
|
+
},
|
355
|
+
sx: {
|
356
|
+
backgroundColor: "transparent",
|
357
|
+
fontFamily: 'Inter',
|
358
|
+
fontWeight: 400,
|
359
|
+
fontSize: '12px'
|
360
|
+
},
|
361
|
+
placeholder: "Create new one..."
|
362
|
+
}),
|
363
|
+
renderTags: (tagValues, getTagProps) => {
|
364
|
+
return tagValues?.map((option, index) => /*#__PURE__*/_jsx(Chip, {
|
365
|
+
variant: "filled",
|
366
|
+
label: option?.value,
|
367
|
+
...getTagProps({
|
368
|
+
index
|
369
|
+
}),
|
370
|
+
onDelete: event => {
|
371
|
+
handleDeleteChip(event, option);
|
372
|
+
},
|
373
|
+
deleteIcon: /*#__PURE__*/_jsx(CloseIcon, {}),
|
374
|
+
sx: {
|
375
|
+
backgroundColor: option?.color,
|
376
|
+
color: '#0F172A',
|
377
|
+
"& .MuiChip-deleteIcon": {
|
378
|
+
flexShrink: 0,
|
379
|
+
"& path": {
|
380
|
+
stroke: '#0F172A !important'
|
381
|
+
}
|
382
|
+
},
|
383
|
+
"&:hover": {
|
384
|
+
opacity: 0.8
|
385
|
+
}
|
386
|
+
}
|
387
|
+
}, index));
|
388
|
+
}
|
389
|
+
}), /*#__PURE__*/_jsx(Divider, {
|
390
|
+
sx: {
|
391
|
+
mt: '12px',
|
392
|
+
borderBottom: `1px solid ${theme?.palette?.editor?.popUpBorderColor}`,
|
393
|
+
boxShadow: theme?.palette?.editor?.dividerDropShadow
|
394
|
+
}
|
395
|
+
}), /*#__PURE__*/_jsx(Box, {
|
396
|
+
sx: {
|
397
|
+
pl: '4px'
|
398
|
+
},
|
399
|
+
children: /*#__PURE__*/_jsxs(List, {
|
400
|
+
sx: {
|
401
|
+
maxHeight: "250px",
|
402
|
+
overflowY: "auto",
|
403
|
+
...customScrollStyles
|
404
|
+
},
|
405
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
406
|
+
sx: {
|
407
|
+
mb: 1,
|
408
|
+
pl: '8px',
|
409
|
+
color: theme?.palette?.editor?.secondaryTextColor,
|
410
|
+
fontFamily: 'Inter',
|
411
|
+
fontWeight: 400,
|
412
|
+
fontSize: '12px'
|
413
|
+
},
|
414
|
+
children: "Choose an option or create one"
|
415
|
+
}), filteredOptions?.map((option, index) => /*#__PURE__*/_jsx(ListItem, {
|
416
|
+
sx: {
|
417
|
+
padding: 0
|
418
|
+
},
|
419
|
+
disablePadding: true,
|
420
|
+
children: /*#__PURE__*/_jsxs(ListItemButton, {
|
421
|
+
onClick: () => handleSelectOption(option),
|
422
|
+
sx: {
|
423
|
+
paddingTop: "4px",
|
424
|
+
paddingBottom: "4px",
|
425
|
+
justifyContent: 'space-between',
|
426
|
+
'&:hover': {
|
427
|
+
'& path': {
|
428
|
+
stroke: theme?.palette?.editor?.activeColor
|
429
|
+
},
|
430
|
+
borderRadius: '12px'
|
431
|
+
}
|
432
|
+
},
|
433
|
+
children: [/*#__PURE__*/_jsx(Chip, {
|
434
|
+
label: option?.value,
|
435
|
+
sx: {
|
436
|
+
backgroundColor: option?.color,
|
437
|
+
color: '#0F172A',
|
438
|
+
fontWeight: 500,
|
439
|
+
fontSize: "12px",
|
440
|
+
fontFamily: "Inter",
|
441
|
+
padding: "4px 12px",
|
442
|
+
borderRadius: "16px",
|
443
|
+
maxWidth: "180px",
|
444
|
+
whiteSpace: "nowrap",
|
445
|
+
overflow: "hidden",
|
446
|
+
textOverflow: "ellipsis"
|
447
|
+
}
|
448
|
+
}), /*#__PURE__*/_jsx(IconButton, {
|
449
|
+
size: "small",
|
450
|
+
sx: {
|
451
|
+
'& path': {
|
452
|
+
stroke: theme?.palette?.editor?.closeButtonSvgStroke
|
453
|
+
},
|
454
|
+
'&:hover': {
|
455
|
+
backgroundColor: 'transparent'
|
456
|
+
}
|
457
|
+
},
|
458
|
+
onClick: e => handleEditOption(e, index),
|
459
|
+
children: /*#__PURE__*/_jsx(Icon, {
|
460
|
+
icon: "rightArrow"
|
461
|
+
})
|
462
|
+
})]
|
463
|
+
})
|
464
|
+
}, index)), inputValue?.trim() && !isExactMatch && /*#__PURE__*/_jsx(ListItem, {
|
465
|
+
disablePadding: true,
|
466
|
+
children: /*#__PURE__*/_jsxs(ListItemButton, {
|
467
|
+
onClick: () => handleAddOption(inputValue),
|
468
|
+
sx: {
|
469
|
+
display: "flex",
|
470
|
+
alignItems: "center"
|
471
|
+
},
|
472
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
473
|
+
sx: {
|
474
|
+
color: theme?.palette?.editor?.secondaryTextColor,
|
475
|
+
marginRight: "6px",
|
476
|
+
fontSize: "14px",
|
477
|
+
fontFamily: "Inter"
|
478
|
+
},
|
479
|
+
children: "Create"
|
480
|
+
}), /*#__PURE__*/_jsx(Chip, {
|
481
|
+
label: `${inputValue}`,
|
482
|
+
sx: {
|
483
|
+
backgroundColor: chipColor,
|
484
|
+
color: '#0F172A',
|
485
|
+
fontWeight: 500,
|
486
|
+
fontSize: "12px",
|
487
|
+
fontFamily: "Inter",
|
488
|
+
borderRadius: "16px",
|
489
|
+
maxWidth: "180px",
|
490
|
+
whiteSpace: "nowrap",
|
491
|
+
overflow: "hidden",
|
492
|
+
textOverflow: "ellipsis"
|
493
|
+
}
|
494
|
+
})]
|
495
|
+
})
|
496
|
+
})]
|
497
|
+
})
|
498
|
+
})]
|
499
|
+
})
|
500
|
+
}), openEditOption ? /*#__PURE__*/_jsx(PropertySettings, {
|
501
|
+
open: openEditOption,
|
502
|
+
anchorEl: anchorElOption,
|
503
|
+
mode: mode,
|
504
|
+
onClose: onClose,
|
505
|
+
onEvent: onEditOption,
|
506
|
+
translation: translation
|
507
|
+
}) : null, showSnackBar ? /*#__PURE__*/_jsx(SnackbarAlert, {
|
508
|
+
message: "Option already selected!",
|
509
|
+
setShowSnackBar: setShowSnackBar
|
510
|
+
}) : null]
|
511
|
+
});
|
512
|
+
};
|
513
|
+
export default SelectV1;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import React from "react";
|
2
2
|
import { useDataView } from "../../Providers/DataViewProvider";
|
3
3
|
import MultiSelectWithPopover from "./Components/MultiSelect";
|
4
|
+
import SelectV1 from "./Components/SelectV1";
|
4
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
5
6
|
const MultiSelectType = props => {
|
6
7
|
const {
|
@@ -24,12 +25,12 @@ const MultiSelectType = props => {
|
|
24
25
|
const coloredValues = [...(value || [])]?.map(m => {
|
25
26
|
return {
|
26
27
|
...m,
|
27
|
-
color: options
|
28
|
+
color: (options || []).find(f => f?.value === m?.value || f?.id === m?.id)?.color || "#FFF"
|
28
29
|
};
|
29
30
|
});
|
30
31
|
const handleChange = data => {
|
31
32
|
onChange(rowIndex, {
|
32
|
-
[property]: data?.filter(f => f?.
|
33
|
+
[property]: data?.filter(f => f?.id)
|
33
34
|
});
|
34
35
|
};
|
35
36
|
const handleUpdate = data => {
|
@@ -42,12 +43,12 @@ const MultiSelectType = props => {
|
|
42
43
|
};
|
43
44
|
onUpdateProperty(updateData);
|
44
45
|
};
|
45
|
-
return /*#__PURE__*/_jsx(
|
46
|
+
return /*#__PURE__*/_jsx(SelectV1, {
|
46
47
|
value: coloredValues,
|
47
48
|
onChange: handleChange,
|
48
49
|
onUpdate: handleUpdate,
|
49
50
|
options: options,
|
50
|
-
|
51
|
+
selectMultiple: true,
|
51
52
|
limitTags: 2,
|
52
53
|
placeholder: label,
|
53
54
|
disabled: readOnly,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import React from "react";
|
2
2
|
import { useDataView } from "../../Providers/DataViewProvider";
|
3
|
-
import Select from "./Components/Select";
|
3
|
+
// import Select from "./Components/Select";
|
4
|
+
import SelectV1 from "./Components/SelectV1";
|
4
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
5
6
|
const SelectType = props => {
|
6
7
|
const {
|
@@ -8,28 +9,47 @@ const SelectType = props => {
|
|
8
9
|
property,
|
9
10
|
value,
|
10
11
|
options,
|
11
|
-
readOnly
|
12
|
+
readOnly,
|
13
|
+
translation
|
12
14
|
} = props;
|
13
15
|
const {
|
14
|
-
onChange
|
16
|
+
onChange,
|
17
|
+
onUpdateProperty
|
15
18
|
} = useDataView();
|
19
|
+
const label = "";
|
16
20
|
const coloredValues = [...(value || [])]?.map(m => {
|
17
21
|
return {
|
18
22
|
...m,
|
19
|
-
color: options
|
23
|
+
color: (options || []).find(f => f?.value === m?.value || f?.id === m?.id)?.color || "#FFF"
|
20
24
|
};
|
21
25
|
});
|
22
26
|
const handleChange = data => {
|
23
27
|
onChange(rowIndex, {
|
24
|
-
[property]: data?.filter(f => f?.
|
28
|
+
[property]: data?.filter(f => f?.id)
|
25
29
|
});
|
26
30
|
};
|
27
|
-
|
31
|
+
const handleUpdate = data => {
|
32
|
+
const updateData = {
|
33
|
+
"label": "Select",
|
34
|
+
"visible": true,
|
35
|
+
"key": property,
|
36
|
+
"type": "select",
|
37
|
+
"options": data
|
38
|
+
};
|
39
|
+
onUpdateProperty(updateData);
|
40
|
+
};
|
41
|
+
return /*#__PURE__*/_jsx(SelectV1, {
|
28
42
|
value: coloredValues,
|
29
|
-
onChange: handleChange,
|
30
43
|
options: options,
|
31
|
-
|
32
|
-
disabled: readOnly
|
44
|
+
selectMultiple: false,
|
45
|
+
disabled: readOnly,
|
46
|
+
limitTags: 2,
|
47
|
+
placeholder: label,
|
48
|
+
property: property,
|
49
|
+
wrapColumn: false,
|
50
|
+
onChange: handleChange,
|
51
|
+
onUpdate: handleUpdate,
|
52
|
+
translation: translation
|
33
53
|
});
|
34
54
|
};
|
35
55
|
export default SelectType;
|
@@ -46,7 +46,8 @@ const AddOptions = props => {
|
|
46
46
|
...edit,
|
47
47
|
options: [{
|
48
48
|
value: value,
|
49
|
-
color: getRandomColor()
|
49
|
+
color: getRandomColor(),
|
50
|
+
id: `multi_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 5)}`
|
50
51
|
}, ...(options || [])]
|
51
52
|
});
|
52
53
|
setValue("");
|
@@ -19,6 +19,7 @@ const EditOption = props => {
|
|
19
19
|
const [edit, setEdit] = useState({
|
20
20
|
...(mode?.edit || {})
|
21
21
|
});
|
22
|
+
const [errorMessage, setErrorMessage] = useState("");
|
22
23
|
const editData = useRef({
|
23
24
|
...edit
|
24
25
|
});
|
@@ -31,10 +32,13 @@ const EditOption = props => {
|
|
31
32
|
const selectedOption = edit?.options[optionIndex] || {};
|
32
33
|
const pickerStyles = ColorPickerStyles(theme);
|
33
34
|
const hideBackButton = edit?.hideBackButton || false;
|
35
|
+
const errorMessageRef = useRef(errorMessage);
|
36
|
+
useEffect(() => {
|
37
|
+
errorMessageRef.current = errorMessage;
|
38
|
+
}, [errorMessage]);
|
34
39
|
useEffect(() => {
|
35
40
|
return () => {
|
36
|
-
|
37
|
-
if (editData?.current) {
|
41
|
+
if (editData?.current && !errorMessageRef.current) {
|
38
42
|
delete editData?.current?.edited;
|
39
43
|
onEvent("updateProperty", {
|
40
44
|
...editData?.current
|
@@ -43,18 +47,24 @@ const EditOption = props => {
|
|
43
47
|
};
|
44
48
|
}, []);
|
45
49
|
const onChange = e => {
|
46
|
-
const
|
50
|
+
const {
|
51
|
+
name,
|
52
|
+
value,
|
53
|
+
delete: isDelete
|
54
|
+
} = e?.target || {};
|
55
|
+
const targetValue = value?.toLowerCase();
|
56
|
+
const updatedOptions = edit?.options?.map((m, i) => {
|
47
57
|
if (i === edit?.optionIndex) {
|
48
58
|
return {
|
49
59
|
...m,
|
50
|
-
[
|
60
|
+
[name]: value
|
51
61
|
};
|
52
62
|
}
|
53
63
|
return m;
|
54
64
|
});
|
55
65
|
|
56
|
-
//
|
57
|
-
if (edit?.optionIndex > -1 &&
|
66
|
+
// If deleting the option
|
67
|
+
if (edit?.optionIndex > -1 && isDelete) {
|
58
68
|
updatedOptions.splice(edit?.optionIndex, 1);
|
59
69
|
}
|
60
70
|
const latest = {
|
@@ -68,14 +78,28 @@ const EditOption = props => {
|
|
68
78
|
...latest,
|
69
79
|
edited: true
|
70
80
|
};
|
81
|
+
if (name === "value" && !value?.trim()) {
|
82
|
+
setErrorMessage("Option name must not be empty");
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
const isDuplicate = name === "value" && targetValue && edit?.options?.some((op, i) => i !== edit?.optionIndex && op?.value?.toLowerCase?.() === targetValue);
|
86
|
+
if (isDuplicate) {
|
87
|
+
setErrorMessage("Option name must be unique");
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
setErrorMessage(""); // Clear error on valid input
|
71
91
|
|
72
|
-
//
|
73
|
-
if (
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
92
|
+
// If delete go back
|
93
|
+
if (isDelete) {
|
94
|
+
if (hideBackButton) {
|
95
|
+
onClose();
|
96
|
+
} else {
|
97
|
+
onEvent("editProperty", {
|
98
|
+
edit: {
|
99
|
+
...latest
|
100
|
+
}
|
101
|
+
});
|
102
|
+
}
|
79
103
|
}
|
80
104
|
};
|
81
105
|
const onBack = () => {
|
@@ -137,7 +161,9 @@ const EditOption = props => {
|
|
137
161
|
value: selectedOption?.value,
|
138
162
|
onChange: onChange,
|
139
163
|
fullWidth: true,
|
140
|
-
placeholder: translation("Option Name")
|
164
|
+
placeholder: translation("Option Name"),
|
165
|
+
helperText: errorMessage,
|
166
|
+
error: !!errorMessage
|
141
167
|
}),
|
142
168
|
labelPlacement: "top"
|
143
169
|
})
|