Skip to content

Commit

Permalink
feat: Survey 10146 input auto focus (#369)
Browse files Browse the repository at this point in the history
* SURVEY-10146 autofocus on input

---------

Co-authored-by: YLui <[email protected]>
  • Loading branch information
flying3615 and YLui authored Aug 17, 2023
1 parent 0a41297 commit 9714ec7
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 15 deletions.
60 changes: 46 additions & 14 deletions src/components/gridForm/GridFormMultiSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { fromPairs, groupBy, isEmpty, pick, toPairs } from "lodash-es";
import {
import { defer, fromPairs, groupBy, isEmpty, pick, toPairs } from "lodash-es";
import React, {
Dispatch,
ForwardedRef,
Fragment,
KeyboardEvent,
ReactElement,
Expand Down Expand Up @@ -73,6 +74,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow>(props: GridForm

const subComponentIsValidRef = useRef<Record<string, boolean>>({});
const optionsInitialising = useRef(false);
const firstInputSubComponent = useRef<HTMLInputElement | null>(null);

const [filter, setFilter] = useState("");
const [initialValues, setInitialValues] = useState("");
Expand Down Expand Up @@ -191,11 +193,21 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow>(props: GridForm
<MenuDivider key={`div_${index}`} />
) : (
<Fragment key={`val_${item.value}`}>
<MenuRadioItem item={item} options={options} setOptions={setOptions} />

<MenuRadioItem
item={item}
options={options}
setOptions={setOptions}
onChecked={() => {
// Default to focus on first input in subComponent
defer(() => {
firstInputSubComponent.current?.focus();
});
}}
/>
{item.checked && item.subComponent && (
<MenuSubComponent
{...{ item, options, setOptions, data, triggerSave }}
ref={firstInputSubComponent}
subComponentIsValid={subComponentIsValidRef.current}
/>
)}
Expand Down Expand Up @@ -350,6 +362,7 @@ const MenuRadioItem = (props: {
item: MultiSelectOption;
options: MultiSelectOption[];
setOptions: (options: MultiSelectOption[]) => void;
onChecked?: () => void;
}) => {
const { item, options, setOptions } = props;

Expand All @@ -369,6 +382,7 @@ const MenuRadioItem = (props: {
e.keepOpen = true;
toggleValue(item);
}
item.checked && props.onChecked && props.onChecked();
}}
>
<LuiCheckboxInput
Expand All @@ -395,17 +409,35 @@ const MenuRadioItem = (props: {
);
};

const MenuSubComponent = (props: {
data: any;
item: MultiSelectOption;
options: MultiSelectOption[];
setOptions: (options: MultiSelectOption[]) => void;
subComponentIsValid: Record<string, boolean>;
triggerSave: () => Promise<void>;
}) => {
const MenuSubComponent = React.forwardRef(MenuSubComponentFr);

function MenuSubComponentFr(
props: {
data: any;
item: MultiSelectOption;
options: MultiSelectOption[];
setOptions: (options: MultiSelectOption[]) => void;
subComponentIsValid: Record<string, boolean>;
triggerSave: () => Promise<void>;
},
ref: ForwardedRef<HTMLInputElement>,
) {
const { data, item, options, setOptions, subComponentIsValid, triggerSave } = props;
const focusableRef = React.useRef<HTMLElement | null>(null);

useEffect(() => {
if (focusableRef.current) {
const firstInputElement = focusableRef.current.querySelectorAll("input")[0] ?? null;
if (typeof ref === "function") {
ref(firstInputElement);
} else if (ref) {
ref.current = firstInputElement;
}
}
}, [ref]);

return (
<FocusableItem className={"LuiDeprecatedForms"} key={`${item.value}_subcomponent`}>
<FocusableItem className={"LuiDeprecatedForms"} key={`${item.value}_subcomponent`} ref={focusableRef}>
{() => (
<GridSubComponentContext.Provider
value={{
Expand All @@ -427,4 +459,4 @@ const MenuSubComponent = (props: {
)}
</FocusableItem>
);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ GridFormMultiSelectInteractions_.play = async ({ canvasElement }) => {
expect(textInput).toBeInTheDocument();
expect(await canvas.findByText("Must not be empty")).toBeInTheDocument();

await userEvent.click(textInput);
// textInput should be autofocus
await userEvent.type(textInput, "Hello");
expect(await canvas.findByText("Press enter or tab to save")).toBeInTheDocument();

Expand Down

0 comments on commit 9714ec7

Please sign in to comment.