mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-30 13:42:01 +03:00
Add arrow up/down+enter navigation to select relation (#275)
* Add arrow up/down+enter navigation to select relation
This commit is contained in:
parent
be863a22c9
commit
3341539eb2
@ -1,4 +1,5 @@
|
|||||||
import { ChangeEvent, ComponentType, useEffect, useState } from 'react';
|
import { ChangeEvent, ComponentType, useEffect, useState } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { FaPlus } from 'react-icons/fa';
|
import { FaPlus } from 'react-icons/fa';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
@ -58,12 +59,21 @@ const StyledEditModeResults = styled.div`
|
|||||||
padding-right: ${(props) => props.theme.spacing(1)};
|
padding-right: ${(props) => props.theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledEditModeResultItem = styled.div`
|
type StyledEditModeResultItemProps = {
|
||||||
|
isSelected: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledEditModeResultItem = styled.div<StyledEditModeResultItemProps>`
|
||||||
height: 32px;
|
height: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
${(props) =>
|
||||||
|
props.isSelected &&
|
||||||
|
`
|
||||||
|
background-color: ${props.theme.tertiaryBackground};
|
||||||
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledCreateButtonIcon = styled.div`
|
const StyledCreateButtonIcon = styled.div`
|
||||||
@ -139,6 +149,72 @@ export function EditableRelation<
|
|||||||
setIsSomeInputInEditMode(false);
|
setIsSomeInputInEditMode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||||
|
useHotkeys(
|
||||||
|
'down',
|
||||||
|
() => {
|
||||||
|
setSelectedIndex((prevSelectedIndex) =>
|
||||||
|
Math.min(
|
||||||
|
prevSelectedIndex + 1,
|
||||||
|
(filterSearchResults.results?.length ?? 0) - 1,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enableOnContentEditable: true,
|
||||||
|
enableOnFormTags: true,
|
||||||
|
preventDefault: true,
|
||||||
|
},
|
||||||
|
[setSelectedIndex, filterSearchResults.results],
|
||||||
|
);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
'up',
|
||||||
|
() => {
|
||||||
|
setSelectedIndex((prevSelectedIndex) =>
|
||||||
|
Math.max(prevSelectedIndex - 1, 0),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enableOnContentEditable: true,
|
||||||
|
enableOnFormTags: true,
|
||||||
|
preventDefault: true,
|
||||||
|
},
|
||||||
|
[setSelectedIndex],
|
||||||
|
);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
'enter',
|
||||||
|
() => {
|
||||||
|
if (isEditMode) {
|
||||||
|
if (
|
||||||
|
filterSearchResults.results &&
|
||||||
|
selectedIndex < filterSearchResults.results.length
|
||||||
|
) {
|
||||||
|
const selectedResult = filterSearchResults.results[selectedIndex];
|
||||||
|
onChange(selectedResult.value);
|
||||||
|
closeEditMode();
|
||||||
|
} else if (canCreate && isNonEmptyString(searchInput)) {
|
||||||
|
onCreate(searchInput);
|
||||||
|
closeEditMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enableOnContentEditable: true,
|
||||||
|
enableOnFormTags: true,
|
||||||
|
},
|
||||||
|
[
|
||||||
|
filterSearchResults.results,
|
||||||
|
selectedIndex,
|
||||||
|
onChange,
|
||||||
|
closeEditMode,
|
||||||
|
canCreate,
|
||||||
|
searchInput,
|
||||||
|
onCreate,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EditableCell
|
<EditableCell
|
||||||
@ -188,6 +264,7 @@ export function EditableRelation<
|
|||||||
filterSearchResults.results.map((result, index) => (
|
filterSearchResults.results.map((result, index) => (
|
||||||
<StyledEditModeResultItem
|
<StyledEditModeResultItem
|
||||||
key={index}
|
key={index}
|
||||||
|
isSelected={index === selectedIndex}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onChange(result.value);
|
onChange(result.value);
|
||||||
closeEditMode();
|
closeEditMode();
|
||||||
|
@ -151,3 +151,58 @@ export const EditRelation: Story = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SelectRelationWithKeys: Story = {
|
||||||
|
render,
|
||||||
|
play: async ({ canvasElement }) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
|
const thirdRowCompanyCell = await canvas.findByText(
|
||||||
|
mockedPeopleData[2].company.name,
|
||||||
|
);
|
||||||
|
|
||||||
|
await userEvent.click(thirdRowCompanyCell);
|
||||||
|
|
||||||
|
const relationInput = await canvas.findByPlaceholderText('Company');
|
||||||
|
|
||||||
|
await userEvent.type(relationInput, 'Air', {
|
||||||
|
delay: 200,
|
||||||
|
});
|
||||||
|
|
||||||
|
await userEvent.type(relationInput, '{arrowdown}');
|
||||||
|
await userEvent.type(relationInput, '{arrowdown}');
|
||||||
|
await userEvent.type(relationInput, '{arrowup}');
|
||||||
|
await userEvent.type(relationInput, '{arrowdown}');
|
||||||
|
await userEvent.type(relationInput, '{enter}');
|
||||||
|
|
||||||
|
const newThirdRowCompanyCell = await canvas.findByText('Aircall');
|
||||||
|
await userEvent.click(newThirdRowCompanyCell);
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
actions: {},
|
||||||
|
msw: [
|
||||||
|
...graphqlMocks.filter((graphqlMock) => {
|
||||||
|
return graphqlMock.info.operationName !== 'UpdatePeople';
|
||||||
|
}),
|
||||||
|
...[
|
||||||
|
graphql.mutation('UpdatePeople', (req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.data({
|
||||||
|
updateOnePerson: {
|
||||||
|
...fetchOneFromData(mockedPeopleData, req.variables.id),
|
||||||
|
...{
|
||||||
|
company: {
|
||||||
|
id: req.variables.companyId,
|
||||||
|
name: 'Aircall',
|
||||||
|
domainName: 'aircall.io',
|
||||||
|
__typename: 'Company',
|
||||||
|
} satisfies GraphqlQueryCompany,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user