next-helios-fe 1.6.12 → 1.6.14
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/package.json
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
"use client";
|
2
2
|
import React, { useState, useEffect, useRef } from "react";
|
3
|
+
import { Dropdown } from "../../../components";
|
3
4
|
import { Icon } from "@iconify/react";
|
4
|
-
import { createPortal } from "react-dom";
|
5
5
|
|
6
6
|
export interface MultipleSelectProps
|
7
|
-
extends Omit<
|
8
|
-
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
9
|
-
"onChange" | "value"
|
10
|
-
> {
|
7
|
+
extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange" | "value"> {
|
11
8
|
options?: {
|
12
9
|
width?: "full" | "fit";
|
13
10
|
height?: "short" | "medium" | "high";
|
@@ -20,6 +17,7 @@ export interface MultipleSelectProps
|
|
20
17
|
}[];
|
21
18
|
placeholder?: string;
|
22
19
|
required?: boolean;
|
20
|
+
disabled?: boolean;
|
23
21
|
value?: string[];
|
24
22
|
onClick?: () => void;
|
25
23
|
onChange?: (e: {
|
@@ -35,6 +33,7 @@ export const MultipleSelect: React.FC<MultipleSelectProps> = ({
|
|
35
33
|
menus,
|
36
34
|
placeholder,
|
37
35
|
required,
|
36
|
+
disabled,
|
38
37
|
value,
|
39
38
|
onClick,
|
40
39
|
onChange,
|
@@ -42,13 +41,10 @@ export const MultipleSelect: React.FC<MultipleSelectProps> = ({
|
|
42
41
|
}) => {
|
43
42
|
const [tempValue, setTempValue] = useState<string[]>([]);
|
44
43
|
const [openDropdown, setOpenDropdown] = useState(false);
|
45
|
-
const [position, setPosition] = useState<{
|
46
|
-
top: number;
|
47
|
-
left: number;
|
48
|
-
} | null>(null);
|
49
44
|
const [dropdownWidth, setDropdownWidth] = useState<number>(0);
|
50
|
-
const
|
51
|
-
const
|
45
|
+
const [dropdownHeight, setDropdownHeight] = useState<number>(0);
|
46
|
+
const inputRef = useRef<HTMLDivElement>(null);
|
47
|
+
const dropdownRef = useRef<HTMLButtonElement>(null);
|
52
48
|
const width = options?.width === "fit" ? "w-fit" : "w-full";
|
53
49
|
const height =
|
54
50
|
options?.height === "short"
|
@@ -58,51 +54,13 @@ export const MultipleSelect: React.FC<MultipleSelectProps> = ({
|
|
58
54
|
: "py-1";
|
59
55
|
|
60
56
|
useEffect(() => {
|
61
|
-
|
62
|
-
if (
|
63
|
-
dropdownRef.current &&
|
64
|
-
!dropdownRef.current.contains(e.target as Node) &&
|
65
|
-
!triggerRef.current?.contains(e.target as Node)
|
66
|
-
) {
|
57
|
+
document.addEventListener("mousedown", (e) => {
|
58
|
+
if (e.target instanceof HTMLElement) {
|
67
59
|
setOpenDropdown(false);
|
68
60
|
}
|
69
|
-
};
|
70
|
-
|
71
|
-
document.addEventListener("mousedown", handleClickOutside);
|
72
|
-
return () => {
|
73
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
74
|
-
};
|
61
|
+
});
|
75
62
|
}, []);
|
76
63
|
|
77
|
-
useEffect(() => {
|
78
|
-
if (triggerRef.current) {
|
79
|
-
const rect = triggerRef.current.getBoundingClientRect();
|
80
|
-
const dropdownHeight = dropdownRef.current?.offsetHeight || 0;
|
81
|
-
const windowHeight = window.innerHeight;
|
82
|
-
|
83
|
-
setPosition({
|
84
|
-
top: rect.bottom + window.scrollY + 10,
|
85
|
-
left: rect.left + window.scrollX,
|
86
|
-
});
|
87
|
-
|
88
|
-
setDropdownWidth(rect.width);
|
89
|
-
|
90
|
-
if (rect.bottom + dropdownHeight > windowHeight) {
|
91
|
-
setPosition((prev) =>
|
92
|
-
prev
|
93
|
-
? { ...prev, top: rect.top + window.scrollY - dropdownHeight - 10 }
|
94
|
-
: null
|
95
|
-
);
|
96
|
-
}
|
97
|
-
}
|
98
|
-
|
99
|
-
if (openDropdown) {
|
100
|
-
document.getElementById("body")!.style.overflow = "hidden";
|
101
|
-
} else {
|
102
|
-
document.getElementById("body")!.style.overflow = "auto";
|
103
|
-
}
|
104
|
-
}, [openDropdown]);
|
105
|
-
|
106
64
|
useEffect(() => {
|
107
65
|
if (value) {
|
108
66
|
setTempValue(value);
|
@@ -118,94 +76,154 @@ export const MultipleSelect: React.FC<MultipleSelectProps> = ({
|
|
118
76
|
}, [tempValue]);
|
119
77
|
|
120
78
|
return (
|
121
|
-
<
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
<
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
79
|
+
<div className="flex flex-row-reverse items-end">
|
80
|
+
<label className={`grid gap-2 ${width}`}>
|
81
|
+
{label && (
|
82
|
+
<span
|
83
|
+
className={`text-sm select-none ${
|
84
|
+
required && "after:content-['*'] after:ml-1 after:text-danger"
|
85
|
+
}`}
|
86
|
+
>
|
87
|
+
{label}
|
88
|
+
</span>
|
89
|
+
)}
|
90
|
+
<div className="relative flex items-center">
|
91
|
+
<div
|
92
|
+
ref={inputRef}
|
93
|
+
className={`group/button flex justify-between items-center gap-2 w-full min-h-10 px-4 border rounded-md caret-transparent focus:outline-none focus:ring-1 focus:ring-primary focus:shadow focus:shadow-primary focus:border-primary-dark ${height} ${
|
94
|
+
disabled
|
95
|
+
? "bg-secondary-light cursor-default pointer-events-none"
|
96
|
+
: "bg-secondary-bg cursor-pointer"
|
97
|
+
} ${
|
98
|
+
openDropdown
|
99
|
+
? "outline-none ring-1 ring-primary shadow shadow-primary border-primary-dark"
|
100
|
+
: "border-default"
|
101
|
+
}`}
|
102
|
+
onClick={(e) => {
|
103
|
+
e.preventDefault();
|
104
|
+
onClick && onClick();
|
105
|
+
setOpenDropdown(true);
|
106
|
+
dropdownRef.current?.click();
|
107
|
+
setDropdownWidth(
|
108
|
+
inputRef?.current?.getBoundingClientRect()?.width || 0
|
109
|
+
);
|
110
|
+
setDropdownHeight(
|
111
|
+
inputRef?.current?.getBoundingClientRect()?.height || 0
|
112
|
+
);
|
113
|
+
}}
|
114
|
+
{...rest}
|
115
|
+
>
|
116
|
+
{!tempValue || tempValue?.length === 0 ? (
|
117
|
+
<span
|
118
|
+
className={`text-slate-300 select-none duration-300 ${
|
119
|
+
openDropdown ? "translate-x-1" : "translate-x-0"
|
120
|
+
}`}
|
121
|
+
>
|
122
|
+
{placeholder}
|
123
|
+
</span>
|
124
|
+
) : (
|
125
|
+
<div className="flex flex-wrap gap-2 h-min pointer-events-none invisible">
|
126
|
+
{tempValue?.map((item) => {
|
127
|
+
return (
|
155
128
|
<div
|
156
|
-
|
157
|
-
|
158
|
-
setTempValue(tempValue.filter((i) => i !== item));
|
159
|
-
}}
|
129
|
+
key={item}
|
130
|
+
className="flex items-center gap-2 px-2 py-0.5 rounded-md bg-primary text-white cursor-default pointer-events-auto"
|
160
131
|
>
|
161
|
-
<
|
132
|
+
<span>{menus.find((i) => i.value === item)?.label}</span>
|
133
|
+
<div
|
134
|
+
className="cursor-pointer"
|
135
|
+
onClick={() => {
|
136
|
+
setTempValue(tempValue.filter((i) => i !== item));
|
137
|
+
}}
|
138
|
+
>
|
139
|
+
<Icon icon="pajamas:close" />
|
140
|
+
</div>
|
162
141
|
</div>
|
163
|
-
|
164
|
-
)
|
165
|
-
|
142
|
+
);
|
143
|
+
})}
|
144
|
+
</div>
|
145
|
+
)}
|
146
|
+
<div className="ms-auto text-xl text-slate-400 pointer-events-none">
|
147
|
+
<Icon
|
148
|
+
icon={`gravity-ui:chevron-${openDropdown ? "up" : "down"}`}
|
149
|
+
/>
|
166
150
|
</div>
|
167
|
-
)}
|
168
|
-
<div className="text-xl text-slate-400 pointer-events-none">
|
169
|
-
<Icon icon={`gravity-ui:chevron-${openDropdown ? "up" : "down"}`} />
|
170
151
|
</div>
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
152
|
+
<div
|
153
|
+
className="absolute flex flex-wrap gap-2 h-min px-4 pointer-events-none"
|
154
|
+
style={{ width: dropdownWidth - 52 }}
|
155
|
+
>
|
156
|
+
{tempValue?.map((item) => {
|
157
|
+
return (
|
158
|
+
<div
|
159
|
+
key={item}
|
160
|
+
className={`flex items-center gap-2 px-2 py-0.5 rounded-md text-white select-none cursor-default pointer-events-auto ${
|
161
|
+
disabled ? "bg-secondary" : "bg-primary"
|
162
|
+
}`}
|
163
|
+
>
|
164
|
+
<span>{menus.find((i) => i.value === item)?.label}</span>
|
165
|
+
<div
|
166
|
+
className="cursor-pointer active:opacity-70 active:duration-300 active:ease-out disabled:active:opacity-100"
|
167
|
+
onClick={() => {
|
168
|
+
if (!disabled) {
|
169
|
+
setTempValue(tempValue.filter((i) => i !== item));
|
170
|
+
}
|
171
|
+
}}
|
172
|
+
>
|
173
|
+
<Icon icon="pajamas:close" />
|
174
|
+
</div>
|
175
|
+
</div>
|
176
|
+
);
|
177
|
+
})}
|
178
|
+
</div>
|
179
|
+
</div>
|
180
|
+
</label>
|
181
|
+
<div className="w-0 overflow-hidden">
|
182
|
+
<Dropdown
|
183
|
+
placement="bottom-start"
|
184
|
+
dismissOnClick={false}
|
185
|
+
trigger={
|
186
|
+
<button
|
187
|
+
type="button"
|
176
188
|
ref={dropdownRef}
|
177
|
-
className="
|
189
|
+
className="w-0 my-0.5"
|
178
190
|
style={{
|
179
|
-
|
180
|
-
left: position.left,
|
181
|
-
width: dropdownWidth,
|
191
|
+
height: dropdownHeight,
|
182
192
|
}}
|
183
193
|
>
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
194
|
+
1
|
195
|
+
</button>
|
196
|
+
}
|
197
|
+
>
|
198
|
+
<div
|
199
|
+
style={{
|
200
|
+
width: dropdownWidth - 11,
|
201
|
+
}}
|
202
|
+
>
|
203
|
+
{menus.length === 0 ? (
|
204
|
+
<div className="flex justify-center">
|
205
|
+
<span className="px-4 py-1">No data found</span>
|
206
|
+
</div>
|
207
|
+
) : (
|
208
|
+
menus.map((item, index) => (
|
209
|
+
<button
|
210
|
+
key={index}
|
211
|
+
type="button"
|
212
|
+
className="min-w-40 w-full my-0.5 px-4 py-2 rounded-md text-sm text-left text-default hover:bg-secondary-light disabled:bg-primary-transparent"
|
213
|
+
disabled={
|
214
|
+
tempValue?.find((i) => i === item.value) ? true : false
|
215
|
+
}
|
216
|
+
onClick={() => {
|
217
|
+
setTempValue([...tempValue, item.value]);
|
218
|
+
}}
|
219
|
+
>
|
220
|
+
{item.label}
|
221
|
+
</button>
|
222
|
+
))
|
223
|
+
)}
|
224
|
+
</div>
|
225
|
+
</Dropdown>
|
208
226
|
</div>
|
209
|
-
</
|
227
|
+
</div>
|
210
228
|
);
|
211
229
|
};
|
@@ -1,7 +1,7 @@
|
|
1
1
|
"use client";
|
2
2
|
import React, { useState, useEffect, useRef } from "react";
|
3
|
+
import { Dropdown } from "../../../components";
|
3
4
|
import { Icon } from "@iconify/react";
|
4
|
-
import { createPortal } from "react-dom";
|
5
5
|
|
6
6
|
export interface SelectProps
|
7
7
|
extends React.SelectHTMLAttributes<HTMLSelectElement> {
|
@@ -27,13 +27,9 @@ export const Select: React.FC<SelectProps> = ({
|
|
27
27
|
}) => {
|
28
28
|
const [tempValue, setTempValue] = useState("");
|
29
29
|
const [openDropdown, setOpenDropdown] = useState(false);
|
30
|
-
const [position, setPosition] = useState<{
|
31
|
-
top: number;
|
32
|
-
left: number;
|
33
|
-
} | null>(null);
|
34
30
|
const [dropdownWidth, setDropdownWidth] = useState<number>(0);
|
35
|
-
const
|
36
|
-
const dropdownRef = useRef<
|
31
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
32
|
+
const dropdownRef = useRef<HTMLButtonElement>(null);
|
37
33
|
const width = options?.width === "fit" ? "w-fit" : "w-full";
|
38
34
|
const height =
|
39
35
|
options?.height === "short"
|
@@ -43,51 +39,13 @@ export const Select: React.FC<SelectProps> = ({
|
|
43
39
|
: "py-1.5";
|
44
40
|
|
45
41
|
useEffect(() => {
|
46
|
-
|
47
|
-
if (
|
48
|
-
dropdownRef.current &&
|
49
|
-
!dropdownRef.current.contains(e.target as Node) &&
|
50
|
-
!triggerRef.current?.contains(e.target as Node)
|
51
|
-
) {
|
42
|
+
document.addEventListener("mousedown", (e) => {
|
43
|
+
if (e.target instanceof HTMLElement) {
|
52
44
|
setOpenDropdown(false);
|
53
45
|
}
|
54
|
-
};
|
55
|
-
|
56
|
-
document.addEventListener("mousedown", handleClickOutside);
|
57
|
-
return () => {
|
58
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
59
|
-
};
|
46
|
+
});
|
60
47
|
}, []);
|
61
48
|
|
62
|
-
useEffect(() => {
|
63
|
-
if (triggerRef.current) {
|
64
|
-
const rect = triggerRef.current.getBoundingClientRect();
|
65
|
-
const dropdownHeight = dropdownRef.current?.offsetHeight || 0;
|
66
|
-
const windowHeight = window.innerHeight;
|
67
|
-
|
68
|
-
setPosition({
|
69
|
-
top: rect.bottom + window.scrollY + 10,
|
70
|
-
left: rect.left + window.scrollX,
|
71
|
-
});
|
72
|
-
|
73
|
-
setDropdownWidth(rect.width);
|
74
|
-
|
75
|
-
if (rect.bottom + dropdownHeight > windowHeight) {
|
76
|
-
setPosition((prev) =>
|
77
|
-
prev
|
78
|
-
? { ...prev, top: rect.top + window.scrollY - dropdownHeight - 10 }
|
79
|
-
: null
|
80
|
-
);
|
81
|
-
}
|
82
|
-
}
|
83
|
-
|
84
|
-
if (openDropdown) {
|
85
|
-
document.getElementById("body")!.style.overflow = "hidden";
|
86
|
-
} else {
|
87
|
-
document.getElementById("body")!.style.overflow = "auto";
|
88
|
-
}
|
89
|
-
}, [openDropdown]);
|
90
|
-
|
91
49
|
useEffect(() => {
|
92
50
|
if (rest.value || rest.value === "") {
|
93
51
|
setTempValue(rest.value as string);
|
@@ -108,24 +66,27 @@ export const Select: React.FC<SelectProps> = ({
|
|
108
66
|
}, [tempValue]);
|
109
67
|
|
110
68
|
return (
|
111
|
-
<
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
onClick={() => setOpenDropdown(!openDropdown)}
|
125
|
-
>
|
69
|
+
<div className="flex flex-row-reverse items-end">
|
70
|
+
<label className={`grid gap-2 ${width}`}>
|
71
|
+
{label && (
|
72
|
+
<span
|
73
|
+
className={`text-sm select-none ${
|
74
|
+
rest.required &&
|
75
|
+
"after:content-['*'] after:ml-1 after:text-danger"
|
76
|
+
}`}
|
77
|
+
>
|
78
|
+
{label}
|
79
|
+
</span>
|
80
|
+
)}
|
81
|
+
<div className="relative flex items-center cursor-pointer">
|
126
82
|
<input
|
83
|
+
ref={inputRef}
|
127
84
|
type="text"
|
128
|
-
className={`w-full px-4 border
|
85
|
+
className={`w-full px-4 border rounded-md bg-secondary-bg cursor-pointer caret-transparent placeholder:duration-300 placeholder:text-slate-300 focus:placeholder:translate-x-1 focus:outline-none focus:ring-1 focus:ring-primary focus:shadow focus:shadow-primary focus:border-primary-dark disabled:bg-secondary-light disabled:text-slate-400 disabled:cursor-default ${height} ${
|
86
|
+
openDropdown
|
87
|
+
? "placeholder:translate-x-1 outline-none ring-1 ring-primary shadow shadow-primary border-primary-dark"
|
88
|
+
: "border-default placeholder:translate-x-0"
|
89
|
+
}`}
|
129
90
|
placeholder={placeholder}
|
130
91
|
required={rest.required}
|
131
92
|
disabled={rest.disabled}
|
@@ -134,55 +95,67 @@ export const Select: React.FC<SelectProps> = ({
|
|
134
95
|
? menus.find((item) => item.value === tempValue)?.label
|
135
96
|
: ""
|
136
97
|
}
|
137
|
-
onClick={() =>
|
98
|
+
onClick={(e) => {
|
99
|
+
e.preventDefault();
|
100
|
+
setOpenDropdown(true);
|
101
|
+
dropdownRef.current?.click();
|
102
|
+
setDropdownWidth(
|
103
|
+
inputRef?.current?.getBoundingClientRect()?.width || 0
|
104
|
+
);
|
105
|
+
}}
|
138
106
|
/>
|
139
107
|
<div className="absolute right-4 text-xl text-slate-400 pointer-events-none">
|
140
108
|
<Icon icon={`gravity-ui:chevron-${openDropdown ? "up" : "down"}`} />
|
141
109
|
</div>
|
142
110
|
</div>
|
143
|
-
{
|
144
|
-
|
145
|
-
|
146
|
-
|
111
|
+
<select className="hidden" {...rest}>
|
112
|
+
{menus.map((item, index) => (
|
113
|
+
<option key={index} value={item.value}>
|
114
|
+
{item.label}
|
115
|
+
</option>
|
116
|
+
))}
|
117
|
+
</select>
|
118
|
+
</label>
|
119
|
+
<div className="w-0 overflow-hidden">
|
120
|
+
<Dropdown
|
121
|
+
placement="bottom-start"
|
122
|
+
trigger={
|
123
|
+
<button
|
124
|
+
type="button"
|
147
125
|
ref={dropdownRef}
|
148
|
-
className=
|
149
|
-
style={{
|
150
|
-
top: position.top,
|
151
|
-
left: position.left,
|
152
|
-
width: dropdownWidth,
|
153
|
-
}}
|
126
|
+
className={`w-0 my-0.5 ${height}`}
|
154
127
|
>
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
128
|
+
1
|
129
|
+
</button>
|
130
|
+
}
|
131
|
+
>
|
132
|
+
<div
|
133
|
+
style={{
|
134
|
+
width: dropdownWidth - 11,
|
135
|
+
}}
|
136
|
+
>
|
137
|
+
{menus.length === 0 ? (
|
138
|
+
<div className="flex justify-center">
|
139
|
+
<span className="px-4 py-1">No data found</span>
|
140
|
+
</div>
|
141
|
+
) : (
|
142
|
+
menus.map((item, index) => (
|
143
|
+
<button
|
144
|
+
key={index}
|
145
|
+
type="button"
|
146
|
+
className="min-w-40 w-full my-0.5 px-4 py-2 rounded-md text-sm text-left hover:bg-secondary-light disabled:bg-primary-transparent disabled:text-primary"
|
147
|
+
disabled={tempValue === item.value}
|
148
|
+
onClick={() => {
|
149
|
+
setTempValue(item.value);
|
150
|
+
}}
|
151
|
+
>
|
152
|
+
{item.label}
|
153
|
+
</button>
|
154
|
+
))
|
155
|
+
)}
|
156
|
+
</div>
|
157
|
+
</Dropdown>
|
178
158
|
</div>
|
179
|
-
|
180
|
-
{menus.map((item, index) => (
|
181
|
-
<option key={index} value={item.value}>
|
182
|
-
{item.label}
|
183
|
-
</option>
|
184
|
-
))}
|
185
|
-
</select>
|
186
|
-
</label>
|
159
|
+
</div>
|
187
160
|
);
|
188
161
|
};
|