Skip to content

Commit

Permalink
feat(Keyboard): begin integrating keyboard shortcuts
Browse files Browse the repository at this point in the history
  • Loading branch information
maxpatiiuk committed Jul 14, 2024
1 parent 6f101d8 commit d19d3ec
Show file tree
Hide file tree
Showing 20 changed files with 355 additions and 222 deletions.
57 changes: 43 additions & 14 deletions specifyweb/frontend/js_src/lib/components/Atoms/DataEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { AnySchema } from '../DataModel/helperTypes';
import type { SpecifyResource } from '../DataModel/legacyTypes';
import type { ViewDescription } from '../FormParse';
import type { cellAlign, cellVerticalAlign } from '../FormParse/cells';
import { userPreferences } from '../Preferences/userPreferences';
import { Button } from './Button';
import { className } from './className';
import type { icons } from './Icons';
Expand All @@ -19,23 +20,24 @@ const dataEntryButton = (
className: string,
title: LocalizedString,
icon: keyof typeof icons
) =>
function (
) => {
const component = (
props: Omit<TagProps<'button'>, 'children' | 'type'> & {
readonly onClick:
| ((event: React.MouseEvent<HTMLButtonElement>) => void)
| undefined;
}
): JSX.Element {
return (
<Button.Icon
className={`${className} ${props.className ?? ''}`}
icon={icon}
title={title}
{...props}
/>
);
};
): JSX.Element => (
<Button.Icon
className={`${className} ${props.className ?? ''}`}
icon={icon}
title={title}
{...props}
/>
);
Object.defineProperty(component, 'name', { value: icon });
return component;
};

export const columnDefinitionsToCss = (
columns: RA<number | undefined>,
Expand All @@ -54,6 +56,12 @@ export const columnDefinitionsToCss = (
* This is called DataEntry instead of Form because "Form" is already taken
*/

const DataEntryAdd = dataEntryButton(
className.dataEntryAdd,
commonText.add(),
'plus'
);

export const DataEntry = {
Grid: wrap<
'div',
Expand Down Expand Up @@ -145,7 +153,29 @@ export const DataEntry = {
})
),
SubFormTitle: wrap('DataEntry.SubFormTitle', 'h3', className.formTitle),
Add: dataEntryButton(className.dataEntryAdd, commonText.add(), 'plus'),
Add({
enableShortcut,
onClick: handleClick,
title = commonText.add(),
...rest
}: Omit<Parameters<typeof DataEntryAdd>[0], 'onClick'> & {
readonly onClick: (() => void) | undefined;
readonly enableShortcut: boolean;
}): JSX.Element {
const addButtonShortcut = userPreferences.useKeyboardShortcut(
'form',
'recordSet',
'addResource',
enableShortcut && rest.disabled !== true ? handleClick : undefined
);
return (
<DataEntryAdd
title={`${title}${addButtonShortcut}`}
onClick={handleClick}
{...rest}
/>
);
},
View: dataEntryButton(className.dataEntryView, commonText.view(), 'eye'),
Edit: dataEntryButton(className.dataEntryEdit, commonText.edit(), 'pencil'),
Clone: dataEntryButton(
Expand Down Expand Up @@ -180,4 +210,3 @@ export const DataEntry = {
) : null;
},
};
/* eslint-enable @typescript-eslint/naming-convention */
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ snapshot(DataEntry.Footer, { children: 'Test' });
snapshot(DataEntry.SubForm, { children: 'Test' });
snapshot(DataEntry.SubFormHeader, { children: 'Test' });
snapshot(DataEntry.SubFormTitle, { children: 'Test' });
snapshot(DataEntry.Add, { onClick: f.never });
snapshot(DataEntry.Add, { onClick: f.never, enableShortcut: true });
snapshot(DataEntry.View, { onClick: f.never });
snapshot(DataEntry.Edit, { onClick: f.never });
snapshot(DataEntry.Clone, { onClick: f.never });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[` renders without errors 1`] = `
exports[`Add renders without errors 1`] = `
<DocumentFragment>
<button
aria-label="Add"
aria-label="Add (A)"
class="icon link rounded !text-green-700 print:hidden "
title="Add"
title="Add (A)"
type="button"
>
<svg
Expand All @@ -25,133 +25,6 @@ exports[` renders without errors 1`] = `
</DocumentFragment>
`;

exports[` renders without errors 2`] = `
<DocumentFragment>
<button
aria-label="View"
class="icon link rounded !text-cyan-400 print:hidden "
title="View"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 12a2 2 0 100-4 2 2 0 000 4z"
/>
<path
clip-rule="evenodd"
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
fill-rule="evenodd"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[` renders without errors 3`] = `
<DocumentFragment>
<button
aria-label="Edit"
class="icon link rounded !text-orange-400 print:hidden "
title="Edit"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[` renders without errors 4`] = `
<DocumentFragment>
<button
aria-label="Clone"
class="icon link rounded !text-amber-700 print:hidden "
title="Clone"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"
/>
<path
d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[` renders without errors 5`] = `
<DocumentFragment>
<button
aria-label="Search"
class="icon link rounded !text-blue-500 print:hidden "
title="Search"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
fill-rule="evenodd"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[` renders without errors 6`] = `
<DocumentFragment>
<button
aria-label="Remove"
class="icon link rounded !text-red-700 print:hidden "
title="Remove"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
fill-rule="evenodd"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[`DataEntry.Cell colspan 1, align right, self stretch 1`] = `
<DocumentFragment>
<div
Expand Down Expand Up @@ -297,3 +170,130 @@ exports[`DataEntry.visit no resource 2`] = `
</a>
</DocumentFragment>
`;

exports[`clipboard renders without errors 1`] = `
<DocumentFragment>
<button
aria-label="Clone"
class="icon link rounded !text-amber-700 print:hidden "
title="Clone"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"
/>
<path
d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[`eye renders without errors 1`] = `
<DocumentFragment>
<button
aria-label="View"
class="icon link rounded !text-cyan-400 print:hidden "
title="View"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 12a2 2 0 100-4 2 2 0 000 4z"
/>
<path
clip-rule="evenodd"
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
fill-rule="evenodd"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[`minus renders without errors 1`] = `
<DocumentFragment>
<button
aria-label="Remove"
class="icon link rounded !text-red-700 print:hidden "
title="Remove"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
fill-rule="evenodd"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[`pencil renders without errors 1`] = `
<DocumentFragment>
<button
aria-label="Edit"
class="icon link rounded !text-orange-400 print:hidden "
title="Edit"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z"
/>
</svg>
</button>
</DocumentFragment>
`;

exports[`search renders without errors 1`] = `
<DocumentFragment>
<button
aria-label="Search"
class="icon link rounded !text-blue-500 print:hidden "
title="Search"
type="button"
>
<svg
aria-hidden="true"
class="w-6 h-6 flex-shrink-0"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
fill-rule="evenodd"
/>
</svg>
</button>
</DocumentFragment>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ exports[`H3 renders without errors 1`] = `
exports[`Key renders without errors 1`] = `
<DocumentFragment>
<kbd
class="bg-gray-200 border-1 dark:border-none dark:bg-neutral-700 rounded-sm mx-1 p-0.5"
class="bg-gray-200 border-1 dark:border-none dark:bg-neutral-700 rounded-sm mx-1 p-0.5 text-xl"
>
View
</kbd>
Expand Down
Loading

0 comments on commit d19d3ec

Please sign in to comment.