pixelize-design-library 2.3.2 → 2.3.4

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.
@@ -11,4 +11,5 @@ Select, SearchSelect, SelectSearch, MultiSelect, Dropdown, Search.
11
11
  ## Key rules
12
12
 
13
13
  - SearchSelect has performance tests; virtualize for large lists
14
- - Dropdown menu is portaled to `<body>` (position fixed) and clamps to the viewport — it right-aligns/flips to stay on-screen near edges
14
+ - Dropdown and SearchSelect main options menu are portaled to `<body>` (`position: fixed`) and clamp to the viewport — right-align/flip above when near edges
15
+ - `insideSelect` prefix: mutually exclusive with main dropdown; menu uses `position: fixed`, flips above/below based on viewport space, and re-anchors on scroll/resize; supports `placeholder` when no value
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom";
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var react_1 = __importDefault(require("react"));
54
+ var react_2 = require("@testing-library/react");
55
+ require("@testing-library/jest-dom");
56
+ var react_3 = require("@chakra-ui/react");
57
+ var SearchSelect_1 = __importDefault(require("./SearchSelect"));
58
+ jest.mock("../../Theme/useCustomTheme", function () { return ({
59
+ useCustomTheme: function () { return ({
60
+ colors: {
61
+ white: "#ffffff",
62
+ black: "#000000",
63
+ gray: {
64
+ 50: "#f9fafb",
65
+ 100: "#f3f4f6",
66
+ 200: "#e5e7eb",
67
+ 300: "#d1d5db",
68
+ 500: "#6b7280",
69
+ 600: "#4b5563",
70
+ 800: "#1f2937",
71
+ },
72
+ primary: {
73
+ 500: "#6366f1",
74
+ 600: "#4f46e5",
75
+ 700: "#4338ca",
76
+ opacity: { 8: "rgba(99,102,241,0.08)" },
77
+ },
78
+ placeholder: { 500: "#9ca3af" },
79
+ semantic: { error: { 500: "#ef4444" } },
80
+ boxborder: { 200: "#e5e7eb", 500: "#d1d5db" },
81
+ background: { 50: "#ffffff" },
82
+ text: { 700: "#374151" },
83
+ boxShadow: { primary: "rgba(99,102,241,0.2)", error: "rgba(239,68,68,0.2)" },
84
+ },
85
+ shadows: { md: "0 4px 6px rgba(0,0,0,0.1)" },
86
+ }); },
87
+ }); });
88
+ beforeAll(function () {
89
+ Object.defineProperty(window, "matchMedia", {
90
+ writable: true,
91
+ configurable: true,
92
+ value: jest.fn().mockImplementation(function (query) { return ({
93
+ matches: false,
94
+ media: query,
95
+ onchange: null,
96
+ addListener: jest.fn(),
97
+ removeListener: jest.fn(),
98
+ addEventListener: jest.fn(),
99
+ removeEventListener: jest.fn(),
100
+ dispatchEvent: jest.fn(),
101
+ }); }),
102
+ });
103
+ Object.defineProperty(window, "innerWidth", { writable: true, configurable: true, value: 1000 });
104
+ Object.defineProperty(window, "innerHeight", { writable: true, configurable: true, value: 800 });
105
+ });
106
+ var options = [
107
+ { id: "1", label: "User One" },
108
+ { id: "2", label: "User Two" },
109
+ ];
110
+ var renderWithChakra = function (ui) {
111
+ return (0, react_2.render)(react_1.default.createElement(react_3.ChakraProvider, null, ui));
112
+ };
113
+ var openMainDropdown = function () {
114
+ react_2.fireEvent.focus(react_2.screen.getByPlaceholderText("Select"));
115
+ };
116
+ var mockControlRect = function (rect) {
117
+ var control = react_2.screen.getByPlaceholderText("Select").parentElement;
118
+ jest.spyOn(control, "getBoundingClientRect").mockReturnValue(__assign({ top: 100, bottom: 140, left: 100, right: 400, width: 300, height: 40, x: 100, y: 100, toJSON: function () { return ({}); } }, rect));
119
+ };
120
+ var setPortalDimensions = function (height, width) {
121
+ if (width === void 0) { width = 300; }
122
+ var portal = document.getElementById("searchselect-dropdown-portal");
123
+ expect(portal).toBeTruthy();
124
+ Object.defineProperty(portal, "offsetHeight", { configurable: true, value: height });
125
+ Object.defineProperty(portal, "offsetWidth", { configurable: true, value: width });
126
+ react_2.fireEvent.scroll(window);
127
+ };
128
+ describe("SearchSelect dropdown positioning", function () {
129
+ afterEach(function () {
130
+ jest.restoreAllMocks();
131
+ });
132
+ it("anchors the options menu with position fixed below the control by default", function () { return __awaiter(void 0, void 0, void 0, function () {
133
+ var portal;
134
+ return __generator(this, function (_a) {
135
+ switch (_a.label) {
136
+ case 0:
137
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, onSelect: jest.fn() }));
138
+ mockControlRect({ top: 100, bottom: 140, left: 100, right: 400, width: 300 });
139
+ openMainDropdown();
140
+ return [4 /*yield*/, (0, react_2.waitFor)(function () {
141
+ expect(document.getElementById("searchselect-dropdown-portal")).toBeInTheDocument();
142
+ })];
143
+ case 1:
144
+ _a.sent();
145
+ portal = document.getElementById("searchselect-dropdown-portal");
146
+ expect(portal).toHaveStyle({ position: "fixed" });
147
+ setPortalDimensions(120);
148
+ expect(getComputedStyle(portal).top).toBe("140px");
149
+ return [2 /*return*/];
150
+ }
151
+ });
152
+ }); });
153
+ it("flips the menu above the control when there is more space above than below", function () { return __awaiter(void 0, void 0, void 0, function () {
154
+ var portal;
155
+ return __generator(this, function (_a) {
156
+ switch (_a.label) {
157
+ case 0:
158
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, onSelect: jest.fn() }));
159
+ mockControlRect({ top: 700, bottom: 740, left: 100, right: 400, width: 300 });
160
+ openMainDropdown();
161
+ return [4 /*yield*/, (0, react_2.waitFor)(function () {
162
+ expect(document.getElementById("searchselect-dropdown-portal")).toBeInTheDocument();
163
+ })];
164
+ case 1:
165
+ _a.sent();
166
+ portal = document.getElementById("searchselect-dropdown-portal");
167
+ setPortalDimensions(200);
168
+ expect(getComputedStyle(portal).top).toBe("500px");
169
+ return [2 /*return*/];
170
+ }
171
+ });
172
+ }); });
173
+ it("clamps the menu horizontally when the control is near the right edge", function () { return __awaiter(void 0, void 0, void 0, function () {
174
+ var portal, left;
175
+ return __generator(this, function (_a) {
176
+ switch (_a.label) {
177
+ case 0:
178
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, onSelect: jest.fn() }));
179
+ mockControlRect({ top: 100, bottom: 140, left: 960, right: 1000, width: 40 });
180
+ openMainDropdown();
181
+ return [4 /*yield*/, (0, react_2.waitFor)(function () {
182
+ expect(document.getElementById("searchselect-dropdown-portal")).toBeInTheDocument();
183
+ })];
184
+ case 1:
185
+ _a.sent();
186
+ portal = document.getElementById("searchselect-dropdown-portal");
187
+ setPortalDimensions(120, 300);
188
+ left = parseFloat(getComputedStyle(portal).left);
189
+ expect(left).toBeLessThan(960);
190
+ expect(left).toBeGreaterThanOrEqual(8);
191
+ return [2 /*return*/];
192
+ }
193
+ });
194
+ }); });
195
+ });
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom";
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var react_1 = __importDefault(require("react"));
54
+ var react_2 = require("@testing-library/react");
55
+ require("@testing-library/jest-dom");
56
+ var react_3 = require("@chakra-ui/react");
57
+ var SearchSelect_1 = __importDefault(require("./SearchSelect"));
58
+ jest.mock("../../Theme/useCustomTheme", function () { return ({
59
+ useCustomTheme: function () { return ({
60
+ colors: {
61
+ white: "#ffffff",
62
+ black: "#000000",
63
+ gray: {
64
+ 50: "#f9fafb",
65
+ 100: "#f3f4f6",
66
+ 200: "#e5e7eb",
67
+ 300: "#d1d5db",
68
+ 500: "#6b7280",
69
+ 600: "#4b5563",
70
+ 800: "#1f2937",
71
+ },
72
+ primary: {
73
+ 500: "#6366f1",
74
+ 600: "#4f46e5",
75
+ 700: "#4338ca",
76
+ opacity: { 8: "rgba(99,102,241,0.08)" },
77
+ },
78
+ placeholder: { 500: "#9ca3af" },
79
+ semantic: { error: { 500: "#ef4444" } },
80
+ boxborder: { 200: "#e5e7eb", 500: "#d1d5db" },
81
+ background: { 50: "#ffffff" },
82
+ text: { 700: "#374151" },
83
+ boxShadow: { primary: "rgba(99,102,241,0.2)", error: "rgba(239,68,68,0.2)" },
84
+ },
85
+ shadows: { md: "0 4px 6px rgba(0,0,0,0.1)" },
86
+ }); },
87
+ }); });
88
+ beforeAll(function () {
89
+ Object.defineProperty(window, "innerWidth", { writable: true, configurable: true, value: 1000 });
90
+ Object.defineProperty(window, "innerHeight", { writable: true, configurable: true, value: 800 });
91
+ Object.defineProperty(window, "matchMedia", {
92
+ writable: true,
93
+ configurable: true,
94
+ value: jest.fn().mockImplementation(function (query) { return ({
95
+ matches: false,
96
+ media: query,
97
+ onchange: null,
98
+ addListener: jest.fn(),
99
+ removeListener: jest.fn(),
100
+ addEventListener: jest.fn(),
101
+ removeEventListener: jest.fn(),
102
+ dispatchEvent: jest.fn(),
103
+ }); }),
104
+ });
105
+ });
106
+ var options = [
107
+ { id: "1", label: "User One" },
108
+ { id: "2", label: "User Two" },
109
+ ];
110
+ var renderWithChakra = function (ui) {
111
+ return (0, react_2.render)(react_1.default.createElement(react_3.ChakraProvider, null, ui));
112
+ };
113
+ var clickInsideTrigger = function () {
114
+ var _a;
115
+ var input = react_2.screen.getByPlaceholderText("Select");
116
+ var prefix = (_a = input.parentElement) === null || _a === void 0 ? void 0 : _a.firstElementChild;
117
+ expect(prefix).toBeTruthy();
118
+ react_2.fireEvent.click(prefix);
119
+ };
120
+ var mockInsideTriggerRect = function (rect) {
121
+ var _a;
122
+ var input = react_2.screen.getByPlaceholderText("Select");
123
+ var prefix = (_a = input.parentElement) === null || _a === void 0 ? void 0 : _a.firstElementChild;
124
+ jest.spyOn(prefix, "getBoundingClientRect").mockReturnValue(__assign({ top: 100, bottom: 140, left: 100, right: 180, width: 80, height: 40, x: 100, y: 100, toJSON: function () { return ({}); } }, rect));
125
+ };
126
+ var setInsidePortalDimensions = function (height, width) {
127
+ if (width === void 0) { width = 128; }
128
+ var portal = document.getElementById("custom-select-portal");
129
+ expect(portal).toBeTruthy();
130
+ Object.defineProperty(portal, "offsetHeight", { configurable: true, value: height });
131
+ Object.defineProperty(portal, "offsetWidth", { configurable: true, value: width });
132
+ react_2.fireEvent.scroll(window);
133
+ };
134
+ describe("SearchSelect insideSelect", function () {
135
+ afterEach(function () {
136
+ jest.restoreAllMocks();
137
+ });
138
+ it("opens only the insideSelect dropdown when its trigger is clicked", function () {
139
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { label: "Users", options: options, isMultiple: true, insideSelect: {
140
+ width: "80px",
141
+ option: [
142
+ { id: 1, label: "Option 1" },
143
+ { id: 2, label: "Option 2" },
144
+ ],
145
+ onSelect: jest.fn(),
146
+ } }));
147
+ clickInsideTrigger();
148
+ expect(document.getElementById("custom-select-portal")).toBeInTheDocument();
149
+ expect(document.getElementById("searchselect-dropdown-portal")).not.toBeInTheDocument();
150
+ });
151
+ it("shows insideSelect placeholder when no value is selected", function () {
152
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, isMultiple: true, insideSelect: {
153
+ width: "80px",
154
+ placeholder: "Filter type",
155
+ option: [{ id: 1, label: "Option 1" }],
156
+ onSelect: jest.fn(),
157
+ } }));
158
+ expect(react_2.screen.getByText("Filter type")).toBeInTheDocument();
159
+ });
160
+ it("anchors insideSelect portal with position fixed", function () {
161
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, isMultiple: true, insideSelect: {
162
+ width: "80px",
163
+ option: [{ id: 1, label: "Option 1" }],
164
+ onSelect: jest.fn(),
165
+ } }));
166
+ clickInsideTrigger();
167
+ var portal = document.getElementById("custom-select-portal");
168
+ expect(portal).toHaveStyle({ position: "fixed" });
169
+ });
170
+ it("opens insideSelect below the trigger by default", function () { return __awaiter(void 0, void 0, void 0, function () {
171
+ var portal;
172
+ return __generator(this, function (_a) {
173
+ switch (_a.label) {
174
+ case 0:
175
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, isMultiple: true, insideSelect: {
176
+ width: "80px",
177
+ option: [{ id: 1, label: "Option 1" }],
178
+ onSelect: jest.fn(),
179
+ } }));
180
+ mockInsideTriggerRect({ top: 100, bottom: 140, left: 100, right: 180, width: 80 });
181
+ clickInsideTrigger();
182
+ return [4 /*yield*/, (0, react_2.waitFor)(function () {
183
+ expect(document.getElementById("custom-select-portal")).toBeInTheDocument();
184
+ })];
185
+ case 1:
186
+ _a.sent();
187
+ portal = document.getElementById("custom-select-portal");
188
+ setInsidePortalDimensions(80);
189
+ expect(getComputedStyle(portal).top).toBe("140px");
190
+ return [2 /*return*/];
191
+ }
192
+ });
193
+ }); });
194
+ it("flips insideSelect above the trigger when near the bottom of the viewport", function () { return __awaiter(void 0, void 0, void 0, function () {
195
+ var portal;
196
+ return __generator(this, function (_a) {
197
+ switch (_a.label) {
198
+ case 0:
199
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, isMultiple: true, insideSelect: {
200
+ width: "80px",
201
+ option: [
202
+ { id: 1, label: "Option 1" },
203
+ { id: 2, label: "Option 2" },
204
+ ],
205
+ onSelect: jest.fn(),
206
+ } }));
207
+ mockInsideTriggerRect({ top: 700, bottom: 740, left: 100, right: 180, width: 80 });
208
+ clickInsideTrigger();
209
+ return [4 /*yield*/, (0, react_2.waitFor)(function () {
210
+ expect(document.getElementById("custom-select-portal")).toBeInTheDocument();
211
+ })];
212
+ case 1:
213
+ _a.sent();
214
+ portal = document.getElementById("custom-select-portal");
215
+ setInsidePortalDimensions(120);
216
+ expect(getComputedStyle(portal).top).toBe("580px");
217
+ return [2 /*return*/];
218
+ }
219
+ });
220
+ }); });
221
+ it("repositions insideSelect portal on scroll while open", function () { return __awaiter(void 0, void 0, void 0, function () {
222
+ var input, prefix, rectSpy;
223
+ var _a;
224
+ return __generator(this, function (_b) {
225
+ switch (_b.label) {
226
+ case 0:
227
+ renderWithChakra(react_1.default.createElement(SearchSelect_1.default, { options: options, isMultiple: true, insideSelect: {
228
+ width: "80px",
229
+ option: [{ id: 1, label: "Option 1" }],
230
+ onSelect: jest.fn(),
231
+ } }));
232
+ input = react_2.screen.getByPlaceholderText("Select");
233
+ prefix = (_a = input.parentElement) === null || _a === void 0 ? void 0 : _a.firstElementChild;
234
+ rectSpy = jest.spyOn(prefix, "getBoundingClientRect").mockReturnValue({
235
+ top: 20,
236
+ bottom: 60,
237
+ left: 10,
238
+ right: 90,
239
+ width: 80,
240
+ height: 40,
241
+ x: 10,
242
+ y: 20,
243
+ toJSON: function () { return ({}); },
244
+ });
245
+ clickInsideTrigger();
246
+ return [4 /*yield*/, (0, react_2.waitFor)(function () {
247
+ var portal = document.getElementById("custom-select-portal");
248
+ expect(getComputedStyle(portal).top).toBe("60px");
249
+ })];
250
+ case 1:
251
+ _b.sent();
252
+ rectSpy.mockReturnValue({
253
+ top: 120,
254
+ bottom: 160,
255
+ left: 40,
256
+ right: 120,
257
+ width: 80,
258
+ height: 40,
259
+ x: 40,
260
+ y: 120,
261
+ toJSON: function () { return ({}); },
262
+ });
263
+ react_2.fireEvent.scroll(window);
264
+ return [4 /*yield*/, (0, react_2.waitFor)(function () {
265
+ var portal = document.getElementById("custom-select-portal");
266
+ expect(getComputedStyle(portal).top).toBe("160px");
267
+ })];
268
+ case 2:
269
+ _b.sent();
270
+ return [2 /*return*/];
271
+ }
272
+ });
273
+ }); });
274
+ });
@@ -81,26 +81,28 @@ var normalizeMultiValue = function (val) {
81
81
  return [];
82
82
  };
