infinity-ui-elements 1.9.25 → 1.9.26
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/dist/components/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/index.esm.js +35 -45
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +35 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3184,12 +3184,14 @@ const Dropdown = React__namespace.forwardRef(({ className, trigger, items = [],
|
|
|
3184
3184
|
const isOpen = controlledOpen !== undefined ? controlledOpen : uncontrolledOpen;
|
|
3185
3185
|
const dropdownRef = React__namespace.useRef(null);
|
|
3186
3186
|
const menuRef = React__namespace.useRef(null);
|
|
3187
|
+
const VIEWPORT_PADDING = 8;
|
|
3188
|
+
const MENU_MAX_HEIGHT = 400;
|
|
3187
3189
|
const [menuPosition, setMenuPosition] = React__namespace.useState({
|
|
3188
3190
|
top: "100%",
|
|
3189
3191
|
bottom: "auto",
|
|
3190
3192
|
left: "0",
|
|
3191
3193
|
right: "auto",
|
|
3192
|
-
maxHeight:
|
|
3194
|
+
maxHeight: `${MENU_MAX_HEIGHT}px`,
|
|
3193
3195
|
});
|
|
3194
3196
|
// Detect if we're on mobile (< 768px)
|
|
3195
3197
|
const [isMobile, setIsMobile] = React__namespace.useState(false);
|
|
@@ -3248,68 +3250,56 @@ const Dropdown = React__namespace.forwardRef(({ className, trigger, items = [],
|
|
|
3248
3250
|
const calculatePosition = () => {
|
|
3249
3251
|
const triggerRect = dropdownRef.current.getBoundingClientRect();
|
|
3250
3252
|
const menuElement = menuRef.current;
|
|
3251
|
-
|
|
3253
|
+
const currentContainerRect = dropdownRef.current.getBoundingClientRect();
|
|
3252
3254
|
const menuRect = menuElement.getBoundingClientRect();
|
|
3253
|
-
const menuHeight = menuRect.height ||
|
|
3254
|
-
const menuWidth = menuRect.width;
|
|
3255
|
+
const menuHeight = menuRect.height || MENU_MAX_HEIGHT;
|
|
3256
|
+
const menuWidth = menuRect.width || 320; // fallback for initial render (w-80 = 320px)
|
|
3255
3257
|
const viewportHeight = window.innerHeight;
|
|
3256
3258
|
const viewportWidth = window.innerWidth;
|
|
3257
|
-
const spaceBelow = viewportHeight - triggerRect.bottom;
|
|
3258
|
-
const spaceAbove = triggerRect.top;
|
|
3259
|
-
const spaceRight = viewportWidth - triggerRect.left;
|
|
3260
|
-
const spaceLeft = triggerRect.right;
|
|
3259
|
+
const spaceBelow = viewportHeight - triggerRect.bottom - VIEWPORT_PADDING;
|
|
3260
|
+
const spaceAbove = triggerRect.top - VIEWPORT_PADDING;
|
|
3261
3261
|
const position = {
|
|
3262
|
-
|
|
3263
|
-
bottom: "auto",
|
|
3264
|
-
left: "auto",
|
|
3265
|
-
right: "auto",
|
|
3266
|
-
maxHeight: "400px",
|
|
3262
|
+
maxHeight: `${MENU_MAX_HEIGHT}px`,
|
|
3267
3263
|
};
|
|
3268
|
-
// Vertical positioning
|
|
3264
|
+
// Vertical positioning: prefer below, flip above if not enough space
|
|
3269
3265
|
if (spaceBelow >= menuHeight || spaceBelow >= spaceAbove) {
|
|
3270
|
-
// Position below trigger
|
|
3271
3266
|
position.top = "100%";
|
|
3272
3267
|
position.bottom = "auto";
|
|
3273
|
-
position.maxHeight = `${Math.min(
|
|
3268
|
+
position.maxHeight = `${Math.min(MENU_MAX_HEIGHT, Math.max(0, spaceBelow))}px`;
|
|
3274
3269
|
}
|
|
3275
3270
|
else {
|
|
3276
|
-
// Position above trigger
|
|
3277
3271
|
position.top = "auto";
|
|
3278
3272
|
position.bottom = "100%";
|
|
3279
|
-
position.maxHeight = `${Math.min(
|
|
3280
|
-
}
|
|
3281
|
-
// Horizontal positioning
|
|
3282
|
-
if (spaceRight >= menuWidth) {
|
|
3283
|
-
// Align to left edge of trigger
|
|
3284
|
-
position.left = "0";
|
|
3285
|
-
position.right = "auto";
|
|
3286
|
-
}
|
|
3287
|
-
else if (spaceLeft >= menuWidth) {
|
|
3288
|
-
// Align to right edge of trigger
|
|
3289
|
-
position.left = "auto";
|
|
3290
|
-
position.right = "0";
|
|
3291
|
-
}
|
|
3292
|
-
else {
|
|
3293
|
-
// Not enough space on either side, try to center or align based on available space
|
|
3294
|
-
if (triggerRect.left + menuWidth > viewportWidth) {
|
|
3295
|
-
position.left = "auto";
|
|
3296
|
-
position.right = "0";
|
|
3297
|
-
}
|
|
3298
|
-
else {
|
|
3299
|
-
position.left = "0";
|
|
3300
|
-
position.right = "auto";
|
|
3301
|
-
}
|
|
3273
|
+
position.maxHeight = `${Math.min(MENU_MAX_HEIGHT, Math.max(0, spaceAbove))}px`;
|
|
3302
3274
|
}
|
|
3275
|
+
// Horizontal: clamp menu left so it stays within viewport
|
|
3276
|
+
const minMenuLeft = VIEWPORT_PADDING;
|
|
3277
|
+
const maxMenuLeft = viewportWidth - menuWidth - VIEWPORT_PADDING;
|
|
3278
|
+
const desiredMenuLeft = Math.max(minMenuLeft, Math.min(maxMenuLeft, triggerRect.left));
|
|
3279
|
+
position.left = `${desiredMenuLeft - currentContainerRect.left}px`;
|
|
3280
|
+
position.right = "auto";
|
|
3303
3281
|
setMenuPosition(position);
|
|
3304
3282
|
};
|
|
3305
|
-
//
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3283
|
+
// Run after layout so menu dimensions are correct (double rAF for paint)
|
|
3284
|
+
let cancelled = false;
|
|
3285
|
+
const scheduleUpdate = () => {
|
|
3286
|
+
requestAnimationFrame(() => {
|
|
3287
|
+
requestAnimationFrame(() => {
|
|
3288
|
+
if (!cancelled &&
|
|
3289
|
+
dropdownRef.current &&
|
|
3290
|
+
menuRef.current) {
|
|
3291
|
+
calculatePosition();
|
|
3292
|
+
}
|
|
3293
|
+
});
|
|
3294
|
+
});
|
|
3295
|
+
};
|
|
3296
|
+
scheduleUpdate();
|
|
3297
|
+
const handleResize = () => scheduleUpdate();
|
|
3298
|
+
const handleScroll = () => scheduleUpdate();
|
|
3310
3299
|
window.addEventListener("resize", handleResize);
|
|
3311
3300
|
window.addEventListener("scroll", handleScroll, true);
|
|
3312
3301
|
return () => {
|
|
3302
|
+
cancelled = true;
|
|
3313
3303
|
window.removeEventListener("resize", handleResize);
|
|
3314
3304
|
window.removeEventListener("scroll", handleScroll, true);
|
|
3315
3305
|
};
|