Fix CustomSelect panel to left-align by default, right-align only when it would overflow the viewport

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Fraxle
2026-05-26 17:09:17 +01:00
co-authored by Claude Sonnet 4.6
parent 90789b5f47
commit d2952cddd2
2 changed files with 21 additions and 4 deletions
+8 -2
View File
@@ -475,8 +475,8 @@
.cs-panel { .cs-panel {
position: absolute; position: absolute;
top: calc(100% + 4px); top: calc(100% + 4px);
right: 0; /* right edge flushes with button's right edge */ left: 0; /* left edge flushes with button's left edge by default */
left: auto; right: auto;
z-index: 1000; z-index: 1000;
background: #fffcf2; background: #fffcf2;
border: 1.5px solid #c9b08a; border: 1.5px solid #c9b08a;
@@ -487,6 +487,12 @@
overflow: hidden; overflow: hidden;
} }
/* Flip panel to right-align when left-align would overflow the viewport */
.cs-panel.cs-panel--right {
left: auto;
right: 0;
}
/* Each option row */ /* Each option row */
.cs-option { .cs-option {
display: block; display: block;
+13 -2
View File
@@ -41,7 +41,9 @@ const html = htm.bind(h);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel, buttonLabel, isOn, noHide, groupedLeft, isLastChild, grpClass }) { export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel, buttonLabel, isOn, noHide, groupedLeft, isLastChild, grpClass }) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const wrapRef = useRef(null); const [flipRight, setFlipRight] = useState(false);
const wrapRef = useRef(null);
const panelRef = useRef(null);
// Close on outside click or Escape // Close on outside click or Escape
useEffect(() => { useEffect(() => {
@@ -60,6 +62,15 @@ export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel,
}; };
}, [open]); }, [open]);
// After the panel renders, check if it overflows the right viewport edge.
// If so, flip it to right-align; otherwise keep it left-aligned.
useEffect(() => {
if (!open) { setFlipRight(false); return; }
if (!panelRef.current) return;
const rect = panelRef.current.getBoundingClientRect();
setFlipRight(rect.right > window.innerWidth - 8);
}, [open]);
// Build the label shown on the button // Build the label shown on the button
const activeOpt = options.find(o => o.value === value); const activeOpt = options.find(o => o.value === value);
const btnLabel = buttonLabel || (isOn const btnLabel = buttonLabel || (isOn
@@ -85,7 +96,7 @@ export function CustomSelect({ value, options, onChange, hideLabel, hidingLabel,
<span class="cs-arrow"></span> <span class="cs-arrow"></span>
</button> </button>
${open && html` ${open && html`
<div class="cs-panel" role="listbox"> <div class=${`cs-panel${flipRight ? ' cs-panel--right' : ''}`} ref=${panelRef} role="listbox">
${isOn && !noHide && html` ${isOn && !noHide && html`
<span <span
class="cs-option" class="cs-option"