Delete key/value on backspace

This commit is contained in:
Gregory Schier
2023-10-29 10:26:38 -07:00
parent f1260911ea
commit 705e30b6e0
4 changed files with 59 additions and 17 deletions

View File

@@ -37,6 +37,7 @@ export interface EditorProps {
onFocus?: () => void;
onBlur?: () => void;
onEnter?: () => void;
onKeyDown?: (e: KeyboardEvent) => void;
singleLine?: boolean;
wrapLines?: boolean;
format?: (v: string) => string;
@@ -60,6 +61,7 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
onChange,
onFocus,
onBlur,
onKeyDown,
onEnter,
className,
singleLine,
@@ -101,6 +103,12 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
handleBlur.current = onBlur;
}, [onBlur]);
// Use ref so we can update the onChange handler without re-initializing the editor
const handleKeyDown = useRef<EditorProps['onKeyDown']>(onKeyDown);
useEffect(() => {
handleKeyDown.current = onKeyDown;
}, [onKeyDown]);
// Update placeholder
const placeholderCompartment = useRef(new Compartment());
useEffect(() => {
@@ -168,6 +176,7 @@ const _Editor = forwardRef<EditorView | undefined, EditorProps>(function Editor(
onChange: handleChange,
onFocus: handleFocus,
onBlur: handleBlur,
onKeyDown: handleKeyDown,
}),
],
});
@@ -242,6 +251,7 @@ function getExtensions({
onChange,
onFocus,
onBlur,
onKeyDown,
onEnter,
}: Pick<EditorProps, 'singleLine' | 'readOnly'> & {
container: HTMLDivElement | null;
@@ -249,6 +259,7 @@ function getExtensions({
onFocus: MutableRefObject<EditorProps['onFocus']>;
onBlur: MutableRefObject<EditorProps['onBlur']>;
onEnter: MutableRefObject<EditorProps['onEnter']>;
onKeyDown: MutableRefObject<EditorProps['onKeyDown']>;
}) {
// TODO: Ensure tooltips render inside the dialog if we are in one.
const parent =
@@ -282,6 +293,7 @@ function getExtensions({
EditorView.domEventHandlers({
focus: onFocus.current,
blur: onBlur.current,
keydown: onKeyDown.current,
}),
// Handle onChange

View File

@@ -7,8 +7,21 @@ import { Editor } from './Editor';
import { IconButton } from './IconButton';
import { HStack, VStack } from './Stacks';
export type InputProps = Omit<HTMLAttributes<HTMLInputElement>, 'onChange' | 'onFocus'> &
Pick<EditorProps, 'contentType' | 'useTemplating' | 'autocomplete' | 'forceUpdateKey' | 'autoFocus' | 'autoSelect' | 'autocompleteVariables'> & {
export type InputProps = Omit<
HTMLAttributes<HTMLInputElement>,
'onChange' | 'onFocus' | 'onKeyDown'
> &
Pick<
EditorProps,
| 'contentType'
| 'useTemplating'
| 'autocomplete'
| 'forceUpdateKey'
| 'autoFocus'
| 'autoSelect'
| 'autocompleteVariables'
| 'onKeyDown'
> & {
name: string;
type?: 'text' | 'password';
label: string;

View File

@@ -132,14 +132,13 @@ export const PairEditor = memo(function PairEditor({
[setPairsAndSave],
);
const handleFocus = useCallback(
(pair: PairContainer) =>
setPairs((pairs) => {
const isLast = pair.id === pairs[pairs.length - 1]?.id;
return isLast ? [...pairs, newPairContainer()] : pairs;
}),
[],
);
const handleFocus = useCallback((pair: PairContainer) => {
return setPairs((pairs) => {
setForceFocusPairId(null);
const isLast = pair.id === pairs[pairs.length - 1]?.id;
return isLast ? [...pairs, newPairContainer()] : pairs;
});
}, []);
// Ensure there's always at least one pair
useEffect(() => {
@@ -177,10 +176,11 @@ export const PairEditor = memo(function PairEditor({
valuePlaceholder={valuePlaceholder}
nameValidate={nameValidate}
valueValidate={valueValidate}
showDelete={!isLast}
onSubmit={handleSubmitRow}
onChange={handleChange}
onFocus={handleFocus}
onDelete={isLast ? undefined : handleDelete}
onDelete={handleDelete}
onEnd={handleEnd}
onMove={handleMove}
/>
@@ -199,6 +199,7 @@ type FormRowProps = {
className?: string;
pairContainer: PairContainer;
forceFocusPairId?: string | null;
showDelete?: boolean;
onMove: (id: string, side: 'above' | 'below') => void;
onEnd: (id: string) => void;
onChange: (pair: PairContainer) => void;
@@ -236,6 +237,7 @@ const FormRow = memo(function FormRow({
onMove,
onSubmit,
pairContainer,
showDelete,
valueAutocomplete,
valuePlaceholder,
valueValidate,
@@ -268,6 +270,20 @@ const FormRow = memo(function FormRow({
const handleFocus = useCallback(() => onFocus?.(pairContainer), [onFocus, pairContainer]);
const handleDelete = useCallback(() => onDelete?.(pairContainer), [onDelete, pairContainer]);
const handleKeyDownName = useMemo(
() => (e: KeyboardEvent) => {
if (
e.key === 'Backspace' &&
pairContainer.pair.name === '' &&
pairContainer.pair.value === ''
) {
e.preventDefault();
onDelete?.(pairContainer);
}
},
[pairContainer, onDelete],
);
const [, connectDrop] = useDrop<PairContainer>(
{
accept: ItemTypes.ROW,
@@ -349,6 +365,7 @@ const FormRow = memo(function FormRow({
defaultValue={pairContainer.pair.name}
label="Name"
name="name"
onKeyDown={handleKeyDownName}
onChange={handleChangeName}
onFocus={handleFocus}
placeholder={namePlaceholder ?? 'name'}
@@ -373,13 +390,13 @@ const FormRow = memo(function FormRow({
/>
</form>
<IconButton
aria-hidden={!onDelete}
disabled={!onDelete}
aria-hidden={!showDelete}
disabled={!showDelete}
color="custom"
icon={onDelete ? 'trash' : 'empty'}
icon={showDelete ? 'trash' : 'empty'}
size="sm"
title="Delete header"
onClick={handleDelete}
onClick={showDelete ? handleDelete : undefined}
className="ml-0.5 !opacity-0 group-hover:!opacity-100 focus-visible:!opacity-100"
/>
</div>