gbs-add-block 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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GBS Building Blocks 2.0 (v1.0.6)
1
+ # GBS Building Blocks 2.0 (v1.0.7)
2
2
 
3
3
  Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
4
4
 
@@ -6,9 +6,10 @@ Latest and upgraded version of GBS building blocks with headless UI and removed
6
6
 
7
7
  For detailed documentation on usage and props, Please visit: [Building Block Documentation v2.0](https://blackmax-designs.gitbook.io/building-block-v2.0)
8
8
 
9
- ## What's New 🎉 (Ver 1.0.6)
9
+ ## What's New 🎉 (Ver 1.0.7)
10
10
 
11
11
  - Uploader Enhancement
12
+ - Select Bug Fix
12
13
 
13
14
  ## Authors
14
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbs-add-block",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "React Component Library",
5
5
  "type": "module",
6
6
  "files": [
@@ -13,6 +13,7 @@ import React, {
13
13
  useImperativeHandle,
14
14
  useRef,
15
15
  } from "react";
16
+ import { createPortal } from "react-dom";
16
17
  import Icon from "../icon/Icon";
17
18
  import { check, search, upDown, x } from "../icon/iconPaths";
18
19
  import type { ItemsProps, SelectHandle, SelectProps } from "./types";
@@ -21,9 +22,11 @@ import { iconClass, popUp, primary } from "../globalStyle";
21
22
  import {
22
23
  useSelectState,
23
24
  useSelectData,
24
- useClickOutside,
25
25
  applyScrollbarStyles,
26
26
  useKeyboardNavigation,
27
+ usePortalPopup,
28
+ getPortalStyles,
29
+ getAnimationClasses,
27
30
  } from "@grampro/headless-helpers";
28
31
 
29
32
  const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
@@ -68,9 +71,16 @@ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
68
71
  const inputRef = useRef<HTMLInputElement>(null);
69
72
  const selectRef = useRef<HTMLDivElement>(null);
70
73
 
71
- useClickOutside(selectRef as React.RefObject<HTMLElement>, () =>
72
- setShowPopover(false)
73
- );
74
+ // Use the custom portal hooks
75
+ const position = usePortalPopup({
76
+ isOpen: showPopover,
77
+ onClose: () => setShowPopover(false),
78
+ triggerRef: selectRef,
79
+ popupHeight: 250,
80
+ offset: 4,
81
+ minSpaceRequired: 50,
82
+ portalSelector: '[data-select-portal="true"]',
83
+ });
74
84
 
75
85
  // Update the handleSelect to accept a SelectItem
76
86
  const handleSelect = useCallback(
@@ -120,97 +130,113 @@ const Select = forwardRef<SelectHandle, SelectProps>((props, ref) => {
120
130
  selected: selectedItem,
121
131
  }));
122
132
 
123
- return (
133
+ // Portal popup content with smart positioning
134
+ const popupContent = showPopover && !disabled && (
124
135
  <div
125
- className="relative w-full mt-2"
126
- ref={selectRef}
127
- id={id}
128
- onKeyDown={handleKeyDown}
136
+ className={`${popUp["pop-up-style"]} ${getAnimationClasses(
137
+ position.placement
138
+ )}`}
139
+ style={getPortalStyles(position, 250)}
140
+ data-select-portal="true"
129
141
  >
130
- <div className="w-full relative">
131
- <button
132
- className={`${error ? primary["error-border"] : "border"} ${
133
- selectStyle["select-button"]
134
- } ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
135
- onClick={togglePopover}
136
- type="button"
137
- disabled={disabled}
138
- >
139
- {selectedDisplay || placeholder}
140
- <Icon
141
- elements={upDown}
142
- svgClass={`${iconClass["grey-common"]} ${
143
- disabled ? "opacity-50" : ""
144
- }`}
142
+ {showSearch && (
143
+ <div className={selectStyle["input-parent"]}>
144
+ <Icon elements={search} svgClass={iconClass["grey-common"]} />
145
+ <input
146
+ autoComplete="off"
147
+ type="text"
148
+ name="search"
149
+ id="search"
150
+ placeholder="Search a value"
151
+ className="w-full outline-none dark:bg-transparent"
152
+ ref={inputRef}
153
+ value={searchTerm}
154
+ onChange={(e) => {
155
+ setSearchTerm(e.target.value);
156
+ if (onFiltering) onFiltering(e.target.value);
157
+ setFocusedIndex(-1);
158
+ }}
145
159
  />
146
- </button>
147
- {selectedDisplay && !disabled && (
160
+ </div>
161
+ )}
162
+ {filteredItems.length > 0 ? (
163
+ filteredItems.map(({ value, label }, index: number) => (
148
164
  <button
149
- className={selectStyle["selectedDisplay-Button"]}
150
- onClick={handleClear}
165
+ key={value}
166
+ ref={(el: any) => (itemRefs.current[index] = el)}
167
+ className={`${selectStyle["filter-button"]} ${
168
+ focusedIndex === index ? "bg-gray-100 dark:bg-gray-700" : ""
169
+ }`}
170
+ onClick={() => handleSelect({ value, label })}
171
+ onMouseEnter={() => setFocusedIndex(index)}
151
172
  >
152
- <Icon elements={x} svgClass={iconClass["grey-common"]} />
173
+ <Icon
174
+ elements={check}
175
+ svgClass={`h-4 w-4 fill-none ${
176
+ selectedItem === value ? "stroke-gray-500" : ""
177
+ }`}
178
+ />
179
+ {label}
153
180
  </button>
154
- )}
155
- {error && <p className={primary["error-primary"]}>{error}</p>}
156
- </div>
181
+ ))
182
+ ) : (
183
+ <div className="text-sm text-center p-2">No Data Found</div>
184
+ )}
185
+ </div>
186
+ );
157
187
 
158
- <input
159
- type="hidden"
160
- name={name}
161
- value={selectedItem || ""}
162
- readOnly
163
- disabled={disabled}
164
- />
165
-
166
- {showPopover && !disabled && (
167
- <div className={popUp["pop-up-style"]}>
168
- {showSearch && (
169
- <div className={selectStyle["input-parent"]}>
170
- <Icon elements={search} svgClass={iconClass["grey-common"]} />
171
- <input
172
- autoComplete="off"
173
- type="text"
174
- name="search"
175
- id="search"
176
- placeholder="Search a value"
177
- className="w-full outline-none"
178
- ref={inputRef}
179
- value={searchTerm}
180
- onChange={(e) => {
181
- setSearchTerm(e.target.value);
182
- if (onFiltering) onFiltering(e.target.value);
183
- setFocusedIndex(-1);
184
- }}
185
- />
186
- </div>
187
- )}
188
- {filteredItems.length > 0 ? (
189
- filteredItems.map(({ value, label }, index: number) => (
190
- <button
191
- key={value}
192
- ref={(el: any) => (itemRefs.current[index] = el)}
193
- className={`${selectStyle["filter-button"]} ${
194
- focusedIndex === index ? "bg-gray-100" : ""
195
- }`}
196
- onClick={() => handleSelect({ value, label })}
197
- onMouseEnter={() => setFocusedIndex(index)}
198
- >
199
- <Icon
200
- elements={check}
201
- svgClass={`h-4 w-4 fill-none ${
202
- selectedItem === value ? "stroke-gray-500" : ""
203
- }`}
204
- />
205
- {label}
206
- </button>
207
- ))
208
- ) : (
209
- <div className="text-sm text-center">No Data Found</div>
188
+ return (
189
+ <>
190
+ <div
191
+ className="relative w-full mt-2"
192
+ ref={selectRef}
193
+ id={id}
194
+ onKeyDown={handleKeyDown}
195
+ >
196
+ <div className="w-full relative">
197
+ <button
198
+ className={`${error ? primary["error-border"] : "border"} ${
199
+ selectStyle["select-button"]
200
+ } ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
201
+ onClick={togglePopover}
202
+ type="button"
203
+ disabled={disabled}
204
+ >
205
+ {selectedDisplay || placeholder}
206
+ <Icon
207
+ elements={upDown}
208
+ svgClass={`${iconClass["grey-common"]} ${
209
+ disabled ? "opacity-50" : ""
210
+ } ${
211
+ showPopover && position.placement === "top" ? "rotate-180" : ""
212
+ }`}
213
+ />
214
+ </button>
215
+ {selectedDisplay && !disabled && (
216
+ <button
217
+ className={selectStyle["selectedDisplay-Button"]}
218
+ onClick={handleClear}
219
+ >
220
+ <Icon elements={x} svgClass={iconClass["grey-common"]} />
221
+ </button>
210
222
  )}
223
+ {error && <p className={primary["error-primary"]}>{error}</p>}
211
224
  </div>
212
- )}
213
- </div>
225
+
226
+ <input
227
+ type="hidden"
228
+ name={name}
229
+ value={selectedItem || ""}
230
+ readOnly
231
+ disabled={disabled}
232
+ />
233
+ </div>
234
+
235
+ {/* Render popup in portal to document.body */}
236
+ {typeof document !== "undefined" &&
237
+ popupContent &&
238
+ createPortal(popupContent, document.body)}
239
+ </>
214
240
  );
215
241
  });
216
242
 
@@ -5,7 +5,7 @@ export const primary = {
5
5
 
6
6
  export const popUp = {
7
7
  "pop-up-style":
8
- "w-full absolute overflow-y-auto border px-2 rounded-lg mt-[1px] scrollbar bg-white z-50 scrollbar h-auto dark:bg-black dark:text-white animate-fade-down animate-once animate-duration-200",
8
+ "overflow-y-auto px-2 border border-slate-200 rounded-lg scrollbar bg-white scrollbar h-auto dark:bg-black dark:text-white animate-fade-down animate-once animate-duration-200",
9
9
  };
10
10
 
11
11
  export const iconClass = {