next-helios-fe 1.6.13 → 1.6.15

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.
@@ -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 triggerRef = useRef<HTMLDivElement>(null);
36
- const dropdownRef = useRef<HTMLDivElement>(null);
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
- const handleClickOutside = (e: MouseEvent) => {
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
- <label className={`grid gap-2 ${width}`}>
112
- {label && (
113
- <span
114
- className={`text-sm select-none ${
115
- rest.required && "after:content-['*'] after:ml-1 after:text-danger"
116
- }`}
117
- >
118
- {label}
119
- </span>
120
- )}
121
- <div className="relative" ref={triggerRef}>
122
- <div
123
- className="relative flex items-center cursor-pointer"
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-default border rounded-md bg-secondary-bg cursor-pointer caret-transparent placeholder:duration-300 placeholder:translate-x-0 focus:placeholder:translate-x-1 placeholder:text-slate-300 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}`}
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={() => setOpenDropdown(true)}
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
- {openDropdown &&
144
- position &&
145
- createPortal(
146
- <div
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="absolute max-h-40 p-1 z-50 pointer-events-auto bg-secondary-bg shadow border rounded-md overflow-auto"
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
- {menus.length === 0 ? (
156
- <div className="flex justify-center">
157
- <span className="px-4 py-1">No data found</span>
158
- </div>
159
- ) : (
160
- menus.map((item, index) => (
161
- <button
162
- key={index}
163
- type="button"
164
- 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"
165
- disabled={tempValue === item.value}
166
- onMouseDown={() => {
167
- setTempValue(item.value);
168
- setOpenDropdown(false);
169
- }}
170
- >
171
- {item.label}
172
- </button>
173
- ))
174
- )}
175
- </div>,
176
- document.body
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
- <select className="hidden" {...rest}>
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
  };