83
83
  var SearchSelect = function (_a) {
84
- var _b, _c, _d, _e, _f, _g, _h, _j;
85
- var id = _a.id, label = _a.label, options = _a.options, onSelect = _a.onSelect, onSearch = _a.onSearch, _k = _a.isOptionLoading, isOptionLoading = _k === void 0 ? false : _k, _l = _a.isLoading, isLoading = _l === void 0 ? false : _l, _m = _a.loadingText, loadingText = _m === void 0 ? "Loading..." : _m, _o = _a.placeholder, placeholder = _o === void 0 ? "Select" : _o, value = _a.value, _p = _a.searchQuery, searchQuery = _p === void 0 ? "" : _p, _q = _a.isMultiple, isMultiple = _q === void 0 ? false : _q, _r = _a.isRequired, isRequired = _r === void 0 ? false : _r, _s = _a.error, error = _s === void 0 ? false : _s, errorMessage = _a.errorMessage, helperText = _a.helperText, _t = _a.width, width = _t === void 0 ? "100%" : _t, height = _a.height, _u = _a.size, size = _u === void 0 ? "md" : _u, chip = _a.chip, information = _a.information, isInformation = _a.isInformation, informationMessage = _a.informationMessage, rightIcon = _a.rightIcon, addNew = _a.addNew, _v = _a.isSelectAll, isSelectAll = _v === void 0 ? false : _v, pagination = _a.pagination, insideSelect = _a.insideSelect, isRemoveAllIcon = _a.isRemoveAllIcon;
84
+ var _b, _c, _d, _e, _f;
85
+ var id = _a.id, label = _a.label, options = _a.options, onSelect = _a.onSelect, onSearch = _a.onSearch, _g = _a.isOptionLoading, isOptionLoading = _g === void 0 ? false : _g, _h = _a.isLoading, isLoading = _h === void 0 ? false : _h, _j = _a.loadingText, loadingText = _j === void 0 ? "Loading..." : _j, _k = _a.placeholder, placeholder = _k === void 0 ? "Select" : _k, value = _a.value, _l = _a.searchQuery, searchQuery = _l === void 0 ? "" : _l, _m = _a.isMultiple, isMultiple = _m === void 0 ? false : _m, _o = _a.isRequired, isRequired = _o === void 0 ? false : _o, _p = _a.error, error = _p === void 0 ? false : _p, errorMessage = _a.errorMessage, helperText = _a.helperText, _q = _a.width, width = _q === void 0 ? "100%" : _q, height = _a.height, _r = _a.size, size = _r === void 0 ? "md" : _r, chip = _a.chip, information = _a.information, isInformation = _a.isInformation, informationMessage = _a.informationMessage, rightIcon = _a.rightIcon, addNew = _a.addNew, _s = _a.isSelectAll, isSelectAll = _s === void 0 ? false : _s, pagination = _a.pagination, insideSelect = _a.insideSelect, isRemoveAllIcon = _a.isRemoveAllIcon;
86
86
  var s = (0, searchSelectSize_1.getSearchSelectSizeStyles)((size || "md"));
87
87
  var insideSelectBoxHeight = height !== null && height !== void 0 ? height : s.insideSelectDefaultHeight;
88
- var _w = (0, react_1.useState)(searchQuery), inputValue = _w[0], setInputValue = _w[1];
89
- var _x = (0, react_1.useState)(false), isOpen = _x[0], setIsOpen = _x[1];
90
- var _y = (0, react_1.useState)(true), hasMore = _y[0], setHasMore = _y[1];
88
+ var _t = (0, react_1.useState)(searchQuery), inputValue = _t[0], setInputValue = _t[1];
89
+ var _u = (0, react_1.useState)(false), isOpen = _u[0], setIsOpen = _u[1];
90
+ var _v = (0, react_1.useState)(true), hasMore = _v[0], setHasMore = _v[1];
91
91
  var inputRef = (0, react_1.useRef)(null);
92
92
  var containerRef = (0, react_1.useRef)(null);
93
93
  var controlRef = (0, react_1.useRef)(null);
94
- var _z = (0, react_1.useState)({ top: 0, left: 0, width: 0 }), dropdownPos = _z[0], setDropdownPos = _z[1];
94
+ var dropdownMenuRef = (0, react_1.useRef)(null);
95
+ var _w = (0, react_1.useState)({ top: 0, left: 0, width: 0 }), dropdownPos = _w[0], setDropdownPos = _w[1];
95
96
  var scrollTimeoutRef = (0, react_1.useRef)(null);
96
- var _0 = (0, react_1.useState)(false), focused = _0[0], setFocused = _0[1];
97
- var _1 = (0, react_1.useState)(false), customSelectOpen = _1[0], setCustomSelectOpen = _1[1];
97
+ var _x = (0, react_1.useState)(false), focused = _x[0], setFocused = _x[1];
98
+ var _y = (0, react_1.useState)(false), customSelectOpen = _y[0], setCustomSelectOpen = _y[1];
98
99
  var customSelectRef = (0, react_1.useRef)(null);
99
- var _2 = (0, react_1.useState)({
100
+ var insideSelectMenuRef = (0, react_1.useRef)(null);
101
+ var _z = (0, react_1.useState)({
100
102
  top: 0,
101
103
  left: 0,
102
104
  width: 0,
103
- }), customSelectPos = _2[0], setCustomSelectPos = _2[1];
105
+ }), customSelectPos = _z[0], setCustomSelectPos = _z[1];
104
106
  var theme = (0, useCustomTheme_1.useCustomTheme)();
105
107
  (0, react_2.useOutsideClick)({
106
108
  ref: containerRef,
@@ -220,28 +222,81 @@ var SearchSelect = function (_a) {
220
222
  }
221
223
  setCustomSelectOpen(false);
222
224
  };
223
- (0, react_1.useEffect)(function () {
224
- if (customSelectOpen && customSelectRef.current) {
225
- var rect = customSelectRef.current.getBoundingClientRect();
226
- setCustomSelectPos({
227
- top: rect.bottom + window.scrollY,
228
- left: rect.left + window.scrollX,
229
- width: rect.width + 30,
230
- });
225
+ // Anchor the insideSelect menu to its trigger (viewport-fixed). Prefer below;
226
+ // flip above when near the bottom; clamp horizontally within the viewport.
227
+ var updateInsideSelectPos = (0, react_1.useCallback)(function () {
228
+ var _a, _b;
229
+ if (!customSelectRef.current)
230
+ return;
231
+ var rect = customSelectRef.current.getBoundingClientRect();
232
+ var gutter = 8;
233
+ var vw = window.innerWidth;
234
+ var vh = window.innerHeight;
235
+ var menuW = ((_a = insideSelectMenuRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || Math.max(rect.width, 128);
236
+ var menuH = ((_b = insideSelectMenuRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 160;
237
+ var left = rect.left;
238
+ if (left + menuW > vw - gutter)
239
+ left = rect.right - menuW;
240
+ left = Math.min(Math.max(left, gutter), Math.max(gutter, vw - menuW - gutter));
241
+ var top = rect.bottom;
242
+ var spaceBelow = vh - rect.bottom;
243
+ var spaceAbove = rect.top;
244
+ if (menuH && top + menuH > vh - gutter && spaceAbove > spaceBelow) {
245
+ top = rect.top - menuH;
231
246
  }
232
- }, [customSelectOpen]);
233
- // Keep the portaled options dropdown anchored to the control (on open + while
234
- // open if the page/modal scrolls or resizes).
247
+ top = Math.min(Math.max(top, gutter), Math.max(gutter, vh - menuH - gutter));
248
+ setCustomSelectPos({
249
+ top: top,
250
+ left: left,
251
+ width: menuW,
252
+ });
253
+ }, []);
254
+ var setInsideSelectMenuRef = (0, react_1.useCallback)(function (node) {
255
+ insideSelectMenuRef.current = node;
256
+ if (node)
257
+ updateInsideSelectPos();
258
+ }, [updateInsideSelectPos]);
259
+ (0, react_1.useEffect)(function () {
260
+ if (!customSelectOpen)
261
+ return;
262
+ updateInsideSelectPos();
263
+ window.addEventListener("scroll", updateInsideSelectPos, true);
264
+ window.addEventListener("resize", updateInsideSelectPos);
265
+ return function () {
266
+ window.removeEventListener("scroll", updateInsideSelectPos, true);
267
+ window.removeEventListener("resize", updateInsideSelectPos);
268
+ };
269
+ }, [customSelectOpen, updateInsideSelectPos]);
270
+ // Anchor the main options menu to the control (viewport-fixed). Prefer below;
271
+ // flip above when near the bottom; clamp horizontally within the viewport.
235
272
  var updateDropdownPos = (0, react_1.useCallback)(function () {
273
+ var _a, _b;
236
274
  if (!controlRef.current)
237
275
  return;
238
276
  var rect = controlRef.current.getBoundingClientRect();
239
- setDropdownPos({
240
- top: rect.bottom + window.scrollY,
241
- left: rect.left + window.scrollX,
242
- width: rect.width,
243
- });
277
+ var gutter = 8;
278
+ var vw = window.innerWidth;
279
+ var vh = window.innerHeight;
280
+ var menuW = ((_a = dropdownMenuRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || rect.width;
281
+ var menuH = ((_b = dropdownMenuRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 320;
282
+ var left = rect.left;
283
+ if (left + menuW > vw - gutter)
284
+ left = rect.right - menuW;
285
+ left = Math.min(Math.max(left, gutter), Math.max(gutter, vw - menuW - gutter));
286
+ var top = rect.bottom;
287
+ var spaceBelow = vh - rect.bottom;
288
+ var spaceAbove = rect.top;
289
+ if (menuH && top + menuH > vh - gutter && spaceAbove > spaceBelow) {
290
+ top = rect.top - menuH;
291
+ }
292
+ top = Math.min(Math.max(top, gutter), Math.max(gutter, vh - menuH - gutter));
293
+ setDropdownPos({ top: top, left: left, width: rect.width });
244
294
  }, []);
295
+ var setDropdownMenuRef = (0, react_1.useCallback)(function (node) {
296
+ dropdownMenuRef.current = node;
297
+ if (node)
298
+ updateDropdownPos();
299
+ }, [updateDropdownPos]);
245
300
  (0, react_1.useEffect)(function () {
246
301
  if (!isOpen)
247
302
  return;
@@ -267,16 +322,47 @@ var SearchSelect = function (_a) {
267
322
  : "0 0 0 0.125rem ".concat((_e = theme.colors.boxShadow) === null || _e === void 0 ? void 0 : _e.primary)
268
323
  : error
269
324
  ? "0 0 0 0.125rem ".concat((_f = theme.colors.boxShadow) === null || _f === void 0 ? void 0 : _f.error)
270
- : "none", transition: "box-shadow 0.2s, border-color 0.2s", onClick: function () { return setIsOpen(true); } },
271
- insideSelect && (react_1.default.createElement(react_2.Box, { position: "relative", ref: customSelectRef, backgroundColor: theme.colors.gray[200], ml: s.insideSelectMarginLeft, h: "-webkit-fill-available", borderRadius: "0.25rem 0 0 0.25rem", onClick: function () { return setCustomSelectOpen(function (prev) { return !prev; }); } },
272
- react_1.default.createElement(react_2.Box, { minW: "5rem", cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "center", width: insideSelect.width, height: insideSelectBoxHeight, pl: "0.5rem", pr: "0.5rem" },
273
- react_1.default.createElement(SelectTruncatedLabel_1.default, { label: (_h = (_g = insideSelect === null || insideSelect === void 0 ? void 0 : insideSelect.value) === null || _g === void 0 ? void 0 : _g.label) !== null && _h !== void 0 ? _h : "", maxWidth: (insideSelect === null || insideSelect === void 0 ? void 0 : insideSelect.width) || "6rem", fontSize: s.fieldFontSize }),
274
- customSelectOpen ? (react_1.default.createElement(lucide_react_1.ChevronUp, { size: s.chevronSize })) : (react_1.default.createElement(lucide_react_1.ChevronDown, { size: s.chevronSize }))),
275
- customSelectOpen && (react_1.default.createElement(react_2.Portal, null,
276
- react_1.default.createElement(react_2.Box, { id: "custom-select-portal", position: "absolute", top: "".concat(customSelectPos.top, "px"), left: "".concat(customSelectPos.left, "px"), zIndex: 1400, bg: theme.colors.white, border: "0.063rem solid", borderColor: theme.colors.gray[300], borderRadius: "md", boxShadow: "md", minW: "10rem", maxW: "38rem" }, (_j = insideSelect === null || insideSelect === void 0 ? void 0 : insideSelect.option) === null || _j === void 0 ? void 0 : _j.map(function (item) { return (react_1.default.createElement(react_2.Box, { key: item.id, display: "flex", alignItems: "center", minH: s.optionRowMinH, px: "0.75rem", fontSize: s.dropdownTextFontSize, _hover: { bg: theme.colors.gray[100] }, cursor: "pointer", onClick: function (e) {
277
- e.stopPropagation();
278
- handleCustomSelect(item);
279
- } }, item.label)); })))))),
325
+ : "none", transition: "box-shadow 0.2s, border-color 0.2s", onClick: function () {
326
+ setCustomSelectOpen(false);
327
+ setIsOpen(true);
328
+ } },
329
+ insideSelect && (function () {
330
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
331
+ var insideLabel = (_a = insideSelect.value) === null || _a === void 0 ? void 0 : _a.label;
332
+ var insidePlaceholder = (_b = insideSelect.placeholder) !== null && _b !== void 0 ? _b : "Select";
333
+ return (react_1.default.createElement(react_2.Box, { position: "relative", ref: customSelectRef, flexShrink: 0, ml: s.insideSelectMarginLeft, h: "-webkit-fill-available", borderRight: "0.063rem solid", borderColor: (_d = (_c = theme.colors.boxborder) === null || _c === void 0 ? void 0 : _c[300]) !== null && _d !== void 0 ? _d : theme.colors.gray[200], bg: customSelectOpen
334
+ ? (_g = (_f = (_e = theme.colors.primary) === null || _e === void 0 ? void 0 : _e.opacity) === null || _f === void 0 ? void 0 : _f[8]) !== null && _g !== void 0 ? _g : theme.colors.gray[100]
335
+ : (_j = (_h = theme.colors.background) === null || _h === void 0 ? void 0 : _h[400]) !== null && _j !== void 0 ? _j : theme.colors.white, borderRadius: "0.375rem 0 0 0.375rem", transition: "background 0.15s ease, box-shadow 0.15s ease", boxShadow: customSelectOpen
336
+ ? "inset 0 0 0 0.063rem ".concat((_k = theme.colors.primary) === null || _k === void 0 ? void 0 : _k[500])
337
+ : "none", onClick: function (e) {
338
+ e.stopPropagation();
339
+ setIsOpen(false);
340
+ setCustomSelectOpen(function (prev) { return !prev; });
341
+ } },
342
+ react_1.default.createElement(react_2.Box, { minW: "4.5rem", cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "center", gap: 1, width: insideSelect.width, height: insideSelectBoxHeight, pl: "0.5rem", pr: "0.375rem" },
343
+ insideLabel ? (react_1.default.createElement(SelectTruncatedLabel_1.default, { label: insideLabel, maxWidth: insideSelect.width || "6rem", fontSize: s.fieldFontSize })) : (react_1.default.createElement(react_2.Text, { fontSize: s.fieldFontSize, fontWeight: 500, color: (_m = (_l = theme.colors.placeholder) === null || _l === void 0 ? void 0 : _l[500]) !== null && _m !== void 0 ? _m : theme.colors.gray[500], isTruncated: true, maxW: insideSelect.width || "6rem" }, insidePlaceholder)),
344
+ react_1.default.createElement(react_2.Box, { as: "span", display: "inline-flex", flexShrink: 0, color: customSelectOpen ? (_o = theme.colors.primary) === null || _o === void 0 ? void 0 : _o[600] : theme.colors.gray[600], transition: "transform 0.2s ease, color 0.15s ease", transform: customSelectOpen ? "rotate(180deg)" : "rotate(0deg)" },
345
+ react_1.default.createElement(lucide_react_1.ChevronDown, { size: s.chevronSize }))),
346
+ customSelectOpen && (react_1.default.createElement(react_2.Portal, null,
347
+ react_1.default.createElement(react_2.Box, { ref: setInsideSelectMenuRef, id: "custom-select-portal", position: "fixed", top: "".concat(customSelectPos.top, "px"), left: "".concat(customSelectPos.left, "px"), zIndex: 1510, bg: theme.colors.white, border: "0.063rem solid", borderColor: (_q = (_p = theme.colors.boxborder) === null || _p === void 0 ? void 0 : _p[200]) !== null && _q !== void 0 ? _q : theme.colors.gray[200], borderRadius: "0.5rem", boxShadow: (_s = (_r = theme.shadows) === null || _r === void 0 ? void 0 : _r.md) !== null && _s !== void 0 ? _s : "md", minW: "".concat(customSelectPos.width, "px"), maxW: "20rem", py: 1, overflow: "hidden" }, (_t = insideSelect.option) === null || _t === void 0 ? void 0 : _t.map(function (item) {
348
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
349
+ var selected = ((_a = insideSelect.value) === null || _a === void 0 ? void 0 : _a.id) === item.id;
350
+ return (react_1.default.createElement(react_2.Box, { key: item.id, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, minH: s.optionRowMinH, py: s.optionRowPy, px: "0.75rem", fontSize: s.dropdownTextFontSize, fontWeight: selected ? 600 : 500, color: selected
351
+ ? (_c = (_b = theme.colors.primary) === null || _b === void 0 ? void 0 : _b[700]) !== null && _c !== void 0 ? _c : (_d = theme.colors.primary) === null || _d === void 0 ? void 0 : _d[600]
352
+ : (_f = (_e = theme.colors.text) === null || _e === void 0 ? void 0 : _e[700]) !== null && _f !== void 0 ? _f : theme.colors.gray[800], bg: selected
353
+ ? (_j = (_h = (_g = theme.colors.primary) === null || _g === void 0 ? void 0 : _g.opacity) === null || _h === void 0 ? void 0 : _h[8]) !== null && _j !== void 0 ? _j : theme.colors.gray[100]
354
+ : "transparent", _hover: {
355
+ bg: selected
356
+ ? (_m = (_l = (_k = theme.colors.primary) === null || _k === void 0 ? void 0 : _k.opacity) === null || _l === void 0 ? void 0 : _l[8]) !== null && _m !== void 0 ? _m : theme.colors.gray[100]
357
+ : (_o = theme.colors.gray) === null || _o === void 0 ? void 0 : _o[50],
358
+ }, cursor: "pointer", onClick: function (e) {
359
+ e.stopPropagation();
360
+ handleCustomSelect(item);
361
+ } },
362
+ react_1.default.createElement(react_2.Text, { isTruncated: true }, item.label),
363
+ selected && (react_1.default.createElement(lucide_react_1.Check, { size: s.chevronSize - 2, color: (_p = theme.colors.primary) === null || _p === void 0 ? void 0 : _p[600] }))));
364
+ }))))));
365
+ })(),
280
366
  isMultiple
281
367
  ? selectedValues
282
368
  .slice(0, (chip === null || chip === void 0 ? void 0 : chip.maxChips) || selectedValues.length)
@@ -284,13 +370,17 @@ var SearchSelect = function (_a) {
284
370
  ? item.label.slice(0, chip.maxText) + "…"
285
371
  : item.label, onIconClick: (chip === null || chip === void 0 ? void 0 : chip.onClick) ? function () { return handleRemove(item === null || item === void 0 ? void 0 : item.id); } : undefined, icon: (chip === null || chip === void 0 ? void 0 : chip.onClick) ? lucide_react_1.CircleX : undefined, colorScheme: "gray", size: s.tagSize })); })
286
372
  : selectedValues.length === 1 &&
287
- !isOpen && (react_1.default.createElement(react_2.Box, { as: "button", type: "button", onClick: function () { return setIsOpen(true); }, fontSize: s.fieldFontSize, color: theme.colors.gray[800], background: "transparent", border: "none", cursor: "pointer", p: 0, display: "flex", alignItems: "center", flex: "1", minW: 0 },
373
+ !isOpen && (react_1.default.createElement(react_2.Box, { as: "button", type: "button", onClick: function () {
374
+ setCustomSelectOpen(false);
375
+ setIsOpen(true);
376
+ }, fontSize: s.fieldFontSize, color: theme.colors.gray[800], background: "transparent", border: "none", cursor: "pointer", p: 0, display: "flex", alignItems: "center", flex: "1", minW: 0 },
288
377
  react_1.default.createElement(SelectTruncatedLabel_1.default, { label: String(selectedValues[0].label), maxWidth: "calc(100% - 2rem)", fontSize: s.fieldFontSize }))),
289
378
  (chip === null || chip === void 0 ? void 0 : chip.maxChips) && isMultiple && selectedValues.length > chip.maxChips && (react_1.default.createElement(Tag_1.default, { key: "extra-count", label: "+ ".concat(selectedValues.length - chip.maxChips), colorScheme: "gray", size: s.tagSize })),
290
379
  (isOpen || inputValue || !selectedValues.length) && (react_1.default.createElement(react_2.Input, { ref: inputRef, variant: "unstyled", size: size, h: s.fieldHeight, minH: s.fieldHeight, fontSize: s.fieldFontSize, flex: "1",
291
380
  // minW="5rem"
292
381
  minW: "0", value: inputValue, onChange: function (e) { return setInputValue(e.target.value); }, onFocus: function () {
293
382
  setFocused(true);
383
+ setCustomSelectOpen(false);
294
384
  setIsOpen(true);
295
385
  }, onBlur: function () { return setFocused(false); }, placeholder: selectedValues.length && !isOpen ? "" : placeholder })),
296
386
  react_1.default.createElement(react_2.Box, { position: "absolute", right: s.rightOffset, top: "50%", transform: "translateY(-50%)", display: "flex", alignItems: "center", gap: 1 },
@@ -304,10 +394,14 @@ var SearchSelect = function (_a) {
304
394
  isLoading ? (react_1.default.createElement(react_2.Spinner, { size: s.spinnerSize })) : isValidIcon(rightIcon === null || rightIcon === void 0 ? void 0 : rightIcon.icon) ? (react_1.default.createElement(react_2.IconButton, { icon: rightIcon === null || rightIcon === void 0 ? void 0 : rightIcon.icon, "aria-label": "right-icon", variant: "ghost", size: s.iconButtonSize, onClick: rightIcon === null || rightIcon === void 0 ? void 0 : rightIcon.onClick })) : (react_1.default.createElement(react_2.Box, { as: "button", onClick: function (e) {
305
395
  e.preventDefault();
306
396
  e.stopPropagation();
307
- setIsOpen(function (prev) { return !prev; });
397
+ setIsOpen(function (prev) {
398
+ if (!prev)
399
+ setCustomSelectOpen(false);
400
+ return !prev;
401
+ });
308
402
  }, "aria-label": "toggle-dropdown", display: "flex", alignItems: "center" }, isOpen ? (react_1.default.createElement(lucide_react_1.ChevronUp, { size: s.chevronSize })) : (react_1.default.createElement(lucide_react_1.ChevronDown, { size: s.chevronSize }))))))),
309
403
  isOpen && (react_1.default.createElement(react_2.Portal, null,
310
- react_1.default.createElement(react_2.Box, { id: "searchselect-dropdown-portal", position: "absolute", top: "".concat(dropdownPos.top, "px"), left: "".concat(dropdownPos.left, "px"), width: "".concat(dropdownPos.width, "px"), zIndex: 1500, maxH: "20rem", borderWidth: 1, borderColor: theme.colors.gray[200], borderRadius: "sm", bg: theme.colors.white, boxShadow: "md", display: "flex", flexDirection: "column" },
404
+ react_1.default.createElement(react_2.Box, { ref: setDropdownMenuRef, id: "searchselect-dropdown-portal", position: "fixed", top: "".concat(dropdownPos.top, "px"), left: "".concat(dropdownPos.left, "px"), width: "".concat(dropdownPos.width, "px"), zIndex: 1500, maxH: "20rem", borderWidth: 1, borderColor: theme.colors.gray[200], borderRadius: "sm", bg: theme.colors.white, boxShadow: "md", display: "flex", flexDirection: "column" },
311
405
  isMultiple && isSelectAll && (react_1.default.createElement(react_2.Box, { py: s.optionRowPy, px: 3, cursor: "pointer", onClick: handleSelectAll, display: "flex", alignItems: "center", gap: 2, borderBottom: "0.063rem solid ".concat(theme.colors.gray[100]) },
312
406
  react_1.default.createElement(Checkbox_1.default, { isChecked: allFilteredSelected, sx: { pointerEvents: "none" }, size: s.checkboxSize }),
313
407
  react_1.default.createElement(react_2.Text, { fontSize: s.dropdownTextFontSize }, allFilteredSelected ? "Unselect All" : "Select All"))),
@@ -52,6 +52,8 @@ export type SearchSelectProps = {
52
52
  value?: Options;
53
53
  option?: Options[];
54
54
  width?: string;
55
+ /** Shown when no value is selected. Defaults to "Select". */
56
+ placeholder?: string;
55
57
  };
56
58
  };
57
59
  export type Options = {
@@ -94,6 +94,7 @@ var TableActions = react_1.default.memo(function (_a) {
94
94
  } },
95
95
  react_1.default.createElement(lucide_react_1.Pencil, { size: 17 }),
96
96
  " Edit")),
97
+ row.actions && ((_d = row === null || row === void 0 ? void 0 : row.actions) === null || _d === void 0 ? void 0 : _d.call(row)),
97
98
  row.onDelete && (react_1.default.createElement(react_2.Button, { size: "sm", variant: "ghost", justifyContent: "flex-start", colorScheme: "red", gap: 2, borderRadius: 0, onClick: function () {
98
99
  var _a;
99
100
  (_a = row.onDelete) === null || _a === void 0 ? void 0 : _a.call(row, row);
@@ -101,8 +102,7 @@ var TableActions = react_1.default.memo(function (_a) {
101
102
  } },
102
103
  react_1.default.createElement(lucide_react_1.Trash2, { size: 17 }),
103
104
  " Delete")),
104
- row.actions && ((_d = row === null || row === void 0 ? void 0 : row.actions) === null || _d === void 0 ? void 0 : _d.call(row)),
105
- !row.onLink && !row.onEdit && !row.onDelete && (react_1.default.createElement(react_2.Button, { size: "sm", variant: "ghost", isDisabled: true, justifyContent: "center" }, "No actions"))))))))));
105
+ !row.onLink && !row.onEdit && !row.onDelete && !row.actions && (react_1.default.createElement(react_2.Button, { size: "sm", variant: "ghost", isDisabled: true, justifyContent: "center" }, "No actions"))))))))));
106
106
  });
107
107
  TableActions.displayName = "TableActions";
108
108
  exports.default = TableActions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixelize-design-library",
3
- "version": "2.3.2",
3
+ "version": "2.3.4",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",