mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-09 11:14:29 +02:00
Doesn't clear the value from the constraint input value popover if you close it and then re-open. In other words, if you accidentally click out, you don't lose your progress. Instead, the popover will open again, with the value you had when you closed it highlighted (so that it's easy to type over if you want to): <img width="452" alt="image" src="https://github.com/user-attachments/assets/d86aa00e-4956-40a8-8fea-e75be5d5425b" /> The reason I'm changing this now is because I noticed that the error wasn't cleared correctly when the popover was closed. If we do it this way instead, then that makes sense, because you can still see the value. This is also how the single-value popover has worked forever. From some quick testing, the single value popover still works as expected: <img width="562" alt="image" src="https://github.com/user-attachments/assets/9041a922-b055-4310-ab60-93ad219981a4" /> As a side note: I'm adding a comment to anyone coming after as to why focus handling on escape doesn't work correctly on the single value button. I was about to go down a rabbit hole on that before I read my own comment on the previous PR. So I thought I'd put that here too.
155 lines
4.7 KiB
TypeScript
155 lines
4.7 KiB
TypeScript
import {
|
|
Button,
|
|
ClickAwayListener,
|
|
type InputBaseComponentProps,
|
|
Popover,
|
|
styled,
|
|
TextField,
|
|
} from '@mui/material';
|
|
import { ScreenReaderOnly } from 'component/common/ScreenReaderOnly/ScreenReaderOnly';
|
|
import { type FC, useId, useRef, useState } from 'react';
|
|
|
|
const StyledPopover = styled(Popover)(({ theme }) => ({
|
|
'& .MuiPaper-root': {
|
|
borderRadius: theme.shape.borderRadiusLarge,
|
|
border: `1px solid ${theme.palette.divider}`,
|
|
padding: theme.spacing(2),
|
|
width: '250px',
|
|
},
|
|
|
|
'&.MuiPopover-root': {
|
|
pointerEvents: 'none',
|
|
},
|
|
|
|
'& .MuiPopover-paper': {
|
|
pointerEvents: 'all',
|
|
},
|
|
}));
|
|
|
|
const StyledTextField = styled(TextField)(({ theme }) => ({
|
|
flexGrow: 1,
|
|
}));
|
|
|
|
const InputRow = styled('div')(({ theme }) => ({
|
|
display: 'flex',
|
|
gap: theme.spacing(1),
|
|
alignItems: 'start',
|
|
width: '100%',
|
|
}));
|
|
|
|
export type OnAddActions = {
|
|
setError: (error: string) => void;
|
|
clearInput: () => void;
|
|
};
|
|
|
|
type AddValuesProps = {
|
|
onAdd: (newValue: string, actions: OnAddActions) => void;
|
|
initialValue?: string;
|
|
open: boolean;
|
|
anchorEl: HTMLElement | null;
|
|
onClose: () => void;
|
|
helpText?: string;
|
|
inputProps?: InputBaseComponentProps;
|
|
};
|
|
|
|
const HelpText = styled('p')(({ theme }) => ({
|
|
color: theme.palette.text.secondary,
|
|
fontSize: theme.typography.caption.fontSize,
|
|
}));
|
|
|
|
const AddButton = styled(Button)(({ theme }) => ({
|
|
minWidth: theme.spacing(4),
|
|
}));
|
|
|
|
export const AddValuesPopover: FC<AddValuesProps> = ({
|
|
initialValue,
|
|
onAdd,
|
|
anchorEl,
|
|
open,
|
|
onClose,
|
|
helpText,
|
|
inputProps,
|
|
}) => {
|
|
const [inputValue, setInputValue] = useState(initialValue || '');
|
|
const [error, setError] = useState('');
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
const inputId = useId();
|
|
const helpTextId = useId();
|
|
|
|
return (
|
|
<StyledPopover
|
|
open={open}
|
|
onTransitionEnter={() => {
|
|
inputRef?.current?.select();
|
|
}}
|
|
disableScrollLock
|
|
anchorEl={anchorEl}
|
|
onClose={onClose}
|
|
anchorOrigin={{
|
|
vertical: 'bottom',
|
|
horizontal: 'left',
|
|
}}
|
|
transformOrigin={{
|
|
vertical: 'top',
|
|
horizontal: 'left',
|
|
}}
|
|
>
|
|
<ClickAwayListener onClickAway={onClose}>
|
|
<form
|
|
onSubmit={(e) => {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
if (!inputValue?.trim()) {
|
|
setError('Value cannot be empty or whitespace');
|
|
return;
|
|
} else {
|
|
onAdd(inputValue, {
|
|
setError,
|
|
clearInput: () => setInputValue(''),
|
|
});
|
|
}
|
|
}}
|
|
>
|
|
<InputRow>
|
|
<ScreenReaderOnly>
|
|
<label htmlFor={inputId}>Constraint Value</label>
|
|
</ScreenReaderOnly>
|
|
<StyledTextField
|
|
id={inputId}
|
|
placeholder='Enter value'
|
|
value={inputValue}
|
|
onChange={(e) => {
|
|
setInputValue(e.target.value);
|
|
setError('');
|
|
}}
|
|
size='small'
|
|
variant='standard'
|
|
fullWidth
|
|
inputRef={inputRef}
|
|
autoFocus
|
|
error={!!error}
|
|
helperText={error}
|
|
aria-describedby={helpTextId}
|
|
inputProps={{
|
|
...inputProps,
|
|
}}
|
|
data-testid='CONSTRAINT_VALUES_INPUT'
|
|
/>
|
|
<AddButton
|
|
variant='text'
|
|
type='submit'
|
|
size='small'
|
|
color='primary'
|
|
disabled={!inputValue?.trim()}
|
|
data-testid='CONSTRAINT_VALUES_ADD_BUTTON'
|
|
>
|
|
Add
|
|
</AddButton>
|
|
</InputRow>
|
|
<HelpText id={helpTextId}>{helpText}</HelpText>
|
|
</form>
|
|
</ClickAwayListener>
|
|
</StyledPopover>
|
|
);
|
|
};
|