@megha-ui/react 1.2.188 → 1.2.190
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.
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { type JSX } from "react";
|
|
2
|
+
type DropdownOption = {
|
|
3
|
+
disabled?: boolean;
|
|
4
|
+
icon?: JSX.Element;
|
|
5
|
+
isDelete?: boolean;
|
|
6
|
+
label: string;
|
|
7
|
+
onDelete?: () => void;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
value: number | string;
|
|
10
|
+
};
|
|
11
|
+
type IconDropdownProps = {
|
|
12
|
+
asteriskColor?: string;
|
|
13
|
+
border?: string;
|
|
14
|
+
checkboxWrapper?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
ClearIcon?: any;
|
|
17
|
+
clearId?: string;
|
|
18
|
+
closeOnSelect?: boolean;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
DropDownIcon?: any;
|
|
21
|
+
dropdownListBG?: string;
|
|
22
|
+
dropdownListWidth?: number | string;
|
|
23
|
+
isClear?: boolean;
|
|
24
|
+
isMultiple?: boolean;
|
|
25
|
+
label?: string;
|
|
26
|
+
labelFontSize?: number;
|
|
27
|
+
labelFontWeight?: number;
|
|
28
|
+
labelMarginBottom?: number;
|
|
29
|
+
marginBottom?: number | string;
|
|
30
|
+
marginLeft?: number | string;
|
|
31
|
+
marginRight?: number | string;
|
|
32
|
+
marginTop?: number | string;
|
|
33
|
+
maxDropdownHeight?: number | string;
|
|
34
|
+
menuFrom?: string;
|
|
35
|
+
compactDisplay?: boolean;
|
|
36
|
+
ultraCompactDisplay?: boolean;
|
|
37
|
+
onChange: (values: (number | string)[]) => void;
|
|
38
|
+
onMenuClose?: (e: MouseEvent) => void;
|
|
39
|
+
options: DropdownOption[];
|
|
40
|
+
placeholder?: string;
|
|
41
|
+
required?: boolean;
|
|
42
|
+
searchBorderColor?: string;
|
|
43
|
+
searchEnabled?: boolean;
|
|
44
|
+
selectedCharLength?: number;
|
|
45
|
+
selectedDisplay?: string;
|
|
46
|
+
selectedValues: (number | string)[];
|
|
47
|
+
style?: React.CSSProperties;
|
|
48
|
+
Tooltip?: any;
|
|
49
|
+
withTooltip?: boolean;
|
|
50
|
+
width?: number | string;
|
|
51
|
+
withValue?: boolean;
|
|
52
|
+
autoPosition?: boolean;
|
|
53
|
+
isSort?: boolean;
|
|
54
|
+
isLoading?: boolean;
|
|
55
|
+
};
|
|
56
|
+
declare const IconDropdown: React.FC<IconDropdownProps>;
|
|
57
|
+
export default IconDropdown;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useDensity } from "../../context/DensityContext";
|
|
4
|
+
import { HiChevronDown } from "react-icons/hi";
|
|
5
|
+
import Block from "../block";
|
|
6
|
+
import Loader from "../loader";
|
|
7
|
+
import Text from "../text";
|
|
8
|
+
const IconDropdown = ({ className, ClearIcon, clearId, closeOnSelect = true, disabled = false, DropDownIcon, dropdownListBG, dropdownListWidth, isClear, maxDropdownHeight = "200px", menuFrom = "left", onChange, onMenuClose, options, searchBorderColor = "#2377ba", searchEnabled = true, selectedDisplay, selectedValues, style, Tooltip, withTooltip = false, withValue, labelFontSize, labelFontWeight, labelMarginBottom, asteriskColor, autoPosition = false, compactDisplay = false, ultraCompactDisplay = false, isSort = true, marginTop, marginRight, marginBottom, marginLeft, width, label, required, border, isLoading = false }) => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const { density } = useDensity();
|
|
11
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
12
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
13
|
+
const [filteredOptions, setFilteredOptions] = useState(options);
|
|
14
|
+
const wrapperRef = useRef(null);
|
|
15
|
+
const clearIconRef = useRef(null);
|
|
16
|
+
const searchInputRef = useRef(null);
|
|
17
|
+
const optionRefs = useRef([]);
|
|
18
|
+
const [highlightIndex, setHighlightIndex] = useState(0);
|
|
19
|
+
const [clickStyle, setClickStyle] = useState({
|
|
20
|
+
left: 0,
|
|
21
|
+
top: "100%",
|
|
22
|
+
});
|
|
23
|
+
const calculateAutoPosition = () => {
|
|
24
|
+
if (!wrapperRef.current)
|
|
25
|
+
return;
|
|
26
|
+
const rect = wrapperRef.current.getBoundingClientRect();
|
|
27
|
+
const bottomSpace = window.innerHeight - rect.bottom;
|
|
28
|
+
const topSpace = rect.top;
|
|
29
|
+
const heightNum = typeof maxDropdownHeight === "number"
|
|
30
|
+
? maxDropdownHeight
|
|
31
|
+
: parseInt(`${maxDropdownHeight}`, 10) || 200;
|
|
32
|
+
if (bottomSpace < heightNum && topSpace > bottomSpace) {
|
|
33
|
+
setClickStyle({ left: 0, bottom: "100%" });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
setClickStyle({ left: 0, top: "100%" });
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
var _a;
|
|
41
|
+
if (isOpen && searchEnabled) {
|
|
42
|
+
(_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
43
|
+
}
|
|
44
|
+
if (isOpen) {
|
|
45
|
+
setHighlightIndex(0);
|
|
46
|
+
}
|
|
47
|
+
}, [isOpen, searchEnabled]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (isOpen) {
|
|
50
|
+
setHighlightIndex(0);
|
|
51
|
+
}
|
|
52
|
+
}, [filteredOptions, isOpen]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
var _a;
|
|
55
|
+
if (isOpen && optionRefs.current[highlightIndex]) {
|
|
56
|
+
(_a = optionRefs.current[highlightIndex]) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: "nearest" });
|
|
57
|
+
}
|
|
58
|
+
}, [highlightIndex, isOpen]);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
function handleClickOutside(event) {
|
|
61
|
+
if (wrapperRef.current &&
|
|
62
|
+
!wrapperRef.current.contains(event.target)) {
|
|
63
|
+
const list = wrapperRef.current.querySelector("ul");
|
|
64
|
+
const isDisplayNone = list && window.getComputedStyle(list).display === "none";
|
|
65
|
+
if (!isDisplayNone) {
|
|
66
|
+
onMenuClose && onMenuClose(event);
|
|
67
|
+
setIsOpen(false);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
72
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
73
|
+
}, [selectedValues, onMenuClose]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const handleKeyDown = (e) => {
|
|
76
|
+
var _a;
|
|
77
|
+
if (!isOpen)
|
|
78
|
+
return;
|
|
79
|
+
if (filteredOptions.length === 0)
|
|
80
|
+
return;
|
|
81
|
+
if (e.key === "ArrowDown") {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
setHighlightIndex((prev) => (prev + 1) % filteredOptions.length);
|
|
84
|
+
}
|
|
85
|
+
else if (e.key === "ArrowUp") {
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
setHighlightIndex((prev) => prev === 0 ? filteredOptions.length - 1 : prev - 1);
|
|
88
|
+
}
|
|
89
|
+
else if (e.key === "Enter") {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
const option = filteredOptions[highlightIndex];
|
|
92
|
+
if (!option)
|
|
93
|
+
return;
|
|
94
|
+
handleSelect(option.value, (_a = option.disabled) !== null && _a !== void 0 ? _a : false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
98
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
99
|
+
}, [isOpen, filteredOptions, highlightIndex]);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (menuFrom !== "left") {
|
|
102
|
+
if (menuFrom === "top") {
|
|
103
|
+
setClickStyle({
|
|
104
|
+
bottom: "calc(100% + 5px)",
|
|
105
|
+
left: 0,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
else if (menuFrom === "bottom") {
|
|
109
|
+
setClickStyle({
|
|
110
|
+
top: 0,
|
|
111
|
+
right: 0,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
setClickStyle({
|
|
116
|
+
right: 0,
|
|
117
|
+
top: "100%",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}, [menuFrom]);
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (!autoPosition)
|
|
124
|
+
return;
|
|
125
|
+
if (isOpen) {
|
|
126
|
+
calculateAutoPosition();
|
|
127
|
+
window.addEventListener("resize", calculateAutoPosition);
|
|
128
|
+
return () => window.removeEventListener("resize", calculateAutoPosition);
|
|
129
|
+
}
|
|
130
|
+
}, [autoPosition, isOpen]);
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
const _options = isSort
|
|
133
|
+
? options
|
|
134
|
+
.sort((a, b) => (a.label > b.label ? 1 : -1))
|
|
135
|
+
.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()))
|
|
136
|
+
: options.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()));
|
|
137
|
+
setFilteredOptions(_options);
|
|
138
|
+
}, [searchTerm, options, isSort]);
|
|
139
|
+
const handleSelect = (value, isDisabled) => {
|
|
140
|
+
if (isDisabled)
|
|
141
|
+
return;
|
|
142
|
+
onChange([value]);
|
|
143
|
+
if (closeOnSelect)
|
|
144
|
+
setIsOpen(false);
|
|
145
|
+
};
|
|
146
|
+
const handleClear = () => {
|
|
147
|
+
if (!isClear)
|
|
148
|
+
return;
|
|
149
|
+
onChange([]);
|
|
150
|
+
};
|
|
151
|
+
const displayValue = selectedValues.length > 0
|
|
152
|
+
? (_b = (_a = options.find((option) => option.value === selectedValues[0])) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : ""
|
|
153
|
+
: searchTerm;
|
|
154
|
+
const labelStyle = {
|
|
155
|
+
fontSize: labelFontSize,
|
|
156
|
+
fontWeight: labelFontWeight,
|
|
157
|
+
marginBottom: labelMarginBottom,
|
|
158
|
+
};
|
|
159
|
+
const asteriskStyle = {
|
|
160
|
+
color: asteriskColor,
|
|
161
|
+
};
|
|
162
|
+
const listItemStyle = {
|
|
163
|
+
paddingTop: 6,
|
|
164
|
+
paddingBottom: 6,
|
|
165
|
+
paddingLeft: "1rem",
|
|
166
|
+
paddingRight: "1rem",
|
|
167
|
+
borderBottom: "1px solid var(--divider-strong, #dddddd)",
|
|
168
|
+
cursor: "pointer",
|
|
169
|
+
};
|
|
170
|
+
const listItemDisabledStyle = {
|
|
171
|
+
cursor: "not-allowed",
|
|
172
|
+
color: "var(--muted, #a0a0a0)",
|
|
173
|
+
backgroundColor: "var(--disabled-bg)",
|
|
174
|
+
pointerEvents: "none",
|
|
175
|
+
};
|
|
176
|
+
const listItemHoverStyle = {
|
|
177
|
+
color: "var(--dropdown-hover-color)",
|
|
178
|
+
backgroundColor: "var(--dropdown-hover-bg)",
|
|
179
|
+
};
|
|
180
|
+
const selectedItemStyle = {
|
|
181
|
+
backgroundColor: "var(--dropdown-selected-bg)",
|
|
182
|
+
color: "var(--dropdown-selected-color)",
|
|
183
|
+
};
|
|
184
|
+
const handleClick = (e) => {
|
|
185
|
+
const clearEle = document.getElementById(clearId || "");
|
|
186
|
+
if (clearEle === e.target) {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
}
|
|
189
|
+
else if (clearEle === null || clearEle === void 0 ? void 0 : clearEle.contains(e.target)) {
|
|
190
|
+
e.preventDefault();
|
|
191
|
+
}
|
|
192
|
+
else if (disabled) {
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
if (!isOpen && autoPosition) {
|
|
197
|
+
calculateAutoPosition();
|
|
198
|
+
}
|
|
199
|
+
setIsOpen(!isOpen);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const wrapMiddle = (text, maxLength, wrapper = "...") => {
|
|
203
|
+
if (maxLength) {
|
|
204
|
+
if (text.length <= maxLength) {
|
|
205
|
+
return text;
|
|
206
|
+
}
|
|
207
|
+
const halfLength = Math.floor((maxLength - wrapper.length) / 2);
|
|
208
|
+
return text.slice(0, halfLength) + wrapper + text.slice(-halfLength);
|
|
209
|
+
}
|
|
210
|
+
return text;
|
|
211
|
+
};
|
|
212
|
+
return (_jsxs("div", { style: {
|
|
213
|
+
width: width !== null && width !== void 0 ? width : "100%",
|
|
214
|
+
marginBottom,
|
|
215
|
+
marginTop,
|
|
216
|
+
marginRight,
|
|
217
|
+
marginLeft,
|
|
218
|
+
}, children: [label && (_jsxs("p", { style: labelStyle, children: [label, required && _jsx("span", { style: asteriskStyle, children: " *" })] })), _jsxs("div", { ref: wrapperRef, className: `${className}`, style: Object.assign({ border, borderRadius: 4, padding: "0 0.5rem", alignItems: "center", display: "flex", minHeight: `var(--control-min-height, ${ultraCompactDisplay
|
|
219
|
+
? "1.5rem"
|
|
220
|
+
: compactDisplay
|
|
221
|
+
? "2rem"
|
|
222
|
+
: density === "ultraCompact"
|
|
223
|
+
? "1.5rem"
|
|
224
|
+
: density === "compact"
|
|
225
|
+
? "2rem"
|
|
226
|
+
: "2.5rem"})`, position: "relative" }, style), children: [_jsxs("div", { style: {
|
|
227
|
+
display: "flex",
|
|
228
|
+
alignItems: "center",
|
|
229
|
+
justifyContent: "space-between",
|
|
230
|
+
cursor: "pointer",
|
|
231
|
+
width: "100%",
|
|
232
|
+
}, ref: clearIconRef, onClick: handleClick, children: [withValue && (displayValue !== null && displayValue !== void 0 ? displayValue : selectedDisplay) && (_jsx("div", { style: { marginRight: "0.5rem" }, title: "Click to clear the value", children: selectedDisplay !== null && selectedDisplay !== void 0 ? selectedDisplay : displayValue })), _jsxs("div", { style: {
|
|
233
|
+
display: "flex",
|
|
234
|
+
alignItems: "center",
|
|
235
|
+
}, children: [isClear && (displayValue || selectedDisplay) && (_jsx("div", { style: { marginRight: "0.5rem" }, onClick: handleClear, id: clearId, title: "Click to clear the value", children: ClearIcon ? (ClearIcon) : (_jsx("span", { style: {
|
|
236
|
+
color: "var(--form-border-color, #dbdfe9)",
|
|
237
|
+
fontSize: "1rem",
|
|
238
|
+
}, children: "X" })) })), disabled ? (Tooltip && Tooltip) : DropDownIcon ? (DropDownIcon) : (_jsx(HiChevronDown, { fontSize: "1rem" })), withTooltip && Tooltip && Tooltip] })] }), _jsxs("ul", { style: Object.assign(Object.assign({ width: dropdownListWidth || "100%", position: "absolute", backgroundColor: dropdownListBG || "var(--dropdown-bg)", boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)", border: "1px solid var(--divider, #f5f5f5)", zIndex: 10, marginTop: 4, borderRadius: 4, overflow: "hidden" }, clickStyle), { display: !isOpen ? "none" : "" }), children: [searchEnabled && (_jsx("li", { style: { padding: "0.5rem" }, children: _jsx("input", { ref: searchInputRef, type: "text", placeholder: "Search...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), disabled: disabled, style: {
|
|
239
|
+
width: "100%",
|
|
240
|
+
padding: "0.5rem",
|
|
241
|
+
boxSizing: "border-box",
|
|
242
|
+
border: "1px solid",
|
|
243
|
+
borderColor: searchBorderColor,
|
|
244
|
+
borderRadius: 4,
|
|
245
|
+
} }) })), _jsx("div", { style: { maxHeight: maxDropdownHeight, overflowY: "auto" }, children: isLoading ? (_jsxs(Block, { as: "div", className: "flex items-center justify-between", children: [_jsx(Text, { as: "span", children: "Loading options" }), _jsx(Loader, { size: 12 })] })) : (filteredOptions.map((option, index) => (_jsxs("li", { ref: (el) => {
|
|
246
|
+
optionRefs.current[index] = el;
|
|
247
|
+
}, onClick: () => handleSelect(option.value, option.disabled || false), style: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, listItemStyle), { display: "flex", alignItems: "center" }), (index === highlightIndex ? listItemHoverStyle : {})), (option.disabled ? listItemDisabledStyle : {})), (index !== highlightIndex &&
|
|
248
|
+
selectedValues.includes(option.value)
|
|
249
|
+
? selectedItemStyle
|
|
250
|
+
: {})), { borderBottom: index === filteredOptions.length - 1
|
|
251
|
+
? "none"
|
|
252
|
+
: "1px solid var(--divider-strong, #dddddd)", wordWrap: "break-word", textWrap: "wrap", justifyContent: "space-between" }), onMouseEnter: (e) => {
|
|
253
|
+
if (!option.disabled) {
|
|
254
|
+
setHighlightIndex(index);
|
|
255
|
+
}
|
|
256
|
+
}, children: [_jsxs("div", { style: {
|
|
257
|
+
display: "flex",
|
|
258
|
+
alignItems: "start",
|
|
259
|
+
width: "100%",
|
|
260
|
+
}, children: [option.icon && option.isDelete && !option.isDelete && (_jsx("span", { style: { margin: "0 0.5rem" }, children: option.icon })), _jsx("span", { children: option.label })] }), option.icon && option.isDelete && option.icon] }, String(option.value))))) })] })] })] }));
|
|
261
|
+
};
|
|
262
|
+
export default IconDropdown;
|
package/dist/index.d.ts
CHANGED
|
@@ -15,3 +15,4 @@ export { default as Toggle } from "./components/toggle";
|
|
|
15
15
|
export { Tabs, Tab, TabList, TabPanel } from "./components/tabs";
|
|
16
16
|
export { formatValue } from "./services/commonService";
|
|
17
17
|
export { default as Chat } from "./components/chat";
|
|
18
|
+
export { default as IconDropDown } from "./components/IconDropDown";
|
package/dist/index.js
CHANGED
|
@@ -15,3 +15,4 @@ export { default as Toggle } from "./components/toggle";
|
|
|
15
15
|
export { Tabs, Tab, TabList, TabPanel } from "./components/tabs";
|
|
16
16
|
export { formatValue } from "./services/commonService";
|
|
17
17
|
export { default as Chat } from "./components/chat";
|
|
18
|
+
export { default as IconDropDown } from "./components/IconDropDown";
|
package/package.json
CHANGED