Skip to content

Commit

Permalink
Implement props.doubleClickToEdit in InputText
Browse files Browse the repository at this point in the history
…plus add a storybook story to cover the behavior and add the prop type to the docs
  • Loading branch information
acusti committed Jan 9, 2024
1 parent 80941d8 commit d792047
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 15 deletions.
4 changes: 2 additions & 2 deletions packages/css-value-input/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ yarn add @acusti/css-value-input

### Props

This is the type signature for the props you can pass to `CSSValueInput`. The
unique features provided by the component are called out and explained
This is the type signature for the props you can pass to `CSSValueInput`.
The unique features provided by the component are called out and explained
above the corresponding prop via JSDoc comments:

```ts
Expand Down
8 changes: 4 additions & 4 deletions packages/css-value-input/src/CSSValueInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@ export default React.forwardRef<HTMLInputElement, Props>(function CSSValueInput(
// ensures that submitting a new value with no unit doesn’t add a unit
const defaultUnit = unit
? getUnitFromCSSValue({
cssValueType,
defaultUnit: unit,
value: submittedValueRef.current,
})
cssValueType,
defaultUnit: unit,
value: submittedValueRef.current,
})
: '';

if (!isCurrentValueFinite) {
Expand Down
10 changes: 9 additions & 1 deletion packages/docs/stories/InputText.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export const MultiLineInputWithInitialValueAndSelectTextOnFocus: Story = {
},
};

// TODO how do i wrap this in a <form onSubmit={() => {console.log('form submitted')}}>?
const SUBMIT_ON_ENTER_PROPS = {
className: 'multi-line-input-text',
maxHeight: 600,
Expand Down Expand Up @@ -103,3 +102,12 @@ export const MultiLineInputWithSubmitOnEnterNoForm: Story = {
name: SUBMIT_ON_ENTER_PROPS.name + '-no-form',
},
};

export const InputWithDoubleClickToEdit: Story = {
args: {
className: 'input-text-double-click-to-edit',
doubleClickToEdit: true,
initialValue: 'Lorem ipsum dolor sit amet',
name: 'double-click-to-edit-input',
},
};
10 changes: 5 additions & 5 deletions packages/dropdown/src/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type MousePosition = { clientX: number; clientY: number };

const { Children, Fragment, useCallback, useEffect, useMemo, useRef, useState } = React;

const noop = () => { }; // eslint-disable-line @typescript-eslint/no-empty-function
const noop = () => {}; // eslint-disable-line @typescript-eslint/no-empty-function

const CHILDREN_ERROR =
'@acusti/dropdown requires either 1 child (the dropdown body) or 2 children: the dropdown trigger and the dropdown body.';
Expand Down Expand Up @@ -679,13 +679,13 @@ export default function Dropdown({
...styleFromProps,
...(outOfBounds.maxHeight
? {
[BODY_MAX_HEIGHT_VAR]: `calc(${outOfBounds.maxHeight}px - var(--uktdd-body-buffer))`,
}
[BODY_MAX_HEIGHT_VAR]: `calc(${outOfBounds.maxHeight}px - var(--uktdd-body-buffer))`,
}
: null),
...(outOfBounds.maxWidth
? {
[BODY_MAX_WIDTH_VAR]: `calc(${outOfBounds.maxWidth}px - var(--uktdd-body-buffer))`,
}
[BODY_MAX_WIDTH_VAR]: `calc(${outOfBounds.maxWidth}px - var(--uktdd-body-buffer))`,
}
: null),
}),
[outOfBounds.maxHeight, outOfBounds.maxWidth, styleFromProps],
Expand Down
7 changes: 7 additions & 0 deletions packages/input-text/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ type Props = {
autoComplete?: HTMLInputElement['autocomplete'];
className?: string;
disabled?: boolean;
/**
* If true, input renders as readonly initially and only becomes interactive
* when double-clicked or when user focuses the readonly input and then
* presses the enter key. Likewise, the input becomes readonly again when
* it is blurred or when the user presses enter or escape.
*/
doubleClickToEdit?: boolean;
enterKeyHint?: InputHTMLAttributes<HTMLInputElement>['enterKeyHint'];
form?: string;
/**
Expand Down
34 changes: 31 additions & 3 deletions packages/input-text/src/InputText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ export type Props = {
autoComplete?: HTMLInputElement['autocomplete'];
className?: string;
disabled?: boolean;
/**
* If true, input renders as readonly initially and only becomes interactive
* when double-clicked or when user focuses the readonly input and then
* presses the enter key. Likewise, the input becomes readonly again when
* it is blurred or when the user presses enter or escape.
*/
doubleClickToEdit?: boolean;
enterKeyHint?: InputHTMLAttributes<HTMLInputElement>['enterKeyHint'];
form?: string;
/**
Expand Down Expand Up @@ -62,6 +69,7 @@ export default React.forwardRef<HTMLInputElement, Props>(function InputText(
autoComplete,
className,
disabled,
doubleClickToEdit,
enterKeyHint,
form,
initialValue,
Expand Down Expand Up @@ -109,17 +117,28 @@ export default React.forwardRef<HTMLInputElement, Props>(function InputText(
inputRef.current.value = initialValue ?? '';
}, [initialValue]);

const [readOnlyState, setReadOnlyState] = useState<boolean | undefined>(
readOnly ?? doubleClickToEdit,
);
const isInitialSelectionRef = useRef<boolean>(true);

const startEditing = useCallback(() => {
if (!doubleClickToEdit) return;
setReadOnlyState(false);
}, [doubleClickToEdit]);

const handleBlur = useCallback(
(event: React.FocusEvent<HTMLInputElement>) => {
if (onBlur) onBlur(event);
if (doubleClickToEdit) {
setReadOnlyState(true);
}
if (!selectTextOnFocus) return;
setInputElement(event.currentTarget);
// When input loses focus, reset isInitialSelection to true for next onSelect event
isInitialSelectionRef.current = true;
},
[onBlur, selectTextOnFocus, setInputElement],
[doubleClickToEdit, onBlur, selectTextOnFocus, setInputElement],
);

const setInputHeight = useCallback(() => {
Expand Down Expand Up @@ -185,9 +204,17 @@ export default React.forwardRef<HTMLInputElement, Props>(function InputText(
// if no form to submit, trigger input blur
event.currentTarget.blur();
}
} else if (doubleClickToEdit && inputRef.current) {
if (readOnlyState) {
if (event.key === 'Enter') {
setReadOnlyState(false);
}
} else if (event.key === 'Enter' || event.key === 'Escape') {
inputRef.current.blur();
}
}
},
[multiLine, onKeyDown, submitOnEnter],
[doubleClickToEdit, multiLine, onKeyDown, readOnlyState, submitOnEnter],
);

// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
Expand All @@ -209,13 +236,14 @@ export default React.forwardRef<HTMLInputElement, Props>(function InputText(
name={name}
onBlur={handleBlur}
onChange={onChange}
onDoubleClick={startEditing}
onFocus={onFocus}
onKeyDown={handleKeyDown}
onKeyUp={onKeyUp}
onSelect={handleSelect}
pattern={pattern}
placeholder={placeholder}
readOnly={readOnly}
readOnly={readOnlyState}
ref={setInputElement}
required={required}
size={size}
Expand Down

0 comments on commit d792047

Please sign in to comment.