DatePickerWithInput: use floating-ui so calendar can overflow scroll containers (#83521)

* move DatePickerWithInput to use floating-ui

* remove position: absolute from DatePicker, remove unnecessary css from CreateTokenModal
This commit is contained in:
Ashley Harrison 2024-02-28 09:45:11 +00:00 committed by GitHub
parent 738e9126de
commit d83319365f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 57 additions and 42 deletions

View File

@ -4107,12 +4107,6 @@ exports[`better eslint`] = {
"public/app/features/search/utils.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/serviceaccounts/components/CreateTokenModal.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"],
[0, 0, 0, "Styles should be written using objects.", "2"],
[0, 0, 0, "Styles should be written using objects.", "3"]
],
"public/app/features/serviceaccounts/components/ServiceAccountProfile.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"]
],

View File

@ -67,7 +67,6 @@ export const getStyles = (theme: GrafanaTheme2) => {
return {
modal: css({
zIndex: theme.zIndex.modal,
position: 'absolute',
boxShadow: theme.shadows.z3,
backgroundColor: theme.colors.background.primary,
border: `1px solid ${theme.colors.border.weak}`,

View File

@ -1,5 +1,6 @@
import { css } from '@emotion/css';
import React, { ChangeEvent } from 'react';
import { autoUpdate, flip, shift, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
import React, { ChangeEvent, useState } from 'react';
import { dateTime } from '@grafana/data';
@ -35,17 +36,41 @@ export const DatePickerWithInput = ({
placeholder = 'Date',
...rest
}: DatePickerWithInputProps) => {
const [open, setOpen] = React.useState(false);
const [open, setOpen] = useState(false);
const styles = useStyles2(getStyles);
// the order of middleware is important!
// see https://floating-ui.com/docs/arrow#order
const middleware = [
flip({
// see https://floating-ui.com/docs/flip#combining-with-shift
crossAxis: false,
boundary: document.body,
}),
shift(),
];
const { context, refs, floatingStyles } = useFloating({
open,
placement: 'bottom-start',
onOpenChange: setOpen,
middleware,
whileElementsMounted: autoUpdate,
strategy: 'fixed',
});
const click = useClick(context);
const dismiss = useDismiss(context);
const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, click]);
return (
<div className={styles.container}>
<Input
ref={refs.setReference}
type="text"
autoComplete={'off'}
placeholder={placeholder}
value={value ? formatDate(value) : value}
onClick={() => setOpen(true)}
onChange={(ev: ChangeEvent<HTMLInputElement>) => {
// Allow resetting the date
if (ev.target.value === '') {
@ -54,20 +79,23 @@ export const DatePickerWithInput = ({
}}
className={styles.input}
{...rest}
{...getReferenceProps()}
/>
<DatePicker
isOpen={open}
value={value && typeof value !== 'string' ? value : dateTime().toDate()}
minDate={minDate}
maxDate={maxDate}
onChange={(ev) => {
onChange(ev);
if (closeOnSelect) {
setOpen(false);
}
}}
onClose={() => setOpen(false)}
/>
<div className={styles.popover} ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
<DatePicker
isOpen={open}
value={value && typeof value !== 'string' ? value : dateTime().toDate()}
minDate={minDate}
maxDate={maxDate}
onChange={(ev) => {
onChange(ev);
if (closeOnSelect) {
setOpen(false);
}
}}
onClose={() => setOpen(false)}
/>
</div>
</div>
);
};
@ -84,5 +112,8 @@ const getStyles = () => {
WebkitAppearance: 'none',
},
}),
popover: css({
zIndex: 1,
}),
};
};

View File

@ -84,13 +84,7 @@ export const CreateTokenModal = ({ isOpen, token, serviceAccountLogin, onCreateT
const modalTitle = !token ? 'Add service account token' : 'Service account token created';
return (
<Modal
isOpen={isOpen}
title={modalTitle}
onDismiss={onCloseInternal}
className={styles.modal}
contentClassName={styles.modalContent}
>
<Modal isOpen={isOpen} title={modalTitle} onDismiss={onCloseInternal} className={styles.modal}>
{!token ? (
<div>
<Field
@ -176,17 +170,14 @@ const getSecondsToLive = (date: Date | string) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
modal: css`
width: 550px;
`,
modalContent: css`
overflow: visible;
`,
modalTokenRow: css`
display: flex;
`,
modalCopyToClipboardButton: css`
margin-left: ${theme.spacing(0.5)};
`,
modal: css({
width: '550px',
}),
modalTokenRow: css({
display: 'flex',
}),
modalCopyToClipboardButton: css({
marginLeft: theme.spacing(0.5),
}),
};
};