Merge claude/2

This commit is contained in:
librelad 2026-05-22 14:57:59 +01:00
commit c987aefb72
3 changed files with 20 additions and 7 deletions

View File

@ -884,7 +884,7 @@ select.form-control:focus {
animation: customSelectIn 0.12s ease-out;
}
.custom-select.flip-up .custom-select-popup {
.custom-select-popup.flip-up {
transform-origin: bottom center;
}
@ -893,7 +893,7 @@ select.form-control:focus {
to { opacity: 1; transform: translateY(0); }
}
.custom-select.flip-up .custom-select-popup {
.custom-select-popup.flip-up {
animation-name: customSelectInUp;
}

View File

@ -252,6 +252,6 @@
line-height: 1.2;
}
.topbar-controls .custom-select-popup {
.custom-select-popup-topbar {
min-width: 140px;
}

View File

@ -56,10 +56,19 @@
this.popup.className = 'custom-select-popup';
this.popup.setAttribute('role', 'listbox');
this.popup.hidden = true;
// The popup is portaled to <body> on open (below), escaping .topbar-controls,
// so carry the topbar's wider-popup styling via a class instead.
if (this.select.closest('.topbar-controls')) {
this.popup.classList.add('custom-select-popup-topbar');
}
// Move the native select inside the wrapper so it stays in the form.
// Move the native select inside the wrapper so it stays in the form. The
// popup is deliberately NOT added here — it's portaled to <body> on
// open() so no ancestor's transform (e.g. a card's :hover translateY,
// which becomes the containing block for position:fixed) can throw off
// its placement or clip it. See open()/close().
this.select.parentNode.insertBefore(this.wrapper, this.select);
this.wrapper.append(this.select, this.button, this.popup);
this.wrapper.append(this.select, this.button);
this.select.classList.add('custom-select-native');
// Forward width-related layout from the native select to the wrapper.
if (this.select.style.maxWidth) {
@ -105,6 +114,9 @@
document.querySelectorAll('.custom-select.is-open').forEach(w => {
if (w !== this.wrapper) w.dispatchEvent(new CustomEvent('custom-select:close'));
});
// Portal into <body> so position:fixed is relative to the viewport,
// immune to any transformed/overflow ancestor.
document.body.appendChild(this.popup);
this.popup.hidden = false;
this.button.setAttribute('aria-expanded', 'true');
this.wrapper.classList.add('is-open');
@ -124,6 +136,7 @@
close() {
if (this.popup.hidden) return;
this.popup.hidden = true;
this.popup.remove(); // detach from <body> so popups don't accumulate
this.button.setAttribute('aria-expanded', 'false');
this.wrapper.classList.remove('is-open');
this.clearFocused();
@ -141,7 +154,7 @@
const spaceBelow = window.innerHeight - rect.bottom;
const popupMax = 280;
const flipUp = spaceBelow < 200 && rect.top > popupMax;
this.wrapper.classList.toggle('flip-up', flipUp);
this.popup.classList.toggle('flip-up', flipUp);
this.popup.style.left = `${rect.left}px`;
this.popup.style.width = `${rect.width}px`;
@ -222,7 +235,7 @@
};
this._outsideClick = (e) => {
if (!this.wrapper.contains(e.target)) this.close();
if (!this.wrapper.contains(e.target) && !this.popup.contains(e.target)) this.close();
};
this._reposition = () => this.positionPopup();