Fix Firefox DatePicker popup positioning at top-left
When Firefox input variant falls through to button variant, the positioning logic, close handler, and click-outside handler still checked variant==='input' and used wrapperRef (which is unattached). Introduced usesNativeInput flag (input variant + not Firefox) so all three handlers correctly use triggerRef for Firefox fallback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e7979afba3
commit
63b3a3a073
@ -144,8 +144,10 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
|
|||||||
}, [value, open]);
|
}, [value, open]);
|
||||||
|
|
||||||
// Position popup
|
// Position popup
|
||||||
|
// Firefox + input variant falls through to button variant, so use triggerRef
|
||||||
|
const usesNativeInput = variant === 'input' && !isFirefox;
|
||||||
const updatePosition = React.useCallback(() => {
|
const updatePosition = React.useCallback(() => {
|
||||||
const el = variant === 'input' ? wrapperRef.current : triggerRef.current;
|
const el = usesNativeInput ? wrapperRef.current : triggerRef.current;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const popupHeight = mode === 'datetime' ? 370 : 320;
|
const popupHeight = mode === 'datetime' ? 370 : 320;
|
||||||
@ -156,7 +158,7 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
|
|||||||
top: flipped ? rect.top - popupHeight - 4 : rect.bottom + 4,
|
top: flipped ? rect.top - popupHeight - 4 : rect.bottom + 4,
|
||||||
left: Math.min(rect.left, window.innerWidth - 290),
|
left: Math.min(rect.left, window.innerWidth - 290),
|
||||||
});
|
});
|
||||||
}, [mode, variant]);
|
}, [mode, usesNativeInput]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
@ -172,13 +174,13 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
|
|||||||
const closePopup = React.useCallback(
|
const closePopup = React.useCallback(
|
||||||
(refocusTrigger = true) => {
|
(refocusTrigger = true) => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
if (variant === 'button') {
|
if (!usesNativeInput) {
|
||||||
onBlur?.();
|
onBlur?.();
|
||||||
} else if (refocusTrigger) {
|
} else if (refocusTrigger) {
|
||||||
setTimeout(() => inputElRef.current?.focus(), 0);
|
setTimeout(() => inputElRef.current?.focus(), 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[variant, onBlur]
|
[usesNativeInput, onBlur]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Dismiss on click outside
|
// Dismiss on click outside
|
||||||
@ -186,13 +188,13 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
|
|||||||
if (!open) return;
|
if (!open) return;
|
||||||
const handler = (e: MouseEvent) => {
|
const handler = (e: MouseEvent) => {
|
||||||
if (popupRef.current?.contains(e.target as Node)) return;
|
if (popupRef.current?.contains(e.target as Node)) return;
|
||||||
if (variant === 'button' && triggerRef.current?.contains(e.target as Node)) return;
|
if (!usesNativeInput && triggerRef.current?.contains(e.target as Node)) return;
|
||||||
if (variant === 'input' && wrapperRef.current?.contains(e.target as Node)) return;
|
if (usesNativeInput && wrapperRef.current?.contains(e.target as Node)) return;
|
||||||
closePopup(false);
|
closePopup(false);
|
||||||
};
|
};
|
||||||
document.addEventListener('mousedown', handler);
|
document.addEventListener('mousedown', handler);
|
||||||
return () => document.removeEventListener('mousedown', handler);
|
return () => document.removeEventListener('mousedown', handler);
|
||||||
}, [open, variant, closePopup]);
|
}, [open, usesNativeInput, closePopup]);
|
||||||
|
|
||||||
// Dismiss on Escape
|
// Dismiss on Escape
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user